Improve marker line behavior; allow manual setting (Ctrl+R)
authorManuel Nickschas <sputnick@quassel-irc.org>
Mon, 26 Apr 2010 19:11:29 +0000 (21:11 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Sat, 1 May 2010 16:01:01 +0000 (18:01 +0200)
The marker line will now be set to the bottom of the current chatview rather than
to the very bottom of the chatview when it makes sense. So if you didn't scroll all
the way down, and switch channels, you can start off where you left reading.

Also there's now an option to disable the automatic setting of the marker line completely.
Using Ctrl+R, you can manually set the marker line to the bottom of the ChatView.

This requires a recent core (older cores will still work, but only show the old behavior).

12 files changed:
src/client/client.cpp
src/client/client.h
src/client/networkmodel.cpp
src/client/networkmodel.h
src/common/buffersyncer.cpp
src/common/buffersyncer.h
src/qtui/bufferwidget.cpp
src/qtui/bufferwidget.h
src/qtui/settingspages/chatviewsettingspage.cpp
src/qtui/settingspages/chatviewsettingspage.ui
src/uisupport/abstractbuffercontainer.cpp
src/uisupport/abstractbuffercontainer.h

index 228d4df..21beda0 100644 (file)
@@ -322,7 +322,7 @@ void Client::setSyncedToCore() {
   connect(bufferSyncer(), SIGNAL(buffersPermanentlyMerged(BufferId, BufferId)), this, SLOT(buffersPermanentlyMerged(BufferId, BufferId)));
   connect(bufferSyncer(), SIGNAL(buffersPermanentlyMerged(BufferId, BufferId)), _messageModel, SLOT(buffersPermanentlyMerged(BufferId, BufferId)));
   connect(bufferSyncer(), SIGNAL(bufferMarkedAsRead(BufferId)), SIGNAL(bufferMarkedAsRead(BufferId)));
   connect(bufferSyncer(), SIGNAL(buffersPermanentlyMerged(BufferId, BufferId)), this, SLOT(buffersPermanentlyMerged(BufferId, BufferId)));
   connect(bufferSyncer(), SIGNAL(buffersPermanentlyMerged(BufferId, BufferId)), _messageModel, SLOT(buffersPermanentlyMerged(BufferId, BufferId)));
   connect(bufferSyncer(), SIGNAL(bufferMarkedAsRead(BufferId)), SIGNAL(bufferMarkedAsRead(BufferId)));
-  connect(networkModel(), SIGNAL(setLastSeenMsg(BufferId, MsgId)), bufferSyncer(), SLOT(requestSetLastSeenMsg(BufferId, const MsgId &)));
+  connect(networkModel(), SIGNAL(requestSetLastSeenMsg(BufferId, MsgId)), bufferSyncer(), SLOT(requestSetLastSeenMsg(BufferId, const MsgId &)));
   signalProxy()->synchronize(bufferSyncer());
 
   // create a new BufferViewManager
   signalProxy()->synchronize(bufferSyncer());
 
   // create a new BufferViewManager
@@ -470,11 +470,17 @@ void Client::setBufferLastSeenMsg(BufferId id, const MsgId &msgId) {
     bufferSyncer()->requestSetLastSeenMsg(id, msgId);
 }
 
     bufferSyncer()->requestSetLastSeenMsg(id, msgId);
 }
 
-void Client::setBufferMarkerLine(BufferId id, const MsgId &msgId) {
+void Client::setMarkerLine(BufferId id, const MsgId &msgId) {
   if(bufferSyncer())
     bufferSyncer()->requestSetMarkerLine(id, msgId);
 }
 
   if(bufferSyncer())
     bufferSyncer()->requestSetMarkerLine(id, msgId);
 }
 
+MsgId Client::markerLine(BufferId id) {
+  if(id.isValid() && networkModel())
+    return networkModel()->markerLineMsgId(id);
+  return MsgId();
+}
+
 void Client::removeBuffer(BufferId id) {
   if(!bufferSyncer()) return;
   bufferSyncer()->requestRemoveBuffer(id);
 void Client::removeBuffer(BufferId id) {
   if(!bufferSyncer()) return;
   bufferSyncer()->requestRemoveBuffer(id);
index ab413b8..cc3803b 100644 (file)
@@ -127,7 +127,9 @@ public:
   static void userInput(const BufferInfo &bufferInfo, const QString &message);
 
   static void setBufferLastSeenMsg(BufferId id, const MsgId &msgId); // this is synced to core and other clients
   static void userInput(const BufferInfo &bufferInfo, const QString &message);
 
   static void setBufferLastSeenMsg(BufferId id, const MsgId &msgId); // this is synced to core and other clients
-  static void setBufferMarkerLine(BufferId id, const MsgId &msgId); // this is synced to core and other clients
+  static void setMarkerLine(BufferId id, const MsgId &msgId); // this is synced to core and other clients
+  static MsgId markerLine(BufferId id);
+
   static void removeBuffer(BufferId id);
   static void renameBuffer(BufferId bufferId, const QString &newName);
   static void mergeBuffersPermanently(BufferId bufferId1, BufferId bufferId2);
   static void removeBuffer(BufferId id);
   static void renameBuffer(BufferId bufferId, const QString &newName);
   static void mergeBuffersPermanently(BufferId bufferId1, BufferId bufferId2);
index d745431..f44c87d 100644 (file)
@@ -1022,6 +1022,7 @@ void NetworkModel::setLastSeenMsgId(const BufferId &bufferId, const MsgId &msgId
     return;
   }
   bufferItem->setLastSeenMsgId(msgId);
     return;
   }
   bufferItem->setLastSeenMsgId(msgId);
+  emit lastSeenMsgSet(bufferId, msgId);
 }
 
 void NetworkModel::setMarkerLineMsgId(const BufferId &bufferId, const MsgId &msgId) {
 }
 
 void NetworkModel::setMarkerLineMsgId(const BufferId &bufferId, const MsgId &msgId) {
@@ -1032,6 +1033,7 @@ void NetworkModel::setMarkerLineMsgId(const BufferId &bufferId, const MsgId &msg
     return;
   }
   bufferItem->setMarkerLineMsgId(msgId);
     return;
   }
   bufferItem->setMarkerLineMsgId(msgId);
+  emit markerLineSet(bufferId, msgId);
 }
 
 void NetworkModel::updateBufferActivity(Message &msg) {
 }
 
 void NetworkModel::updateBufferActivity(Message &msg) {
@@ -1087,7 +1089,7 @@ void NetworkModel::updateBufferActivity(BufferItem *bufferItem, const Message &m
 
   bufferItem->updateActivityLevel(msg);
   if(bufferItem->isCurrentBuffer())
 
   bufferItem->updateActivityLevel(msg);
   if(bufferItem->isCurrentBuffer())
-    emit setLastSeenMsg(bufferItem->bufferId(), msg.msgId());
+    emit requestSetLastSeenMsg(bufferItem->bufferId(), msg.msgId());
 }
 
 void NetworkModel::setBufferActivity(const BufferId &bufferId, BufferInfo::ActivityLevel level) {
 }
 
 void NetworkModel::setBufferActivity(const BufferId &bufferId, BufferInfo::ActivityLevel level) {
index 52b49eb..daf8243 100644 (file)
@@ -340,7 +340,9 @@ public slots:
   void networkRemoved(const NetworkId &networkId);
 
 signals:
   void networkRemoved(const NetworkId &networkId);
 
 signals:
-  void setLastSeenMsg(BufferId bufferId, MsgId msgId);
+  void requestSetLastSeenMsg(BufferId buffer, MsgId msg);
+  void lastSeenMsgSet(BufferId buffer, MsgId msg);
+  void markerLineSet(BufferId buffer, MsgId msg);
 
 private slots:
   void checkForRemovedBuffers(const QModelIndex &parent, int start, int end);
 
 private slots:
   void checkForRemovedBuffers(const QModelIndex &parent, int start, int end);
index 4987429..222f65b 100644 (file)
@@ -59,6 +59,9 @@ bool BufferSyncer::setMarkerLine(BufferId buffer, const MsgId &msgId) {
   if(!msgId.isValid())
     return false;
 
   if(!msgId.isValid())
     return false;
 
+  if(_markerLines.value(buffer) == msgId)
+    return false;
+
   _markerLines[buffer] = msgId;
   SYNC(ARG(buffer), ARG(msgId))
   emit markerLineSet(buffer, msgId);
   _markerLines[buffer] = msgId;
   SYNC(ARG(buffer), ARG(msgId))
   emit markerLineSet(buffer, msgId);
index 3de31db..716178a 100644 (file)
@@ -45,7 +45,7 @@ public slots:
   void initSetMarkerLines(const QVariantList &);
 
   virtual inline void requestSetLastSeenMsg(BufferId buffer, const MsgId &msgId) { REQUEST(ARG(buffer), ARG(msgId)) }
   void initSetMarkerLines(const QVariantList &);
 
   virtual inline void requestSetLastSeenMsg(BufferId buffer, const MsgId &msgId) { REQUEST(ARG(buffer), ARG(msgId)) }
-  virtual inline void requestSetMarkerLine(BufferId buffer, const MsgId &msgId) { REQUEST(ARG(buffer), ARG(msgId)) }
+  virtual inline void requestSetMarkerLine(BufferId buffer, const MsgId &msgId) { REQUEST(ARG(buffer), ARG(msgId)) setMarkerLine(buffer, msgId); }
 
   virtual inline void requestRemoveBuffer(BufferId buffer) { REQUEST(ARG(buffer)) }
   virtual void removeBuffer(BufferId buffer);
 
   virtual inline void requestRemoveBuffer(BufferId buffer) { REQUEST(ARG(buffer)) }
   virtual void removeBuffer(BufferId buffer);
index ecfdceb..ab06899 100644 (file)
 #include "action.h"
 #include "actioncollection.h"
 #include "bufferwidget.h"
 #include "action.h"
 #include "actioncollection.h"
 #include "bufferwidget.h"
+#include "chatline.h"
 #include "chatview.h"
 #include "chatviewsearchbar.h"
 #include "chatviewsearchcontroller.h"
 #include "chatview.h"
 #include "chatviewsearchbar.h"
 #include "chatviewsearchcontroller.h"
+#include "chatviewsettings.h"
 #include "client.h"
 #include "iconloader.h"
 #include "multilineedit.h"
 #include "client.h"
 #include "iconloader.h"
 #include "multilineedit.h"
@@ -38,7 +40,8 @@
 
 BufferWidget::BufferWidget(QWidget *parent)
   : AbstractBufferContainer(parent),
 
 BufferWidget::BufferWidget(QWidget *parent)
   : AbstractBufferContainer(parent),
-    _chatViewSearchController(new ChatViewSearchController(this))
+    _chatViewSearchController(new ChatViewSearchController(this)),
+    _autoMarkerLine(true)
 {
   ui.setupUi(this);
   layout()->setContentsMargins(0, 0, 0, 0);
 {
   ui.setupUi(this);
   layout()->setContentsMargins(0, 0, 0, 0);
@@ -86,6 +89,13 @@ BufferWidget::BufferWidget(QWidget *parent)
   zoomOriginalChatview->setIcon(SmallIcon("zoom-original"));
   zoomOriginalChatview->setText(tr("Actual Size"));
   //zoomOriginalChatview->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_0)); // used for RTS switching
   zoomOriginalChatview->setIcon(SmallIcon("zoom-original"));
   zoomOriginalChatview->setText(tr("Actual Size"));
   //zoomOriginalChatview->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_0)); // used for RTS switching
+
+  Action *setMarkerLine = coll->add<Action>("SetMarkerLineToBottom", this, SLOT(setMarkerLine()));
+  setMarkerLine->setText(tr("Set Marker Line"));
+  setMarkerLine->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
+
+  ChatViewSettings s;
+  s.initAndNotify("AutoMarkerLine", this, SLOT(setAutoMarkerLine(QVariant)), true);
 }
 
 BufferWidget::~BufferWidget() {
 }
 
 BufferWidget::~BufferWidget() {
@@ -93,6 +103,10 @@ BufferWidget::~BufferWidget() {
   _chatViewSearchController = 0;
 }
 
   _chatViewSearchController = 0;
 }
 
+void BufferWidget::setAutoMarkerLine(const QVariant &v) {
+  _autoMarkerLine = v.toBool();
+}
+
 AbstractChatView *BufferWidget::createChatView(BufferId id) {
   ChatView *chatView;
   chatView = new ChatView(id, this);
 AbstractChatView *BufferWidget::createChatView(BufferId id) {
   ChatView *chatView;
   chatView = new ChatView(id, this);
@@ -129,7 +143,6 @@ void BufferWidget::scrollToHighlight(QGraphicsItem *highlightItem) {
   }
 }
 
   }
 }
 
-
 void BufferWidget::zoomIn() {
   ChatView *view = qobject_cast<ChatView *>(ui.stackedWidget->currentWidget());
   if(view)
 void BufferWidget::zoomIn() {
   ChatView *view = qobject_cast<ChatView *>(ui.stackedWidget->currentWidget());
   if(view)
@@ -194,3 +207,45 @@ bool BufferWidget::eventFilter(QObject *watched, QEvent *event) {
     return false;
   }
 }
     return false;
   }
 }
+
+void BufferWidget::currentChanged(const QModelIndex &current, const QModelIndex &previous) {
+  ChatView *prevView = qobject_cast<ChatView *>(ui.stackedWidget->currentWidget());
+
+  AbstractBufferContainer::currentChanged(current, previous); // switch first to avoid a redraw
+
+  // we need to hide the marker line if it's already/still at the bottom of the view (and not scrolled up)
+  ChatView *curView = qobject_cast<ChatView *>(ui.stackedWidget->currentWidget());
+  if(curView) {
+    BufferId curBufferId = current.data(NetworkModel::BufferIdRole).value<BufferId>();
+    if(curBufferId.isValid()) {
+      MsgId markerMsgId = Client::networkModel()->markerLineMsgId(curBufferId);
+      if(markerMsgId == curView->lastMsgId() && markerMsgId == curView->lastVisibleMsgId())
+        curView->setMarkerLineVisible(false);
+      else
+        curView->setMarkerLineVisible(true);
+    }
+  }
+
+  if(prevView && autoMarkerLine())
+    setMarkerLine(prevView, false);
+}
+
+void BufferWidget::setMarkerLine(ChatView *view, bool allowGoingBack) {
+  if(!view)
+    view = qobject_cast<ChatView *>(ui.stackedWidget->currentWidget());
+  if(!view)
+    return;
+
+  ChatLine *lastLine = view->lastVisibleChatLine();
+  if(lastLine) {
+    if(!allowGoingBack) {
+      QModelIndex idx = lastLine->index();
+      BufferId bufId = view->scene()->singleBufferId();
+      MsgId msgId = idx.data(MessageModel::MsgIdRole).value<MsgId>();
+      MsgId oldMsgId = Client::markerLine(bufId);
+      if(oldMsgId.isValid() && msgId <= oldMsgId)
+        return;
+    }
+    view->setMarkedLine(lastLine);
+  }
+}
index 3efb87a..dc8b823 100644 (file)
@@ -26,6 +26,7 @@
 #include "abstractbuffercontainer.h"
 
 class QGraphicsItem;
 #include "abstractbuffercontainer.h"
 
 class QGraphicsItem;
+class ChatView;
 class ChatViewSearchBar;
 class ChatViewSearchController;
 
 class ChatViewSearchBar;
 class ChatViewSearchController;
 
@@ -44,9 +45,13 @@ public:
 protected:
   virtual AbstractChatView *createChatView(BufferId);
   virtual void removeChatView(BufferId);
 protected:
   virtual AbstractChatView *createChatView(BufferId);
   virtual void removeChatView(BufferId);
+  virtual inline bool autoMarkerLine() const { return _autoMarkerLine; }
 
 protected slots:
 
 protected slots:
+  virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous);
   virtual void showChatView(BufferId);
   virtual void showChatView(BufferId);
+public slots:
+  virtual void setMarkerLine(ChatView *view = 0, bool allowGoingBack = true);
 
 private slots:
   void scrollToHighlight(QGraphicsItem *highlightItem);
 
 private slots:
   void scrollToHighlight(QGraphicsItem *highlightItem);
@@ -54,11 +59,15 @@ private slots:
   void zoomOut();
   void zoomOriginal();
 
   void zoomOut();
   void zoomOriginal();
 
+  void setAutoMarkerLine(const QVariant &);
+
 private:
   Ui::BufferWidget ui;
   QHash<BufferId, QWidget *> _chatViews;
 
   ChatViewSearchController *_chatViewSearchController;
 private:
   Ui::BufferWidget ui;
   QHash<BufferId, QWidget *> _chatViews;
 
   ChatViewSearchController *_chatViewSearchController;
+
+  bool _autoMarkerLine;
 };
 
 #endif
 };
 
 #endif
