From 99934fe47293f61e1e62ecc0f0d49f958a992c32 Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Tue, 4 Nov 2008 22:10:48 +0100 Subject: [PATCH] current highlighted search result is no longer reset when the search string changes but still matches --- src/qtui/chatviewsearchcontroller.cpp | 168 +++++++++++++++++++------- src/qtui/chatviewsearchcontroller.h | 4 + 2 files changed, 131 insertions(+), 41 deletions(-) diff --git a/src/qtui/chatviewsearchcontroller.cpp b/src/qtui/chatviewsearchcontroller.cpp index 3828de64..ab270a59 100644 --- a/src/qtui/chatviewsearchcontroller.cpp +++ b/src/qtui/chatviewsearchcontroller.cpp @@ -107,58 +107,138 @@ void ChatViewSearchController::updateHighlights(bool reuse) { if(!_scene) return; + if(reuse) { + QSet chatLines; + foreach(SearchHighlightItem *highlightItem, _highlightItems) { + ChatLine *line = qgraphicsitem_cast(highlightItem->parentItem()); + if(line) + chatLines << line; + } + foreach(ChatLine *line, QList(chatLines.toList())) { + updateHighlights(line); + } + } else { + QPointF oldHighlightPos; + if(!_highlightItems.isEmpty() && _currentHighlight < _highlightItems.count()) { + oldHighlightPos = _highlightItems[_currentHighlight]->scenePos(); + } + qDeleteAll(_highlightItems); + _highlightItems.clear(); + Q_ASSERT(_highlightItems.isEmpty()); + + if(searchString().isEmpty() || !(_searchSenders || _searchMsgs)) + return; + + checkMessagesForHighlight(); + + if(!_highlightItems.isEmpty()) { + if(!oldHighlightPos.isNull()) { + int start = 0; int end = _highlightItems.count() - 1; + QPointF startPos; + QPointF endPos; + while(1) { + startPos = _highlightItems[start]->scenePos(); + endPos = _highlightItems[end]->scenePos(); + if(startPos == oldHighlightPos) { + _currentHighlight = start; + break; + } + if(endPos == oldHighlightPos) { + _currentHighlight = end; + break; + } + if(end - start == 1) { + _currentHighlight = start; + break; + } + int pivot = (end + start) / 2; + QPointF pivotPos = _highlightItems[pivot]->scenePos(); + if(startPos.y() == endPos.y()) { + if(oldHighlightPos.x() <= pivotPos.x()) + end = pivot; + else + start = pivot; + } else { + if(oldHighlightPos.y() <= pivotPos.y()) + end = pivot; + else + start = pivot; + } + } + } else { + _currentHighlight = _highlightItems.count() - 1; + } + _highlightItems[_currentHighlight]->setHighlighted(true); + emit newCurrentHighlight(_highlightItems[_currentHighlight]); + } + } +} + +void ChatViewSearchController::checkMessagesForHighlight(int start, int end) { QAbstractItemModel *model = _scene->model(); Q_ASSERT(model); + if(end == -1) { + end = model->rowCount() - 1; + if(end == -1) + return; + } - QList chatLines; - if(reuse) { - foreach(SearchHighlightItem *highlightItem, _highlightItems) { - ChatLine *line = dynamic_cast(highlightItem->parentItem()); - if(!line || chatLines.contains(line)) + QModelIndex index; + for(int row = start; row <= end; row++) { + if(_searchOnlyRegularMsgs) { + index = model->index(row, 0); + if(!checkType((Message::Type)index.data(MessageModel::TypeRole).toInt())) continue; - chatLines << line; + highlightLine(_scene->chatLine(row)); } } +} - qDeleteAll(_highlightItems); - _highlightItems.clear(); - Q_ASSERT(_highlightItems.isEmpty()); +void ChatViewSearchController::updateHighlights(ChatLine *line) { + QList checkItems; + if(_searchSenders) + checkItems << &(line->item(MessageModel::SenderColumn)); - if(searchString().isEmpty() || !(_searchSenders || _searchMsgs)) - return; + if(_searchMsgs) + checkItems << &(line->item(MessageModel::ContentsColumn)); - if(reuse) { - QModelIndex index; - foreach(ChatLine *line, chatLines) { - if(_searchOnlyRegularMsgs) { - index = model->index(line->row(), 0); - if(!checkType((Message::Type)index.data(MessageModel::TypeRole).toInt())) - continue; - } - highlightLine(line); - } - } else { - // we have to crawl through the data - QModelIndex index; - QString plainText; - int rowCount = model->rowCount(); - for(int row = 0; row < rowCount; row++) { - ChatLine *line = _scene->chatLine(row); - - if(_searchOnlyRegularMsgs) { - index = model->index(row, 0); - if(!checkType((Message::Type)index.data(MessageModel::TypeRole).toInt())) - continue; - } - highlightLine(line); + QHash > wordRects; + foreach(ChatItem *item, checkItems) { + foreach(QRectF wordRect, item->findWords(searchString(), caseSensitive())) { + wordRects[wordRect.x() + item->x()][wordRect.y()] = wordRect; } } - if(!_highlightItems.isEmpty()) { - _highlightItems.last()->setHighlighted(true); - _currentHighlight = _highlightItems.count() - 1; - emit newCurrentHighlight(_highlightItems.last()); + bool deleteAll = false; + QAbstractItemModel *model = _scene->model(); + Q_ASSERT(model); + if(_searchOnlyRegularMsgs) { + QModelIndex index = model->index(line->row(), 0); + if(!checkType((Message::Type)index.data(MessageModel::TypeRole).toInt())) + deleteAll = true; + } + + + foreach(QGraphicsItem *child, line->childItems()) { + SearchHighlightItem *highlightItem = qgraphicsitem_cast(child); + if(!highlightItem) + continue; + + if(!deleteAll && wordRects.contains(highlightItem->pos().x()) && wordRects[highlightItem->pos().x()].contains(highlightItem->pos().y())) { + QRectF &wordRect = wordRects[highlightItem->pos().x()][highlightItem->pos().y()]; + highlightItem->updateGeometry(wordRect.width(), wordRect.height()); + } else { + int pos = _highlightItems.indexOf(highlightItem); + if(pos == _currentHighlight) { + highlightPrev(); + } else if (pos < _currentHighlight) { + _currentHighlight--; + } + + _highlightItems.removeAt(pos); + delete highlightItem; + } } } @@ -284,8 +364,7 @@ SearchHighlightItem::SearchHighlightItem(QRectF wordRect, QGraphicsItem *parent) _timeLine(150) { setPos(wordRect.x(), wordRect.y()); - qreal sizedelta = wordRect.height() * 0.1; - _boundingRect = QRectF(-sizedelta, -sizedelta, wordRect.width() + 2 * sizedelta, wordRect.height() + 2 * sizedelta); + updateGeometry(wordRect.width(), wordRect.height()); connect(&_timeLine, SIGNAL(valueChanged(qreal)), this, SLOT(updateHighlight(qreal))); } @@ -320,6 +399,13 @@ void SearchHighlightItem::paint(QPainter *painter, const QStyleOptionGraphicsIte painter->drawRoundedRect(boundingRect(), radius, radius); } +void SearchHighlightItem::updateGeometry(qreal width, qreal height) { + prepareGeometryChange(); + qreal sizedelta = height * 0.1; + _boundingRect = QRectF(-sizedelta, -sizedelta, width + 2 * sizedelta, height + 2 * sizedelta); + update(); +} + bool SearchHighlightItem::firstInLine(QGraphicsItem *item1, QGraphicsItem *item2) { if(item1->pos().y() != item2->pos().y()) return item1->pos().y() < item2->pos().y(); diff --git a/src/qtui/chatviewsearchcontroller.h b/src/qtui/chatviewsearchcontroller.h index ca7bea8f..83c904c1 100644 --- a/src/qtui/chatviewsearchcontroller.h +++ b/src/qtui/chatviewsearchcontroller.h @@ -79,7 +79,10 @@ private: inline Qt::CaseSensitivity caseSensitive() const { return _caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; } inline bool checkType(Message::Type type) const { return type & (Message::Plain | Message::Notice | Message::Action); } + + void checkMessagesForHighlight(int start = 0, int end = -1); void highlightLine(ChatLine *line); + void updateHighlights(ChatLine *line); }; @@ -92,6 +95,7 @@ class SearchHighlightItem : public QObject, public QGraphicsItem { public: SearchHighlightItem(QRectF wordRect, QGraphicsItem *parent = 0); virtual inline QRectF boundingRect() const { return _boundingRect; } + void updateGeometry(qreal width, qreal height); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); enum { Type = ChatScene::SearchHighlightType }; virtual inline int type() const { return Type; } -- 2.20.1