Changed the BufferView System to a MVC Design Pattern
authorMarcus Eggenberger <egs@quassel-irc.org>
Mon, 18 Jun 2007 15:09:21 +0000 (15:09 +0000)
committerMarcus Eggenberger <egs@quassel-irc.org>
Mon, 18 Jun 2007 15:09:21 +0000 (15:09 +0000)
gui/CMakeLists.txt
gui/buffer.cpp
gui/buffer.h
gui/bufferview.cpp
gui/bufferview.h
gui/bufferviewwidget.cpp [new file with mode: 0644]
gui/bufferviewwidget.h [new file with mode: 0644]
gui/mainwin.cpp
gui/mainwin.h
gui/ui/bufferviewwidget.ui

index 91ff392..f118eae 100644 (file)
@@ -1,11 +1,11 @@
 SET(gui_SRCS chatwidget.cpp channelwidgetinput.cpp tabcompleter.cpp mainwin.cpp serverlist.cpp buffer.cpp bufferwidget.cpp
 SET(gui_SRCS chatwidget.cpp channelwidgetinput.cpp tabcompleter.cpp mainwin.cpp serverlist.cpp buffer.cpp bufferwidget.cpp
-             identities.cpp coreconnectdlg.cpp guiproxy.cpp bufferview.cpp style.cpp settingsdlg.cpp settingspages.cpp)
+             identities.cpp coreconnectdlg.cpp guiproxy.cpp bufferview.cpp bufferviewwidget.cpp style.cpp settingsdlg.cpp settingspages.cpp)
 SET(gui_HDRS style.h)
 SET(gui_MOCS chatwidget.h channelwidgetinput.h tabcompleter.h mainwin.h serverlist.h identities.h coreconnectdlg.h
 SET(gui_HDRS style.h)
 SET(gui_MOCS chatwidget.h channelwidgetinput.h tabcompleter.h mainwin.h serverlist.h identities.h coreconnectdlg.h
-             guiproxy.h bufferview.h buffer.h bufferwidget.h settingsdlg.h settingspages.h)
+             guiproxy.h bufferview.h buffer.h bufferwidget.h bufferviewwidget.h settingsdlg.h settingspages.h)
 SET(gui_UICS identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui mainwin.ui
              nickeditdlg.ui serverlistdlg.ui servereditdlg.ui coreconnectdlg.ui ircwidget.ui
 SET(gui_UICS identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui mainwin.ui
              nickeditdlg.ui serverlistdlg.ui servereditdlg.ui coreconnectdlg.ui ircwidget.ui
-             bufferview.ui bufferwidget.ui settingsdlg.ui
+             bufferviewwidget.ui bufferwidget.ui settingsdlg.ui
              buffermgmntsettingspage.ui connectionsettingspage.ui)
 
 # This prepends ui/ to the UIC names, so we don't have to do this ourselves.
              buffermgmntsettingspage.ui connectionsettingspage.ui)
 
 # This prepends ui/ to the UIC names, so we don't have to do this ourselves.
index 9c9726e..cf764c1 100644 (file)
@@ -67,6 +67,13 @@ void Buffer::init() {
 
 }
 
 
 }
 
