X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fclient%2Ftreemodel.cpp;h=9a01abf455c57446112474184a35a44f2240b676;hp=929622d6af3eb92ec81e5b6dfcce91027c217037;hb=f953257711e147661ce79e4da4c8b84f083e3e95;hpb=7df7429c009d2bea4c516e87f1ec4c956c722e09 diff --git a/src/client/treemodel.cpp b/src/client/treemodel.cpp index 929622d6..9a01abf4 100644 --- a/src/client/treemodel.cpp +++ b/src/client/treemodel.cpp @@ -21,6 +21,7 @@ #include "treemodel.h" #include +#include /***************************************** * Abstract Items of a TreeModel @@ -32,150 +33,100 @@ AbstractTreeItem::AbstractTreeItem(AbstractTreeItem *parent) } AbstractTreeItem::~AbstractTreeItem() { - removeAllChilds(); } quint64 AbstractTreeItem::id() const { - return (quint64)this; + return qHash(this); } -int AbstractTreeItem::defaultColumn() const { - // invalid QModelIndexes aka rootNodes get their Childs stuffed into column -1 - // all others to 0 - if(parent() == 0) - return -1; - else - return 0; -} - -void AbstractTreeItem::appendChild(int column, AbstractTreeItem *item) { - if(!_childItems.contains(column)) { - _childItems[column] = QList(); - _childHash[column] = QHash(); - } +bool AbstractTreeItem::newChild(AbstractTreeItem *item) { + // check if a child with that ID is already known + Q_ASSERT(childById(item->id()) == 0); + + int newRow = childCount(); + emit beginAppendChilds(newRow, newRow); + _childItems.append(item); + emit endAppendChilds(); - _childItems[column].append(item); - _childHash[column][item->id()] = item; - - connect(item, SIGNAL(destroyed()), this, SLOT(childDestroyed())); -} - -void AbstractTreeItem::appendChild(AbstractTreeItem *child) { - appendChild(defaultColumn(), child); + return true; } -void AbstractTreeItem::removeChild(int column, int row) { - if(!_childItems.contains(column) - || _childItems[column].size() <= row) - return; +bool AbstractTreeItem::removeChild(int row) { + if(childCount() <= row) + return false; - if(column == defaultColumn()) - emit beginRemoveChilds(row, row); - - AbstractTreeItem *treeitem = _childItems[column].value(row); - _childItems[column].removeAt(row); - _childHash[column].remove(_childHash[column].key(treeitem)); - disconnect(treeitem, 0, this, 0); + child(row)->removeAllChilds(); + emit beginRemoveChilds(row, row); + AbstractTreeItem *treeitem = _childItems.takeAt(row); treeitem->deleteLater(); + emit endRemoveChilds(); - if(column == defaultColumn()) - emit endRemoveChilds(); -} - -void AbstractTreeItem::removeChild(int row) { - removeChild(defaultColumn(), row); + return true; } -void AbstractTreeItem::removeChildById(int column, const quint64 &id) { - if(!_childHash[column].contains(id)) - return; +bool AbstractTreeItem::removeChildById(const quint64 &id) { + const int numChilds = childCount(); - AbstractTreeItem *treeItem = _childHash[column][id]; - int row = _childItems[column].indexOf(treeItem); - Q_ASSERT(row >= 0); - removeChild(column, row); -} - -void AbstractTreeItem::removeChildById(const quint64 &id) { - removeChildById(defaultColumn(), id); + for(int i = 0; i < numChilds; i++) { + if(_childItems[i]->id() == id) + return removeChild(i); + } + + return false; } void AbstractTreeItem::removeAllChilds() { - if(childCount() == 0) + const int numChilds = childCount(); + + if(numChilds == 0) return; + + AbstractTreeItem *child; - emit beginRemoveChilds(0, childCount() - 1); + QList::iterator childIter; - AbstractTreeItem *child; - foreach(int column, _childItems.keys()) { - QList::iterator iter = _childItems[column].begin(); - while(iter != _childItems[column].end()) { - child = *iter; - _childHash[column].remove(_childHash[column].key(child)); - iter = _childItems[column].erase(iter); - disconnect(child, 0, this, 0); - child->removeAllChilds(); - child->deleteLater(); - } + childIter = _childItems.begin(); + while(childIter != _childItems.end()) { + child = *childIter; + child->removeAllChilds(); + childIter++; } - emit endRemoveChilds(); -} -AbstractTreeItem *AbstractTreeItem::child(int column, int row) const { - if(!_childItems.contains(column) - || _childItems[column].size() <= row) - return 0; - else - return _childItems[column].value(row); + emit beginRemoveChilds(0, numChilds - 1); + childIter = _childItems.begin(); + while(childIter != _childItems.end()) { + child = *childIter; + childIter = _childItems.erase(childIter); + child->deleteLater(); + } + emit endRemoveChilds(); } AbstractTreeItem *AbstractTreeItem::child(int row) const { - return child(defaultColumn(), row); -} - -AbstractTreeItem *AbstractTreeItem::childById(int column, const quint64 &id) const { - if(!_childHash.contains(column) - || !_childHash[column].contains(id)) + if(childCount() <= row) return 0; else - return _childHash[column].value(id); + return _childItems[row]; } AbstractTreeItem *AbstractTreeItem::childById(const quint64 &id) const { - return childById(defaultColumn(), id); -} - -int AbstractTreeItem::childCount(int column) const { - if(!_childItems.contains(column)) - return 0; - else - return _childItems[column].count(); + const int numChilds = childCount(); + for(int i = 0; i < numChilds; i++) { + if(_childItems[i]->id() == id) + return _childItems[i]; + } + return 0; } int AbstractTreeItem::childCount() const { - return childCount(defaultColumn()); -} - -int AbstractTreeItem::column() const { - if(!parent()) - return -1; - - QHash >::const_iterator iter = parent()->_childItems.constBegin(); - while(iter != parent()->_childItems.constEnd()) { - if(iter.value().contains(const_cast(this))) - return iter.key(); - iter++; - } - - // unable to find us o_O - return parent()->defaultColumn(); + return _childItems.count(); } int AbstractTreeItem::row() const { if(!parent()) return -1; else - return parent()->_childItems[column()].indexOf(const_cast(this)); + return parent()->_childItems.indexOf(const_cast(this)); } AbstractTreeItem *AbstractTreeItem::parent() const { @@ -190,36 +141,20 @@ 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; +void AbstractTreeItem::dumpChildList() { + qDebug() << "==== Childlist for Item:" << this << id() << "===="; + if(childCount() > 0) { + AbstractTreeItem *child; + QList::const_iterator childIter = _childItems.constBegin(); + while(childIter != _childItems.constEnd()) { + child = *childIter; + qDebug() << "Row:" << child->row() << child << child->id() << child->data(0, Qt::DisplayRole); + childIter++; } - 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 beginRemoveChilds(row, row); - emit endRemoveChilds(); + qDebug() << "==== End Of Childlist ===="; } - + /***************************************** * SimpleTreeItem *****************************************/ @@ -233,10 +168,23 @@ SimpleTreeItem::~SimpleTreeItem() { } QVariant SimpleTreeItem::data(int column, int role) const { - if(role == Qt::DisplayRole && column < _itemData.count()) + if(column >= columnCount() || role != Qt::DisplayRole) + return QVariant(); + else return _itemData[column]; +} + +bool SimpleTreeItem::setData(int column, const QVariant &value, int role) { + if(column > columnCount() || role != Qt::DisplayRole) + return false; + + if(column == columnCount()) + _itemData.append(value); else - return QVariant(); + _itemData[column] = value; + + emit dataChanged(column); + return true; } int SimpleTreeItem::columnCount() const { @@ -266,10 +214,23 @@ QVariant PropertyMapItem::data(int column, int role) const { if(column >= columnCount()) return QVariant(); - if(role != Qt::DisplayRole) + switch(role) { + case Qt::ToolTipRole: + return toolTip(column); + case Qt::DisplayRole: + return property(_propertyOrder[column].toAscii()); + default: return QVariant(); + } + +} - return property(_propertyOrder[column].toAscii()); +bool PropertyMapItem::setData(int column, const QVariant &value, int role) { + if(column >= columnCount() || role != Qt::DisplayRole) + return false; + + emit dataChanged(column); + return setProperty(_propertyOrder[column].toAscii(), value); } int PropertyMapItem::columnCount() const { @@ -286,9 +247,23 @@ void PropertyMapItem::appendProperty(const QString &property) { * TreeModel *****************************************/ TreeModel::TreeModel(const QList &data, QObject *parent) - : QAbstractItemModel(parent) + : QAbstractItemModel(parent), + _childStatus(QModelIndex(), 0, 0, 0), + _aboutToRemoveOrInsert(false) { rootItem = new SimpleTreeItem(data, 0); + connectItem(rootItem); + + if(QCoreApplication::instance()->arguments().contains("--debugmodel")) { + connect(this, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(debug_rowsAboutToBeInserted(const QModelIndex &, int, int))); + connect(this, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(debug_rowsAboutToBeRemoved(const QModelIndex &, int, int))); + connect(this, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(debug_rowsInserted(const QModelIndex &, int, int))); + connect(this, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(debug_rowsRemoved(const QModelIndex &, int, int))); + } } TreeModel::~TreeModel() { @@ -304,9 +279,9 @@ QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) con if(!parent.isValid()) parentItem = rootItem; else - parentItem = static_cast(parent.internalPointer()); + parentItem = static_cast(parent.internalPointer()); - AbstractTreeItem *childItem = parentItem->child(parent.column(), row); + AbstractTreeItem *childItem = parentItem->child(row); if(childItem) return createIndex(row, column, childItem); @@ -322,7 +297,7 @@ QModelIndex TreeModel::indexById(quint64 id, const QModelIndex &parent) const { else parentItem = static_cast(parent.internalPointer()); - AbstractTreeItem *childItem = parentItem->childById(parent.column(), id); + AbstractTreeItem *childItem = parentItem->childById(id); if(childItem) return createIndex(childItem->row(), 0, childItem); @@ -340,16 +315,18 @@ QModelIndex TreeModel::indexByItem(AbstractTreeItem *item) const { return QModelIndex(); else return createIndex(item->row(), 0, item); - } QModelIndex TreeModel::parent(const QModelIndex &index) const { - if(!index.isValid()) + if(!index.isValid()) { + qWarning() << "TreeModel::parent(): has been asked for the rootItems Parent!"; return QModelIndex(); + } AbstractTreeItem *childItem = static_cast(index.internalPointer()); - AbstractTreeItem *parentItem = static_cast(childItem->parent()); - + AbstractTreeItem *parentItem = childItem->parent(); + + Q_ASSERT(parentItem); if(parentItem == rootItem) return QModelIndex(); @@ -363,7 +340,7 @@ int TreeModel::rowCount(const QModelIndex &parent) const { else parentItem = static_cast(parent.internalPointer()); - return parentItem->childCount(parent.column()); + return parentItem->childCount(); } int TreeModel::columnCount(const QModelIndex &parent) const { @@ -390,10 +367,18 @@ QVariant TreeModel::data(const QModelIndex &index, int role) const { if(!index.isValid()) return QVariant(); - AbstractTreeItem *item = static_cast(index.internalPointer()); + AbstractTreeItem *item = static_cast(index.internalPointer()); return item->data(index.column(), role); } +bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { + if(!index.isValid()) + return false; + + AbstractTreeItem *item = static_cast(index.internalPointer()); + return item->setData(index.column(), value, role); +} + Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const { AbstractTreeItem *item; if(!index.isValid()) @@ -419,7 +404,7 @@ void TreeModel::itemDataChanged(int column) { if(column == -1) { leftIndex = createIndex(item->row(), 0, item); - rightIndex = createIndex(item->row(), item->columnCount()-1, item); + rightIndex = createIndex(item->row(), item->columnCount() - 1, item); } else { leftIndex = createIndex(item->row(), column, item); rightIndex = leftIndex; @@ -428,85 +413,129 @@ void TreeModel::itemDataChanged(int column) { emit dataChanged(leftIndex, rightIndex); } -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)), +void TreeModel::connectItem(AbstractTreeItem *item) { + connect(item, SIGNAL(dataChanged(int)), this, SLOT(itemDataChanged(int))); - connect(child, SIGNAL(newChild(AbstractTreeItem *)), - this, SLOT(newChild(AbstractTreeItem *))); - - connect(child, SIGNAL(beginRemoveChilds(int, int)), - this, SLOT(beginRemoveChilds(int, int))); + connect(item, SIGNAL(beginAppendChilds(int, int)), + this, SLOT(beginAppendChilds(int, int))); + connect(item, SIGNAL(endAppendChilds()), + this, SLOT(endAppendChilds())); - connect(child, SIGNAL(endRemoveChilds()), + connect(item, SIGNAL(beginRemoveChilds(int, int)), + this, SLOT(beginRemoveChilds(int, int))); + connect(item, SIGNAL(endRemoveChilds()), this, SLOT(endRemoveChilds())); } -void TreeModel::newChild(AbstractTreeItem *child) { - appendChild(static_cast(sender()), child); +void TreeModel::beginAppendChilds(int firstRow, int lastRow) { + AbstractTreeItem *parentItem = qobject_cast(sender()); + if(!parentItem) { + qWarning() << "TreeModel::beginAppendChilds(): cannot append Childs to unknown parent"; + return; + } + + QModelIndex parent = indexByItem(parentItem); + Q_ASSERT(!_aboutToRemoveOrInsert); + + _aboutToRemoveOrInsert = true; + _childStatus = ChildStatus(parent, rowCount(parent), firstRow, lastRow); + beginInsertRows(parent, firstRow, lastRow); +} + +void TreeModel::endAppendChilds() { + AbstractTreeItem *parentItem = qobject_cast(sender()); + if(!parentItem) { + qWarning() << "TreeModel::endAppendChilds(): cannot append Childs to unknown parent"; + return; + } + Q_ASSERT(_aboutToRemoveOrInsert); + ChildStatus cs = _childStatus; + QModelIndex parent = indexByItem(parentItem); + Q_ASSERT(cs.parent == parent); + Q_ASSERT(rowCount(parent) == cs.childCount + cs.end - cs.start + 1); + + _aboutToRemoveOrInsert = false; + for(int i = cs.start; i <= cs.end; i++) { + connectItem(parentItem->child(i)); + } + endInsertRows(); } void TreeModel::beginRemoveChilds(int firstRow, int lastRow) { - QModelIndex parent = indexByItem(static_cast(sender())); + AbstractTreeItem *parentItem = qobject_cast(sender()); + if(!parentItem) { + qWarning() << "TreeModel::beginRemoveChilds(): cannot append Childs to unknown parent"; + return; + } + QModelIndex parent = indexByItem(parentItem); + Q_ASSERT(firstRow <= lastRow); + Q_ASSERT(parentItem->childCount() > lastRow); + Q_ASSERT(!_aboutToRemoveOrInsert); + + _aboutToRemoveOrInsert = true; + _childStatus = ChildStatus(parent, rowCount(parent), firstRow, lastRow); beginRemoveRows(parent, firstRow, lastRow); } void TreeModel::endRemoveChilds() { + AbstractTreeItem *parentItem = qobject_cast(sender()); + if(!parentItem) { + qWarning() << "TreeModel::endRemoveChilds(): cannot append Childs to unknown parent"; + return; + } + Q_ASSERT(_aboutToRemoveOrInsert); + ChildStatus cs = _childStatus; + QModelIndex parent = indexByItem(parentItem); + Q_ASSERT(cs.parent == parent); + Q_ASSERT(rowCount(parent) == cs.childCount - cs.end + cs.start - 1); + + _aboutToRemoveOrInsert = false; endRemoveRows(); } -bool TreeModel::removeRow(int row, const QModelIndex &parent) { - if(row > rowCount(parent)) - return false; - - AbstractTreeItem *item; - if(!parent.isValid()) - item = rootItem; - else - item = static_cast(parent.internalPointer()); - - beginRemoveRows(parent, row, row); - item->removeChild(parent.column(), row); - endRemoveRows(); - return true; +void TreeModel::clear() { + rootItem->removeAllChilds(); } -bool TreeModel::removeRows(int row, int count, const QModelIndex &parent) { - // check if there is work to be done - if(count == 0) - return true; +void TreeModel::debug_rowsAboutToBeInserted(const QModelIndex &parent, int start, int end) { + // qDebug() << "debug_rowsAboutToBeInserted" << parent << parent.internalPointer() << parent.data().toString() << rowCount(parent) << start << end; +} - // out of range check - if(row + count - 1 > rowCount(parent) || row < 0 || count < 0) - return false; - - AbstractTreeItem *item; - if(!parent.isValid()) - item = rootItem; - else - item = static_cast(parent.internalPointer()); - - - beginRemoveRows(parent, row, row + count - 1); +void TreeModel::debug_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { + AbstractTreeItem *parentItem; + parentItem = static_cast(parent.internalPointer()); + if(!parentItem) + parentItem = rootItem; + qDebug() << "#" << parent << parentItem << parent.data().toString() << rowCount(parent) << start << end; + + QModelIndex child; + AbstractTreeItem *childItem; + for(int i = end; i >= start; i--) { + child = parent.child(i, 0); + childItem = parentItem->child(i); + Q_ASSERT(childItem); + qDebug() << ">>>" << i << child << childItem->id() << child.data().toString(); + } +} - for(int i = row + count - 1; i >= 0; i--) { - item->removeChild(parent.column(), i); +void TreeModel::debug_rowsInserted(const QModelIndex &parent, int start, int end) { + AbstractTreeItem *parentItem; + parentItem = static_cast(parent.internalPointer()); + if(!parentItem) + parentItem = rootItem; + qDebug() << "#" << parent << parentItem << parent.data().toString() << rowCount(parent) << start << end; + + QModelIndex child; + AbstractTreeItem *childItem; + for(int i = start; i <= end; i++) { + child = parent.child(i, 0); + childItem = parentItem->child(i); + Q_ASSERT(childItem); + qDebug() << "<<<" << i << child << childItem->id() << child.data().toString(); } - endRemoveRows(); - return true; } -void TreeModel::clear() { - removeRows(0, rowCount()); - reset(); +void TreeModel::debug_rowsRemoved(const QModelIndex &parent, int start, int end) { + // qDebug() << "debug_rowsRemoved" << parent << parent.internalPointer() << parent.data().toString() << rowCount(parent) << start << end; }