index 76780b1..fd59024 100644 (file)
@@ -19,6 +19,7 @@
  ***************************************************************************/
 
 #include "chatviewsettingspage.h"
  ***************************************************************************/
 
 #include "chatviewsettingspage.h"
+#include "client.h"
 #include "colorbutton.h"
 #include "qtui.h"
 #include "qtuistyle.h"
 #include "colorbutton.h"
 #include "qtui.h"
 #include "qtuistyle.h"
@@ -33,6 +34,13 @@ ChatViewSettingsPage::ChatViewSettingsPage(QWidget *parent)
   ui.showWebPreview->setEnabled(false);
 #endif
 
   ui.showWebPreview->setEnabled(false);
 #endif
 
+  // FIXME remove with protocol v11
+  if(!(Client::coreFeatures() & Quassel::SynchronizedMarkerLine)) {
+    ui.autoMarkerLine->setEnabled(false);
+    ui.autoMarkerLine->setChecked(true);
+    ui.autoMarkerLine->setToolTip(tr("You need at 0.6 quasselcore to use this feature"));
+  }
+
   initAutoWidgets();
 }
 
   initAutoWidgets();
 }
 
index 378c651..5bc64ce 100644 (file)
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>486</width>
     <x>0</x>
     <y>0</y>
     <width>486</width>
