X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fclient%2Ftreemodel.cpp;h=ec6ce7af5ac4672ef7d20571d6027e81fc8c4420;hp=bee4cfaffe2c8ed11a596d3d162ddcfdef14a921;hb=8699dd758516d0ded076811e8ea656adc95e69d0;hpb=6250a7e25eb2c0a6794d4aa5679c70082d825031 diff --git a/src/client/treemodel.cpp b/src/client/treemodel.cpp index bee4cfaf..ec6ce7af 100644 --- a/src/client/treemodel.cpp +++ b/src/client/treemodel.cpp @@ -1,11 +1,11 @@ /*************************************************************************** - * Copyright (C) 2005-07 by The Quassel Team * + * Copyright (C) 2005-08 by the Quassel Project * * 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 * @@ -18,104 +18,236 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include "global.h" #include "treemodel.h" +#include + /***************************************** - * Buffer Items stored in the Tree Model + * Abstract Items of a TreeModel *****************************************/ -TreeItem::TreeItem(const QList &data, TreeItem *parent) +AbstractTreeItem::AbstractTreeItem(AbstractTreeItem *parent) : QObject(parent), - itemData(data), _parentItem(parent), _flags(Qt::ItemIsSelectable | Qt::ItemIsEnabled) { } -TreeItem::TreeItem(TreeItem *parent) - : QObject(parent), - itemData(QList()), - _parentItem(parent), - _flags(Qt::ItemIsSelectable | Qt::ItemIsEnabled) -{ +AbstractTreeItem::~AbstractTreeItem() { + AbstractTreeItem *child; + foreach(int key, _childItems.keys()) { + QList::iterator iter = _childItems[key].begin(); + while(iter != _childItems[key].end()) { + child = *iter; + iter = _childItems[key].erase(iter); + disconnect(child, 0, this, 0); + child->deleteLater(); + } + } +} + +quint64 AbstractTreeItem::id() const { + return (quint64)this; } -TreeItem::~TreeItem() { - qDeleteAll(_childItems); +int AbstractTreeItem::defaultColumn() const { + // invalid QModelIndexes aka rootNodes get their Childs stuffed into column -1 + // all others to 0 + if(_parentItem == 0) + return -1; + else + return 0; } -uint TreeItem::id() const { - return (uint)this; +void AbstractTreeItem::appendChild(int column, AbstractTreeItem *item) { + if(!_childItems.contains(column)) { + _childItems[column] = QList(); + _childHash[column] = QHash(); + } + + _childItems[column].append(item); + _childHash[column][item->id()] = item; + + connect(item, SIGNAL(destroyed()), this, SLOT(childDestroyed())); } -void TreeItem::appendChild(TreeItem *item) { - _childItems.append(item); - _childHash[item->id()] = item; - connect(item, SIGNAL(destroyed()), - this, SLOT(childDestroyed())); +void AbstractTreeItem::appendChild(AbstractTreeItem *child) { + appendChild(defaultColumn(), child); } -void TreeItem::removeChild(int row) { - if(row >= _childItems.size()) +void AbstractTreeItem::removeChild(int column, int row) { + if(!_childItems.contains(column) + || _childItems[column].size() <= row) return; - TreeItem *treeitem = _childItems.value(row); - _childItems.removeAt(row); - _childHash.remove(_childHash.key(treeitem)); + + AbstractTreeItem *treeitem = _childItems[column].value(row); + _childItems[column].removeAt(row); + _childHash[column].remove(_childHash[column].key(treeitem)); + disconnect(treeitem, 0, this, 0); + treeitem->deleteLater(); } -TreeItem *TreeItem::child(int row) const { - if(row < _childItems.size()) - return _childItems.value(row); - else +void AbstractTreeItem::removeChild(int row) { + removeChild(defaultColumn(), row); +} + +AbstractTreeItem *AbstractTreeItem::child(int column, int row) const { + if(!_childItems.contains(column) + || _childItems[column].size() <= row) return 0; + else + return _childItems[column].value(row); } -TreeItem *TreeItem::childById(const uint &id) const { - if(_childHash.contains(id)) - return _childHash.value(id); +AbstractTreeItem *AbstractTreeItem::child(int row) const { + return child(defaultColumn(), row); +} + +AbstractTreeItem *AbstractTreeItem::childById(int column, const uint &id) const { + if(!_childHash.contains(column) + || !_childHash[column].contains(id)) + return 0; else + return _childHash[column].value(id); +} + +AbstractTreeItem *AbstractTreeItem::childById(const uint &id) const { + return childById(defaultColumn(), id); +} + +int AbstractTreeItem::childCount(int column) const { + if(!_childItems.contains(column)) return 0; + else + return _childItems[column].count(); } -int TreeItem::childCount() const { - return _childItems.count(); +int AbstractTreeItem::childCount() const { + return childCount(defaultColumn()); } -int TreeItem::row() const { - if(_parentItem) - return _parentItem->_childItems.indexOf(const_cast(this)); +int AbstractTreeItem::column() const { + if(!_parentItem) + return -1; + + QHash >::const_iterator iter = _parentItem->_childItems.constBegin(); + while(iter != _parentItem->_childItems.constEnd()) { + if(iter.value().contains(const_cast(this))) + return iter.key(); + iter++; + } + + // unable to find us o_O + return _parentItem->defaultColumn(); +} + +int AbstractTreeItem::row() const { + if(!_parentItem) + return -1; else - return 0; + return _parentItem->_childItems[column()].indexOf(const_cast(this)); } -TreeItem *TreeItem::parent() { +AbstractTreeItem *AbstractTreeItem::parent() { return _parentItem; } -int TreeItem::columnCount() const { - return itemData.count(); +Qt::ItemFlags AbstractTreeItem::flags() const { + return _flags; +} + +void AbstractTreeItem::setFlags(Qt::ItemFlags flags) { + _flags = flags; +} + +void AbstractTreeItem::childDestroyed() { + AbstractTreeItem *item = static_cast(sender()); + + if(!item) { + qWarning() << "AbstractTreeItem::childDestroyed() received null pointer!"; + return; + } + + QHash >::const_iterator iter = _childItems.constBegin(); + int column, row = -1; + while(iter != _childItems.constEnd()) { + row = iter.value().indexOf(item); + if(row != -1) { + column = iter.key(); + break; + } + iter++; + } + + if(row == -1) { + qWarning() << "AbstractTreeItem::childDestroyed(): unknown Child died:" << item << "parent:" << this; + return; + } + + _childItems[column].removeAt(row); + _childHash[column].remove(_childHash[column].key(item)); + emit childDestroyed(row); +} + +/***************************************** + * SimpleTreeItem + *****************************************/ +SimpleTreeItem::SimpleTreeItem(const QList &data, AbstractTreeItem *parent) + : AbstractTreeItem(parent), + _itemData(data) +{ +} + +SimpleTreeItem::~SimpleTreeItem() { } -QVariant TreeItem::data(int column, int role) const { - if(role == Qt::DisplayRole && column < itemData.count()) - return itemData[column]; +QVariant SimpleTreeItem::data(int column, int role) const { + if(role == Qt::DisplayRole && column < _itemData.count()) + return _itemData[column]; else return QVariant(); } -Qt::ItemFlags TreeItem::flags() const { - return _flags; +int SimpleTreeItem::columnCount() const { + return _itemData.count(); } -void TreeItem::setFlags(Qt::ItemFlags flags) { - _flags = flags; +/***************************************** + * PropertyMapItem + *****************************************/ +PropertyMapItem::PropertyMapItem(const QStringList &propertyOrder, AbstractTreeItem *parent) + : AbstractTreeItem(parent), + _propertyOrder(propertyOrder) +{ +} + +PropertyMapItem::PropertyMapItem(AbstractTreeItem *parent) + : AbstractTreeItem(parent), + _propertyOrder(QStringList()) +{ } -void TreeItem::childDestroyed() { - TreeItem *item = static_cast(sender()); - removeChild(item->row()); + +PropertyMapItem::~PropertyMapItem() { } +QVariant PropertyMapItem::data(int column, int role) const { + if(column >= columnCount()) + return QVariant(); + + if(role != Qt::DisplayRole) + return QVariant(); + + return property(_propertyOrder[column].toAscii()); +} + +int PropertyMapItem::columnCount() const { + return _propertyOrder.count(); +} + +void PropertyMapItem::appendProperty(const QString &property) { + _propertyOrder << property; +} + /***************************************** @@ -124,7 +256,7 @@ void TreeItem::childDestroyed() { TreeModel::TreeModel(const QList &data, QObject *parent) : QAbstractItemModel(parent) { - rootItem = new TreeItem(data, 0); + rootItem = new SimpleTreeItem(data, 0); } TreeModel::~TreeModel() { @@ -135,14 +267,15 @@ QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) con if(!hasIndex(row, column, parent)) return QModelIndex(); - TreeItem *parentItem; + AbstractTreeItem *parentItem; if(!parent.isValid()) parentItem = rootItem; else - parentItem = static_cast(parent.internalPointer()); + parentItem = static_cast(parent.internalPointer()); - TreeItem *childItem = parentItem->child(row); + AbstractTreeItem *childItem = parentItem->child(parent.column(), row); + if(childItem) return createIndex(row, column, childItem); else @@ -150,26 +283,40 @@ QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) con } QModelIndex TreeModel::indexById(uint id, const QModelIndex &parent) const { - TreeItem *parentItem; + AbstractTreeItem *parentItem; if(!parent.isValid()) parentItem = rootItem; else - parentItem = static_cast(parent.internalPointer()); + parentItem = static_cast(parent.internalPointer()); + + AbstractTreeItem *childItem = parentItem->childById(parent.column(), id); - TreeItem *childItem = parentItem->childById(id); if(childItem) return createIndex(childItem->row(), 0, childItem); else return QModelIndex(); } +QModelIndex TreeModel::indexByItem(AbstractTreeItem *item) const { + if(item == 0) { + qWarning() << "TreeModel::indexByItem(AbstractTreeItem *item) received NULL-Pointer"; + return QModelIndex(); + } + + if(item == rootItem) + return QModelIndex(); + else + return createIndex(item->row(), 0, item); + +} + QModelIndex TreeModel::parent(const QModelIndex &index) const { if(!index.isValid()) return QModelIndex(); - TreeItem *childItem = static_cast(index.internalPointer()); - TreeItem *parentItem = static_cast(childItem->parent()); + AbstractTreeItem *childItem = static_cast(index.internalPointer()); + AbstractTreeItem *parentItem = static_cast(childItem->parent()); if(parentItem == rootItem) return QModelIndex(); @@ -178,36 +325,49 @@ QModelIndex TreeModel::parent(const QModelIndex &index) const { } int TreeModel::rowCount(const QModelIndex &parent) const { - TreeItem *parentItem; + AbstractTreeItem *parentItem; if(!parent.isValid()) parentItem = rootItem; else - parentItem = static_cast(parent.internalPointer()); - - return parentItem->childCount(); + parentItem = static_cast(parent.internalPointer()); + + return parentItem->childCount(parent.column()); } int TreeModel::columnCount(const QModelIndex &parent) const { - if(parent.isValid()) - return static_cast(parent.internalPointer())->columnCount(); - else - return rootItem->columnCount(); + Q_UNUSED(parent) + // since there the Qt Views don't draw more columns than the header has columns + // we can be lazy and simply return the count of header columns + // actually this gives us more freedom cause we don't have to ensure that a rows parent + // has equal or more columns than that row + +// if(parent.isValid()) { +// AbstractTreeItem *child; +// if(child = static_cast(parent.internalPointer())->child(parent.column(), parent.row())) +// return child->columnCount(); +// else +// return static_cast(parent.internalPointer())->columnCount(); +// } else { +// return rootItem->columnCount(); +// } + + return rootItem->columnCount(); } QVariant TreeModel::data(const QModelIndex &index, int role) const { if(!index.isValid()) return QVariant(); - TreeItem *item = static_cast(index.internalPointer()); + AbstractTreeItem *item = static_cast(index.internalPointer()); return item->data(index.column(), role); } Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const { - TreeItem *item; + AbstractTreeItem *item; if(!index.isValid()) item = rootItem; else - item = static_cast(index.internalPointer()); + item = static_cast(index.internalPointer()); return item->flags(); } @@ -218,18 +378,61 @@ QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int rol return QVariant(); } +void TreeModel::itemDataChanged(int column) { + AbstractTreeItem *item = qobject_cast(sender()); + QModelIndex itemIndex; + + if(item == rootItem) + itemIndex = QModelIndex(); + else + itemIndex = createIndex(item->row(), column, item); + + emit dataChanged(itemIndex, itemIndex); +} + +void TreeModel::appendChild(AbstractTreeItem *parent, AbstractTreeItem *child) { + if(parent == 0 or child == 0) { + qWarning() << "TreeModel::appendChild(parent, child) parent and child have to be valid pointers!" << parent << child; + return; + } + + int nextRow = parent->childCount(); + beginInsertRows(indexByItem(parent), nextRow, nextRow); + parent->appendChild(child); + endInsertRows(); + + connect(child, SIGNAL(dataChanged(int)), + this, SLOT(itemDataChanged(int))); + + connect(child, SIGNAL(newChild(AbstractTreeItem *)), + this, SLOT(newChild(AbstractTreeItem *))); + + connect(child, SIGNAL(childDestroyed(int)), + this, SLOT(childDestroyed(int))); +} + +void TreeModel::newChild(AbstractTreeItem *child) { + appendChild(static_cast(sender()), child); +} + +void TreeModel::childDestroyed(int row) { + QModelIndex parent = indexByItem(static_cast(sender())); + beginRemoveRows(parent, row, row); + endRemoveRows(); +} + bool TreeModel::removeRow(int row, const QModelIndex &parent) { if(row > rowCount(parent)) return false; - TreeItem *item; + AbstractTreeItem *item; if(!parent.isValid()) item = rootItem; else - item = static_cast(parent.internalPointer()); + item = static_cast(parent.internalPointer()); beginRemoveRows(parent, row, row); - item->removeChild(row); + item->removeChild(parent.column(), row); endRemoveRows(); return true; } @@ -243,17 +446,17 @@ bool TreeModel::removeRows(int row, int count, const QModelIndex &parent) { if(row + count - 1 > rowCount(parent) || row < 0 || count < 0) return false; - TreeItem *item; + AbstractTreeItem *item; if(!parent.isValid()) item = rootItem; else - item = static_cast(parent.internalPointer()); + item = static_cast(parent.internalPointer()); beginRemoveRows(parent, row, row + count - 1); for(int i = row + count - 1; i >= 0; i--) { - item->removeChild(i); + item->removeChild(parent.column(), i); } endRemoveRows(); return true; @@ -261,4 +464,5 @@ bool TreeModel::removeRows(int row, int count, const QModelIndex &parent) { void TreeModel::clear() { removeRows(0, rowCount()); + reset(); }