X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fclient%2Ftreemodel.cpp;h=3e243a42023924d4357bc43b7e47ff0133c89fea;hp=6fc0c25b38a333944e46729caa3e83811e73a009;hb=a700bd999215313b075ced5a1e3ba4ea8917fbbc;hpb=c0e4730a50f812cd3795d47561357ff221094f8c diff --git a/src/client/treemodel.cpp b/src/client/treemodel.cpp index 6fc0c25b..3e243a42 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-2020 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -15,578 +15,609 @@ * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "treemodel.h" -#include +#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) +AbstractTreeItem::AbstractTreeItem(AbstractTreeItem* parent) + : QObject(parent) + , _flags(Qt::ItemIsSelectable | Qt::ItemIsEnabled) +{} + +bool AbstractTreeItem::newChild(AbstractTreeItem* item) { + int newRow = childCount(); + emit beginAppendChilds(newRow, newRow); + _childItems.append(item); + emit endAppendChilds(); + return true; } -AbstractTreeItem::~AbstractTreeItem() { -} +bool AbstractTreeItem::newChilds(const QList& items) +{ + if (items.isEmpty()) + return false; + + int nextRow = childCount(); + int lastRow = nextRow + items.count() - 1; + + emit beginAppendChilds(nextRow, lastRow); + _childItems << items; + emit endAppendChilds(); -quint64 AbstractTreeItem::id() const { - return qHash(this); + return true; } -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::removeChild(int row) +{ + if (row < 0 || childCount() <= row) + return false; + + child(row)->removeAllChilds(); + emit beginRemoveChilds(row, row); + AbstractTreeItem* treeitem = _childItems.takeAt(row); + delete treeitem; + emit endRemoveChilds(); + + checkForDeletion(); + + 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; +void AbstractTreeItem::removeAllChilds() +{ + const int numChilds = childCount(); + + if (numChilds == 0) + return; + + AbstractTreeItem* child; + + QList::iterator childIter; + + childIter = _childItems.begin(); + while (childIter != _childItems.end()) { + child = *childIter; + child->setTreeItemFlags({}); // disable self deletion, as this would only fuck up consitency and the child gets deleted anyways + child->removeAllChilds(); + ++childIter; } - itemIter++; - } - int nextRow = childCount(); - int lastRow = nextRow + items.count() - 1; + emit beginRemoveChilds(0, numChilds - 1); + childIter = _childItems.begin(); + while (childIter != _childItems.end()) { + child = *childIter; + childIter = _childItems.erase(childIter); + delete child; + } + emit endRemoveChilds(); - emit beginAppendChilds(nextRow, lastRow); - itemIter = items.constBegin(); - while(itemIter != items.constEnd()) { - _childItems.append(*itemIter); - itemIter++; - } - emit endAppendChilds(); + checkForDeletion(); +} - return true; +void AbstractTreeItem::removeChildLater(AbstractTreeItem* child) +{ + Q_ASSERT(child); + QCoreApplication::postEvent(this, new RemoveChildLaterEvent(child)); } -bool AbstractTreeItem::removeChild(int row) { - if(childCount() <= row) - return false; +void AbstractTreeItem::customEvent(QEvent* event) +{ + if (event->type() != QEvent::User) + return; + + event->accept(); - child(row)->removeAllChilds(); - emit beginRemoveChilds(row, row); - AbstractTreeItem *treeitem = _childItems.takeAt(row); - treeitem->deleteLater(); - emit endRemoveChilds(); + auto* removeEvent = static_cast(event); + int childRow = _childItems.indexOf(removeEvent->child()); + if (childRow == -1) + return; - return true; -} + // since we are called asynchronously we have to recheck if the item in question still has no childs + if (removeEvent->child()->childCount()) + return; -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; + removeChild(childRow); } -void AbstractTreeItem::removeAllChilds() { - const int numChilds = childCount(); - - if(numChilds == 0) - return; - - AbstractTreeItem *child; +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); - QList::iterator childIter; + 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; - childIter = _childItems.begin(); - while(childIter != _childItems.end()) { - child = *childIter; - child->removeAllChilds(); - childIter++; - } + if (oldParent) + oldParent->checkForDeletion(); - emit beginRemoveChilds(0, numChilds - 1); - childIter = _childItems.begin(); - while(childIter != _childItems.end()) { - child = *childIter; - childIter = _childItems.erase(childIter); - child->deleteLater(); - } - emit endRemoveChilds(); + return success; } -AbstractTreeItem *AbstractTreeItem::child(int row) const { - if(childCount() <= row) - return 0; - else - return _childItems[row]; +AbstractTreeItem* AbstractTreeItem::child(int row) const +{ + if (childCount() <= row) + return nullptr; + else + return _childItems[row]; } -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; +int AbstractTreeItem::childCount(int column) const +{ + if (column > 0) + return 0; + else + return _childItems.count(); } -int AbstractTreeItem::childCount(int column) const { - if(column > 0) - return 0; - else - return _childItems.count(); +int AbstractTreeItem::row() const +{ + if (!parent()) { + qWarning() << "AbstractTreeItem::row():" << this << "has no parent AbstractTreeItem as it's parent! parent is" << QObject::parent(); + return -1; + } + + 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_; } -int AbstractTreeItem::row() const { - if(!parent()) - return -1; - else - return parent()->_childItems.indexOf(const_cast(this)); +void AbstractTreeItem::dumpChildList() +{ + 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->data(0, Qt::DisplayRole); + ++childIter; + } + } + qDebug() << "==== End Of Childlist ===="; } -AbstractTreeItem *AbstractTreeItem::parent() const { - return qobject_cast(QObject::parent()); +/***************************************** + * SimpleTreeItem + *****************************************/ +SimpleTreeItem::SimpleTreeItem(QList data, AbstractTreeItem* parent) + : AbstractTreeItem(parent) + , _itemData(std::move(data)) +{} + +QVariant SimpleTreeItem::data(int column, int role) const +{ + if (column >= columnCount() || role != Qt::DisplayRole) + return QVariant(); + else + return _itemData[column]; } -Qt::ItemFlags AbstractTreeItem::flags() const { - return _flags; +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 + _itemData[column] = value; + + emit dataChanged(column); + return true; } -void AbstractTreeItem::setFlags(Qt::ItemFlags flags) { - _flags = flags; +int SimpleTreeItem::columnCount() const +{ + return _itemData.count(); } -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++; +/***************************************** + * PropertyMapItem + *****************************************/ +PropertyMapItem::PropertyMapItem(AbstractTreeItem* parent) + : AbstractTreeItem(parent) +{} + +QVariant PropertyMapItem::data(int column, int role) const +{ + if (column >= columnCount()) + return QVariant(); + + switch (role) { + case Qt::ToolTipRole: + return toolTip(column); + case Qt::DisplayRole: + case TreeModel::SortRole: // fallthrough, since SortRole should default to DisplayRole + return property(propertyOrder()[column].toLatin1()); + default: + return QVariant(); } - } - qDebug() << "==== End Of Childlist ===="; +} + +bool PropertyMapItem::setData(int column, const QVariant& value, int role) +{ + if (column >= columnCount() || role != Qt::DisplayRole) + return false; + + setProperty(propertyOrder()[column].toLatin1(), value); + emit dataChanged(column); + return true; +} + +int PropertyMapItem::columnCount() const +{ + return propertyOrder().count(); } /***************************************** - * SimpleTreeItem + * TreeModel *****************************************/ -SimpleTreeItem::SimpleTreeItem(const QList &data, AbstractTreeItem *parent) - : AbstractTreeItem(parent), - _itemData(data) +TreeModel::TreeModel(const QList& data, QObject* parent) + : QAbstractItemModel(parent) + , _childStatus(QModelIndex(), 0, 0, 0) + , _aboutToRemoveOrInsert(false) +{ + rootItem = new SimpleTreeItem(data, nullptr); + connectItem(rootItem); + + if (Quassel::isOptionSet("debugmodel")) { + connect(this, &QAbstractItemModel::rowsAboutToBeInserted, this, &TreeModel::debug_rowsAboutToBeInserted); + connect(this, &QAbstractItemModel::rowsAboutToBeRemoved, this, &TreeModel::debug_rowsAboutToBeRemoved); + connect(this, &QAbstractItemModel::rowsInserted, this, &TreeModel::debug_rowsInserted); + connect(this, &QAbstractItemModel::rowsRemoved, this, &TreeModel::debug_rowsRemoved); + connect(this, &QAbstractItemModel::dataChanged, this, &TreeModel::debug_dataChanged); + } +} + +TreeModel::~TreeModel() +{ + delete rootItem; +} + +AbstractTreeItem* TreeModel::root() const +{ + return rootItem; +} + +QModelIndex TreeModel::index(int row, int column, const QModelIndex& parent) const { + if (row < 0 || row >= rowCount(parent) || column < 0 || column >= columnCount(parent)) + return {}; + + AbstractTreeItem* parentItem; + + if (!parent.isValid()) + parentItem = rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + AbstractTreeItem* childItem = parentItem->child(row); + + if (childItem) + return createIndex(row, column, childItem); + else + return {}; } -SimpleTreeItem::~SimpleTreeItem() { +QModelIndex TreeModel::indexByItem(AbstractTreeItem* item) const +{ + if (item == nullptr) { + qWarning() << "TreeModel::indexByItem(AbstractTreeItem *item) received NULL-Pointer"; + return {}; + } + + if (item == rootItem) + return {}; + else + return createIndex(item->row(), 0, item); } -QVariant SimpleTreeItem::data(int column, int role) const { - if(column >= columnCount() || role != Qt::DisplayRole) - return QVariant(); - else - return _itemData[column]; +QModelIndex TreeModel::parent(const QModelIndex& index) const +{ + if (!index.isValid()) { + // ModelTest does this + // qWarning() << "TreeModel::parent(): has been asked for the rootItems Parent!"; + return {}; + } + + auto* childItem = static_cast(index.internalPointer()); + AbstractTreeItem* parentItem = childItem->parent(); + + Q_ASSERT(parentItem); + if (parentItem == rootItem) + return {}; + + return createIndex(parentItem->row(), 0, parentItem); } -bool SimpleTreeItem::setData(int column, const QVariant &value, int role) { - if(column > columnCount() || role != Qt::DisplayRole) - return false; +int TreeModel::rowCount(const QModelIndex& parent) const +{ + AbstractTreeItem* parentItem; + if (!parent.isValid()) + parentItem = rootItem; + else + parentItem = static_cast(parent.internalPointer()); - if(column == columnCount()) - _itemData.append(value); - else - _itemData[column] = value; + 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 + + // 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 +{ + if (!index.isValid()) + return QVariant(); - emit dataChanged(column); - return true; + auto* item = static_cast(index.internalPointer()); + return item->data(index.column(), role); } -int SimpleTreeItem::columnCount() const { - return _itemData.count(); +bool TreeModel::setData(const QModelIndex& index, const QVariant& value, int role) +{ + if (!index.isValid()) + return false; + + auto* item = static_cast(index.internalPointer()); + return item->setData(index.column(), value, role); } -/***************************************** - * PropertyMapItem - *****************************************/ -PropertyMapItem::PropertyMapItem(const QStringList &propertyOrder, AbstractTreeItem *parent) - : AbstractTreeItem(parent), - _propertyOrder(propertyOrder) +Qt::ItemFlags TreeModel::flags(const QModelIndex& index) const { + if (!index.isValid()) { + return rootItem->flags() & Qt::ItemIsDropEnabled; + } + else { + auto* item = static_cast(index.internalPointer()); + return item->flags(); + } } -PropertyMapItem::PropertyMapItem(AbstractTreeItem *parent) - : AbstractTreeItem(parent), - _propertyOrder(QStringList()) +QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return rootItem->data(section, role); + else + return QVariant(); } +void TreeModel::itemDataChanged(int column) +{ + auto* item = qobject_cast(sender()); + QModelIndex leftIndex, rightIndex; + + if (item == rootItem) + return; -PropertyMapItem::~PropertyMapItem() { + if (column == -1) { + leftIndex = createIndex(item->row(), 0, item); + rightIndex = createIndex(item->row(), item->columnCount() - 1, item); + } + else { + leftIndex = createIndex(item->row(), column, item); + rightIndex = leftIndex; + } + + emit dataChanged(leftIndex, rightIndex); } - -QVariant PropertyMapItem::data(int column, int role) const { - if(column >= columnCount()) - return QVariant(); - switch(role) { - 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(); - } - +void TreeModel::connectItem(AbstractTreeItem* item) +{ + connect(item, &AbstractTreeItem::dataChanged, this, &TreeModel::itemDataChanged); + + connect(item, &AbstractTreeItem::beginAppendChilds, this, &TreeModel::beginAppendChilds); + connect(item, &AbstractTreeItem::endAppendChilds, this, &TreeModel::endAppendChilds); + + connect(item, &AbstractTreeItem::beginRemoveChilds, this, &TreeModel::beginRemoveChilds); + connect(item, &AbstractTreeItem::endRemoveChilds, this, &TreeModel::endRemoveChilds); } -bool PropertyMapItem::setData(int column, const QVariant &value, int role) { - if(column >= columnCount() || role != Qt::DisplayRole) - return false; +void TreeModel::beginAppendChilds(int firstRow, int lastRow) +{ + auto* parentItem = qobject_cast(sender()); + if (!parentItem) { + qWarning() << "TreeModel::beginAppendChilds(): cannot append Children to unknown parent"; + return; + } + + QModelIndex parent = indexByItem(parentItem); + Q_ASSERT(!_aboutToRemoveOrInsert); - emit dataChanged(column); - return setProperty(_propertyOrder[column].toAscii(), value); + _aboutToRemoveOrInsert = true; + _childStatus = ChildStatus(parent, rowCount(parent), firstRow, lastRow); + beginInsertRows(parent, firstRow, lastRow); } -int PropertyMapItem::columnCount() const { - return _propertyOrder.count(); +void TreeModel::endAppendChilds() +{ + auto* parentItem = qobject_cast(sender()); + if (!parentItem) { + qWarning() << "TreeModel::endAppendChilds(): cannot append Children to unknown parent"; + return; + } + Q_ASSERT(_aboutToRemoveOrInsert); + ChildStatus cs = _childStatus; +#ifndef QT_NO_DEBUG + QModelIndex parent = indexByItem(parentItem); + Q_ASSERT(cs.parent == parent); + Q_ASSERT(rowCount(parent) == cs.childCount + cs.end - cs.start + 1); +#endif + _aboutToRemoveOrInsert = false; + for (int i = cs.start; i <= cs.end; i++) { + connectItem(parentItem->child(i)); + } + endInsertRows(); } - -void PropertyMapItem::appendProperty(const QString &property) { - _propertyOrder << property; + +void TreeModel::beginRemoveChilds(int firstRow, int lastRow) +{ + auto* parentItem = qobject_cast(sender()); + if (!parentItem) { + qWarning() << "TreeModel::beginRemoveChilds(): cannot append Children to unknown parent"; + return; + } + + for (int i = firstRow; i <= lastRow; i++) { + disconnect(parentItem->child(i), nullptr, this, nullptr); + } + + // 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() +{ + auto* parentItem = qobject_cast(sender()); + if (!parentItem) { + qWarning() << "TreeModel::endRemoveChilds(): cannot remove Children from unknown parent"; + return; + } + // concistency checks + Q_ASSERT(_aboutToRemoveOrInsert); +#ifndef QT_NO_DEBUG + ChildStatus cs = _childStatus; + QModelIndex parent = indexByItem(parentItem); + Q_ASSERT(cs.parent == parent); + Q_ASSERT(rowCount(parent) == cs.childCount - cs.end + cs.start - 1); +#endif + _aboutToRemoveOrInsert = false; -/***************************************** - * TreeModel - *****************************************/ -TreeModel::TreeModel(const QList &data, QObject *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))); - connect(this, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), - this, SLOT(debug_dataChanged(const QModelIndex &, const QModelIndex &))); - } -} - -TreeModel::~TreeModel() { - delete rootItem; -} - -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) - return createIndex(row, column, childItem); - else - 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 - return createIndex(item->row(), 0, item); -} - -QModelIndex TreeModel::parent(const QModelIndex &index) const { - if(!index.isValid()) { - 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); -} - -int TreeModel::rowCount(const QModelIndex &parent) const { - AbstractTreeItem *parentItem; - if(!parent.isValid()) - parentItem = rootItem; - else + endRemoveRows(); +} + +void TreeModel::clear() +{ + rootItem->removeAllChilds(); +} + +void TreeModel::debug_rowsAboutToBeInserted(const QModelIndex& parent, int start, int end) +{ + qDebug() << "debug_rowsAboutToBeInserted" << parent << parent.internalPointer() << parent.data().toString() << rowCount(parent) << start + << end; +} + +void TreeModel::debug_rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) +{ + AbstractTreeItem* parentItem; parentItem = static_cast(parent.internalPointer()); + if (!parentItem) + parentItem = rootItem; + qDebug() << "debug_rowsAboutToBeRemoved" << parent << parentItem << parent.data().toString() << rowCount(parent) << start << end; + + // Make sure model is valid first + if (!parent.model()) { + qDebug() << "Parent model is not valid!" << end; + return; + } - return parentItem->childCount(parent.column()); + QModelIndex child; + for (int i = end; i >= start; i--) { + child = parent.model()->index(i, 0, parent); + Q_ASSERT(parentItem->child(i)); + qDebug() << ">>>" << i << child << child.data().toString(); + } } -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 - -// AbstractTreeItem *parentItem; -// if(!parent.isValid()) -// parentItem = rootItem; -// else -// parentItem = static_cast(parent.internalPointer()); -// return parentItem->columnCount(); +void TreeModel::debug_rowsInserted(const QModelIndex& parent, int start, int end) +{ + AbstractTreeItem* parentItem; + parentItem = static_cast(parent.internalPointer()); + if (!parentItem) + parentItem = rootItem; + qDebug() << "debug_rowsInserted:" << parent << parentItem << parent.data().toString() << rowCount(parent) << start << end; + + // Make sure model is valid first + if (!parent.model()) { + qDebug() << "Parent model is not valid!" << end; + return; + } + + QModelIndex child; + for (int i = start; i <= end; i++) { + child = parent.model()->index(i, 0, parent); + Q_ASSERT(parentItem->child(i)); + qDebug() << "<<<" << i << child << child.data().toString(); + } } -QVariant TreeModel::data(const QModelIndex &index, int role) const { - if(!index.isValid()) - return QVariant(); - - 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 { - 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 { - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return rootItem->data(section, role); - else - return QVariant(); -} - -void TreeModel::itemDataChanged(int column) { - AbstractTreeItem *item = qobject_cast(sender()); - QModelIndex leftIndex, rightIndex; - - if(item == rootItem) - return; - - if(column == -1) { - leftIndex = createIndex(item->row(), 0, item); - rightIndex = createIndex(item->row(), item->columnCount() - 1, item); - } else { - leftIndex = createIndex(item->row(), column, item); - rightIndex = leftIndex; - } - - emit dataChanged(leftIndex, rightIndex); -} - -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()), - this, SLOT(endRemoveChilds())); -} - -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) { - AbstractTreeItem *parentItem = qobject_cast(sender()); - if(!parentItem) { - 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 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(); -} - -void TreeModel::clear() { - rootItem->removeAllChilds(); -} - -void TreeModel::debug_rowsAboutToBeInserted(const QModelIndex &parent, int start, int end) { - qDebug() << "debug_rowsAboutToBeInserted" << parent << parent.internalPointer() << parent.data().toString() << rowCount(parent) << start << end; -} - -void TreeModel::debug_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - AbstractTreeItem *parentItem; - parentItem = static_cast(parent.internalPointer()); - if(!parentItem) - parentItem = rootItem; - qDebug() << "debug_rowsAboutToBeRemoved" << 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(); - } -} - -void TreeModel::debug_rowsInserted(const QModelIndex &parent, int start, int end) { - AbstractTreeItem *parentItem; - parentItem = static_cast(parent.internalPointer()); - if(!parentItem) - parentItem = rootItem; - qDebug() << "debug_rowsInserted:" << 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(); - } -} - -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(); +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; } - qDebug() << " row:" << row << displayData; - } }