First let me explain what I'm trying to achieve:
In your browser, hit Ctrl + f and type "q". The result of that operation is what I'm trying to achieve. It seems like this should be a solved problem, but despite the many hours I've spent researching, reading documentation, and asking around in the Qt IRC, I'm still stuck. Maybe somebody here will be able to give me a hand.
The following Qt classes are what I'm currently dealing with, in case you want to brush up a bit.:
Qt::DisplayRole
QModelIndex::data
QAbstractItemView::setDelegate
QTextEdit::setExtraSelections (only as a reference)
QAbstractDocumentLayout::Selection
QTextDocument::drawContents
QStyledItemDelegate::paint
QStyleOptionViewItem
QStyleOption::rect
QTableView
QAbstractItemModel::match
Learn to Model/View Program with Qt
So now, let me explain how I have things set up, and what the results of my research and interactions with the Qt IRC has lead me to believe I should do.
I am using a QStandardItemModel along with a QTableView. Each row that gets appended to the QStandardItemModel has several columns. As we know, each of these columns is represented in the QStandardItemModel as a QModelIndex. We can pull its displayed text by accessing its data(Qt::DisplayRole).
Conveniently, given a search string, QStandardItemModel::match will return a QModelIndexList of every QModelIndex that, well, matched in the column. Of course, if you have several columns in every row, you would need to preform this match over each column, but I can worry about performance here later.
So cool, that problem is solved. We have our list of every QModelIndex that had a matching string. Now, what I want to do is highlight that string in each column. For example:
Search string: "col"
This is a column | This is aColumn | This is aColumn | This is a co
Parts that would appear highlighted are what I have in bold above. In order to achieve this, I knew from reading the Model/View docs that I needed to subclass a QStyledItemDelegate and reimplement its paint function. So I started there.
The next problem to solve would be, how in the world to select a specific piece of text in the DisplayRole and only highlight it? You can't use Qt::BackgroundRole, that would set the entire index's background color. Enter QTextDocument.
I still need to do more digging to see how exactly I can implement that behavior, but from what I was told in Qt IRC, QTextEdit has a function called setExtraSelections. Looking at how that is implemented, it leverages QAbstractTextDocumentLayout::Selection and various cursor functions available to me in QTextDocument.
However, sadly I cannot even begin to solve that problem, because the first step is to actually ensure that I can render a QTextDocument to the QTableView with my reimplemented custom delegate paint function. This is where I'm stuck currently. I've seen this post, here and the one it references:
Similar question that doesn't solve my issue
Its not exactly what I was looking for, but I figured it would help me at least get something rendering. It looks though like in his code, he's drawing the control (which is literally what QStyledItemDelegate does), and then tries to paint his QTextDocument over it. Maybe that's not what that is doing but it sure looks like it.
In any case, when I tried that, it looked like the QTextDocument had no effect. If I commented out the drawControl call, then no text would be rendered at all. Here is my code for that:
void CustomDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
if (index.column() == contentColumn)
{
painter->save();
QTextDocument contentDocument;
//opt.widget->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter);
opt.text = "Things";
painter->setBrush(QBrush(Qt::darkCyan));
contentDocument.drawContents(painter, opt.rect);
painter->restore();
}
else
{
QStyledItemDelegate::paint(painter, option, index);
}
}
You can see I just typed text "Things" to see if I could just get that to render. To no avail.
Before summarizing my question I want to mention that no, I cannot use a QTextEdit. There are specific columns that I need to word wrap, while others I do not want to word wrap. QTableView displays the data exactly as I expect to see it.
So my question is this: Is the QTextDocument rendering through the paint event of a subclassed QStyledItemDelegate the preferred way to handle this? If not, how else should I deal with it?
If so, how do I make it work as I expect? What is wrong with the code that I have?
Bonus 2 parter question Once I can render, how can I actually leverage the QTextDocument API to highlight only specific pieces, given that the list of model indexes that contain the text to be highlighted is discovered in a completely different function and at a different time than when the paint function executes?
Update 0 Using the QTextDocument API to make multiple selections is looking like an impossible feat. The column that I would be drawing contents to needs to word wrap and expand.
From what I can tell, I calling drawContents manually means handling resizing, word wrapping, and many other things manually which is not a path I want to go down if that is indeed the case.
I've got another way in mind, I will update if it works.
Update 1 I have accomplished what I want in another way. Unfortunately, I cannot use Qt for what I want. Qt's Model/View system is entirely too inefficient and getting it to do what I need causes it to be extremely and unacceptably slow. How did I accomplish the highlighting?
I will describe in an answer. If nobody gives me a better answer, I will pick mine as the best.