1 /***************************************************************************
2 * Copyright (C) 2005-07 by the Quassel IRC Team *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include <QColor> // FIXME Dependency on QtGui!
23 #include "buffertreemodel.h"
25 #include "mappedselectionmodel.h"
26 #include <QAbstractItemView>
28 #include "bufferinfo.h"
30 #include "signalproxy.h"
32 /*****************************************
34 *****************************************/
35 BufferTreeItem::BufferTreeItem(Buffer *buffer, TreeItem *parent)
38 activity(Buffer::NoActivity)
40 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
41 if(buf->bufferType() == Buffer::QueryType)
42 flags |= Qt::ItemIsDropEnabled;
46 quint64 BufferTreeItem::id() const {
47 return buf->bufferInfo().uid();
50 void BufferTreeItem::setActivity(const Buffer::ActivityLevel &level) {
54 QString BufferTreeItem::text(int column) const {
59 return buf->networkName();
65 QColor BufferTreeItem::foreground(int column) const {
67 // for the time beeing we ignore the column :)
68 if(activity & Buffer::Highlight) {
69 return QColor(Qt::red);
70 } else if(activity & Buffer::NewMessage) {
71 return QColor(Qt::darkYellow);
72 } else if(activity & Buffer::OtherActivity) {
73 return QColor(Qt::darkGreen);
76 return QColor(Qt::black);
78 return QColor(Qt::gray);
83 QVariant BufferTreeItem::data(int column, int role) const {
87 case Qt::ForegroundRole:
88 return foreground(column);
89 case BufferTreeModel::BufferTypeRole:
90 return int(buf->bufferType());
91 case BufferTreeModel::BufferActiveRole:
92 return buf->isActive();
93 case BufferTreeModel::BufferUidRole:
94 return buf->bufferInfo().uid();
95 case BufferTreeModel::NetworkIdRole:
96 return buf->bufferInfo().networkId();
99 return TreeItem::data(column, role);
103 /*****************************************
105 *****************************************/
106 NetworkTreeItem::NetworkTreeItem(const uint &netid, const QString &network, TreeItem *parent)
112 itemData << net << "";
113 setFlags(Qt::ItemIsEnabled);
116 QVariant NetworkTreeItem::data(int column, int role) const {
118 case BufferTreeModel::NetworkIdRole:
121 return TreeItem::data(column, role);
125 quint64 NetworkTreeItem::id() const {
129 /*****************************************
131 *****************************************/
132 BufferTreeModel::BufferTreeModel(QObject *parent)
133 : TreeModel(BufferTreeModel::defaultHeader(), parent),
134 _selectionModelSynchronizer(new SelectionModelSynchronizer(this)),
135 _propertyMapper(new ModelPropertyMapper(this))
137 // initialize the Property Mapper
138 _propertyMapper->setModel(this);
139 delete _propertyMapper->selectionModel();
140 MappedSelectionModel *mappedSelectionModel = new MappedSelectionModel(this);
141 _propertyMapper->setSelectionModel(mappedSelectionModel);
142 synchronizeSelectionModel(mappedSelectionModel);
144 connect(_selectionModelSynchronizer, SIGNAL(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)),
145 this, SLOT(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)));
148 QList<QVariant >BufferTreeModel::defaultHeader() {
149 QList<QVariant> data;
150 data << tr("Buffer") << tr("Network");
154 void BufferTreeModel::synchronizeSelectionModel(MappedSelectionModel *selectionModel) {
155 selectionModelSynchronizer()->addSelectionModel(selectionModel);
158 void BufferTreeModel::synchronizeView(QAbstractItemView *view) {
159 MappedSelectionModel *mappedSelectionModel = new MappedSelectionModel(view->model());
160 selectionModelSynchronizer()->addSelectionModel(mappedSelectionModel);
161 Q_ASSERT(mappedSelectionModel);
162 delete view->selectionModel();
163 view->setSelectionModel(mappedSelectionModel);
166 void BufferTreeModel::mapProperty(int column, int role, QObject *target, const QByteArray &property) {
167 propertyMapper()->addMapping(column, role, target, property);
170 bool BufferTreeModel::isBufferIndex(const QModelIndex &index) const {
172 return parent(index) != QModelIndex();
175 Buffer *BufferTreeModel::getBufferByIndex(const QModelIndex &index) const {
176 BufferTreeItem *item = static_cast<BufferTreeItem *>(index.internalPointer());
177 return item->buffer();
180 QModelIndex BufferTreeModel::getOrCreateNetworkItemIndex(Buffer *buffer) {
181 QString net = buffer->networkName();
182 uint netId = buffer->networkId();
183 TreeItem *networkItem;
185 if(!(networkItem = rootItem->childById(netId))) {
186 int nextRow = rootItem->childCount();
187 networkItem = new NetworkTreeItem(netId, net, rootItem);
189 beginInsertRows(QModelIndex(), nextRow, nextRow);
190 rootItem->appendChild(networkItem);
194 Q_ASSERT(networkItem);
195 return index(networkItem->row(), 0);
198 QModelIndex BufferTreeModel::getOrCreateBufferItemIndex(Buffer *buffer) {
199 QModelIndex networkItemIndex = getOrCreateNetworkItemIndex(buffer);
200 NetworkTreeItem *networkItem = static_cast<NetworkTreeItem*>(networkItemIndex.internalPointer());
201 TreeItem *bufferItem;
203 if(!(bufferItem = networkItem->childById(buffer->bufferInfo().uid()))) {
204 int nextRow = networkItem->childCount();
205 bufferItem = new BufferTreeItem(buffer, networkItem);
207 beginInsertRows(networkItemIndex, nextRow, nextRow);
208 networkItem->appendChild(bufferItem);
212 Q_ASSERT(bufferItem);
213 return index(bufferItem->row(), 0, networkItemIndex);
216 QStringList BufferTreeModel::mimeTypes() const {
217 // mimetypes we accept for drops
219 // comma separated list of colon separated pairs of networkid and bufferid
220 // example: 0:1,0:2,1:4
221 types << "application/Quassel/BufferItemList";
225 bool BufferTreeModel::mimeContainsBufferList(const QMimeData *mimeData) {
226 return mimeData->hasFormat("application/Quassel/BufferItemList");
229 QList< QPair<uint, uint> > BufferTreeModel::mimeDataToBufferList(const QMimeData *mimeData) {
230 QList< QPair<uint, uint> > bufferList;
232 if(!mimeContainsBufferList(mimeData))
235 QStringList rawBufferList = QString::fromAscii(mimeData->data("application/Quassel/BufferItemList")).split(",");
236 uint networkId, bufferUid;
237 foreach(QString rawBuffer, rawBufferList) {
238 if(!rawBuffer.contains(":"))
240 networkId = rawBuffer.section(":", 0, 0).toUInt();
241 bufferUid = rawBuffer.section(":", 1, 1).toUInt();
242 bufferList.append(qMakePair(networkId, bufferUid));
248 QMimeData *BufferTreeModel::mimeData(const QModelIndexList &indexes) const {
249 QMimeData *mimeData = new QMimeData();
251 QStringList bufferlist;
252 QString netid, uid, bufferid;
253 foreach(QModelIndex index, indexes) {
254 netid = QString::number(index.data(NetworkIdRole).toUInt());
255 uid = QString::number(index.data(BufferUidRole).toUInt());
256 bufferid = QString("%1:%2").arg(netid).arg(uid);
257 if(!bufferlist.contains(bufferid))
258 bufferlist << bufferid;
261 mimeData->setData("application/Quassel/BufferItemList", bufferlist.join(",").toAscii());
266 bool BufferTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) {
271 if(!mimeContainsBufferList(data))
274 // target must be a query
275 Buffer::Type targetType = (Buffer::Type)parent.data(BufferTreeModel::BufferTypeRole).toInt();
276 if(targetType != Buffer::QueryType)
279 QList< QPair<uint, uint> > bufferList = mimeDataToBufferList(data);
281 // exactly one buffer has to be dropped
282 if(bufferList.count() != 1)
285 uint netId = bufferList.first().first;
286 uint bufferId = bufferList.first().second;
288 // no self merges (would kill us)
289 if(bufferId == parent.data(BufferUidRole).toUInt())
292 Q_ASSERT(rootItem->childById(netId));
293 Q_ASSERT(rootItem->childById(netId)->childById(bufferId));
295 // source must be a query too
296 Buffer::Type sourceType = (Buffer::Type)rootItem->childById(netId)->childById(bufferId)->data(0, BufferTypeRole).toInt();
297 if(sourceType != Buffer::QueryType)
300 // TODO: warn user about buffermerge!
301 qDebug() << "merging" << bufferId << parent.data(BufferUidRole).toInt();
302 removeRow(parent.row(), parent.parent());
307 void BufferTreeModel::bufferUpdated(Buffer *buffer) {
308 QModelIndex itemindex = getOrCreateBufferItemIndex(buffer);
309 emit invalidateFilter();
310 emit dataChanged(itemindex, itemindex);
313 // This Slot indicates that the user has selected a different buffer in the gui
314 void BufferTreeModel::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) {
316 Buffer *newCurrentBuffer;
317 if(isBufferIndex(index) && currentBuffer != (newCurrentBuffer = getBufferByIndex(index))) {
318 currentBuffer = newCurrentBuffer;
319 bufferActivity(Buffer::NoActivity, currentBuffer);
320 emit bufferSelected(currentBuffer);
321 emit selectionChanged(index);
325 void BufferTreeModel::bufferActivity(Buffer::ActivityLevel level, Buffer *buffer) {
326 BufferTreeItem *bufferItem = static_cast<BufferTreeItem*>(getOrCreateBufferItemIndex(buffer).internalPointer());
327 if(buffer != currentBuffer)
328 bufferItem->setActivity(level);
330 bufferItem->setActivity(Buffer::NoActivity);
331 bufferUpdated(buffer);
334 void BufferTreeModel::selectBuffer(Buffer *buffer) {
335 QModelIndex index = getOrCreateBufferItemIndex(buffer);
337 setCurrentIndex(index, 0);