+QString Buffer::displayName() {
+  if(bufferType() == ServerBuffer)
+    return tr("status");
+  else
+    return bufferName();
+}
+
 void Buffer::setActive(bool a) {
   if(a != active) {
     active = a;
 void Buffer::setActive(bool a) {
   if(a != active) {
     active = a;
index 7738ebe..944b07c 100644 (file)
@@ -49,16 +49,27 @@ class Buffer : public QObject {
     static void init();
 
     enum Type { ServerBuffer, ChannelBuffer, QueryBuffer };
     static void init();
 
     enum Type { ServerBuffer, ChannelBuffer, QueryBuffer };
+
+    enum Activity {
+      NoActivity = 0x00,
+      OtherActivity = 0x01,
+      NewMessage = 0x02,
+      Highlight = 0x40
+    };
+    Q_DECLARE_FLAGS(ActivityLevel, Activity)
+    
     Type bufferType() { return type; }
     bool isActive() { return active; }
 
     QString networkName() { return _networkName; }
     QString bufferName() { return _bufferName; }
     Type bufferType() { return type; }
     bool isActive() { return active; }
 
     QString networkName() { return _networkName; }
     QString bufferName() { return _bufferName; }
+    QString displayName();
     BufferId bufferId() { return id; }
     QList<ChatLine *> contents() { return lines; }
     VarMap nickList() { return nicks; }
     QString topic() { return _topic; }
     QString ownNick() { return _ownNick; }
     BufferId bufferId() { return id; }
     QList<ChatLine *> contents() { return lines; }
     VarMap nickList() { return nicks; }
     QString topic() { return _topic; }
     QString ownNick() { return _ownNick; }
+    bool isStatusBuffer() { return bufferType() == ServerBuffer; }
 
   signals:
     void userInput(BufferId, QString);
 
   signals:
     void userInput(BufferId, QString);
@@ -104,5 +115,6 @@ class Buffer : public QObject {
     QList<ChatLine *> lines;
 
 };
     QList<ChatLine *> lines;
 
 };
+Q_DECLARE_OPERATORS_FOR_FLAGS(Buffer::ActivityLevel)    
 
 #endif
 
 #endif
index f49898c..e0923cf 100644 (file)
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#include "global.h"
 #include "bufferview.h"
 #include "bufferview.h"
-
-BufferViewWidget::BufferViewWidget(QWidget *parent) : QWidget(parent) {
-  ui.setupUi(this);
-
-  //setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
-}
-
-
-QSize BufferViewWidget::sizeHint() const {
-  return QSize(150,100);
-
-}
-
-/**************************************************************************/
-
-BufferView::BufferView(QString n, int m, QStringList nets, QWidget *parent) : QDockWidget(parent) {
-  setObjectName(QString("View-"+n)); // should be unique for mainwindow state!
-  name = n; mode = m;
-  setWindowTitle(name);
+#include "bufferviewwidget.h"
+
+/*****************************************
+* The TreeView showing the Buffers
+*****************************************/
+BufferViewFilter::BufferViewFilter(QAbstractItemModel *model, Modes filtermode, QStringList nets, QObject *parent) : QSortFilterProxyModel(parent) {
+  setSourceModel(model);
+  mode = filtermode;
   networks = nets;
   networks = nets;
-  currentBuffer = 0;
-  setWidget(new BufferViewWidget(this));
-  tree = qobject_cast<BufferViewWidget*>(widget())->tree();
-  tree->header()->hide();
-  tree->setSortingEnabled(true);
-  tree->setRootIsDecorated(true);
-  tree->setIndentation(10);
-  //tree->setAnimated(true);
-  connect(tree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(itemClicked(QTreeWidgetItem*)));
-  connect(tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(itemDoubleClicked(QTreeWidgetItem*)));
-  connect(this, SIGNAL(fakeUserInput(BufferId, QString)), guiProxy, SLOT(gsUserInput(BufferId, QString)));
   
   
+  connect(model, SIGNAL(invalidateFilter()), this, SLOT(invalidateMe()));
+  connect(model, SIGNAL(updateSelection(const QModelIndex &, QItemSelectionModel::SelectionFlags)), this, SLOT(select(const QModelIndex &, QItemSelectionModel::SelectionFlags)));
+    
+  connect(this, SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), model, SLOT(changeCurrent(const QModelIndex &, const QModelIndex &)));
+  connect(this, SIGNAL(doubleClicked(const QModelIndex &)), model, SLOT(doubleClickReceived(const QModelIndex &)));
 }
 
 }
 
-void BufferView::setBuffers(QList<Buffer *> buffers) {
-  tree->clear(); bufitems.clear(); netitems.clear();
-  foreach(Buffer *b, buffers) {
-    bufferUpdated(b);
-  }
+void BufferViewFilter::invalidateMe() {
+  invalidateFilter();
 }
 
 }
 
-void BufferView::bufferUpdated(Buffer *b) {
-  if(bufitems.contains(b)) {
-    // FIXME this looks ugly
-    /*
-      this is actually fugly! :) - EgS
-      if anyone else wonders what this does: it takes the TreeItem related to the buffer out of the parents child list
-      therefore we need to know the childs index
-    */
-    QTreeWidgetItem *item = bufitems[b]->parent()->takeChild(bufitems[b]->parent()->indexOfChild(bufitems[b]));
-    delete item;
-    bufitems.remove(b);
-  }
-  if(shouldShow(b)) {
-    QString net = b->networkName();
-    QString buf = b->bufferName();
-    QTreeWidgetItem *item;
-    QStringList label;
-    if(b->bufferType() == Buffer::ServerBuffer) label << tr("Status");
-    else label << buf;
-    if((mode & SomeNets) || ( mode & AllNets)) {
-      if(!netitems.contains(net)) {
-        netitems[net] = new QTreeWidgetItem(tree, QStringList(net));
-        netitems[net]->setFlags(Qt::ItemIsEnabled);
-      }
-      QTreeWidgetItem *ni = netitems[net];
-      ni->setExpanded(true);
-      ni->setFlags(Qt::ItemIsEnabled);
-      item = new QTreeWidgetItem(ni, label);
-    } else {
-      item = new QTreeWidgetItem(label);
-    }
-    //item->setFlags(Qt::ItemIsEnabled);
-    bufitems[b] = item;
-    // TODO Use style engine!
-    if(!b->isActive()) {
-      item->setForeground(0, QColor("grey"));
-    }
-    if(b == currentBuffer) {
-      // this fixes the multiple simultaneous selections
-      emit bufferSelected(b);
-      //item->setSelected(true);
-    }
-  }
-  foreach(QString key, netitems.keys()) {
-    if(!netitems[key]->childCount()) {
-      delete netitems[key];
-      QTreeWidgetItem *item = netitems[key]->parent()->takeChild(netitems[key]->parent()->indexOfChild(netitems[key]));
-      delete item;
-      netitems.remove(key);
-    }
-  }
+void BufferViewFilter::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) {
+  emit updateSelection(mapFromSource(index), command);
 }
 
 }
 
-void BufferView::bufferActivity(uint level, Buffer *b) {
-  QColor c;
-  if(bufitems.contains(b) and b != currentBuffer) {
-    if(level & Highlight) {
-      c = QColor(Qt::red);
-    } else if(level & NewMessage) {
-      c = QColor(Qt::darkYellow);
-    } else if(level & OtherActivity) {
-      c = QColor(Qt::darkGreen);
-    }
-    bufitems[b]->setForeground(0, c);
-  }
+void BufferViewFilter::changeCurrent(const QModelIndex &current, const QModelIndex &previous) {
+  emit currentChanged(mapToSource(current), mapToSource(previous));
 }
 
 }
 
-void BufferView::clearActivity(Buffer *b) {
-  QColor c;
-  // it should be sane not to check if b is in bufitems since we just checked before calling this function
-  if(b->isActive()) {
-      c = QColor(Qt::black);
-  } else {
-    c = QColor(Qt::gray);
-  }
-  bufitems[b]->setForeground(0, c);
+void BufferViewFilter::doubleClickReceived(const QModelIndex &clicked) {
+  emit doubleClicked(mapToSource(clicked));
 }
 
 }
 
-bool BufferView::shouldShow(Buffer *b) {
-  // bool f = false;
-  if((mode & NoActive) && b->isActive()) return false;
-  if((mode & NoInactive) && !b->isActive()) return false;
-  if((mode & NoChannels) && b->bufferType() == Buffer::ChannelBuffer) return false;
-  if((mode & NoQueries) && b->bufferType() == Buffer::QueryBuffer) return false;
-  if((mode & NoServers) && b->bufferType() == Buffer::ServerBuffer) return false;
-  if((mode & SomeNets) && !networks.contains(b->networkName())) return false;
+bool BufferViewFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const {
+  QModelIndex child = source_parent.child(source_row, 0);
+  if(!child.isValid())
+    return true; // can't imagine this case but true sounds good :)
+  
+  Buffer::Type bufferType = (Buffer::Type) child.data(BufferTreeModel::BufferTypeRole).toInt();
+  if((mode & NoChannels) && bufferType == Buffer::ChannelBuffer) return false;
+  if((mode & NoQueries) && bufferType == Buffer::QueryBuffer) return false;
+  if((mode & NoServers) && bufferType == Buffer::ServerBuffer) return false;
+
+  bool isActive = child.data(BufferTreeModel::BufferActiveRole).toBool();
+  if((mode & NoActive) && isActive) return false;
+  if((mode & NoInactive) && !isActive) return false;
+
+  QString net = child.data(Qt::DisplayRole).toString();
+  if((mode & SomeNets) && !networks.contains(net)) return false;
+    
   return true;
 }
 
   return true;
 }
 
-void BufferView::bufferDestroyed(Buffer *b) {
-
+/*****************************************
+* The TreeView showing the Buffers
+*****************************************/
+BufferView::BufferView(QWidget *parent) : QTreeView(parent) {
 }
 
 }
 
-void BufferView::itemClicked(QTreeWidgetItem *item) {
-  Buffer *b = bufitems.key(item);
-  if(b) {
-    // there is a buffer associated with the item (aka: status/channel/query)
-    emit bufferSelected(b);
-  } else {
-    // network item
-    item->setExpanded(!item->isExpanded());
-  }
+void BufferView::init() {
+  setIndentation(10);
+  header()->hide();
+  header()->hideSection(1);
+  
+  setDragEnabled(true);
+  setAcceptDrops(true);
+  setDropIndicatorShown(true);
+  
+  connect(selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), model(), SLOT(changeCurrent(const QModelIndex &, const QModelIndex &)));
+  connect(this, SIGNAL(doubleClicked(const QModelIndex &)), model(), SLOT(doubleClickReceived(const QModelIndex &)));
+  connect(model(), SIGNAL(updateSelection(const QModelIndex &, QItemSelectionModel::SelectionFlags)), selectionModel(), SLOT(select(const QModelIndex &, QItemSelectionModel::SelectionFlags)));
 }
 
 }
 
-void BufferView::itemDoubleClicked(QTreeWidgetItem *item) {
-  Buffer *b = bufitems.key(item);
-  if(b && Buffer::ChannelBuffer == b->bufferType()) {
-    emit fakeUserInput(b->bufferId(), QString("/join " + b->bufferName()));
-    emit bufferSelected(b);
-  }
+void BufferView::setFilteredModel(QAbstractItemModel *model, BufferViewFilter::Modes mode, QStringList nets) {
+  BufferViewFilter *filter = new BufferViewFilter(model, mode, nets);
+  setModel(filter);
 }
 
 }
 
-void BufferView::selectBuffer(Buffer *b) {
-  QTreeWidgetItem *item = 0;
-  if(bufitems.contains(b)) item = bufitems[b];
-  QList<QTreeWidgetItem *> sel = tree->selectedItems();
-  foreach(QTreeWidgetItem *i, sel) { if(i != item) i->setSelected(false); }
-  if(item) {
-    item->setSelected(true);
-    clearActivity(b);
-    currentBuffer = b;
-  } else {
-    currentBuffer = 0;
-  }
-}
index a76e327..49f3a80 100644 (file)
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#ifndef _BUFFERVIEW_H_
-#define _BUFFERVIEW_H_
+#ifndef _BUFFERVIEWWIDGET_H_
+#define _BUFFERVIEWWIDGET_H_
 
 #include <QtGui>
 
 #include <QtGui>
-#include "ui_bufferview.h"
-#include "guiproxy.h"
+#include <QFlags>
 #include "buffer.h"
 
 #include "buffer.h"
 
-typedef QHash<QString, QHash<QString, Buffer*> > BufferHash;
-
-class BufferViewWidget : public QWidget {
+/*****************************************
+ * Buffer View Filter
+ *****************************************/
+class BufferViewFilter : public QSortFilterProxyModel {
   Q_OBJECT
   Q_OBJECT
+  
+public:
+  enum Mode {
+    NoActive = 0x01,
+    NoInactive = 0x02,
+    SomeNets = 0x04,
+    AllNets = 0x08,
+    NoChannels = 0x10,
+    NoQueries = 0x20,
+    NoServers = 0x40
+  };
+  Q_DECLARE_FLAGS(Modes, Mode)
+
+  BufferViewFilter(QAbstractItemModel *model, Modes mode, QStringList nets, QObject *parent = 0);
+  
+public slots:
+  void invalidateMe();
+  void changeCurrent(const QModelIndex &, const QModelIndex &);
+  void doubleClickReceived(const QModelIndex &);
+  void select(const QModelIndex &, QItemSelectionModel::SelectionFlags);
+  
+signals:
+  void currentChanged(const QModelIndex &, const QModelIndex &);
+  void doubleClicked(const QModelIndex &);
+  void updateSelection(const QModelIndex &, QItemSelectionModel::SelectionFlags);
+  
+private:
+  bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
 
 
-  public:
-    BufferViewWidget(QWidget *parent = 0);
-
-    QTreeWidget *tree() { return ui.tree; }
-
-    virtual QSize sizeHint () const;
-
-  signals:
-    void bufferSelected(QString net, QString buf);
-
-  private slots:
-
-
-  private:
-    Ui::BufferViewWidget ui;
-
+  Modes mode;
+  QStringList networks;
 };
 };
+Q_DECLARE_OPERATORS_FOR_FLAGS(BufferViewFilter::Modes)    
 
 
-class BufferView : public QDockWidget {
+/*****************************************
+ * The TreeView showing the Buffers
+ *****************************************/
+class BufferView : public QTreeView {
   Q_OBJECT
   Q_OBJECT
-
-  public:
-    enum Mode {
-      NoActive = 0x01, NoInactive = 0x02,
-      SomeNets = 0x04, AllNets = 0x08,
-      NoChannels = 0x10, NoQueries = 0x20, NoServers = 0x40
-    };
   
   
-    enum ActivityLevel {
-      NoActivity = 0x00, OtherActivity = 0x01,
-      NewMessage = 0x02, Highlight = 0x40
-    };
-    
-    BufferView(QString name, int mode, QStringList nets = QStringList(), QWidget *parent = 0);
-    void setMode(int mode, QStringList nets = QStringList());
-    void setName(QString name);
-
-
-  public slots:
-    void bufferUpdated(Buffer *);
-    void bufferActivity(uint, Buffer *);
-    void bufferDestroyed(Buffer *);
-    void setBuffers(QList<Buffer *>);
-    void selectBuffer(Buffer *);
-
-  signals:
-    void bufferSelected(Buffer *);
-    void fakeUserInput(BufferId, QString);
-    
-  private slots:
-    void itemClicked(QTreeWidgetItem *item);
-    void itemDoubleClicked(QTreeWidgetItem *item);
-    
-  private:
-    int mode;
-    QString name;
-    QStringList networks;
-    Buffer *currentBuffer;
-    //QHash<QString, QHash<QString, Buffer*> > buffers;
-    QHash<Buffer *, QTreeWidgetItem *> bufitems;
-    QHash<QString, QTreeWidgetItem *> netitems;
-    //QHash<QString, QHash<QString, QTreeWidgetItem *> > items;
-    QTreeWidget *tree;
-
-    bool shouldShow(Buffer *);
-    void clearActivity(Buffer *);
+public:
+  BufferView(QWidget *parent = 0);
+  void init();
+  void setFilteredModel(QAbstractItemModel *model, BufferViewFilter::Modes mode, QStringList nets);
+  
 };
 
 
 };
 
 
-#endif
+#endif
\ No newline at end of file
diff --git a/gui/bufferviewwidget.cpp b/gui/bufferviewwidget.cpp
new file mode 100644 (file)
index 0000000..31023f7
--- /dev/null
@@ -0,0 +1,403 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   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 "global.h"
+#include "bufferviewwidget.h"
+
+/*****************************************
+ *  Buffer Items stored in the Tree Model
+ *****************************************/
+TreeItem::TreeItem(QList<QVariant> &data, TreeItem *parent) {
+  itemData = data;
+  parentItem = parent;
+  foreground = Qt::black;
+}
+
+TreeItem::TreeItem(TreeItem *parent) {
+  itemData = QList<QVariant>();
+  parentItem = parent;
+  foreground = Qt::black;
+}
+
+TreeItem::~TreeItem() {
+  qDeleteAll(childItems);
+}
+
+void TreeItem::appendChild(TreeItem *item) {
+  childItems.append(item);
+}
+
+void TreeItem::removeChild(int row) {
+  childItems.removeAt(row);
+}
+
+TreeItem *TreeItem::child(int row) {
+  return childItems.value(row);
+}
+
+int TreeItem::childCount() const {
+  return childItems.count();
+}
+
+int TreeItem::row() const {
+  if(parentItem)
+    return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));
+  else
+    return 0;
+}
+
+TreeItem *TreeItem::parent() {
+  return parentItem;
+}
+
+int TreeItem::columnCount() const {
+  return itemData.count();
+}
+
+void TreeItem::setForeground(QColor newcolor) {
+  foreground = newcolor;
+}
+
+QVariant TreeItem::data(int column, int role) const {
+  switch(role) {
+    case Qt::DisplayRole:
+      if(column < itemData.count())
+        return itemData[column];
+      else
+        return QVariant();
+
+    case Qt::ForegroundRole:
+      return foreground;
+      
+    default:
+      return QVariant();
+      
+  }
+}
+
+/*****************************************
+*  Fancy Buffer Items
+*****************************************/
+BufferTreeItem::BufferTreeItem(Buffer *buffer, TreeItem *parent) : TreeItem(parent) {
+  buf = buffer;
+  activity = Buffer::NoActivity;
+}
+
+void BufferTreeItem::setActivity(const Buffer::ActivityLevel &level) {
+  activity = level;
+}
+
+QString BufferTreeItem::text(int column) const {
+  switch(column) {
+    case 0:
+      return buf->displayName();
+    case 1:
+      return buf->networkName();
+    default:
+      return QString();
+  }
+}
+
+QColor BufferTreeItem::foreground(int column) const {
+  // for the time beeing we ignore the column :)
+  if(activity & Buffer::Highlight) {
+    return QColor(Qt::red);
+  } else if(activity & Buffer::NewMessage) {
+    return QColor(Qt::darkYellow);
+  } else if(activity & Buffer::OtherActivity) {
+    return QColor(Qt::darkGreen);
+  } else {
+    if(buf->isActive())
+      return QColor(Qt::black);
+    else
+      return QColor(Qt::gray);
+  }
+}
+
+
+QVariant BufferTreeItem::data(int column, int role) const {
+  switch(role) {
+    case Qt::DisplayRole:
+      return text(column);
+    case Qt::ForegroundRole:
+      return foreground(column);
+    case BufferTreeModel::BufferTypeRole:
+      return buf->bufferType();
+    case BufferTreeModel::BufferActiveRole:
+      return buf->isActive();
+    default:
+      return QVariant();
+  }
+}
+
+/*****************************************
+ * BufferTreeModel
+ *****************************************/
+BufferTreeModel::BufferTreeModel(QObject *parent) : QAbstractItemModel(parent) {
+  QList<QVariant> rootData;
+  rootData << "Buffer" << "Network";
+  rootItem = new TreeItem(rootData, 0);
+  
+  connect(this, SIGNAL(fakeUserInput(BufferId, QString)), guiProxy, SLOT(gsUserInput(BufferId, QString)));
+}
+
+BufferTreeModel::~BufferTreeModel() {
+  delete rootItem;
+}
+
+QModelIndex BufferTreeModel::index(int row, int column, const QModelIndex &parent) const {
+  if(!hasIndex(row, column, parent))
+    return QModelIndex();
+  
+  TreeItem *parentItem;
+  
+  if(!parent.isValid())
+    parentItem = rootItem;
+  else
+    parentItem = static_cast<TreeItem*>(parent.internalPointer());
+  
+  TreeItem *childItem = parentItem->child(row);
+  if(childItem)
+    return createIndex(row, column, childItem);
+  else
+    return QModelIndex();
+}
+
+QModelIndex BufferTreeModel::parent(const QModelIndex &index) const {
+  if(!index.isValid())
+    return QModelIndex();
+  
+  TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
+  TreeItem *parentItem = childItem->parent();
+  
+  if(parentItem == rootItem)
+    return QModelIndex();
+  
+  return createIndex(parentItem->row(), 0, parentItem);
+}
+
+int BufferTreeModel::rowCount(const QModelIndex &parent) const {
+  TreeItem *parentItem;
+  if(parent.column() > 0)
+    return 0;
+  
+  if(!parent.isValid())
+    parentItem = rootItem;
+  else
+    parentItem = static_cast<TreeItem*>(parent.internalPointer());
+  
+  return parentItem->childCount();
+}
+
+int BufferTreeModel::columnCount(const QModelIndex &parent) const {
+  if(parent.isValid())
+    return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
+  else
+    return rootItem->columnCount();
+}
+
+QVariant BufferTreeModel::data(const QModelIndex &index, int role) const {
+  if(!index.isValid())
+    return QVariant();
+
+  TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
+  return item->data(index.column(), role);
+}
+
+Qt::ItemFlags BufferTreeModel::flags(const QModelIndex &index) const {
+  if(!index.isValid())
+    return 0;
+
+  // I think this is pretty ugly..
+  if(isBufferIndex(index)) {
+    Buffer *buffer = getBufferByIndex(index);
+    if(buffer->bufferType() == Buffer::QueryBuffer)
+      return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
+    else
+      return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+  } else {
+    return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; 
+  }
+}
+
+QVariant BufferTreeModel::headerData(int section, Qt::Orientation orientation, int role) const {
+  if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
+    return rootItem->data(section, role);
+  else
+    return QVariant();
+}
+
+bool BufferTreeModel::removeRow(int row, const QModelIndex &parent) {
+  beginRemoveRows(parent, row, row);
+  TreeItem *item = static_cast<TreeItem*>(parent.internalPointer());
+  item->removeChild(row);
+  endRemoveRows();
+  return true;
+}
+
+bool BufferTreeModel::isBufferIndex(const QModelIndex &index) const {
+  return parent(index) != QModelIndex();
+}
+
+Buffer *BufferTreeModel::getBufferByIndex(const QModelIndex &index) const {
+  BufferTreeItem *item = static_cast<BufferTreeItem *>(index.internalPointer());
+  return item->buffer();
+}
+
+QModelIndex BufferTreeModel::getOrCreateNetworkItemIndex(Buffer *buffer) {
+  QString net = buffer->networkName();
+  
+  if(networkItem.contains(net)) {
+    return index(networkItem[net]->row(), 0);
+  } else {
+    QList<QVariant> data;
+    data << net << "";
+    
+    int nextRow = rootItem->childCount();
+    
+    beginInsertRows(QModelIndex(), nextRow, nextRow);
+    rootItem->appendChild(new TreeItem(data, rootItem));
+    endInsertRows();
+    
+    networkItem[net] = rootItem->child(nextRow);
+    return index(nextRow, 0);
+  }
+}
+
+QModelIndex BufferTreeModel::getOrCreateBufferItemIndex(Buffer *buffer) {
+  QModelIndex networkItemIndex = getOrCreateNetworkItemIndex(buffer);
+  
+  if(bufferItem.contains(buffer)) {
+    return index(bufferItem[buffer]->row(), 0, networkItemIndex);
+  } else {
+    // first we determine the parent of the new Item
+    TreeItem *networkItem = static_cast<TreeItem*>(networkItemIndex.internalPointer());
+
+    int nextRow = networkItem->childCount();
+    
+    beginInsertRows(networkItemIndex, nextRow, nextRow);
+    networkItem->appendChild(new BufferTreeItem(buffer, networkItem));
+    endInsertRows();
+                         
+    bufferItem[buffer] = static_cast<BufferTreeItem *>(networkItem->child(nextRow));
+    return index(nextRow, 0, networkItemIndex);
+  }
+}
+
+QStringList BufferTreeModel::mimeTypes() const {
+  QStringList types;
+  types << "application/Quassel/BufferItem/row"
+    << "application/Quassel/BufferItem/network";
+  return types;
+}
+
+QMimeData *BufferTreeModel::mimeData(const QModelIndexList &indexes) const {
+  QMimeData *mimeData = new QMimeData();
+
+  QModelIndex index = indexes.first();
+  
+  mimeData->setData("application/Quassel/BufferItem/row", QByteArray::number(index.row()));
+  mimeData->setData("application/Quassel/BufferItem/network", getBufferByIndex(index)->networkName().toUtf8());
+  return mimeData;
+}
+
+bool BufferTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) {
+  int sourcerow = data->data("application/Quassel/BufferItem/row").toInt();
+  QString network = QString::fromUtf8(data->data("application/Quassel/BufferItem/network"));
+  
+  if(!networkItem.contains(network))
+    return false;
+
+  if(!isBufferIndex(parent)) // dropping at a network -> no merging needed
+    return false;
+
+  Buffer *sourceBuffer = static_cast<BufferTreeItem *>(networkItem[network]->child(sourcerow))->buffer();
+  Buffer *targetBuffer = getBufferByIndex(parent);
+  
+  qDebug() << "merging" << sourceBuffer->bufferName() << "with" << targetBuffer->bufferName();
+  bufferItem.remove(getBufferByIndex(parent));
+  removeRow(parent.row(), BufferTreeModel::parent(parent));
+  
+  return true;
+}
+
+void BufferTreeModel::bufferUpdated(Buffer *buffer) {
+  QModelIndex itemindex = getOrCreateBufferItemIndex(buffer);
+  emit invalidateFilter();
+  emit dataChanged(itemindex, itemindex);
+}
+
+// This Slot indicates that the user has selected a different buffer in the gui
+void BufferTreeModel::changeCurrent(const QModelIndex &current, const QModelIndex &previous) {
+  if(isBufferIndex(current)) {
+    currentBuffer = getBufferByIndex(current);
+    bufferActivity(Buffer::NoActivity, currentBuffer);
+    emit bufferSelected(currentBuffer);
+  }
+}
+
+// we received a double click on a buffer, so we're going to join it
+void BufferTreeModel::doubleClickReceived(const QModelIndex &clicked) {
+  if(isBufferIndex(clicked)) {
+    Buffer *buffer = getBufferByIndex(clicked);
+    if(!buffer->isStatusBuffer()) 
+      emit fakeUserInput(buffer->bufferId(), QString("/join " + buffer->bufferName()));
+  }
+    
+}
+
+void BufferTreeModel::bufferActivity(Buffer::ActivityLevel level, Buffer *buffer) {
+  if(bufferItem.contains(buffer) and buffer != currentBuffer)
+    bufferItem[buffer]->setActivity(level);
+  else
+    bufferItem[buffer]->setActivity(Buffer::NoActivity);
+  bufferUpdated(buffer);
+}
+
+void BufferTreeModel::selectBuffer(Buffer *buffer) {
+  QModelIndex index = getOrCreateBufferItemIndex(buffer);
+  emit updateSelection(index, QItemSelectionModel::ClearAndSelect);
+}
+
+
+/*****************************************
+ * This Widget Contains the BufferView
+ *****************************************/
+BufferViewWidget::BufferViewWidget(QWidget *parent) : QWidget(parent) {
+  ui.setupUi(this);
+}
+
+QSize BufferViewWidget::sizeHint() const {
+  return QSize(150,100);
+}
+
+
+/*****************************************
+ * Dock and API for the BufferViews
+ *****************************************/
+BufferViewDock::BufferViewDock(QAbstractItemModel *model, QString viewname, BufferViewFilter::Modes mode, QStringList nets, QWidget *parent) : QDockWidget(parent) {
+  setObjectName(QString("View-" + viewname)); // should be unique for mainwindow state!
+  setWindowTitle(viewname);
+
+  BufferViewWidget *viewWidget = new BufferViewWidget(this);
+  viewWidget->treeView()->setFilteredModel(model, mode, nets);
+  viewWidget->treeView()->init();
+  setWidget(viewWidget);
+}
diff --git a/gui/bufferviewwidget.h b/gui/bufferviewwidget.h
new file mode 100644 (file)
index 0000000..a14d173
--- /dev/null
@@ -0,0 +1,168 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   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 _BUFFERVIEW_H_
+#define _BUFFERVIEW_H_
+
+#include <QtGui>
+#include <QtCore>
+
+#include "guiproxy.h"
+#include "buffer.h"
+#include "ui_bufferviewwidget.h"
+#include "bufferview.h"
+
+/*****************************************
+ *  general item used in the Tree Model
+ *****************************************/
+class TreeItem {
+public:
+  TreeItem(QList<QVariant> &data, TreeItem *parent = 0);
+  TreeItem(TreeItem *parent = 0);
+  virtual ~TreeItem();
+  
+  void appendChild(TreeItem *child);
+  void removeChild(int row);
+                   
+  TreeItem *child(int row);
+  int childCount() const;
+  int columnCount() const;
+  virtual QVariant data(int column, int role) const;
+  int row() const;
+  TreeItem *parent();
+
+  void setForeground(QColor);
+    
+private:
+  QList<TreeItem*> childItems;
+  TreeItem *parentItem;
+  QList<QVariant> itemData;
+  
+  QColor foreground;
+};
+
+
+/*****************************************
+ *  Fancy Buffer Items
+ *****************************************/
+class BufferTreeItem : public TreeItem{
+public:
+  BufferTreeItem(Buffer *, TreeItem *parent = 0);
+  QVariant data(int column, int role) const;
+  Buffer *buffer() const { return buf; }
+  void setActivity(const Buffer::ActivityLevel &);
+  
+private:
+    QString text(int column) const;
+    QColor foreground(int column) const;
+    Buffer *buf;
+    Buffer::ActivityLevel activity;
+};
+
+
+/*****************************************
+ * BufferTreeModel
+ *****************************************/
+class BufferTreeModel : public QAbstractItemModel {
+  Q_OBJECT
+  
+public:
+  enum  myRoles {
+    BufferTypeRole = Qt::UserRole,
+    BufferActiveRole
+  };
+  
+  
+  BufferTreeModel(QObject *parent = 0);
+  ~BufferTreeModel();
+  
+  QVariant data(const QModelIndex &index, int role) const;
+  Qt::ItemFlags flags(const QModelIndex &index) const;
+  QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+  QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+  QModelIndex parent(const QModelIndex &index) const;
+  int rowCount(const QModelIndex &parent = QModelIndex()) const;
+  int columnCount(const QModelIndex &parent = QModelIndex()) const;
+  
+  void clearActivity(Buffer *buffer);
+  
+public slots:
+  void bufferUpdated(Buffer *);    
+  void changeCurrent(const QModelIndex &, const QModelIndex &);
+  void selectBuffer(Buffer *buffer);
+  void doubleClickReceived(const QModelIndex &);
+  void bufferActivity(Buffer::ActivityLevel, Buffer *buffer);
+  
+signals:
+  void bufferSelected(Buffer *);
+  void invalidateFilter();
+  void fakeUserInput(BufferId, QString);
+  void updateSelection(const QModelIndex &, QItemSelectionModel::SelectionFlags);
+    
+private:
+  bool isBufferIndex(const QModelIndex &) const;
+  Buffer *getBufferByIndex(const QModelIndex &) const;
+  QModelIndex getOrCreateNetworkItemIndex(Buffer *buffer);
+  QModelIndex getOrCreateBufferItemIndex(Buffer *buffer);
+
+  bool removeRow(int row, const QModelIndex &parent = QModelIndex());
+    
+  QStringList mimeTypes() const;
+  QMimeData *mimeData(const QModelIndexList &) const;
+  bool dropMimeData(const QMimeData *, Qt::DropAction, int, int, const QModelIndex &);
+  TreeItem *rootItem;
+  
+  QHash<QString, TreeItem*> networkItem;
+  QHash<Buffer *, BufferTreeItem*> bufferItem;
+  Buffer *currentBuffer;
+};
+
+
+
+
+/*****************************************
+ * This Widget Contains the BufferView
+ *****************************************/
+class BufferViewWidget : public QWidget {
+  Q_OBJECT
+
+public:
+  BufferViewWidget(QWidget *parent = 0);
+  virtual QSize sizeHint () const;
+  BufferView *treeView() { return ui.treeView; }  
+
+private:
+  Ui::BufferViewWidget ui;
+  
+};
+
+
+/*****************************************
+ * Dock and API for the BufferViews
+ *****************************************/
+class BufferViewDock : public QDockWidget {
+  Q_OBJECT
+
+public:
+  BufferViewDock(QAbstractItemModel *model, QString name, BufferViewFilter::Modes mode, QStringList nets = QStringList(), QWidget *parent = 0);
+};
+
+
+#endif
index 7c4eb51..0a69121 100644 (file)
@@ -29,7 +29,7 @@
 
 #include "mainwin.h"
 #include "buffer.h"
 
 #include "mainwin.h"
 #include "buffer.h"