-    <height>475</height>
+    <height>492</height>
    </rect>
   </property>
   <property name="windowTitle">
    </rect>
   </property>
   <property name="windowTitle">
@@ -88,6 +88,9 @@
    </item>
    <item>
     <widget class="QCheckBox" name="allowMircColors">
    </item>
    <item>
     <widget class="QCheckBox" name="allowMircColors">
+     <property name="toolTip">
+      <string>Show colored text in the chat window</string>
+     </property>
      <property name="text">
       <string>Allow colored text (mIRC color codes)</string>
      </property>
      <property name="text">
       <string>Allow colored text (mIRC color codes)</string>
      </property>
      </property>
     </widget>
    </item>
      </property>
     </widget>
    </item>
+   <item>
+    <widget class="QCheckBox" name="autoMarkerLine">
+     <property name="toolTip">
+      <string>Set the marker line to the bottom of the current chat window when selecting another channel</string>
+     </property>
+     <property name="text">
+      <string>Set marker line automatically when switching chats</string>
+     </property>
+     <property name="checked">
+      <bool>true</bool>
+     </property>
+     <property name="settingsKey" stdset="0">
+      <string notr="true">AutoMarkerLine</string>
+     </property>
+     <property name="defaultValue" stdset="0">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
    <item>
     <widget class="QGroupBox" name="useCustomColors">
      <property name="title">
    <item>
     <widget class="QGroupBox" name="useCustomColors">
      <property name="title">
   <tabstop>customChatViewFont</tabstop>
   <tabstop>allowMircColors</tabstop>
   <tabstop>showWebPreview</tabstop>
   <tabstop>customChatViewFont</tabstop>
   <tabstop>allowMircColors</tabstop>
   <tabstop>showWebPreview</tabstop>
