X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fclient%2Ftreemodel.cpp;h=64cc26fe333ae79f6980593a192942aca8438423;hp=ace9d3d7a73ee1eee3b14eeada69bc6b2c62f08b;hb=46d75f41de7c1aaee605c096da28d4b0d8abf138;hpb=89c07686d193fe31e1b3ea45735b3f5a0d1e6cfb diff --git a/src/client/treemodel.cpp b/src/client/treemodel.cpp index ace9d3d7..64cc26fe 100644 --- a/src/client/treemodel.cpp +++ b/src/client/treemodel.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-08 by the Quassel Project * + * Copyright (C) 2005-09 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -20,96 +20,73 @@ #include "treemodel.h" -#include #include +#include + +#include "quassel.h" + +class RemoveChildLaterEvent : public QEvent { +public: + RemoveChildLaterEvent(AbstractTreeItem *child) : QEvent(QEvent::User), _child(child) {}; + inline AbstractTreeItem *child() { return _child; } +private: + AbstractTreeItem *_child; +}; + /***************************************** * Abstract Items of a TreeModel *****************************************/ AbstractTreeItem::AbstractTreeItem(AbstractTreeItem *parent) : QObject(parent), - _flags(Qt::ItemIsSelectable | Qt::ItemIsEnabled) + _flags(Qt::ItemIsSelectable | Qt::ItemIsEnabled), + _treeItemFlags(0) { } -AbstractTreeItem::~AbstractTreeItem() { -} - -quint64 AbstractTreeItem::id() const { - return qHash(this); -} - 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(); - return true; } bool AbstractTreeItem::newChilds(const QList &items) { if(items.isEmpty()) return false; - - QList::const_iterator itemIter = items.constBegin(); - AbstractTreeItem *item; - while(itemIter != items.constEnd()) { - item = *itemIter; - if(childById(item->id()) != 0) { - qWarning() << "AbstractTreeItem::newChilds(): received child that is already attached" << item << item->id(); - return false; - } - itemIter++; - } int nextRow = childCount(); int lastRow = nextRow + items.count() - 1; emit beginAppendChilds(nextRow, lastRow); - itemIter = items.constBegin(); - while(itemIter != items.constEnd()) { - _childItems.append(*itemIter); - itemIter++; - } + _childItems << items; emit endAppendChilds(); return true; } bool AbstractTreeItem::removeChild(int row) { - if(childCount() <= row) + if(row < 0 || childCount() <= row) return false; child(row)->removeAllChilds(); emit beginRemoveChilds(row, row); AbstractTreeItem *treeitem = _childItems.takeAt(row); - treeitem->deleteLater(); + delete treeitem; emit endRemoveChilds(); - return true; -} + checkForDeletion(); -bool AbstractTreeItem::removeChildById(const quint64 &id) { - const int numChilds = childCount(); - - for(int i = 0; i < numChilds; i++) { - if(_childItems[i]->id() == id) - return removeChild(i); - } - - return false; + return true; } void AbstractTreeItem::removeAllChilds() { const int numChilds = childCount(); - + if(numChilds == 0) return; - + AbstractTreeItem *child; QList::iterator childIter; @@ -117,6 +94,7 @@ void AbstractTreeItem::removeAllChilds() { childIter = _childItems.begin(); while(childIter != _childItems.end()) { child = *childIter; + child->setTreeItemFlags(0); // disable self deletion, as this would only fuck up consitency and the child gets deleted anyways child->removeAllChilds(); childIter++; } @@ -126,62 +104,99 @@ void AbstractTreeItem::removeAllChilds() { while(childIter != _childItems.end()) { child = *childIter; childIter = _childItems.erase(childIter); - child->deleteLater(); + delete child; } emit endRemoveChilds(); + + checkForDeletion(); } -AbstractTreeItem *AbstractTreeItem::child(int row) const { - if(childCount() <= row) - return 0; - else - return _childItems[row]; +void AbstractTreeItem::removeChildLater(AbstractTreeItem *child) { + Q_ASSERT(child); + QCoreApplication::postEvent(this, new RemoveChildLaterEvent(child)); } -AbstractTreeItem *AbstractTreeItem::childById(const quint64 &id) const { - const int numChilds = childCount(); - for(int i = 0; i < numChilds; i++) { - if(_childItems[i]->id() == id) - return _childItems[i]; - } - return 0; +void AbstractTreeItem::customEvent(QEvent *event) { + if(event->type() != QEvent::User) + return; + + event->accept(); + + RemoveChildLaterEvent *removeEvent = static_cast(event); + int childRow = _childItems.indexOf(removeEvent->child()); + if(childRow == -1) + return; + + removeChild(childRow); } -int AbstractTreeItem::childCount() const { - return _childItems.count(); +bool AbstractTreeItem::reParent(AbstractTreeItem *newParent) { + // currently we support only re parenting if the child that's about to be + // adopted does not have any children itself. + if(childCount() != 0) { + qDebug() << "AbstractTreeItem::reParent(): cannot reparent" << this << "with children."; + return false; + } + + int oldRow = row(); + if(oldRow == -1) + return false; + + emit parent()->beginRemoveChilds(oldRow, oldRow); + parent()->_childItems.removeAt(oldRow); + emit parent()->endRemoveChilds(); + + AbstractTreeItem *oldParent = parent(); + setParent(newParent); + + bool success = newParent->newChild(this); + if(!success) + qWarning() << "AbstractTreeItem::reParent(): failed to attach to new parent after removing from old parent! this:" << this << "new parent:" << newParent; + + if(oldParent) + oldParent->checkForDeletion(); + + return success; } -int AbstractTreeItem::row() const { - if(!parent()) - return -1; +AbstractTreeItem *AbstractTreeItem::child(int row) const { + if(childCount() <= row) + return 0; else - return parent()->_childItems.indexOf(const_cast(this)); + return _childItems[row]; } -AbstractTreeItem *AbstractTreeItem::parent() const { - return qobject_cast(QObject::parent()); +int AbstractTreeItem::childCount(int column) const { + if(column > 0) + return 0; + else + return _childItems.count(); } -Qt::ItemFlags AbstractTreeItem::flags() const { - return _flags; -} +int AbstractTreeItem::row() const { + if(!parent()) { + qWarning() << "AbstractTreeItem::row():" << this << "has no parent AbstractTreeItem as it's parent! parent is" << QObject::parent(); + return -1; + } -void AbstractTreeItem::setFlags(Qt::ItemFlags flags) { - _flags = flags; + int row_ = parent()->_childItems.indexOf(const_cast(this)); + if(row_ == -1) + qWarning() << "AbstractTreeItem::row():" << this << "is not in the child list of" << QObject::parent(); + return row_; } void AbstractTreeItem::dumpChildList() { - qDebug() << "==== Childlist for Item:" << this << id() << "===="; + qDebug() << "==== Childlist for Item:" << this << "===="; 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); + qDebug() << "Row:" << child->row() << child << child->data(0, Qt::DisplayRole); childIter++; } } - qDebug() << "==== End Of Childlist ===="; + qDebug() << "==== End Of Childlist ===="; } /***************************************** @@ -238,7 +253,7 @@ PropertyMapItem::PropertyMapItem(AbstractTreeItem *parent) PropertyMapItem::~PropertyMapItem() { } - + QVariant PropertyMapItem::data(int column, int role) const { if(column >= columnCount()) return QVariant(); @@ -247,11 +262,12 @@ QVariant PropertyMapItem::data(int column, int role) const { case Qt::ToolTipRole: return toolTip(column); case Qt::DisplayRole: + case TreeModel::SortRole: // fallthrough, since SortRole should default to DisplayRole return property(_propertyOrder[column].toAscii()); default: return QVariant(); } - + } bool PropertyMapItem::setData(int column, const QVariant &value, int role) { @@ -265,7 +281,7 @@ bool PropertyMapItem::setData(int column, const QVariant &value, int role) { int PropertyMapItem::columnCount() const { return _propertyOrder.count(); } - + void PropertyMapItem::appendProperty(const QString &property) { _propertyOrder << property; } @@ -283,7 +299,7 @@ TreeModel::TreeModel(const QList &data, QObject *parent) rootItem = new SimpleTreeItem(data, 0); connectItem(rootItem); - if(QCoreApplication::instance()->arguments().contains("--debugmodel")) { + if(Quassel::isOptionSet("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)), @@ -292,6 +308,8 @@ TreeModel::TreeModel(const QList &data, QObject *parent) this, SLOT(debug_rowsInserted(const QModelIndex &, int, int))); connect(this, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SLOT(debug_rowsRemoved(const QModelIndex &, int, int))); + connect(this, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, SLOT(debug_dataChanged(const QModelIndex &, const QModelIndex &))); } } @@ -302,14 +320,14 @@ TreeModel::~TreeModel() { QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const { if(!hasIndex(row, column, parent)) return QModelIndex(); - + AbstractTreeItem *parentItem; - + if(!parent.isValid()) parentItem = rootItem; else parentItem = static_cast(parent.internalPointer()); - + AbstractTreeItem *childItem = parentItem->child(row); if(childItem) @@ -318,28 +336,12 @@ QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) con return QModelIndex(); } -QModelIndex TreeModel::indexById(quint64 id, const QModelIndex &parent) const { - AbstractTreeItem *parentItem; - - if(!parent.isValid()) - parentItem = rootItem; - else - parentItem = static_cast(parent.internalPointer()); - - AbstractTreeItem *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 @@ -351,14 +353,14 @@ QModelIndex TreeModel::parent(const QModelIndex &index) const { qWarning() << "TreeModel::parent(): has been asked for the rootItems Parent!"; return QModelIndex(); } - + AbstractTreeItem *childItem = static_cast(index.internalPointer()); AbstractTreeItem *parentItem = childItem->parent(); Q_ASSERT(parentItem); if(parentItem == rootItem) return QModelIndex(); - + return createIndex(parentItem->row(), 0, parentItem); } @@ -369,27 +371,23 @@ int TreeModel::rowCount(const QModelIndex &parent) const { else parentItem = static_cast(parent.internalPointer()); - return parentItem->childCount(); + return parentItem->childCount(parent.column()); } int TreeModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) + return rootItem->columnCount(); // 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(); +// AbstractTreeItem *parentItem; +// if(!parent.isValid()) +// parentItem = rootItem; +// else +// parentItem = static_cast(parent.internalPointer()); +// return parentItem->columnCount(); } QVariant TreeModel::data(const QModelIndex &index, int role) const { @@ -409,12 +407,12 @@ bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int rol } Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const { - AbstractTreeItem *item; - if(!index.isValid()) - item = rootItem; - else - item = static_cast(index.internalPointer()); - return item->flags(); + if(!index.isValid()) { + return rootItem->flags() & Qt::ItemIsDropEnabled; + } else { + AbstractTreeItem *item = static_cast(index.internalPointer()); + return item->flags(); + } } QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const { @@ -445,12 +443,12 @@ void TreeModel::itemDataChanged(int column) { void TreeModel::connectItem(AbstractTreeItem *item) { connect(item, SIGNAL(dataChanged(int)), this, SLOT(itemDataChanged(int))); - + connect(item, SIGNAL(beginAppendChilds(int, int)), this, SLOT(beginAppendChilds(int, int))); connect(item, SIGNAL(endAppendChilds()), this, SLOT(endAppendChilds())); - + connect(item, SIGNAL(beginRemoveChilds(int, int)), this, SLOT(beginRemoveChilds(int, int))); connect(item, SIGNAL(endRemoveChilds()), @@ -466,7 +464,7 @@ void TreeModel::beginAppendChilds(int firstRow, int lastRow) { QModelIndex parent = indexByItem(parentItem); Q_ASSERT(!_aboutToRemoveOrInsert); - + _aboutToRemoveOrInsert = true; _childStatus = ChildStatus(parent, rowCount(parent), firstRow, lastRow); beginInsertRows(parent, firstRow, lastRow); @@ -497,29 +495,37 @@ void TreeModel::beginRemoveChilds(int firstRow, int lastRow) { qWarning() << "TreeModel::beginRemoveChilds(): cannot append Childs to unknown parent"; return; } + + for(int i = firstRow; i <= lastRow; i++) { + disconnect(parentItem->child(i), 0, this, 0); + } + + // consitency checks 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"; + qWarning() << "TreeModel::endRemoveChilds(): cannot remove Childs from unknown parent"; return; } + + // concistency checks 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(); } @@ -536,7 +542,7 @@ void TreeModel::debug_rowsAboutToBeRemoved(const QModelIndex &parent, int start, parentItem = static_cast(parent.internalPointer()); if(!parentItem) parentItem = rootItem; - qDebug() << "#" << parent << parentItem << parent.data().toString() << rowCount(parent) << start << end; + qDebug() << "debug_rowsAboutToBeRemoved" << parent << parentItem << parent.data().toString() << rowCount(parent) << start << end; QModelIndex child; AbstractTreeItem *childItem; @@ -544,7 +550,7 @@ void TreeModel::debug_rowsAboutToBeRemoved(const QModelIndex &parent, int start, child = parent.child(i, 0); childItem = parentItem->child(i); Q_ASSERT(childItem); - qDebug() << ">>>" << i << child << childItem->id() << child.data().toString(); + qDebug() << ">>>" << i << child << child.data().toString(); } } @@ -553,7 +559,7 @@ void TreeModel::debug_rowsInserted(const QModelIndex &parent, int start, int end parentItem = static_cast(parent.internalPointer()); if(!parentItem) parentItem = rootItem; - qDebug() << "#" << parent << parentItem << parent.data().toString() << rowCount(parent) << start << end; + qDebug() << "debug_rowsInserted:" << parent << parentItem << parent.data().toString() << rowCount(parent) << start << end; QModelIndex child; AbstractTreeItem *childItem; @@ -561,10 +567,22 @@ void TreeModel::debug_rowsInserted(const QModelIndex &parent, int start, int end child = parent.child(i, 0); childItem = parentItem->child(i); Q_ASSERT(childItem); - qDebug() << "<<<" << i << child << childItem->id() << child.data().toString(); + qDebug() << "<<<" << i << child << child.data().toString(); } } void TreeModel::debug_rowsRemoved(const QModelIndex &parent, int start, int end) { qDebug() << "debug_rowsRemoved" << parent << parent.internalPointer() << parent.data().toString() << rowCount(parent) << start << end; } + +void TreeModel::debug_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { + qDebug() << "debug_dataChanged" << topLeft << bottomRight; + QStringList displayData; + for(int row = topLeft.row(); row <= bottomRight.row(); row++) { + displayData = QStringList(); + for(int column = topLeft.column(); column <= bottomRight.column(); column++) { + displayData << data(topLeft.sibling(row, column), Qt::DisplayRole).toString(); + } + qDebug() << " row:" << row << displayData; + } +}