-#include "bufferview.h"
+#include "bufferviewwidget.h"
 #include "serverlist.h"
 #include "coreconnectdlg.h"
 #include "settingsdlg.h"
 #include "serverlist.h"
 #include "coreconnectdlg.h"
 #include "settingsdlg.h"
@@ -153,32 +153,41 @@ void MainWin::setupMenus() {
 }
 
 void MainWin::setupViews() {
 }
 
 void MainWin::setupViews() {
-  BufferView *all = new BufferView(tr("All Buffers"), BufferView::AllNets);
-  registerBufferView(all);
-  addDockWidget(Qt::LeftDockWidgetArea, all);
-  BufferView *allchans = new BufferView(tr("All Channels"), BufferView::AllNets|BufferView::NoQueries|BufferView::NoServers);
-  registerBufferView(allchans);
-  addDockWidget(Qt::LeftDockWidgetArea, allchans);
-  BufferView *allqrys = new BufferView(tr("All Queries"), BufferView::AllNets|BufferView::NoChannels|BufferView::NoServers);
-  registerBufferView(allqrys);
-  addDockWidget(Qt::RightDockWidgetArea, allqrys);
-  BufferView *allnets = new BufferView(tr("All Networks"), BufferView::AllNets|BufferView::NoChannels|BufferView::NoQueries);
-  registerBufferView(allnets);
-  addDockWidget(Qt::RightDockWidgetArea, allnets);
+  BufferTreeModel *model = new BufferTreeModel();
+  connect(model, SIGNAL(bufferSelected(Buffer *)), this, SLOT(showBuffer(Buffer *)));
+  connect(this, SIGNAL(bufferSelected(Buffer *)), model, SLOT(selectBuffer(Buffer *)));
+  connect(this, SIGNAL(bufferUpdated(Buffer *)), model, SLOT(bufferUpdated(Buffer *)));
+  connect(this, SIGNAL(bufferActivity(Buffer::ActivityLevel, Buffer *)), model, SLOT(bufferActivity(Buffer::ActivityLevel, Buffer *)));
+  
+  BufferViewDock *all = new BufferViewDock(model, tr("All Buffers"), BufferViewFilter::AllNets);
+  registerBufferViewDock(all);
+  
+  BufferViewDock *allchans = new BufferViewDock(model, tr("All Channels"), BufferViewFilter::AllNets|BufferViewFilter::NoQueries|BufferViewFilter::NoServers);
+  registerBufferViewDock(allchans);
+  
+  BufferViewDock *allqrys = new BufferViewDock(model, tr("All Queries"), BufferViewFilter::AllNets|BufferViewFilter::NoChannels|BufferViewFilter::NoServers);
+  registerBufferViewDock(allqrys);
+
+  
+  BufferViewDock *allnets = new BufferViewDock(model, tr("All Networks"), BufferViewFilter::AllNets|BufferViewFilter::NoChannels|BufferViewFilter::NoQueries);
+  registerBufferViewDock(allnets);
+
 
   ui.menuViews->addSeparator();
 }
 
 
   ui.menuViews->addSeparator();
 }
 
