1 /***************************************************************************
2 * Copyright (C) 2005-07 by The Quassel 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) any later version. *
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 ***************************************************************************/
22 #include "bufferviewwidget.h"
24 /*****************************************
25 * Buffer Items stored in the Tree Model
26 *****************************************/
27 TreeItem::TreeItem(QList<QVariant> &data, TreeItem *parent) {
30 foreground = Qt::black;
33 TreeItem::TreeItem(TreeItem *parent) {
34 itemData = QList<QVariant>();
36 foreground = Qt::black;
39 TreeItem::~TreeItem() {
40 qDeleteAll(childItems);
43 void TreeItem::appendChild(TreeItem *item) {
44 childItems.append(item);
47 void TreeItem::removeChild(int row) {
48 childItems.removeAt(row);
51 TreeItem *TreeItem::child(int row) {
52 return childItems.value(row);
55 int TreeItem::childCount() const {
56 return childItems.count();
59 int TreeItem::row() const {
61 return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));
66 TreeItem *TreeItem::parent() {
70 int TreeItem::columnCount() const {
71 return itemData.count();
74 void TreeItem::setForeground(QColor newcolor) {
75 foreground = newcolor;
78 QVariant TreeItem::data(int column, int role) const {
81 if(column < itemData.count())
82 return itemData[column];
86 case Qt::ForegroundRole:
95 /*****************************************
97 *****************************************/
98 BufferTreeItem::BufferTreeItem(Buffer *buffer, TreeItem *parent) : TreeItem(parent) {
100 activity = Buffer::NoActivity;
103 void BufferTreeItem::setActivity(const Buffer::ActivityLevel &level) {
107 QString BufferTreeItem::text(int column) const {
110 return buf->displayName();
112 return buf->networkName();
118 QColor BufferTreeItem::foreground(int column) const {
119 // for the time beeing we ignore the column :)
120 if(activity & Buffer::Highlight) {
121 return QColor(Qt::red);
122 } else if(activity & Buffer::NewMessage) {
123 return QColor(Qt::darkYellow);
124 } else if(activity & Buffer::OtherActivity) {
125 return QColor(Qt::darkGreen);
128 return QColor(Qt::black);
130 return QColor(Qt::gray);
135 QVariant BufferTreeItem::data(int column, int role) const {
137 case Qt::DisplayRole:
139 case Qt::ForegroundRole:
140 return foreground(column);
141 case BufferTreeModel::BufferTypeRole:
142 return buf->bufferType();
143 case BufferTreeModel::BufferActiveRole:
144 return buf->isActive();
150 /*****************************************
152 *****************************************/
153 BufferTreeModel::BufferTreeModel(QObject *parent) : QAbstractItemModel(parent) {
154 QList<QVariant> rootData;
155 rootData << "Buffer" << "Network";
156 rootItem = new TreeItem(rootData, 0);
158 connect(this, SIGNAL(fakeUserInput(BufferId, QString)), ClientProxy::instance(), SLOT(gsUserInput(BufferId, QString)));
161 BufferTreeModel::~BufferTreeModel() {
165 QModelIndex BufferTreeModel::index(int row, int column, const QModelIndex &parent) const {
166 if(!hasIndex(row, column, parent))
167 return QModelIndex();
169 TreeItem *parentItem;
171 if(!parent.isValid())
172 parentItem = rootItem;
174 parentItem = static_cast<TreeItem*>(parent.internalPointer());
176 TreeItem *childItem = parentItem->child(row);
178 return createIndex(row, column, childItem);
180 return QModelIndex();
183 QModelIndex BufferTreeModel::parent(const QModelIndex &index) const {
185 return QModelIndex();
187 TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
188 TreeItem *parentItem = childItem->parent();
190 if(parentItem == rootItem)
191 return QModelIndex();
193 return createIndex(parentItem->row(), 0, parentItem);
196 int BufferTreeModel::rowCount(const QModelIndex &parent) const {
197 TreeItem *parentItem;
198 if(parent.column() > 0)
201 if(!parent.isValid())
202 parentItem = rootItem;
204 parentItem = static_cast<TreeItem*>(parent.internalPointer());
206 return parentItem->childCount();
209 int BufferTreeModel::columnCount(const QModelIndex &parent) const {
211 return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
213 return rootItem->columnCount();
216 QVariant BufferTreeModel::data(const QModelIndex &index, int role) const {
220 TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
221 return item->data(index.column(), role);
224 Qt::ItemFlags BufferTreeModel::flags(const QModelIndex &index) const {
228 // I think this is pretty ugly..
229 if(isBufferIndex(index)) {
230 Buffer *buffer = getBufferByIndex(index);
231 if(buffer->bufferType() == Buffer::QueryBuffer)
232 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
234 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
236 return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled;
240 QVariant BufferTreeModel::headerData(int section, Qt::Orientation orientation, int role) const {
241 if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
242 return rootItem->data(section, role);
247 bool BufferTreeModel::removeRow(int row, const QModelIndex &parent) {
248 beginRemoveRows(parent, row, row);
249 TreeItem *item = static_cast<TreeItem*>(parent.internalPointer());
250 item->removeChild(row);
255 bool BufferTreeModel::isBufferIndex(const QModelIndex &index) const {
256 return parent(index) != QModelIndex();
259 Buffer *BufferTreeModel::getBufferByIndex(const QModelIndex &index) const {
260 BufferTreeItem *item = static_cast<BufferTreeItem *>(index.internalPointer());
261 return item->buffer();
264 QModelIndex BufferTreeModel::getOrCreateNetworkItemIndex(Buffer *buffer) {
265 QString net = buffer->networkName();
267 if(networkItem.contains(net)) {
268 return index(networkItem[net]->row(), 0);
270 QList<QVariant> data;
273 int nextRow = rootItem->childCount();
275 beginInsertRows(QModelIndex(), nextRow, nextRow);
276 rootItem->appendChild(new TreeItem(data, rootItem));
279 networkItem[net] = rootItem->child(nextRow);
280 return index(nextRow, 0);
284 QModelIndex BufferTreeModel::getOrCreateBufferItemIndex(Buffer *buffer) {
285 QModelIndex networkItemIndex = getOrCreateNetworkItemIndex(buffer);
287 if(bufferItem.contains(buffer)) {
288 return index(bufferItem[buffer]->row(), 0, networkItemIndex);
290 // first we determine the parent of the new Item
291 TreeItem *networkItem = static_cast<TreeItem*>(networkItemIndex.internalPointer());
293 int nextRow = networkItem->childCount();
295 beginInsertRows(networkItemIndex, nextRow, nextRow);
296 networkItem->appendChild(new BufferTreeItem(buffer, networkItem));
299 bufferItem[buffer] = static_cast<BufferTreeItem *>(networkItem->child(nextRow));
300 return index(nextRow, 0, networkItemIndex);
304 QStringList BufferTreeModel::mimeTypes() const {
306 types << "application/Quassel/BufferItem/row"
307 << "application/Quassel/BufferItem/network";
311 QMimeData *BufferTreeModel::mimeData(const QModelIndexList &indexes) const {
312 QMimeData *mimeData = new QMimeData();
314 QModelIndex index = indexes.first();
316 mimeData->setData("application/Quassel/BufferItem/row", QByteArray::number(index.row()));
317 mimeData->setData("application/Quassel/BufferItem/network", getBufferByIndex(index)->networkName().toUtf8());
321 bool BufferTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) {
322 int sourcerow = data->data("application/Quassel/BufferItem/row").toInt();
323 QString network = QString::fromUtf8(data->data("application/Quassel/BufferItem/network"));
325 if(!networkItem.contains(network))
328 if(!isBufferIndex(parent)) // dropping at a network -> no merging needed
331 Buffer *sourceBuffer = static_cast<BufferTreeItem *>(networkItem[network]->child(sourcerow))->buffer();
332 Buffer *targetBuffer = getBufferByIndex(parent);
334 if(sourceBuffer == targetBuffer) // we won't merge with ourself :)
338 if(QMessageBox::warning(static_cast<QWidget *>(QObject::parent()),
339 tr("Merge Buffers?"),
340 tr("Do you really want to merge the following Buffers?<br />%1.%2<br />%3.%4").arg(sourceBuffer->networkName()).arg(sourceBuffer->bufferName()).arg(targetBuffer->networkName()).arg(targetBuffer->bufferName()),
341 QMessageBox::Yes|QMessageBox::No) == QMessageBox::No)
345 qDebug() << "merging" << sourceBuffer->bufferName() << "with" << targetBuffer->bufferName();
346 bufferItem.remove(getBufferByIndex(parent));
347 removeRow(parent.row(), BufferTreeModel::parent(parent));
352 void BufferTreeModel::bufferUpdated(Buffer *buffer) {
353 QModelIndex itemindex = getOrCreateBufferItemIndex(buffer);
354 emit invalidateFilter();
355 emit dataChanged(itemindex, itemindex);
358 // This Slot indicates that the user has selected a different buffer in the gui
359 void BufferTreeModel::changeCurrent(const QModelIndex ¤t, const QModelIndex &previous) {
360 if(isBufferIndex(current)) {
361 currentBuffer = getBufferByIndex(current);
362 bufferActivity(Buffer::NoActivity, currentBuffer);
363 emit bufferSelected(currentBuffer);
364 emit updateSelection(current, QItemSelectionModel::ClearAndSelect);
368 // we received a double click on a buffer, so we're going to join it
369 void BufferTreeModel::doubleClickReceived(const QModelIndex &clicked) {
370 if(isBufferIndex(clicked)) {
371 Buffer *buffer = getBufferByIndex(clicked);
372 if(!buffer->isStatusBuffer())
373 emit fakeUserInput(buffer->bufferId(), QString("/join " + buffer->bufferName()));
378 void BufferTreeModel::bufferActivity(Buffer::ActivityLevel level, Buffer *buffer) {
379 if(bufferItem.contains(buffer) and buffer != currentBuffer)
380 bufferItem[buffer]->setActivity(level);
382 bufferItem[buffer]->setActivity(Buffer::NoActivity);
383 bufferUpdated(buffer);
386 void BufferTreeModel::selectBuffer(Buffer *buffer) {
387 QModelIndex index = getOrCreateBufferItemIndex(buffer);
388 emit updateSelection(index, QItemSelectionModel::ClearAndSelect);
392 /*****************************************
393 * This Widget Contains the BufferView
394 *****************************************/
395 BufferViewWidget::BufferViewWidget(QWidget *parent) : QWidget(parent) {
399 QSize BufferViewWidget::sizeHint() const {
400 return QSize(150,100);
404 /*****************************************
405 * Dock and API for the BufferViews
406 *****************************************/
407 BufferViewDock::BufferViewDock(QAbstractItemModel *model, QString viewname, BufferViewFilter::Modes mode, QStringList nets, QWidget *parent) : QDockWidget(parent) {
408 setObjectName(QString("View-" + viewname)); // should be unique for mainwindow state!
409 setWindowTitle(viewname);
411 BufferViewWidget *viewWidget = new BufferViewWidget(this);
412 viewWidget->treeView()->setFilteredModel(model, mode, nets);
413 setWidget(viewWidget);