From: Manuel Nickschas Date: Tue, 29 Jun 2010 20:51:13 +0000 (+0200) Subject: Add shortcut that jumps to the markerline X-Git-Tag: 0.7-beta1~40 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=3013f4e095802e906c85878436da9e2ee3f9028c Add shortcut that jumps to the markerline By default (and subject to change), Ctrl+K now jumps to the markerline (which is either set manually by Ctrl+R, or by default automatically when switching channels). If necessary, additional backlog will be fetched first. Note that this might require multiple presses of Ctrl+K if you tinkered with message filters after setting the markerline, and also for markerlines that have been set using older clients. The markerline will now never be set on a day change message. --- diff --git a/src/qtui/bufferwidget.cpp b/src/qtui/bufferwidget.cpp index 047759eb..7b4e9545 100644 --- a/src/qtui/bufferwidget.cpp +++ b/src/qtui/bufferwidget.cpp @@ -94,6 +94,10 @@ BufferWidget::BufferWidget(QWidget *parent) setMarkerLine->setText(tr("Set Marker Line")); setMarkerLine->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R)); + Action *jumpToMarkerLine = QtUi::actionCollection("Navigation")->add("JumpToMarkerLine", this, SLOT(jumpToMarkerLine())); + jumpToMarkerLine->setText(tr("Go to Marker Line")); + jumpToMarkerLine->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_K)); + ChatViewSettings s; s.initAndNotify("AutoMarkerLine", this, SLOT(setAutoMarkerLine(QVariant)), true); } @@ -250,3 +254,12 @@ void BufferWidget::setMarkerLine(ChatView *view, bool allowGoingBack) { view->setMarkerLine(msgId); } } + +void BufferWidget::jumpToMarkerLine(ChatView *view, bool requestBacklog) { + if(!view) + view = qobject_cast(ui.stackedWidget->currentWidget()); + if(!view) + return; + + view->jumpToMarkerLine(requestBacklog); +} diff --git a/src/qtui/bufferwidget.h b/src/qtui/bufferwidget.h index b818435a..4eb8b6d9 100644 --- a/src/qtui/bufferwidget.h +++ b/src/qtui/bufferwidget.h @@ -44,6 +44,7 @@ public: public slots: virtual void setMarkerLine(ChatView *view = 0, bool allowGoingBack = true); + virtual void jumpToMarkerLine(ChatView *view = 0, bool requestBacklog = true); protected: virtual AbstractChatView *createChatView(BufferId); diff --git a/src/qtui/chatline.h b/src/qtui/chatline.h index 45365208..94981562 100644 --- a/src/qtui/chatline.h +++ b/src/qtui/chatline.h @@ -41,6 +41,8 @@ public: inline QModelIndex index() const { return model()->index(row(), 0); } inline MsgId msgId() const { return index().data(MessageModel::MsgIdRole).value(); } + inline Message::Type msgType() const { return (Message::Type)index().data(MessageModel::TypeRole).toInt(); } + inline int row() const { return _row; } inline void setRow(int row) { _row = row; } diff --git a/src/qtui/chatscene.cpp b/src/qtui/chatscene.cpp index f7d4bd1b..3ab059a3 100644 --- a/src/qtui/chatscene.cpp +++ b/src/qtui/chatscene.cpp @@ -66,8 +66,9 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal w _firstLineRow(-1), _viewportHeight(0), _markerLine(new MarkerLineItem(width)), - _markerLineValid(false), _markerLineVisible(false), + _markerLineValid(false), + _markerLineJumpPending(false), _cutoffMode(CutoffRight), _selectingItem(0), _selectionStart(-1), @@ -147,7 +148,7 @@ ColumnHandleItem *ChatScene::secondColumnHandle() const { return _secondColHandle; } -ChatLine *ChatScene::chatLine(MsgId msgId, bool matchExact) const { +ChatLine *ChatScene::chatLine(MsgId msgId, bool matchExact, bool ignoreDayChange) const { if(!_lines.count()) return 0; @@ -169,21 +170,37 @@ ChatLine *ChatScene::chatLine(MsgId msgId, bool matchExact) const { } } - if(start != end && (*start)->msgId() == msgId) + 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 - return _lines.last(); - if(start == _lines.begin()) // not (yet?) in our scene + 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 - return *(--start); + 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 { @@ -206,35 +223,64 @@ bool ChatScene::containsBuffer(const BufferId &id) const { void ChatScene::setMarkerLineVisible(bool visible) { _markerLineVisible = visible; if(visible && _markerLineValid) - _markerLine->setVisible(true); + markerLine()->setVisible(true); else - _markerLine->setVisible(false); + markerLine()->setVisible(false); } void ChatScene::setMarkerLine(MsgId msgId) { if(!isSingleBufferScene()) return; - if(!msgId.isValid()) { + + if(!msgId.isValid()) msgId = Client::markerLine(singleBufferId()); - if(!msgId.isValid()) { - _markerLineValid = false; - _markerLine->setVisible(false); - return; + + 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); +} - ChatLine *line = chatLine(msgId, false); - if(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); - return; +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(); } } } @@ -242,7 +288,6 @@ void ChatScene::setMarkerLine(MsgId msgId) { 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:"; @@ -330,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())); } } @@ -371,7 +418,7 @@ void ChatScene::rowsInserted(const QModelIndex &index, int start, int end) { } // now move the marker line if necessary. we don't need to do anything if we appended lines though... - if(!_markerLineValid || !atBottom) + if(!_markerLineValid) setMarkerLine(); } @@ -395,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); diff --git a/src/qtui/chatscene.h b/src/qtui/chatscene.h index 56212adc..a5cbe7bd 100644 --- a/src/qtui/chatscene.h +++ b/src/qtui/chatscene.h @@ -88,18 +88,22 @@ public: inline ChatLine *chatLine(const QModelIndex &index) const { return _lines.value(index.row()); } //! Find the ChatLine belonging to a MsgId - /** Searches for the ChatLine belonging to a MsgId. + /** Searches for the ChatLine belonging to a MsgId. If there are more than one ChatLine with the same msgId, + * the first one is returned. * Note that this method performs a binary search, hence it has as complexity of O(log n). * If matchExact is false, and we don't have an exact match for the given msgId, we return the visible line right * above the requested one. * \param msgId The message ID to look for * \param matchExact Whether we find only exact matches + * \param ignoreDayChange Whether we ignore day change messages * \return The ChatLine corresponding to the given MsgId */ - ChatLine *chatLine(MsgId msgId, bool matchExact = true) const; + ChatLine *chatLine(MsgId msgId, bool matchExact = true, bool ignoreDayChange = true) const; inline ChatLine *lastLine() const { return _lines.count() ? _lines.last() : 0; } + inline MarkerLineItem *markerLine() const { return _markerLine; } + inline bool isSingleBufferScene() const { return _singleBufferId.isValid(); } inline BufferId singleBufferId() const { return _singleBufferId; } bool containsBuffer(const BufferId &id) const; @@ -128,6 +132,7 @@ public: void setMarkerLineVisible(bool visible = true); void setMarkerLine(MsgId msgId = MsgId()); + void jumpToMarkerLine(bool requestBacklog); // these are used by the chatitems to notify the scene and manage selections void setSelectingItem(ChatItem *item); @@ -195,7 +200,7 @@ private: qreal _viewportHeight; MarkerLineItem *_markerLine; - bool _markerLineValid, _markerLineVisible; + bool _markerLineVisible, _markerLineValid, _markerLineJumpPending; ColumnHandleItem *_firstColHandle, *_secondColHandle; qreal _firstColHandlePos, _secondColHandlePos; diff --git a/src/qtui/chatview.cpp b/src/qtui/chatview.cpp index 96d7ee2f..cc5009b9 100644 --- a/src/qtui/chatview.cpp +++ b/src/qtui/chatview.cpp @@ -241,7 +241,7 @@ QList ChatView::visibleChatLinesSorted(Qt::ItemSelectionMode mode) c return result; } -ChatLine *ChatView::lastVisibleChatLine() const { +ChatLine *ChatView::lastVisibleChatLine(bool ignoreDayChange) const { if(!scene()) return 0; @@ -253,7 +253,7 @@ ChatLine *ChatView::lastVisibleChatLine() const { QSet visibleLines = visibleChatLines(Qt::ContainsItemBoundingRect); foreach(ChatLine *line, visibleLines) { - if(line->row() > row) + if(line->row() > row && (ignoreDayChange? line->msgType() != Message::DayChange : true)) row = line->row(); } @@ -283,6 +283,10 @@ void ChatView::markerLineSet(BufferId buffer, MsgId msgId) { scene()->setMarkerLineVisible(true); } +void ChatView::jumpToMarkerLine(bool requestBacklog) { + scene()->jumpToMarkerLine(requestBacklog); +} + void ChatView::addActionsToMenu(QMenu *menu, const QPointF &pos) { // zoom actions BufferWidget *bw = qobject_cast(bufferContainer()); diff --git a/src/qtui/chatview.h b/src/qtui/chatview.h index c2aa6040..51522d23 100644 --- a/src/qtui/chatview.h +++ b/src/qtui/chatview.h @@ -65,7 +65,7 @@ public: /** Using this method more efficient than calling visibleChatLinesSorted() and taking its last element. * \return The last fully visible ChatLine in the view */ - ChatLine *lastVisibleChatLine() const; + ChatLine *lastVisibleChatLine(bool ignoreDayChange = false) const; virtual void addActionsToMenu(QMenu *, const QPointF &pos); @@ -86,6 +86,7 @@ public slots: void setMarkerLineVisible(bool visible = true); void setMarkerLine(MsgId msgId); + void jumpToMarkerLine(bool requestBacklog); protected: virtual bool event(QEvent *event); diff --git a/src/qtui/markerlineitem.cpp b/src/qtui/markerlineitem.cpp index 9782a793..563ef4ed 100644 --- a/src/qtui/markerlineitem.cpp +++ b/src/qtui/markerlineitem.cpp @@ -25,13 +25,21 @@ MarkerLineItem::MarkerLineItem(qreal sceneWidth, QGraphicsItem *parent) : QGraphicsObject(parent), - _boundingRect(0, 0, sceneWidth, 1) + _boundingRect(0, 0, sceneWidth, 1), + _chatLine(0) { + setVisible(false); setZValue(8); styleChanged(); // init brush and height connect(QtUi::style(), SIGNAL(changed()), SLOT(styleChanged())); } +void MarkerLineItem::setChatLine(ChatLine *line) { + _chatLine = line; + if(!line) + setVisible(false); +} + void MarkerLineItem::styleChanged() { _brush = QtUi::style()->brush(UiStyle::MarkerLine); diff --git a/src/qtui/markerlineitem.h b/src/qtui/markerlineitem.h index 3911da8a..827fa258 100644 --- a/src/qtui/markerlineitem.h +++ b/src/qtui/markerlineitem.h @@ -25,6 +25,8 @@ #include "chatscene.h" +class ChatLine; + class MarkerLineItem : public QGraphicsObject { Q_OBJECT @@ -33,10 +35,13 @@ public: virtual inline int type() const { return ChatScene::MarkerLineType; } inline QRectF boundingRect() const { return _boundingRect; } - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + inline ChatLine *chatLine() const { return _chatLine; } + public slots: + //! Set the ChatLine this MarkerLineItem is associated to + void setChatLine(ChatLine *line); void sceneRectChanged(const QRectF &); private slots: @@ -45,6 +50,7 @@ private slots: private: QRectF _boundingRect; QBrush _brush; + ChatLine *_chatLine; }; #endif