From: Marcus Eggenberger Date: Mon, 18 Jun 2007 15:09:21 +0000 (+0000) Subject: Changed the BufferView System to a MVC Design Pattern X-Git-Tag: 0.1.0~212 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=6fc26e28a07a2b6bbc60ee786514a802e628d6d3 Changed the BufferView System to a MVC Design Pattern --- diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 91ff392c..f118eae7 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -1,11 +1,11 @@ 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 - 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 - 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. diff --git a/gui/buffer.cpp b/gui/buffer.cpp index 9c9726e1..cf764c1b 100644 --- a/gui/buffer.cpp +++ b/gui/buffer.cpp @@ -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; diff --git a/gui/buffer.h b/gui/buffer.h index 7738ebe1..944b07cc 100644 --- a/gui/buffer.h +++ b/gui/buffer.h @@ -49,16 +49,27 @@ class Buffer : public QObject { 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; } + QString displayName(); BufferId bufferId() { return id; } QList 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); @@ -104,5 +115,6 @@ class Buffer : public QObject { QList lines; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(Buffer::ActivityLevel) #endif diff --git a/gui/bufferview.cpp b/gui/bufferview.cpp index f49898cf..e0923cff 100644 --- a/gui/bufferview.cpp +++ b/gui/bufferview.cpp @@ -18,171 +18,82 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include "global.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; - currentBuffer = 0; - setWidget(new BufferViewWidget(this)); - tree = qobject_cast(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 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 ¤t, 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; } -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 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; - } -} diff --git a/gui/bufferview.h b/gui/bufferview.h index a76e3272..49f3a809 100644 --- a/gui/bufferview.h +++ b/gui/bufferview.h @@ -18,86 +18,64 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#ifndef _BUFFERVIEW_H_ -#define _BUFFERVIEW_H_ +#ifndef _BUFFERVIEWWIDGET_H_ +#define _BUFFERVIEWWIDGET_H_ #include -#include "ui_bufferview.h" -#include "guiproxy.h" +#include #include "buffer.h" -typedef QHash > BufferHash; - -class BufferViewWidget : public QWidget { +/***************************************** + * Buffer View Filter + *****************************************/ +class BufferViewFilter : public QSortFilterProxyModel { 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 - - 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); - 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 > buffers; - QHash bufitems; - QHash netitems; - //QHash > 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 index 00000000..31023f74 --- /dev/null +++ b/gui/bufferviewwidget.cpp @@ -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 &data, TreeItem *parent) { + itemData = data; + parentItem = parent; + foreground = Qt::black; +} + +TreeItem::TreeItem(TreeItem *parent) { + itemData = QList(); + 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(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 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(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(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(parent.internalPointer()); + + return parentItem->childCount(); +} + +int BufferTreeModel::columnCount(const QModelIndex &parent) const { + if(parent.isValid()) + return static_cast(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(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(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(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 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(networkItemIndex.internalPointer()); + + int nextRow = networkItem->childCount(); + + beginInsertRows(networkItemIndex, nextRow, nextRow); + networkItem->appendChild(new BufferTreeItem(buffer, networkItem)); + endInsertRows(); + + bufferItem[buffer] = static_cast(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(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 ¤t, 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 index 00000000..a14d173d --- /dev/null +++ b/gui/bufferviewwidget.h @@ -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 +#include + +#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 &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 childItems; + TreeItem *parentItem; + QList 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 networkItem; + QHash 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 diff --git a/gui/mainwin.cpp b/gui/mainwin.cpp index 7c4eb517..0a691214 100644 --- a/gui/mainwin.cpp +++ b/gui/mainwin.cpp @@ -29,7 +29,7 @@ #include "mainwin.h" #include "buffer.h" -#include "bufferview.h" +#include "bufferviewwidget.h" #include "serverlist.h" #include "coreconnectdlg.h" #include "settingsdlg.h" @@ -153,32 +153,41 @@ void MainWin::setupMenus() { } 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(); } -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(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()); - view->setAllowedAreas(Qt::RightDockWidgetArea|Qt::LeftDockWidgetArea); - netViews.append(view); - ui.menuViews->addAction(view->toggleViewAction()); + */ } void MainWin::showServerList() { @@ -305,17 +314,19 @@ void MainWin::recvMessage(Message msg) { b = getBuffer(net, msg.target); } */ + + Buffer *b = getBuffer(msg.buffer); - uint level = BufferView::OtherActivity; + Buffer::ActivityLevel level = Buffer::OtherActivity; if(msg.type == Message::Plain or msg.type == Message::Notice){ - level |= BufferView::NewMessage; + level |= Buffer::NewMessage; } if(msg.flags & Message::Highlight){ - level |= BufferView::Highlight; + level |= Buffer::Highlight; } - emit bufferActivity(level, b); + //b->displayMsg(msg); b->appendChatLine(new ChatLine(msg)); } diff --git a/gui/mainwin.h b/gui/mainwin.h index df7154c0..8092395c 100644 --- a/gui/mainwin.h +++ b/gui/mainwin.h @@ -30,7 +30,7 @@ class ServerListDlg; class CoreConnectDlg; -class BufferView; +class BufferViewDock; class Buffer; class BufferWidget; class SettingsDlg; @@ -50,7 +50,7 @@ class MainWin : public QMainWindow { ~MainWin(); void init(); - void registerBufferView(BufferView *); + void registerBufferViewDock(BufferViewDock *); 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 bufferActivity(uint, Buffer *); + void bufferActivity(Buffer::ActivityLevel, Buffer *); void bufferDestroyed(Buffer *); void backlogReceived(Buffer *, QList); void requestBacklog(BufferId, QVariant, QVariant); @@ -124,7 +124,7 @@ class MainWin : public QMainWindow { //QHash > coreBackLog; QList coreBuffers; - QList netViews; + QList netViews; QTimer *layoutTimer; QList layoutQueue; diff --git a/gui/ui/bufferviewwidget.ui b/gui/ui/bufferviewwidget.ui index 1eaebe32..c1efab78 100644 --- a/gui/ui/bufferviewwidget.ui +++ b/gui/ui/bufferviewwidget.ui @@ -34,28 +34,21 @@ 0 - - - - 5 - 5 - 0 - 0 - - - - - 16777215 - 16777215 - - + - false + true + + + BufferView + QTreeView +
bufferview.h
+
+