X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fchatscene.cpp;h=e5537a054b3da285450b8779b4a2ade17b5c0d91;hp=ed90582c1642c4785b61fd3d3d4486f47636d007;hb=a4eb9eaf480ea9df5b4a070ad40171c5f2345440;hpb=6330f7fe3d19113cbf29944a9b6e8b503893d4a9 diff --git a/src/qtui/chatscene.cpp b/src/qtui/chatscene.cpp index ed90582c..e5537a05 100644 --- a/src/qtui/chatscene.cpp +++ b/src/qtui/chatscene.cpp @@ -46,6 +46,8 @@ #include "columnhandleitem.h" #include "contextmenuactionprovider.h" #include "iconloader.h" +#include "mainwin.h" +#include "markerlineitem.h" #include "messagefilter.h" #include "qtui.h" #include "qtuistyle.h" @@ -63,6 +65,10 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal w _sceneRect(0, 0, width, 0), _firstLineRow(-1), _viewportHeight(0), + _markerLine(new MarkerLineItem(width)), + _markerLineVisible(false), + _markerLineValid(false), + _markerLineJumpPending(false), _cutoffMode(CutoffRight), _selectingItem(0), _selectionStart(-1), @@ -76,6 +82,9 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal w _singleBufferId = filter->singleBufferId(); } + addItem(_markerLine); + connect(this, SIGNAL(sceneRectChanged(const QRectF &)), _markerLine, SLOT(sceneRectChanged(const QRectF &))); + ChatViewSettings defaultSettings; int defaultFirstColHandlePos = defaultSettings.value("FirstColumnHandlePos", 80).toInt(); int defaultSecondColHandlePos = defaultSettings.value("SecondColumnHandlePos", 200).toInt(); @@ -106,6 +115,8 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal w this, SLOT(rowsInserted(const QModelIndex &, int, int))); connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), this, SLOT(rowsAboutToBeRemoved(const QModelIndex &, int, int))); + connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(rowsRemoved())); connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), SLOT(dataChanged(QModelIndex, QModelIndex))); #ifdef HAVE_WEBKIT @@ -137,10 +148,67 @@ ColumnHandleItem *ChatScene::secondColumnHandle() const { return _secondColHandle; } +ChatLine *ChatScene::chatLine(MsgId msgId, bool matchExact, bool ignoreDayChange) const { + if(!_lines.count()) + return 0; + + QList::ConstIterator start = _lines.begin(); + QList::ConstIterator end = _lines.end(); + QList::ConstIterator middle; + + int n = int(end - start); + int half; + + while(n > 0) { + half = n >> 1; + middle = start + half; + if((*middle)->msgId() < msgId) { + start = middle + 1; + n -= half + 1; + } else { + n = half; + } + } + + if(start != end && (*start)->msgId() == msgId && (ignoreDayChange? (*start)->msgType() != Message::DayChange : true)) + return *start; + + if(matchExact) + return 0; + + if(start == _lines.begin()) // not (yet?) in our scene + return 0; + + // if we didn't find the exact msgId, take the next-lower one (this makes sense for lastSeen) + + if(start == end) { // higher than last element + if(!ignoreDayChange) + return _lines.last(); + + for(int i = _lines.count() -1; i >= 0; i--) { + if(_lines.at(i)->msgType() != Message::DayChange) + return _lines.at(i); + } + return 0; + } + + // return the next-lower line + if(!ignoreDayChange) + return *(--start); + + do { + if((*(--start))->msgType() != Message::DayChange) + return *start; + } while(start != _lines.begin()); + return 0; +} + ChatItem *ChatScene::chatItemAt(const QPointF &scenePos) const { - ChatLine *line = qgraphicsitem_cast(itemAt(scenePos)); - if(line) - return line->itemAt(line->mapFromScene(scenePos)); + foreach(QGraphicsItem *item, items(scenePos, Qt::IntersectsItemBoundingRect, Qt::AscendingOrder)) { + ChatLine *line = qgraphicsitem_cast(item); + if(line) + return line->itemAt(line->mapFromScene(scenePos)); + } return 0; } @@ -152,10 +220,74 @@ bool ChatScene::containsBuffer(const BufferId &id) const { return false; } +void ChatScene::setMarkerLineVisible(bool visible) { + _markerLineVisible = visible; + if(visible && _markerLineValid) + markerLine()->setVisible(true); + else + markerLine()->setVisible(false); +} + +void ChatScene::setMarkerLine(MsgId msgId) { + if(!isSingleBufferScene()) + return; + + if(!msgId.isValid()) + msgId = Client::markerLine(singleBufferId()); + + if(msgId.isValid()) { + ChatLine *line = chatLine(msgId, false, true); + if(line) { + markerLine()->setChatLine(line); + // if this was the last line, we won't see it because it's outside the sceneRect + // .. which is exactly what we want :) + markerLine()->setPos(line->pos() + QPointF(0, line->height())); + + // DayChange messages might have been hidden outside the scene rect, don't make the markerline visible then! + if(markerLine()->pos().y() >= sceneRect().y()) { + _markerLineValid = true; + if(_markerLineVisible) + markerLine()->setVisible(true); + if(_markerLineJumpPending) { + _markerLineJumpPending = false; + if(markerLine()->isVisible()) { + markerLine()->ensureVisible(QRectF(), 50, 50); + } + } + return; + } + } + } + _markerLineValid = false; + markerLine()->setVisible(false); +} + +void ChatScene::jumpToMarkerLine(bool requestBacklog) { + if(!isSingleBufferScene()) + return; + + if(markerLine()->isVisible()) { + markerLine()->ensureVisible(QRectF(), 50, 50); + return; + } + if(!_markerLineValid && requestBacklog) { + MsgId msgId = Client::markerLine(singleBufferId()); + if(msgId.isValid()) { + _markerLineJumpPending = true; + Client::backlogManager()->requestBacklog(singleBufferId(), msgId, -1, -1, 0); + + // If we filtered out the lastSeenMsg (by changing filters after setting it), we'd never jump because the above request + // won't fetch any prior lines. Thus, trigger a dynamic backlog request just in case, so repeated + // jump tries will eventually cause enough backlog to be fetched. + // This is a bit hackish, but not wasteful, as jumping to the top of the ChatView would trigger a dynamic fetch anyway. + this->requestBacklog(); + } + } +} + void ChatScene::rowsInserted(const QModelIndex &index, int start, int end) { Q_UNUSED(index); - // QModelIndex sidx = model()->index(start, 2); // QModelIndex eidx = model()->index(end, 2); // qDebug() << "rowsInserted:"; @@ -243,6 +375,8 @@ void ChatScene::rowsInserted(const QModelIndex &index, int start, int end) { for(int i = 0; i <= end; i++) { line = _lines.at(i); line->setPos(0, line->pos().y() - h); + if(line == markerLine()->chatLine()) + markerLine()->setPos(line->pos() + QPointF(0, line->height())); } } @@ -282,6 +416,10 @@ void ChatScene::rowsInserted(const QModelIndex &index, int start, int end) { if(atBottom) { emit lastLineChanged(_lines.last(), h); } + + // now move the marker line if necessary. we don't need to do anything if we appended lines though... + if(!_markerLineValid) + setMarkerLine(); } void ChatScene::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { @@ -304,6 +442,8 @@ void ChatScene::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int e QList::iterator lineIter = _lines.begin() + start; int lineCount = start; while(lineIter != _lines.end() && lineCount <= end) { + if((*lineIter) == markerLine()->chatLine()) + markerLine()->setChatLine(0); h += (*lineIter)->height(); delete *lineIter; lineIter = _lines.erase(lineIter); @@ -375,6 +515,11 @@ void ChatScene::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int e updateSceneRect(); } +void ChatScene::rowsRemoved() { + // move the marker line if necessary + setMarkerLine(); +} + void ChatScene::dataChanged(const QModelIndex &tl, const QModelIndex &br) { layout(tl.row(), br.row(), _sceneRect.width()); } @@ -422,6 +567,7 @@ void ChatScene::layout(int start, int end, qreal width) { updateSceneRect(width); setHandleXLimits(); + setMarkerLine(); emit layoutChanged(); // clock_t endT = clock(); @@ -501,6 +647,7 @@ void ChatScene::secondHandlePositionChanged(qreal xpos) { void ChatScene::setHandleXLimits() { _firstColHandle->setXLimits(0, _secondColHandle->sceneLeft()); _secondColHandle->setXLimits(_firstColHandle->sceneRight(), width() - minContentsWidth); + update(); } void ChatScene::setSelectingItem(ChatItem *item) { @@ -870,14 +1017,6 @@ void ChatScene::updateSceneRect(const QRectF &rect) { update(); } -bool ChatScene::event(QEvent *e) { - if(e->type() == QEvent::ApplicationPaletteChange) { - _firstColHandle->setColor(QApplication::palette().windowText().color()); - _secondColHandle->setColor(QApplication::palette().windowText().color()); - } - return QGraphicsScene::event(e); -} - // ======================================== // Webkit Only stuff // ========================================