-void MainWin::registerBufferView(BufferView *view) {
+void MainWin::registerBufferViewDock(BufferViewDock *dock) {
+  addDockWidget(Qt::LeftDockWidgetArea, dock);
+  dock->setAllowedAreas(Qt::RightDockWidgetArea|Qt::LeftDockWidgetArea);
+  netViews.append(dock);
+  ui.menuViews->addAction(dock->toggleViewAction());
+  
+  /*
   connect(this, SIGNAL(bufferSelected(Buffer *)), view, SLOT(selectBuffer(Buffer *)));
   connect(this, SIGNAL(bufferSelected(Buffer *)), view, SLOT(selectBuffer(Buffer *)));
-  connect(this, SIGNAL(bufferUpdated(Buffer *)), view, SLOT(bufferUpdated(Buffer *)));
-  connect(this, SIGNAL(bufferActivity(uint, Buffer *)), view, SLOT(bufferActivity(uint, Buffer *)));
   connect(this, SIGNAL(bufferDestroyed(Buffer *)), view, SLOT(bufferDestroyed(Buffer *)));
   connect(view, SIGNAL(bufferSelected(Buffer *)), this, SLOT(showBuffer(Buffer *)));
   view->setBuffers(buffers.values());
   connect(this, SIGNAL(bufferDestroyed(Buffer *)), view, SLOT(bufferDestroyed(Buffer *)));
   connect(view, SIGNAL(bufferSelected(Buffer *)), this, SLOT(showBuffer(Buffer *)));
   view->setBuffers(buffers.values());
-  view->setAllowedAreas(Qt::RightDockWidgetArea|Qt::LeftDockWidgetArea);
-  netViews.append(view);
-  ui.menuViews->addAction(view->toggleViewAction());
+   */
 }
 
 void MainWin::showServerList() {
 }
 
 void MainWin::showServerList() {
@@ -305,17 +314,19 @@ void MainWin::recvMessage(Message msg) {
     b = getBuffer(net, msg.target);
   }
   */
     b = getBuffer(net, msg.target);
   }
   */
+  
+
   Buffer *b = getBuffer(msg.buffer);
   
   Buffer *b = getBuffer(msg.buffer);
   
-  uint level = BufferView::OtherActivity;
+  Buffer::ActivityLevel level = Buffer::OtherActivity;
   if(msg.type == Message::Plain or msg.type == Message::Notice){
   if(msg.type == Message::Plain or msg.type == Message::Notice){
-    level |= BufferView::NewMessage;
+    level |= Buffer::NewMessage;
   }
   if(msg.flags & Message::Highlight){
   }
   if(msg.flags & Message::Highlight){
-    level |= BufferView::Highlight;
+    level |= Buffer::Highlight;
   }
   }
-    
   emit bufferActivity(level, b);
   emit bufferActivity(level, b);
+
   //b->displayMsg(msg);
   b->appendChatLine(new ChatLine(msg));
 }
   //b->displayMsg(msg);
   b->appendChatLine(new ChatLine(msg));
 }
