Provide some new accessors for Chat{View|Scene}
authorManuel Nickschas <sputnick@quassel-irc.org>
Sat, 1 May 2010 15:57:52 +0000 (17:57 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Sat, 1 May 2010 16:01:01 +0000 (18:01 +0200)
This allows accessing the currently visible ChatLines in a view, and
a ChatLine by MsgId in a scene.

src/qtui/chatline.h
src/qtui/chatscene.cpp
src/qtui/chatscene.h
src/qtui/chatview.cpp
src/qtui/chatview.h

index 824d50e..a7c68e8 100644 (file)
@@ -37,11 +37,14 @@ public:
 
   virtual inline QRectF boundingRect () const { return QRectF(0, 0, _width, _height); }
 
-  inline int row() { return _row; }
+  inline QModelIndex index() const { return model()->index(row(), 0); }
+  inline MsgId msgId() const { return index().data(MessageModel::MsgIdRole).value<MsgId>(); }
+  inline int row() const { return _row; }
   inline void setRow(int row) { _row = row; }
 
   inline const QAbstractItemModel *model() const { return _model; }
   inline ChatScene *chatScene() const { return qobject_cast<ChatScene *>(scene()); }
+  inline ChatView *chatView() const { return chatScene()->chatView(); }
 
   inline qreal width() const { return _width; }
   inline qreal height() const { return _height; }
index 1c1dd90..cb5b3f7 100644 (file)
@@ -138,6 +138,33 @@ ColumnHandleItem *ChatScene::secondColumnHandle() const {
   return _secondColHandle;
 }
 
+ChatLine *ChatScene::chatLine(MsgId msgId) const {
+  if(!_lines.count())
+    return 0;
+
+  QList<ChatLine*>::ConstIterator start = _lines.begin();
+  QList<ChatLine*>::ConstIterator end = _lines.end();
+  QList<ChatLine*>::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)->msgId() == msgId)
+    return *start;
+
+  return 0;
+}
+
 ChatItem *ChatScene::chatItemAt(const QPointF &scenePos) const {
   ChatLine *line = qgraphicsitem_cast<ChatLine*>(itemAt(scenePos));
   if(line)
index f3d6273..3daf861 100644 (file)
@@ -82,7 +82,19 @@ public:
 
   ChatView *chatView() const;
   ChatItem *chatItemAt(const QPointF &pos) const;
-  inline ChatLine *chatLine(int row) { return (row < _lines.count()) ? _lines[row] : 0; }
+  inline ChatLine *chatLine(int row) const { return (row < _lines.count()) ? _lines.value(row) : 0; }
+  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.
+   *  Note that this method performs a binary search, hence it has as complexity of O(log n).
+   *  If there is more than one ChatLine for the given ID, the first one will be returned.
+   *  \param msgId The message ID to look for
+   *  \return The ChatLine corresponding to the given MsgId
+   */
+  ChatLine *chatLine(MsgId msgId) const;
+
+  inline ChatLine *lastLine() const { return _lines.count() ? _lines.last() : 0; }
 
   inline bool isSingleBufferScene() const { return _singleBufferId.isValid(); }
   inline BufferId singleBufferId() const { return _singleBufferId; }
index 71c1427..453ac04 100644 (file)
 #include "qtuistyle.h"
 #include "clientignorelistmanager.h"
 
+#include "chatline.h"
+
 ChatView::ChatView(BufferId bufferId, QWidget *parent)
   : QGraphicsView(parent),
-    AbstractChatView(),
-    _bufferContainer(0),
-    _currentScaleFactor(1),
-    _invalidateFilter(false)
+    AbstractChatView()
 {
   QList<BufferId> filterList;
   filterList.append(bufferId);
@@ -47,15 +46,16 @@ ChatView::ChatView(BufferId bufferId, QWidget *parent)
 
 ChatView::ChatView(MessageFilter *filter, QWidget *parent)
   : QGraphicsView(parent),
-    AbstractChatView(),
-    _bufferContainer(0),
-    _currentScaleFactor(1),
-    _invalidateFilter(false)
+    AbstractChatView()
 {
   init(filter);
 }
 
 void ChatView::init(MessageFilter *filter) {
+  _bufferContainer = 0;
+  _currentScaleFactor = 1;
+  _invalidateFilter = false;
+
   setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
   setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
   setAlignment(Qt::AlignLeft|Qt::AlignBottom);
@@ -202,7 +202,58 @@ MsgId ChatView::lastMsgId() const {
   if(!model || model->rowCount() == 0)
     return MsgId();
 
-  return model->data(model->index(model->rowCount() - 1, 0), MessageModel::MsgIdRole).value<MsgId>();
+  return model->index(model->rowCount() - 1, 0).data(MessageModel::MsgIdRole).value<MsgId>();
+}
+
+MsgId ChatView::lastVisibleMsgId() const {
+  ChatLine *line = lastVisibleChatLine();
+
+  if(line)
+    return line->msgId();
+
+  return MsgId();
+}
+
+bool chatLinePtrLessThan(ChatLine *one, ChatLine *other) {
+  return one->row() < other->row();
+}
+
+QSet<ChatLine *> ChatView::visibleChatLines(Qt::ItemSelectionMode mode) const {
+  QSet<ChatLine *> result;
+  foreach(QGraphicsItem *item, items(viewport()->rect().adjusted(-1, -1, 1, 1), mode)) {
+    ChatLine *line = qgraphicsitem_cast<ChatLine *>(item);
+    if(line)
+      result.insert(line);
+  }
+  return result;
+}
+
+QList<ChatLine *> ChatView::visibleChatLinesSorted(Qt::ItemSelectionMode mode) const {
+  QList<ChatLine *> result = visibleChatLines(mode).toList();
+  qSort(result.begin(), result.end(), chatLinePtrLessThan);
+  return result;
+}
+
+ChatLine *ChatView::lastVisibleChatLine() const {
+  if(!scene())
+    return 0;
+
+  QAbstractItemModel *model = scene()->model();
+  if(!model || model->rowCount() == 0)
+    return 0;
+
+  int row = -1;
+
+  QSet<ChatLine *> visibleLines = visibleChatLines(Qt::ContainsItemBoundingRect);
+  foreach(ChatLine *line, visibleLines) {
+    if(line->row() > row)
+      row = line->row();
+  }
+
+  if(row >= 0)
+    return scene()->chatLine(row);
+
+  return 0;
 }
 
 void ChatView::addActionsToMenu(QMenu *menu, const QPointF &pos) {
index 3c2eba1..4fb3661 100644 (file)
@@ -42,11 +42,31 @@ public:
   ChatView(BufferId bufferId, QWidget *parent = 0);
 
   virtual MsgId lastMsgId() const;
+  virtual MsgId lastVisibleMsgId() const;
   inline AbstractBufferContainer *bufferContainer() const { return _bufferContainer; }
   inline void setBufferContainer(AbstractBufferContainer *c) { _bufferContainer = c; }
 
   inline ChatScene *scene() const { return _scene; }
 
+  //! Return a set of ChatLines currently visible in the view
+  /** \param mode How partially visible ChatLines are handled
+   *  \return A set of visible ChatLines
+   */
+  QSet<ChatLine *> visibleChatLines(Qt::ItemSelectionMode mode = Qt::ContainsItemBoundingRect) const;
+
+  //! Return a sorted list of ChatLines currently visible in the view
+  /** \param mode How partially visible ChatLines are handled
+   *  \return A list of visible ChatLines sorted by row
+   *  \note If the order of ChatLines does not matter, use visibleChatLines() instead
+   */
+  QList<ChatLine *> visibleChatLinesSorted(Qt::ItemSelectionMode mode = Qt::ContainsItemBoundingRect) const;
+
+  //! Return the last fully visible ChatLine in this view
+  /** 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;
+
   virtual void addActionsToMenu(QMenu *, const QPointF &pos);
 
   virtual bool event(QEvent *event);