X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fclient%2Fbuffertreemodel.cpp;h=d62d8045f98fbe3bde9b81276590d224e39e6975;hp=c6fb9964e9a1800c4d345e468a769c37025bb16a;hb=4d8086fa41a49c3b2ba31484ce3c59416f5de294;hpb=06a03c2c69ee934aaeec83512bae2fffee83a340 diff --git a/src/client/buffertreemodel.cpp b/src/client/buffertreemodel.cpp index c6fb9964..d62d8045 100644 --- a/src/client/buffertreemodel.cpp +++ b/src/client/buffertreemodel.cpp @@ -1,11 +1,11 @@ /*************************************************************************** - * Copyright (C) 2005-07 by The Quassel Team * + * Copyright (C) 2005-07 by the Quassel IRC 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. * + * (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 * @@ -20,21 +20,31 @@ #include // FIXME Dependency on QtGui! -#include "client.h" -//#include "clientproxy.h" #include "buffertreemodel.h" + +#include "mappedselectionmodel.h" +#include + +#include "bufferinfo.h" +#include "client.h" #include "signalproxy.h" /***************************************** * Fancy Buffer Items *****************************************/ -BufferTreeItem::BufferTreeItem(Buffer *buffer, TreeItem *parent) : TreeItem(parent) { - buf = buffer; - activity = Buffer::NoActivity; +BufferTreeItem::BufferTreeItem(Buffer *buffer, TreeItem *parent) + : TreeItem(parent), + buf(buffer), + activity(Buffer::NoActivity) +{ + Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; + if(buf->bufferType() == Buffer::QueryType) + flags |= Qt::ItemIsDropEnabled; + setFlags(flags); } -uint BufferTreeItem::id() const { - return buf->bufferId().uid(); +quint64 BufferTreeItem::id() const { + return buf->bufferInfo().uid(); } void BufferTreeItem::setActivity(const Buffer::ActivityLevel &level) { @@ -44,7 +54,7 @@ void BufferTreeItem::setActivity(const Buffer::ActivityLevel &level) { QString BufferTreeItem::text(int column) const { switch(column) { case 0: - return buf->displayName(); + return buf->name(); case 1: return buf->networkName(); default: @@ -52,7 +62,8 @@ QString BufferTreeItem::text(int column) const { } } -QColor BufferTreeItem::foreground(int /*column*/) const { +QColor BufferTreeItem::foreground(int column) const { + Q_UNUSED(column) // for the time beeing we ignore the column :) if(activity & Buffer::Highlight) { return QColor(Qt::red); @@ -71,56 +82,67 @@ QColor BufferTreeItem::foreground(int /*column*/) const { QVariant BufferTreeItem::data(int column, int role) const { switch(role) { - case Qt::DisplayRole: - return text(column); - case Qt::ForegroundRole: - return foreground(column); - case BufferTreeModel::BufferNameRole: - return buf->bufferName(); - case BufferTreeModel::BufferTypeRole: - return buf->bufferType(); - case BufferTreeModel::BufferActiveRole: - return buf->isActive(); - case BufferTreeModel::BufferIdRole: - return buf->bufferId().uid(); - default: - return QVariant(); + case Qt::DisplayRole: + return text(column); + case Qt::ForegroundRole: + return foreground(column); + case BufferTreeModel::BufferTypeRole: + return int(buf->bufferType()); + case BufferTreeModel::BufferActiveRole: + return buf->isActive(); + case BufferTreeModel::BufferUidRole: + return buf->bufferInfo().uid(); + case BufferTreeModel::NetworkIdRole: + return buf->bufferInfo().networkId(); + + default: + return TreeItem::data(column, role); } } -Qt::ItemFlags BufferTreeItem::flags() const { - Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; - if(buf->bufferType() == Buffer::QueryBuffer) - flags |= Qt::ItemIsDropEnabled; - - return flags; -} - /***************************************** * Network Items *****************************************/ -NetworkTreeItem::NetworkTreeItem(const QString &network, TreeItem *parent) : TreeItem(parent) { +NetworkTreeItem::NetworkTreeItem(const uint &netid, const QString &network, TreeItem *parent) + : TreeItem(parent), + _networkId(netid), + net(network) +{ net = network; itemData << net << ""; + setFlags(Qt::ItemIsEnabled); } -uint NetworkTreeItem::id() const { - return qHash(net); +QVariant NetworkTreeItem::data(int column, int role) const { + switch(role) { + case BufferTreeModel::NetworkIdRole: + return _networkId; + default: + return TreeItem::data(column, role); + } } -Qt::ItemFlags NetworkTreeItem::flags() const { - return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; +quint64 NetworkTreeItem::id() const { + return _networkId; } /***************************************** * BufferTreeModel *****************************************/ BufferTreeModel::BufferTreeModel(QObject *parent) - : TreeModel(BufferTreeModel::defaultHeader(), parent) + : TreeModel(BufferTreeModel::defaultHeader(), parent), + _selectionModelSynchronizer(new SelectionModelSynchronizer(this)), + _propertyMapper(new ModelPropertyMapper(this)) { - //connect(this, SIGNAL(fakeUserInput(BufferId, QString)), - // ClientProxy::instance(), SLOT(gsUserInput(BufferId, QString))); - Client::signalProxy()->attachSignal(this, SIGNAL(fakeUserInput(BufferId, QString)), SIGNAL(sendInput(BufferId, QString))); + // initialize the Property Mapper + _propertyMapper->setModel(this); + delete _propertyMapper->selectionModel(); + MappedSelectionModel *mappedSelectionModel = new MappedSelectionModel(this); + _propertyMapper->setSelectionModel(mappedSelectionModel); + synchronizeSelectionModel(mappedSelectionModel); + + connect(_selectionModelSynchronizer, SIGNAL(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)), + this, SLOT(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags))); } QListBufferTreeModel::defaultHeader() { @@ -129,6 +151,22 @@ QListBufferTreeModel::defaultHeader() { return data; } +void BufferTreeModel::synchronizeSelectionModel(MappedSelectionModel *selectionModel) { + selectionModelSynchronizer()->addSelectionModel(selectionModel); +} + +void BufferTreeModel::synchronizeView(QAbstractItemView *view) { + MappedSelectionModel *mappedSelectionModel = new MappedSelectionModel(view->model()); + selectionModelSynchronizer()->addSelectionModel(mappedSelectionModel); + Q_ASSERT(mappedSelectionModel); + delete view->selectionModel(); + view->setSelectionModel(mappedSelectionModel); +} + +void BufferTreeModel::mapProperty(int column, int role, QObject *target, const QByteArray &property) { + propertyMapper()->addMapping(column, role, target, property); +} + bool BufferTreeModel::isBufferIndex(const QModelIndex &index) const { // not so purdy... return parent(index) != QModelIndex(); @@ -141,11 +179,12 @@ Buffer *BufferTreeModel::getBufferByIndex(const QModelIndex &index) const { QModelIndex BufferTreeModel::getOrCreateNetworkItemIndex(Buffer *buffer) { QString net = buffer->networkName(); + uint netId = buffer->networkId(); TreeItem *networkItem; - if(not(networkItem = rootItem->childById(qHash(net)))) { + if(!(networkItem = rootItem->childById(netId))) { int nextRow = rootItem->childCount(); - networkItem = new NetworkTreeItem(net, rootItem); + networkItem = new NetworkTreeItem(netId, net, rootItem); beginInsertRows(QModelIndex(), nextRow, nextRow); rootItem->appendChild(networkItem); @@ -161,7 +200,7 @@ QModelIndex BufferTreeModel::getOrCreateBufferItemIndex(Buffer *buffer) { NetworkTreeItem *networkItem = static_cast(networkItemIndex.internalPointer()); TreeItem *bufferItem; - if(not(bufferItem = networkItem->childById(buffer->bufferId().uid()))) { + if(!(bufferItem = networkItem->childById(buffer->bufferInfo().uid()))) { int nextRow = networkItem->childCount(); bufferItem = new BufferTreeItem(buffer, networkItem); @@ -175,76 +214,110 @@ QModelIndex BufferTreeModel::getOrCreateBufferItemIndex(Buffer *buffer) { } QStringList BufferTreeModel::mimeTypes() const { + // mimetypes we accept for drops QStringList types; - types << "application/Quassel/BufferItem/row" - << "application/Quassel/BufferItem/network" - << "application/Quassel/BufferItem/bufferId"; + // comma separated list of colon separated pairs of networkid and bufferid + // example: 0:1,0:2,1:4 + types << "application/Quassel/BufferItemList"; return types; } +bool BufferTreeModel::mimeContainsBufferList(const QMimeData *mimeData) { + return mimeData->hasFormat("application/Quassel/BufferItemList"); +} + +QList< QPair > BufferTreeModel::mimeDataToBufferList(const QMimeData *mimeData) { + QList< QPair > bufferList; + + if(!mimeContainsBufferList(mimeData)) + return bufferList; + + QStringList rawBufferList = QString::fromAscii(mimeData->data("application/Quassel/BufferItemList")).split(","); + uint networkId, bufferUid; + foreach(QString rawBuffer, rawBufferList) { + if(!rawBuffer.contains(":")) + continue; + networkId = rawBuffer.section(":", 0, 0).toUInt(); + bufferUid = rawBuffer.section(":", 1, 1).toUInt(); + bufferList.append(qMakePair(networkId, bufferUid)); + } + return bufferList; +} + + 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()); - mimeData->setData("application/Quassel/BufferItem/bufferId", QByteArray::number(getBufferByIndex(index)->bufferId().uid())); + QStringList bufferlist; + QString netid, uid, bufferid; + foreach(QModelIndex index, indexes) { + netid = QString::number(index.data(NetworkIdRole).toUInt()); + uid = QString::number(index.data(BufferUidRole).toUInt()); + bufferid = QString("%1:%2").arg(netid).arg(uid); + if(!bufferlist.contains(bufferid)) + bufferlist << bufferid; + } + + mimeData->setData("application/Quassel/BufferItemList", bufferlist.join(",").toAscii()); + return mimeData; } -bool BufferTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction /*action*/, int /*row*/, int /*column*/, const QModelIndex &parent) { - foreach(QString mimeType, mimeTypes()) { - if(!(data->hasFormat(mimeType))) - return false; // whatever the drop is... it's not a buffer... - } - - int sourcerow = data->data("application/Quassel/BufferItem/row").toInt(); - QString network = QString::fromUtf8(data->data("application/Quassel/BufferItem/network")); - - Q_ASSERT(rootItem->childById(qHash(network))); +bool BufferTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { + Q_UNUSED(action) + Q_UNUSED(row) + Q_UNUSED(column) - if(parent == QModelIndex()) // can't be a query... + if(!mimeContainsBufferList(data)) + return false; + + // target must be a query + Buffer::Type targetType = (Buffer::Type)parent.data(BufferTreeModel::BufferTypeRole).toInt(); + if(targetType != Buffer::QueryType) return false; - - Buffer *sourceBuffer = static_cast(rootItem->childById(qHash(network))->child(sourcerow))->buffer(); - Buffer *targetBuffer = getBufferByIndex(parent); - if(!(sourceBuffer->bufferType() & targetBuffer->bufferType() & Buffer::QueryBuffer)) // only queries can be merged + QList< QPair > bufferList = mimeDataToBufferList(data); + + // exactly one buffer has to be dropped + if(bufferList.count() != 1) return false; + + uint netId = bufferList.first().first; + uint bufferId = bufferList.first().second; + + // no self merges (would kill us) + if(bufferId == parent.data(BufferUidRole).toUInt()) + return false; - if(sourceBuffer == targetBuffer) // we won't merge with ourself :) + Q_ASSERT(rootItem->childById(netId)); + Q_ASSERT(rootItem->childById(netId)->childById(bufferId)); + + // source must be a query too + Buffer::Type sourceType = (Buffer::Type)rootItem->childById(netId)->childById(bufferId)->data(0, BufferTypeRole).toInt(); + if(sourceType != Buffer::QueryType) return false; // TODO: warn user about buffermerge! - qDebug() << "merging" << sourceBuffer->bufferName() << "with" << targetBuffer->bufferName(); - removeRow(parent.row(), BufferTreeModel::parent(parent)); + qDebug() << "merging" << bufferId << parent.data(BufferUidRole).toInt(); + removeRow(parent.row(), 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); +void BufferTreeModel::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) { + Q_UNUSED(command) + Buffer *newCurrentBuffer; + if(isBufferIndex(index) && currentBuffer != (newCurrentBuffer = getBufferByIndex(index))) { + currentBuffer = newCurrentBuffer; bufferActivity(Buffer::NoActivity, currentBuffer); emit bufferSelected(currentBuffer); - emit selectionChanged(current); - } -} - -// 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())); + emit selectionChanged(index); } } @@ -259,7 +332,6 @@ void BufferTreeModel::bufferActivity(Buffer::ActivityLevel level, Buffer *buffer void BufferTreeModel::selectBuffer(Buffer *buffer) { QModelIndex index = getOrCreateBufferItemIndex(buffer); - emit selectionChanged(index); + // SUPER UGLY! + setCurrentIndex(index, 0); } - -