+  <tabstop>autoMarkerLine</tabstop>
   <tabstop>useCustomColors</tabstop>
   <tabstop>actionMsgColor</tabstop>
   <tabstop>channelMsgColor</tabstop>
   <tabstop>useCustomColors</tabstop>
   <tabstop>actionMsgColor</tabstop>
   <tabstop>channelMsgColor</tabstop>
index 4691c94..65377fe 100644 (file)
@@ -97,8 +97,6 @@ void AbstractBufferContainer::setCurrentBuffer(BufferId bufferId) {
   if(prevBufferId.isValid() && _chatViews.contains(prevBufferId)) {
     MsgId msgId = _chatViews.value(prevBufferId)->lastMsgId();
     Client::setBufferLastSeenMsg(prevBufferId, msgId);
   if(prevBufferId.isValid() && _chatViews.contains(prevBufferId)) {
     MsgId msgId = _chatViews.value(prevBufferId)->lastMsgId();
     Client::setBufferLastSeenMsg(prevBufferId, msgId);
-    if(autoSetMarkerLine())
-      Client::setBufferMarkerLine(prevBufferId, msgId);
   }
 
   if(!bufferId.isValid()) {
   }
 
   if(!bufferId.isValid()) {
index cc77efd..474e10a 100644 (file)
@@ -52,7 +52,10 @@ protected:
    */
   virtual void removeChatView(BufferId) = 0;
 
    */
   virtual void removeChatView(BufferId) = 0;
 
-  virtual inline bool autoSetMarkerLine() const { return true; }
+  //! If true, the marker line will be set automatically on buffer switch
+  /** \return Whether the marker line should be set on buffer switch
+   */
+  virtual inline bool autoMarkerLine() const { return true; }
 
 protected slots:
   virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous);
 
 protected slots:
   virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous);