introducing query merging (per drag & drop). needs a core update
authorMarcus Eggenberger <egs@quassel-irc.org>
Mon, 29 Dec 2008 17:58:04 +0000 (18:58 +0100)
committerMarcus Eggenberger <egs@quassel-irc.org>
Mon, 29 Dec 2008 17:58:04 +0000 (18:58 +0100)
21 files changed:
src/client/client.cpp
src/client/client.h
src/client/messagefilter.cpp
src/client/messagemodel.cpp
src/client/messagemodel.h
src/client/networkmodel.cpp
src/client/networkmodel.h
src/common/buffersyncer.cpp
src/common/buffersyncer.h
src/core/SQL/SQLite/13/update_backlog_bufferid.sql [new file with mode: 0644]
src/core/core.cpp
src/core/core.h
src/core/corebuffersyncer.cpp [new file with mode: 0644]
src/core/corebuffersyncer.h [new file with mode: 0644]
src/core/coresession.cpp
src/core/sql.qrc
src/core/sqlitestorage.cpp
src/core/sqlitestorage.h
src/core/storage.h
src/uisupport/bufferview.cpp
src/uisupport/bufferview.h

index 9956cd2..52a2d13 100644 (file)
@@ -286,6 +286,8 @@ void Client::setSyncedToCore() {
   connect(bufferSyncer(), SIGNAL(lastSeenMsgSet(BufferId, MsgId)), _networkModel, SLOT(setLastSeenMsgId(BufferId, MsgId)));
   connect(bufferSyncer(), SIGNAL(bufferRemoved(BufferId)), this, SLOT(bufferRemoved(BufferId)));
   connect(bufferSyncer(), SIGNAL(bufferRenamed(BufferId, QString)), this, SLOT(bufferRenamed(BufferId, QString)));
   connect(bufferSyncer(), SIGNAL(lastSeenMsgSet(BufferId, MsgId)), _networkModel, SLOT(setLastSeenMsgId(BufferId, MsgId)));
   connect(bufferSyncer(), SIGNAL(bufferRemoved(BufferId)), this, SLOT(bufferRemoved(BufferId)));
   connect(bufferSyncer(), SIGNAL(bufferRenamed(BufferId, QString)), this, SLOT(bufferRenamed(BufferId, QString)));
+  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(initDone()), this, SLOT(requestInitialBacklog()));
   connect(networkModel(), SIGNAL(setLastSeenMsg(BufferId, MsgId)), bufferSyncer(), SLOT(requestSetLastSeenMsg(BufferId, const MsgId &)));
   signalProxy()->synchronize(bufferSyncer());
   connect(bufferSyncer(), SIGNAL(initDone()), this, SLOT(requestInitialBacklog()));
   connect(networkModel(), SIGNAL(setLastSeenMsg(BufferId, MsgId)), bufferSyncer(), SLOT(requestSetLastSeenMsg(BufferId, const MsgId &)));
   signalProxy()->synchronize(bufferSyncer());
@@ -404,6 +406,12 @@ void Client::renameBuffer(BufferId bufferId, const QString &newName) {
   bufferSyncer()->requestRenameBuffer(bufferId, newName);
 }
 
   bufferSyncer()->requestRenameBuffer(bufferId, newName);
 }
 
+void Client::mergeBuffersPermanently(BufferId bufferId1, BufferId bufferId2) {
+  if(!bufferSyncer())
+    return;
+  bufferSyncer()->requestMergeBuffersPermanently(bufferId1, bufferId2);
+}
+
 void Client::bufferRemoved(BufferId bufferId) {
   // select a sane buffer (status buffer)
   /* we have to manually select a buffer because otherwise inconsitent changes
 void Client::bufferRemoved(BufferId bufferId) {
   // select a sane buffer (status buffer)
   /* we have to manually select a buffer because otherwise inconsitent changes
@@ -429,6 +437,12 @@ void Client::bufferRenamed(BufferId bufferId, const QString &newName) {
   }
 }
 
   }
 }
 
+void Client::buffersPermanentlyMerged(BufferId bufferId1, BufferId bufferId2) {
+  QModelIndex idx = networkModel()->bufferIndex(bufferId1);
+  bufferModel()->setCurrentIndex(bufferModel()->mapFromSource(idx));
+  networkModel()->removeBuffer(bufferId2);
+}
+
 void Client::logMessage(QtMsgType type, const char *msg) {
   fprintf(stderr, "%s\n", msg);
   fflush(stderr);
 void Client::logMessage(QtMsgType type, const char *msg) {
   fprintf(stderr, "%s\n", msg);
   fflush(stderr);
index ac3663d..362b523 100644 (file)
@@ -114,6 +114,7 @@ public:
   static void setBufferLastSeenMsg(BufferId id, const MsgId &msgId); // this is synced to core and other clients
   static void removeBuffer(BufferId id);
   static void renameBuffer(BufferId bufferId, const QString &newName);
   static void setBufferLastSeenMsg(BufferId id, const MsgId &msgId); // this is synced to core and other clients
   static void removeBuffer(BufferId id);
   static void renameBuffer(BufferId bufferId, const QString &newName);
+  static void mergeBuffersPermanently(BufferId bufferId1, BufferId bufferId2);
 
   static void logMessage(QtMsgType type, const char *msg);
   static inline const QString &debugLog() { return instance()->_debugLogBuffer; }
 
   static void logMessage(QtMsgType type, const char *msg);
   static inline const QString &debugLog() { return instance()->_debugLogBuffer; }
@@ -164,6 +165,7 @@ public slots:
 
   void bufferRemoved(BufferId bufferId);
   void bufferRenamed(BufferId bufferId, const QString &newName);
 
   void bufferRemoved(BufferId bufferId);
   void bufferRenamed(BufferId bufferId, const QString &newName);
+  void buffersPermanentlyMerged(BufferId bufferId1, BufferId bufferId2);
 
 private slots:
   void disconnectedFromCore();
 
 private slots:
   void disconnectedFromCore();
index f7a1d81..cc2ec8b 100644 (file)
@@ -44,6 +44,8 @@ MessageFilter::MessageFilter(MessageModel *source, const QList<BufferId> &buffer
 }
 
 void MessageFilter::init() {
 }
 
 void MessageFilter::init() {
+  setDynamicSortFilter(true);
+
   BufferSettings defaultSettings;
   _messageTypeFilter = defaultSettings.messageFilter();
   defaultSettings.notify("MessageTypeFilter", this, SLOT(messageTypeFilterChanged()));
   BufferSettings defaultSettings;
   _messageTypeFilter = defaultSettings.messageFilter();
   defaultSettings.notify("MessageTypeFilter", this, SLOT(messageTypeFilterChanged()));
index 1ece82f..945ac7d 100644 (file)
@@ -385,6 +385,16 @@ void MessageModel::messagesReceived(BufferId bufferId, int count) {
     _messagesWaiting.remove(bufferId);
 }
 
     _messagesWaiting.remove(bufferId);
 }
 
+void MessageModel::buffersPermanentlyMerged(BufferId bufferId1, BufferId bufferId2) {
+  for(int i = 0; i < _messageList.count(); i++) {
+    if(_messageList[i]->bufferId() == bufferId2) {
+      _messageList[i]->setBufferId(bufferId1);
+      QModelIndex idx = index(i, 0);
+      emit dataChanged(idx, idx);
+    }
+  }
+}
+
 // ========================================
 //  MessageModelItem
 // ========================================
 // ========================================
 //  MessageModelItem
 // ========================================
@@ -426,7 +436,6 @@ bool MessageModelItem::setData(int column, const QVariant &value, int role) {
   }
 }
 
   }
 }
 
-
 // Stuff for later
 bool MessageModelItem::lessThan(const MessageModelItem *m1, const MessageModelItem *m2){
   return (*m1) < (*m2);
 // Stuff for later
 bool MessageModelItem::lessThan(const MessageModelItem *m1, const MessageModelItem *m2){
   return (*m1) < (*m2);
index c7c975d..b65fbbf 100644 (file)
@@ -72,6 +72,7 @@ public:
 public slots:
   void requestBacklog(BufferId bufferId);
   void messagesReceived(BufferId bufferId, int count);
 public slots:
   void requestBacklog(BufferId bufferId);
   void messagesReceived(BufferId bufferId, int count);
+  void buffersPermanentlyMerged(BufferId bufferId1, BufferId bufferId2);
 
 protected:
   virtual MessageModelItem *createMessageModelItem(const Message &) = 0;
 
 protected:
   virtual MessageModelItem *createMessageModelItem(const Message &) = 0;
@@ -111,6 +112,7 @@ public:
   inline const QDateTime &timeStamp() const { return _timestamp; }
   inline MsgId msgId() const { return _msgId; }
   inline BufferId bufferId() const { return _bufferId; }
   inline const QDateTime &timeStamp() const { return _timestamp; }
   inline MsgId msgId() const { return _msgId; }
   inline BufferId bufferId() const { return _bufferId; }
+  inline void setBufferId(BufferId bufferId) { _bufferId = bufferId; }
   inline Message::Type msgType() const { return _type; }
   inline Message::Flags msgFlags() const { return _flags; }
   
   inline Message::Type msgType() const { return _type; }
   inline Message::Flags msgFlags() const { return _flags; }
   
index 7d64442..962c9f8 100644 (file)
@@ -891,49 +891,6 @@ QMimeData *NetworkModel::mimeData(const QModelIndexList &indexes) const {
   return mimeData;
 }
 
   return mimeData;
 }
 
-bool NetworkModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) {
-  Q_UNUSED(action)
-  Q_UNUSED(row)
-  Q_UNUSED(column)
-
-  if(!mimeContainsBufferList(data))
-    return false;
-
-  // target must be a query
-  BufferInfo::Type targetType = (BufferInfo::Type)parent.data(NetworkModel::BufferTypeRole).toInt();
-  if(targetType != BufferInfo::QueryBuffer)
-    return false;
-
-  QList< QPair<NetworkId, BufferId> > bufferList = mimeDataToBufferList(data);
-
-  // exactly one buffer has to be dropped
-  if(bufferList.count() != 1)
-    return false;
-
-  NetworkId netId = bufferList.first().first;
-  BufferId bufferId = bufferList.first().second;
-
-  // no self merges (would kill us)
-  if(bufferId == parent.data(BufferIdRole).value<BufferId>())
-    return false;
-
-  NetworkItem *netItem = findNetworkItem(netId);
-  Q_ASSERT(netItem);
-
-  BufferItem *bufferItem = netItem->findBufferItem(bufferId);
-  Q_ASSERT(bufferItem);
-
-  // source must be a query too
-  if(bufferItem->bufferType() != BufferInfo::QueryBuffer)
-    return false;
-
-  // TODO: warn user about buffermerge!
-  qDebug() << "merging" << bufferId << parent.data(BufferIdRole).value<BufferId>();
-  removeRow(parent.row(), parent.parent());
-
-  return true;
-}
-
 void NetworkModel::attachNetwork(Network *net) {
   NetworkItem *netItem = networkItem(net->networkId());
   netItem->attachNetwork(net);
 void NetworkModel::attachNetwork(Network *net) {
   NetworkItem *netItem = networkItem(net->networkId());
   netItem->attachNetwork(net);
index e765252..7412d13 100644 (file)
@@ -277,7 +277,6 @@ public:
 
   virtual QStringList mimeTypes() const;
   virtual QMimeData *mimeData(const QModelIndexList &) const;
 
   virtual QStringList mimeTypes() const;
   virtual QMimeData *mimeData(const QModelIndexList &) const;
-  virtual bool dropMimeData(const QMimeData *, Qt::DropAction, int, int, const QModelIndex &);
 
   void attachNetwork(Network *network);
 
 
   void attachNetwork(Network *network);
 
index 816227f..c6fa1e7 100644 (file)
@@ -65,12 +65,14 @@ void BufferSyncer::initSetLastSeenMsg(const QVariantList &list) {
 }
 
 void BufferSyncer::removeBuffer(BufferId buffer) {
 }
 
 void BufferSyncer::removeBuffer(BufferId buffer) {
-  if(_lastSeenMsg.contains(buffer)) {
+  if(_lastSeenMsg.contains(buffer))
     _lastSeenMsg.remove(buffer);
     _lastSeenMsg.remove(buffer);
-    emit bufferRemoved(buffer);
-  }
+  emit bufferRemoved(buffer);
 }
 
 }
 
-// void BufferSyncer::renameBuffer(BufferId buffer, QString newName) {
-//   emit bufferRenamed(buffer, newName);
-// }
+
+void BufferSyncer::mergeBuffersPermanently(BufferId buffer1, BufferId buffer2) {
+  if(_lastSeenMsg.contains(buffer2))
+    _lastSeenMsg.remove(buffer2);
+  emit buffersPermanentlyMerged(buffer1, buffer2);
+}
index 92ca54d..f57caae 100644 (file)
@@ -38,19 +38,29 @@ public slots:
   void initSetLastSeenMsg(const QVariantList &);
 
   virtual inline void requestSetLastSeenMsg(BufferId buffer, const MsgId &msgId) { emit setLastSeenMsgRequested(buffer, msgId); }
   void initSetLastSeenMsg(const QVariantList &);
 
   virtual inline void requestSetLastSeenMsg(BufferId buffer, const MsgId &msgId) { emit setLastSeenMsgRequested(buffer, msgId); }
+
   virtual inline void requestRemoveBuffer(BufferId buffer) { emit removeBufferRequested(buffer); }
   virtual void removeBuffer(BufferId buffer);
   virtual inline void requestRemoveBuffer(BufferId buffer) { emit removeBufferRequested(buffer); }
   virtual void removeBuffer(BufferId buffer);
+
   virtual inline void requestRenameBuffer(BufferId buffer, QString newName) { emit renameBufferRequested(buffer, newName); }
   virtual inline void renameBuffer(BufferId buffer, QString newName) { emit bufferRenamed(buffer, newName); }
 
   virtual inline void requestRenameBuffer(BufferId buffer, QString newName) { emit renameBufferRequested(buffer, newName); }
   virtual inline void renameBuffer(BufferId buffer, QString newName) { emit bufferRenamed(buffer, newName); }
 
+  virtual inline void requestMergeBuffersPermanently(BufferId buffer1, BufferId buffer2) { emit mergeBuffersPermanentlyRequested(buffer1, buffer2); }
+  virtual void mergeBuffersPermanently(BufferId buffer1, BufferId buffer2);
+
 signals:
   void lastSeenMsgSet(BufferId buffer, const MsgId &msgId);
   void setLastSeenMsgRequested(BufferId buffer, const MsgId &msgId);
 signals:
   void lastSeenMsgSet(BufferId buffer, const MsgId &msgId);
   void setLastSeenMsgRequested(BufferId buffer, const MsgId &msgId);
+
   void removeBufferRequested(BufferId buffer);
   void bufferRemoved(BufferId buffer);
   void removeBufferRequested(BufferId buffer);
   void bufferRemoved(BufferId buffer);
+
   void renameBufferRequested(BufferId buffer, QString newName);
   void bufferRenamed(BufferId buffer, QString newName);
 
   void renameBufferRequested(BufferId buffer, QString newName);
   void bufferRenamed(BufferId buffer, QString newName);
 
+  void mergeBuffersPermanentlyRequested(BufferId buffer1, BufferId buffer2);
+  void buffersPermanentlyMerged(BufferId buffer1, BufferId buffer2);
+
 protected slots:
   bool setLastSeenMsg(BufferId buffer, const MsgId &msgId);
 
 protected slots:
   bool setLastSeenMsg(BufferId buffer, const MsgId &msgId);
 
diff --git a/src/core/SQL/SQLite/13/update_backlog_bufferid.sql b/src/core/SQL/SQLite/13/update_backlog_bufferid.sql
new file mode 100644 (file)
index 0000000..b490b29
--- /dev/null
@@ -0,0 +1,3 @@
+UPDATE backlog
+SET bufferid = :newbufferid
+WHERE bufferid = :oldbufferid
index 830a79b..233157b 100644 (file)
@@ -63,7 +63,7 @@ Core::Core() : storage(0) {
     exit(1); // TODO make this less brutal (especially for mono client -> popup)
   }
   connect(&_storageSyncTimer, SIGNAL(timeout()), this, SLOT(syncStorage()));
     exit(1); // TODO make this less brutal (especially for mono client -> popup)
   }
   connect(&_storageSyncTimer, SIGNAL(timeout()), this, SLOT(syncStorage()));
-  _storageSyncTimer.start(10 * 60 * 1000); // in msecs
+  _storageSyncTimer.start(10 * 60 * 1000); // 10 minutes
 }
 
 void Core::init() {
 }
 
 void Core::init() {
index 6ddb6e8..8945b0e 100644 (file)
@@ -300,6 +300,17 @@ class Core : public QObject {
     return instance()->storage->renameBuffer(user, bufferId, newName);
   }
 
     return instance()->storage->renameBuffer(user, bufferId, newName);
   }
 
+  //! Merge the content of two Buffers permanently. This cannot be reversed!
+  /** \note This method is threadsafe.
+   *  \param user      The id of the buffer owner
+   *  \param bufferId1 The bufferId of the remaining buffer
+   *  \param bufferId2 The buffer that is about to be removed
+   *  \return true if successfulln
+   */
+  static inline bool mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2) {
+    return instance()->storage->mergeBuffersPermanently(user, bufferId1, bufferId2);
+  }
+
   //! Update the LastSeenDate for a Buffer
   /** This Method is used to make the LastSeenDate of a Buffer persistent
    *  \note This method is threadsafe.
   //! Update the LastSeenDate for a Buffer
   /** This Method is used to make the LastSeenDate of a Buffer persistent
    *  \note This method is threadsafe.
@@ -324,6 +335,8 @@ class Core : public QObject {
 
   const QDateTime &startTime() const { return _startTime; }
 
 
   const QDateTime &startTime() const { return _startTime; }
 
+  static inline QTimer &syncTimer() { return instance()->_storageSyncTimer; }
+
 public slots:
   //! Make storage data persistent
   /** \note This method is threadsafe.
 public slots:
   //! Make storage data persistent
   /** \note This method is threadsafe.
diff --git a/src/core/corebuffersyncer.cpp b/src/core/corebuffersyncer.cpp
new file mode 100644 (file)
index 0000000..f218508
--- /dev/null
@@ -0,0 +1,112 @@
+/***************************************************************************
+ *   Copyright (C) 2005-08 by the Quassel Project                          *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include "corebuffersyncer.h"
+
+#include "core.h"
+#include "coresession.h"
+#include "corenetwork.h"
+#include "ircchannel.h"
+
+CoreBufferSyncer::CoreBufferSyncer(CoreSession *parent)
+  : BufferSyncer(parent),
+    _coreSession(parent)
+{
+}
+
+void CoreBufferSyncer::requestSetLastSeenMsg(BufferId buffer, const MsgId &msgId) {
+  if(setLastSeenMsg(buffer, msgId))
+    dirtyBuffers << buffer;
+}
+
+void CoreBufferSyncer::storeDirtyIds() {
+  UserId userId = _coreSession->user();
+  MsgId msgId;
+  foreach(BufferId bufferId, dirtyBuffers) {
+    msgId = lastSeenMsg(bufferId);
+    if(msgId.isValid())
+      Core::setBufferLastSeenMsg(userId, bufferId, msgId);
+  }
+  dirtyBuffers.clear();
+}
+
+void CoreBufferSyncer::removeBuffer(BufferId bufferId) {
+  BufferInfo bufferInfo = Core::getBufferInfo(_coreSession->user(), bufferId);
+  if(!bufferInfo.isValid()) {
+    qWarning() << "CoreBufferSyncer::removeBuffer(): invalid BufferId:" << bufferId << "for User:" << _coreSession->user();
+    return;
+  }
+
+  if(bufferInfo.type() == BufferInfo::StatusBuffer) {
+    qWarning() << "CoreBufferSyncer::removeBuffer(): Status Buffers cannot be removed!";
+    return;
+  }
+
+  if(bufferInfo.type() == BufferInfo::ChannelBuffer) {
+    CoreNetwork *net = _coreSession->network(bufferInfo.networkId());
+    if(!net) {
+      qWarning() << "CoreBufferSyncer::removeBuffer(): Received BufferInfo with unknown networkId!";
+      return;
+    }
+    IrcChannel *chan = net->ircChannel(bufferInfo.bufferName());
+    if(chan) {
+      qWarning() << "CoreBufferSyncer::removeBuffer(): Unable to remove Buffer for joined Channel:" << bufferInfo.bufferName();
+      return;
+    }
+  }
+  if(Core::removeBuffer(_coreSession->user(), bufferId))
+    BufferSyncer::removeBuffer(bufferId);
+}
+
+void CoreBufferSyncer::renameBuffer(BufferId bufferId, QString newName) {
+  BufferInfo bufferInfo = Core::getBufferInfo(_coreSession->user(), bufferId);
+  if(!bufferInfo.isValid()) {
+    qWarning() << "CoreBufferSyncer::renameBuffer(): invalid BufferId:" << bufferId << "for User:" << _coreSession->user();
+    return;
+  }
+
+  if(bufferInfo.type() != BufferInfo::QueryBuffer) {
+    qWarning() << "CoreBufferSyncer::renameBuffer(): only QueryBuffers can be renamed" << bufferId;
+    return;
+  }
+
+  if(Core::renameBuffer(_coreSession->user(), bufferId, newName))
+    BufferSyncer::renameBuffer(bufferId, newName);
+}
+
+void CoreBufferSyncer::mergeBuffersPermanently(BufferId bufferId1, BufferId bufferId2) {
+  BufferInfo bufferInfo1 = Core::getBufferInfo(_coreSession->user(), bufferId1);
+  BufferInfo bufferInfo2 = Core::getBufferInfo(_coreSession->user(), bufferId2);
+  qDebug() << Q_FUNC_INFO << bufferInfo1 << bufferInfo2;
+  if(!bufferInfo1.isValid() || !bufferInfo2.isValid()) {
+    qWarning() << "CoreBufferSyncer::mergeBufferPermanently(): invalid BufferIds:" << bufferId1 << bufferId2 << "for User:" << _coreSession->user();
+    return;
+  }
+
+  if(bufferInfo1.type() != BufferInfo::QueryBuffer || bufferInfo2.type() != BufferInfo::QueryBuffer) {
+    qWarning() << "CoreBufferSyncer::mergeBufferPermanently(): only QueryBuffers can be merged!" << bufferId1 << bufferId2;
+    return;
+  }
+
+  if(Core::mergeBuffersPermanently(_coreSession->user(), bufferId1, bufferId2)) {
+    qDebug () << "HUUUUP";
+    BufferSyncer::mergeBuffersPermanently(bufferId1, bufferId2);
+  }
+}
diff --git a/src/core/corebuffersyncer.h b/src/core/corebuffersyncer.h
new file mode 100644 (file)
index 0000000..0c3a8c0
--- /dev/null
@@ -0,0 +1,54 @@
+/***************************************************************************
+ *   Copyright (C) 2005-08 by the Quassel Project                          *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef COREBUFFERSYNCER_H
+#define COREBUFFERSYNCER_H
+
+#include "buffersyncer.h"
+
+class CoreSession;
+
+class CoreBufferSyncer : public BufferSyncer {
+  Q_OBJECT
+
+public:
+  CoreBufferSyncer(CoreSession *parent);
+
+public slots:
+  virtual void requestSetLastSeenMsg(BufferId buffer, const MsgId &msgId);
+
+  virtual inline void requestRemoveBuffer(BufferId buffer) { removeBuffer(buffer); }
+  virtual void removeBuffer(BufferId bufferId);
+
+  virtual inline void requestRenameBuffer(BufferId buffer, QString newName) { renameBuffer(buffer, newName); }
+  virtual void renameBuffer(BufferId buffer, QString newName);
+
+  virtual inline void requestMergeBuffersPermanently(BufferId buffer1, BufferId buffer2) { mergeBuffersPermanently(buffer1, buffer2); }
+  virtual void mergeBuffersPermanently(BufferId buffer1, BufferId buffer2);
+
+  void storeDirtyIds();
+
+private:
+  CoreSession *_coreSession;
+
+  QSet<BufferId> dirtyBuffers;
+};
+
+#endif //COREBUFFERSYNCER_H
index 841ae7c..fd9a872 100644 (file)
@@ -80,7 +80,8 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
   foreach(BufferId id, lastSeenHash.keys())
     _bufferSyncer->requestSetLastSeenMsg(id, lastSeenHash[id]);
 
   foreach(BufferId id, lastSeenHash.keys())
     _bufferSyncer->requestSetLastSeenMsg(id, lastSeenHash[id]);
 
-  connect(_bufferSyncer, SIGNAL(lastSeenMsgSet(BufferId, MsgId)), this, SLOT(storeBufferLastSeenMsg(BufferId, MsgId)));
+  // connect(_bufferSyncer, SIGNAL(lastSeenMsgSet(BufferId, MsgId)), this, SLOT(storeBufferLastSeenMsg(BufferId, MsgId)));
+  connect(&(Core::instance()->syncTimer()), SIGNAL(timeout()), _bufferSyncer, SLOT(storeDirtyIds()));
   p->synchronize(_bufferSyncer);
 
 
   p->synchronize(_bufferSyncer);
 
 
@@ -158,6 +159,7 @@ void CoreSession::loadSettings() {
 }
 
 void CoreSession::saveSessionState() const {
 }
 
 void CoreSession::saveSessionState() const {
+  _bufferSyncer->storeDirtyIds();
 }
 
 void CoreSession::restoreSessionState() {
 }
 
 void CoreSession::restoreSessionState() {
index 2c2c50e..319a568 100644 (file)
@@ -77,6 +77,7 @@
     <file>./SQL/SQLite/13/setup_130_identity.sql</file>
     <file>./SQL/SQLite/13/setup_140_identity_nick.sql</file>
     <file>./SQL/SQLite/13/setup_999_version.sql</file>
     <file>./SQL/SQLite/13/setup_130_identity.sql</file>
     <file>./SQL/SQLite/13/setup_140_identity_nick.sql</file>
     <file>./SQL/SQLite/13/setup_999_version.sql</file>
+    <file>./SQL/SQLite/13/update_backlog_bufferid.sql</file>
     <file>./SQL/SQLite/13/update_buffer_lastseen.sql</file>
     <file>./SQL/SQLite/13/update_buffer_name.sql</file>
     <file>./SQL/SQLite/13/update_buffer_persistent_channel.sql</file>
     <file>./SQL/SQLite/13/update_buffer_lastseen.sql</file>
     <file>./SQL/SQLite/13/update_buffer_name.sql</file>
     <file>./SQL/SQLite/13/update_buffer_persistent_channel.sql</file>
index dea348f..718dc59 100644 (file)
@@ -808,6 +808,27 @@ bool SqliteStorage::renameBuffer(const UserId &user, const BufferId &bufferId, c
   return true;
 }
 
   return true;
 }
 
+bool SqliteStorage::mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2) {
+  if(!isValidBuffer(user, bufferId1) || !isValidBuffer(user, bufferId2))
+    return false;
+
+  QSqlQuery query(logDb());
+  query.prepare(queryString("update_backlog_bufferid"));
+  query.bindValue(":oldbufferid", bufferId2.toInt());
+  query.bindValue(":newbufferid", bufferId1.toInt());
+  safeExec(query);
+  if(!watchQuery(query))
+    return false;
+
+  QSqlQuery delBufferQuery(logDb());
+  delBufferQuery.prepare(queryString("delete_buffer_for_bufferid"));
+  delBufferQuery.bindValue(":bufferid", bufferId2.toInt());
+  safeExec(delBufferQuery);
+  watchQuery(delBufferQuery);
+
+  return true;
+}
+
 void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId) {
   QSqlQuery query(logDb());
   query.prepare(queryString("update_buffer_lastseen"));
 void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId) {
   QSqlQuery query(logDb());
   query.prepare(queryString("update_buffer_lastseen"));
index 9b6d2c7..6ad80fe 100644 (file)
@@ -80,6 +80,7 @@ public slots:
   virtual QList<BufferId> requestBufferIdsForNetwork(UserId user, NetworkId networkId);
   virtual bool removeBuffer(const UserId &user, const BufferId &bufferId);
   virtual bool renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName);
   virtual QList<BufferId> requestBufferIdsForNetwork(UserId user, NetworkId networkId);
   virtual bool removeBuffer(const UserId &user, const BufferId &bufferId);
   virtual bool renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName);
+  virtual bool mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2);
   virtual void setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId);
   virtual QHash<BufferId, MsgId> bufferLastSeenMsgIds(UserId user);
 
   virtual void setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId);
   virtual QHash<BufferId, MsgId> bufferLastSeenMsgIds(UserId user);
 
index a7aaae9..9612a59 100644 (file)
@@ -274,7 +274,16 @@ public slots:
    *  \return true if successfull
    */
   virtual bool renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName) = 0;
    *  \return true if successfull
    */
   virtual bool renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName) = 0;
-  
+
+  //! Merge the content of two Buffers permanently. This cannot be reversed!
+  /** \note This method is threadsafe.
+   *  \param user      The id of the buffer owner
+   *  \param bufferId1 The bufferId of the remaining buffer
+   *  \param bufferId2 The buffer that is about to be removed
+   *  \return true if successfull
+   */
+  virtual bool mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2) = 0;
+
   //! Update the LastSeenDate for a Buffer
   /** This Method is used to make the LastSeenDate of a Buffer persistent
    * \param user      The Owner of that Buffer
   //! Update the LastSeenDate for a Buffer
   /** This Method is used to make the LastSeenDate of a Buffer persistent
    * \param user      The Owner of that Buffer
index eadf8f7..c883434 100644 (file)
@@ -196,6 +196,37 @@ void BufferView::keyPressEvent(QKeyEvent *event) {
   QTreeView::keyPressEvent(event);
 }
 
   QTreeView::keyPressEvent(event);
 }
 
+void BufferView::dropEvent(QDropEvent *event) {
+  QList< QPair<NetworkId, BufferId> > bufferList = Client::networkModel()->mimeDataToBufferList(event->mimeData());
+
+  if(bufferList.count() != 1)
+    return QTreeView::dropEvent(event);
+
+  NetworkId networkId = bufferList[0].first;
+  BufferId bufferId2 = bufferList[0].second;
+
+  QModelIndex index = indexAt(event->pos());
+  if(index.data(NetworkModel::ItemTypeRole) != NetworkModel::BufferItemType)
+    return;
+
+  if(index.data(NetworkModel::BufferTypeRole) != BufferInfo::QueryBuffer)
+    return;
+
+  if(index.data(NetworkModel::NetworkIdRole).value<NetworkId>() != networkId)
+    return;
+
+  BufferId bufferId1 = index.data(NetworkModel::BufferIdRole).value<BufferId>();
+  if(bufferId1 == bufferId2)
+    return;
+
+  int res = QMessageBox::question(0, tr("Merge buffers permanently?"),
+                                 tr("Do you want to merge the buffer \"%1\" permanently into buffer \"%2\"?\n This cannot be reversed!").arg(Client::networkModel()->bufferName(bufferId2)).arg(Client::networkModel()->bufferName(bufferId1)),
+                                 QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
+  if(res == QMessageBox::Yes) {
+    Client::mergeBuffersPermanently(bufferId1, bufferId2);
+  }
+}
+
 void BufferView::removeSelectedBuffers(bool permanently) {
   if(!config())
     return;
 void BufferView::removeSelectedBuffers(bool permanently) {
   if(!config())
     return;
index ad411a8..032cd0f 100644 (file)
@@ -63,6 +63,7 @@ signals:
 
 protected:
   virtual void keyPressEvent(QKeyEvent *);
 
 protected:
   virtual void keyPressEvent(QKeyEvent *);
+  virtual void dropEvent(QDropEvent *event);
   virtual void rowsInserted(const QModelIndex & parent, int start, int end);
   virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
   virtual void wheelEvent(QWheelEvent *);
   virtual void rowsInserted(const QModelIndex & parent, int start, int end);
   virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
   virtual void wheelEvent(QWheelEvent *);