X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fchatviewsearchcontroller.cpp;h=1290d657a1d71a8a574615ce2a636cd080254b39;hp=1635d90970183a4921ac76e4f238e8aabf79baf9;hb=e60110ec2df2c8a50b3ad94fb10f9ec769225bc2;hpb=49f966fd9c04f3aa3149be73bb61b8e1781ce1c2 diff --git a/src/qtui/chatviewsearchcontroller.cpp b/src/qtui/chatviewsearchcontroller.cpp index 1635d909..1290d657 100644 --- a/src/qtui/chatviewsearchcontroller.cpp +++ b/src/qtui/chatviewsearchcontroller.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-08 by the Quassel Project * + * Copyright (C) 2005-09 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -69,6 +69,7 @@ void ChatViewSearchController::setSearchString(const QString &searchString) { return; connect(_scene, SIGNAL(destroyed()), this, SLOT(sceneDestroyed())); + connect(_scene, SIGNAL(layoutChanged()), this, SLOT(repositionHighlights())); updateHighlights(); } @@ -106,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[(quint64)(wordRect.x() + item->x())][(quint64)(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((quint64)(highlightItem->pos().x())) && wordRects[(quint64)(highlightItem->pos().x())].contains((quint64)(highlightItem->pos().y()))) { + QRectF &wordRect = wordRects[(quint64)(highlightItem->pos().x())][(quint64)(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; + } } } @@ -176,6 +257,50 @@ void ChatViewSearchController::highlightLine(ChatLine *line) { } } +void ChatViewSearchController::repositionHighlights() { + QSet chatLines; + foreach(SearchHighlightItem *item, _highlightItems) { + ChatLine *line = qgraphicsitem_cast(item->parentItem()); + if(line) + chatLines << line; + } + QList chatLineList(chatLines.toList()); + foreach(ChatLine *line, chatLineList) { + repositionHighlights(line); + } +} + +void ChatViewSearchController::repositionHighlights(ChatLine *line) { + QList searchHighlights; + foreach(QGraphicsItem *child, line->childItems()) { + SearchHighlightItem *highlightItem = qgraphicsitem_cast(child); + if(highlightItem) + searchHighlights << highlightItem; + } + + if(searchHighlights.isEmpty()) + return; + + QList wordPos; + if(_searchSenders) { + foreach(QRectF wordRect, line->senderItem().findWords(searchString(), caseSensitive())) { + wordPos << QPointF(wordRect.x() + line->senderItem().x(), wordRect.y()); + } + } + if(_searchMsgs) { + foreach(QRectF wordRect, line->contentsItem().findWords(searchString(), caseSensitive())) { + wordPos << QPointF(wordRect.x() + line->contentsItem().x(), wordRect.y()); + } + } + + qSort(searchHighlights.begin(), searchHighlights.end(), SearchHighlightItem::firstInLine); + + Q_ASSERT(wordPos.count() == searchHighlights.count()); + for(int i = 0; i < searchHighlights.count(); i++) { + searchHighlights.at(i)->setPos(wordPos.at(i)); + } +} + void ChatViewSearchController::sceneDestroyed() { // WARNING: don't call any methods on scene! _scene = 0; @@ -239,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))); } @@ -260,7 +384,7 @@ void SearchHighlightItem::setHighlighted(bool highlighted) { } void SearchHighlightItem::updateHighlight(qreal value) { - _alpha = 100 + 155 * value; + _alpha = 100 + (int)(155 * value); update(); } @@ -274,3 +398,17 @@ void SearchHighlightItem::paint(QPainter *painter, const QStyleOptionGraphicsIte qreal radius = boundingRect().height() * 0.30; 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(); + else + return item1->pos().x() < item2->pos().x(); +}