index df7154c..8092395 100644 (file)
@@ -30,7 +30,7 @@
 
 class ServerListDlg;
 class CoreConnectDlg;
 
 class ServerListDlg;
 class CoreConnectDlg;
-class BufferView;
+class BufferViewDock;
 class Buffer;
 class BufferWidget;
 class SettingsDlg;
 class Buffer;
 class BufferWidget;
 class SettingsDlg;
@@ -50,7 +50,7 @@ class MainWin : public QMainWindow {
     ~MainWin();
 
     void init();
     ~MainWin();
 
     void init();
-    void registerBufferView(BufferView *);
+    void registerBufferViewDock(BufferViewDock *);
 
   protected:
     void closeEvent(QCloseEvent *event);
 
   protected:
     void closeEvent(QCloseEvent *event);
@@ -59,7 +59,7 @@ class MainWin : public QMainWindow {
     void sendInput(BufferId, QString message);
     void bufferSelected(Buffer *);
     void bufferUpdated(Buffer *);
     void sendInput(BufferId, QString message);
     void bufferSelected(Buffer *);
     void bufferUpdated(Buffer *);
-    void bufferActivity(uint, Buffer *);
+    void bufferActivity(Buffer::ActivityLevel, Buffer *);
     void bufferDestroyed(Buffer *);
     void backlogReceived(Buffer *, QList<Message>);
     void requestBacklog(BufferId, QVariant, QVariant);
     void bufferDestroyed(Buffer *);
     void backlogReceived(Buffer *, QList<Message>);
     void requestBacklog(BufferId, QVariant, QVariant);
@@ -124,7 +124,7 @@ class MainWin : public QMainWindow {
     //QHash<QString, QList<Message> > coreBackLog;
     QList<BufferId> coreBuffers;
 
     //QHash<QString, QList<Message> > coreBackLog;
     QList<BufferId> coreBuffers;
 
-    QList<BufferView *> netViews;
+    QList<BufferViewDock *> netViews;
 
     QTimer *layoutTimer;
     QList<Message> layoutQueue;
 
     QTimer *layoutTimer;
     QList<Message> layoutQueue;
index 1eaebe3..c1efab7 100644 (file)
     <number>0</number>
    </property>
    <item>
     <number>0</number>
    </property>
    <item>
-    <widget class="QTreeWidget" name="tree" >
-     <property name="sizePolicy" >
-      <sizepolicy>
-       <hsizetype>5</hsizetype>
-       <vsizetype>5</vsizetype>
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="maximumSize" >
-      <size>
-       <width>16777215</width>
-       <height>16777215</height>
-      </size>
-     </property>
+    <widget class="BufferView" name="treeView" >
      <property name="rootIsDecorated" >
      <property name="rootIsDecorated" >
-      <bool>false</bool>
+      <bool>true</bool>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
+ <customwidgets>
+  <customwidget>
+   <class>BufferView</class>
+   <extends>QTreeView</extends>
+   <header>bufferview.h</header>
+  </customwidget>
+ </customwidgets>
  <resources/>
  <connections/>
 </ui>
  <resources/>
  <connections/>
 </ui>