X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fuisupport%2Fflatproxymodel.cpp;h=d177b6e5daca5e7b227c11b60d046aa7c3ee2bb9;hp=ef19074277941be4139ed0218b33fb045060588f;hb=c1cf157116de7fc3da96203aa6f03c38c7ebb650;hpb=920643004f172d255dd2420d1b03adea3b3a07b2 diff --git a/src/uisupport/flatproxymodel.cpp b/src/uisupport/flatproxymodel.cpp index ef190742..d177b6e5 100644 --- a/src/uisupport/flatproxymodel.cpp +++ b/src/uisupport/flatproxymodel.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-08 by the Quassel Project * + * Copyright (C) 2005-2018 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -15,653 +15,681 @@ * 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 "flatproxymodel.h" -#include #include +#include -FlatProxyModel::FlatProxyModel(QObject *parent) - : QAbstractProxyModel(parent), - _rootSourceItem(0) +FlatProxyModel::FlatProxyModel(QObject* parent) + : QAbstractProxyModel(parent) +{} + +QModelIndex FlatProxyModel::mapFromSource(const QModelIndex& sourceIndex) const { + if (!sourceIndex.isValid()) + return {}; + + SourceItem* sourceItem = sourceToInternal(sourceIndex); + Q_ASSERT(sourceItem); + return createIndex(sourceItem->pos(), sourceIndex.column(), sourceItem); } -QModelIndex FlatProxyModel::mapFromSource(const QModelIndex &sourceIndex) const { - if(!sourceIndex.isValid()) - return QModelIndex(); +QModelIndex FlatProxyModel::mapToSource(const QModelIndex& proxyIndex) const +{ + if (!proxyIndex.isValid()) + return {}; + + Q_ASSERT(proxyIndex.model() == this); + Q_ASSERT(_rootSourceItem); + + int row = proxyIndex.row(); + QModelIndex sourceParent; + SourceItem* sourceItem = _rootSourceItem->findChild(row); + while (sourceItem) { + if (sourceItem->pos() == row) { + return sourceModel()->index(sourceItem->sourceRow(), proxyIndex.column(), sourceParent); + } + else { + sourceParent = sourceModel()->index(sourceItem->sourceRow(), 0, sourceParent); + sourceItem = sourceItem->findChild(row); + } + } - SourceItem *sourceItem = sourceToInternal(sourceIndex); - Q_ASSERT(sourceItem); - return createIndex(sourceItem->pos(), sourceIndex.column(), sourceItem); + qWarning() << "FlatProxyModel::mapToSource(): couldn't find source index for" << proxyIndex; + Q_ASSERT(false); + return {}; // make compilers happy :) } -QModelIndex FlatProxyModel::mapToSource(const QModelIndex &proxyIndex) const { - if(!proxyIndex.isValid()) - return QModelIndex(); +bool FlatProxyModel::_RangeRect::operator<(const FlatProxyModel::_RangeRect& other) const +{ + if (left != other.left) + return left < other.left; - Q_ASSERT(proxyIndex.model() == this); - Q_ASSERT(_rootSourceItem); + if (right != other.right) + return right < other.right; - int row = proxyIndex.row(); - QModelIndex sourceParent; - SourceItem *sourceItem = _rootSourceItem->findChild(row); - while(sourceItem) { - if(sourceItem->pos() == row) { - return sourceModel()->index(sourceItem->sourceRow(), proxyIndex.column(), sourceParent); - } else { - sourceParent = sourceModel()->index(sourceItem->sourceRow(), 0, sourceParent); - sourceItem = sourceItem->findChild(row); - } - } + if (top != other.top) + return top < other.top; - qWarning() << "FlatProxyModel::mapToSource(): couldn't find source index for" << proxyIndex; - Q_ASSERT(false); - return QModelIndex(); // make compilers happy :) + // top == other.top + return bottom < other.bottom; } -bool FlatProxyModel::_RangeRect::operator<(const FlatProxyModel::_RangeRect &other) const { - if(left != other.left) - return left < other.left; +QItemSelection FlatProxyModel::mapSelectionFromSource(const QItemSelection& sourceSelection) const +{ + QList<_RangeRect> newRanges; + QHash itemLookup; + // basics steps of the loop: + // 1. convert each source ItemSelectionRange to a mapped Range (internal one for easier post processing) + // 2. insert it into the list of previously mapped Ranges sorted by top location + for (int i = 0; i < sourceSelection.count(); i++) { + const QItemSelectionRange& currentRange = sourceSelection[i]; + QModelIndex currentParent = currentRange.topLeft().parent(); + Q_ASSERT(currentParent == currentRange.bottomRight().parent()); + + SourceItem* parentItem = nullptr; + if (!itemLookup.contains(currentParent)) { + parentItem = sourceToInternal(currentParent); + itemLookup[currentParent] = parentItem; + } + else { + parentItem = itemLookup[currentParent]; + } + + _RangeRect newRange = {currentRange.topLeft().column(), + currentRange.bottomRight().column(), + currentRange.topLeft().row(), + currentRange.bottomRight().row(), + parentItem->child(currentRange.topLeft().row()), + parentItem->child(currentRange.bottomRight().row())}; + + if (newRanges.isEmpty()) { + newRanges << newRange; + continue; + } + + _RangeRect& first = newRanges[0]; + if (newRange < first) { + newRanges.prepend(newRange); + continue; + } + + bool inserted = false; + for (int j = 0; j < newRanges.count() - 1; j++) { + _RangeRect& a = newRanges[j]; + _RangeRect& b = newRanges[j + 1]; + + if (a < newRange && newRange < b) { + newRanges[j + 1] = newRange; + inserted = true; + break; + } + } + if (inserted) + continue; + + _RangeRect& last = newRanges[newRanges.count() - 1]; + if (last < newRange) { + newRanges.append(newRange); + continue; + } + + Q_ASSERT(false); + } - if(right != other.right) - return right < other.right; + // we've got a sorted list of ranges now. so we can easily check if there is a possibility to merge + for (int i = newRanges.count() - 1; i > 0; i--) { + _RangeRect& a = newRanges[i - 1]; + _RangeRect& b = newRanges[i]; + if (a.left != b.left || a.right != b.right) + continue; + + if (a.bottom < b.top - 1) { + continue; + } + + // all merge checks passed! + if (b.bottom > a.bottom) { + a.bottom = b.bottom; + a.bottomItem = b.bottomItem; + } // otherwise b is totally enclosed in a -> nothing to do but drop b. + newRanges.removeAt(i); + } - if(top != other.top) - return top < other.top; + QItemSelection proxySelection; + for (int i = 0; i < newRanges.count(); i++) { + _RangeRect& r = newRanges[i]; + proxySelection << QItemSelectionRange(createIndex(r.top, r.left, r.topItem), createIndex(r.bottom, r.right, r.bottomItem)); + } + return proxySelection; +} - // top == other.top - return bottom < other.bottom; +QItemSelection FlatProxyModel::mapSelectionToSource(const QItemSelection& proxySelection) const +{ + QItemSelection sourceSelection; + + for (int i = 0; i < proxySelection.count(); i++) { + const QItemSelectionRange& range = proxySelection[i]; + + SourceItem* topLeftItem = nullptr; + SourceItem* bottomRightItem = nullptr; + auto* currentItem = static_cast(range.topLeft().internalPointer()); + int row = range.topLeft().row(); + int left = range.topLeft().column(); + int right = range.bottomRight().column(); + while (currentItem && row <= range.bottomRight().row()) { + Q_ASSERT(currentItem->pos() == row); + if (!topLeftItem) + topLeftItem = currentItem; + + if (currentItem->parent() == topLeftItem->parent()) { + bottomRightItem = currentItem; + } + else { + Q_ASSERT(topLeftItem && bottomRightItem); + sourceSelection << QItemSelectionRange(mapToSource(createIndex(topLeftItem->pos(), left, topLeftItem)), + mapToSource(createIndex(bottomRightItem->pos(), right, bottomRightItem))); + topLeftItem = nullptr; + bottomRightItem = nullptr; + } + + // update loop vars + currentItem = currentItem->next(); + row++; + } + + if (topLeftItem && bottomRightItem) { // there should be one range left. + sourceSelection << QItemSelectionRange(mapToSource(createIndex(topLeftItem->pos(), left, topLeftItem)), + mapToSource(createIndex(bottomRightItem->pos(), right, bottomRightItem))); + } + } + + return sourceSelection; } -QItemSelection FlatProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const { - QList<_RangeRect> newRanges; - QHash itemLookup; - // basics steps of the loop: - // 1. convert each source ItemSelectionRange to a mapped Range (internal one for easier post processing) - // 2. insert it into the list of previously mapped Ranges sorted by top location - for(int i = 0; i < sourceSelection.count(); i++) { - const QItemSelectionRange ¤tRange = sourceSelection[i]; - QModelIndex currentParent = currentRange.topLeft().parent(); - Q_ASSERT(currentParent == currentRange.bottomRight().parent()); +void FlatProxyModel::setSourceModel(QAbstractItemModel* sourceModel) +{ + if (QAbstractProxyModel::sourceModel()) { + disconnect(QAbstractProxyModel::sourceModel(), nullptr, this, nullptr); + } + + QAbstractProxyModel::setSourceModel(sourceModel); + + emit layoutAboutToBeChanged(); + removeSubTree(QModelIndex(), false /* don't emit removeRows() */); + insertSubTree(QModelIndex(), false /* don't emit insertRows() */); + emit layoutChanged(); - SourceItem *parentItem = 0; - if(!itemLookup.contains(currentParent)) { - parentItem = sourceToInternal(currentParent); - itemLookup[currentParent] = parentItem; - } else { - parentItem = itemLookup[currentParent]; + if (sourceModel) { + connect(sourceModel, &QAbstractItemModel::columnsAboutToBeInserted, this, &FlatProxyModel::on_columnsAboutToBeInserted); + connect(sourceModel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &FlatProxyModel::on_columnsAboutToBeRemoved); + connect(sourceModel, &QAbstractItemModel::columnsInserted, this, &FlatProxyModel::on_columnsInserted); + connect(sourceModel, &QAbstractItemModel::columnsRemoved, this, &FlatProxyModel::on_columnsRemoved); + + connect(sourceModel, &QAbstractItemModel::dataChanged, this, &FlatProxyModel::on_dataChanged); + // on_headerDataChanged(Qt::Orientation orientation, int first, int last) + + connect(sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, &FlatProxyModel::on_layoutAboutToBeChanged); + connect(sourceModel, &QAbstractItemModel::layoutChanged, this, &FlatProxyModel::on_layoutChanged); + + connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &FlatProxyModel::on_modelAboutToBeReset); + // void on_modelReset() + + connect(sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &FlatProxyModel::on_rowsAboutToBeInserted); + connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &FlatProxyModel::on_rowsAboutToBeRemoved); + connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &FlatProxyModel::on_rowsInserted); + connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, &FlatProxyModel::on_rowsRemoved); } +} - _RangeRect newRange = { currentRange.topLeft().column(), currentRange.bottomRight().column(), - currentRange.topLeft().row(), currentRange.bottomRight().row(), - parentItem->child(currentRange.topLeft().row()), parentItem->child(currentRange.bottomRight().row()) }; +void FlatProxyModel::insertSubTree(const QModelIndex& source_idx, bool emitInsert) +{ + SourceItem* newSubTree = new SourceItem(source_idx.row(), sourceToInternal(sourceModel()->parent(source_idx))); - if(newRanges.isEmpty()) { - newRanges << newRange; - continue; + if (newSubTree->parent()) { + newSubTree->setPos(newSubTree->parent()->pos() + source_idx.row() + 1); } + SourceItem* lastItem = insertSubTreeHelper(newSubTree, newSubTree, source_idx); + + Q_ASSERT(lastItem); + Q_ASSERT(lastItem->next() == nullptr); + + if (emitInsert) + beginInsertRows(QModelIndex(), newSubTree->pos(), lastItem->pos()); + + if (newSubTree->parent()) { + if (newSubTree->parent()->childCount() > source_idx.row()) { + SourceItem* next = newSubTree->parent()->child(source_idx.row()); + lastItem->setNext(next); + int nextPos = lastItem->pos() + 1; + while (next) { + next->setPos(nextPos); + next = next->next(); + nextPos++; + } + } + if (source_idx.row() > 0) { + SourceItem* previous = newSubTree->parent()->child(source_idx.row() - 1); + while (previous->childCount() > 0) { + previous = previous->child(previous->childCount() - 1); + } + previous->setNext(newSubTree); + } + else { + newSubTree->parent()->setNext(newSubTree); + } + } + else { + _rootSourceItem = newSubTree; + } + + if (emitInsert) + endInsertRows(); +} - _RangeRect &first = newRanges[0]; - if(newRange < first) { - newRanges.prepend(newRange); - continue; +FlatProxyModel::SourceItem* FlatProxyModel::insertSubTreeHelper(SourceItem* parentItem, SourceItem* lastItem_, const QModelIndex& source_idx) +{ + SourceItem* lastItem = lastItem_; + SourceItem* newItem = nullptr; + for (int row = 0; row < sourceModel()->rowCount(source_idx); row++) { + newItem = new SourceItem(row, parentItem); + newItem->setPos(lastItem->pos() + 1); + lastItem->setNext(newItem); + lastItem = insertSubTreeHelper(newItem, newItem, sourceModel()->index(row, 0, source_idx)); } + return lastItem; +} - bool inserted = false; - for(int j = 0; j < newRanges.count() - 1; j++) { - _RangeRect &a = newRanges[j]; - _RangeRect &b = newRanges[j + 1]; +void FlatProxyModel::removeSubTree(const QModelIndex& source_idx, bool emitRemove) +{ + SourceItem* sourceItem = sourceToInternal(source_idx); + if (!sourceItem) + return; + + SourceItem* prevItem = sourceItem->parent(); + if (sourceItem->sourceRow() > 0) { + prevItem = prevItem->child(sourceItem->sourceRow() - 1); + while (prevItem->childCount() > 0) { + prevItem = prevItem->child(prevItem->childCount() - 1); + } + } - if(a < newRange && newRange < b) { - newRanges[j + 1] = newRange; - inserted = true; - break; - } + SourceItem* lastItem = sourceItem; + while (lastItem->childCount() > 0) { + lastItem = lastItem->child(lastItem->childCount() - 1); } - if(inserted) - continue; - _RangeRect &last = newRanges[newRanges.count() - 1]; - if(last < newRange) { - newRanges.append(newRange); - continue; + if (emitRemove) + beginRemoveRows(QModelIndex(), sourceItem->pos(), lastItem->pos()); + + int nextPos = 0; + if (prevItem) { + prevItem->setNext(lastItem->next()); + nextPos = prevItem->pos() + 1; } - - Q_ASSERT(false); - } - - // we've got a sorted list of ranges now. so we can easily check if there is a possibility to merge - for(int i = newRanges.count() - 1; i > 0; i--) { - _RangeRect &a = newRanges[i - 1]; - _RangeRect &b = newRanges[i]; - if(a.left != b.left || a.right != b.right) - continue; - - if(a.bottom < b.top - 1) { - continue; - } - - // all merge checks passed! - if(b.bottom > a.bottom) { - a.bottom = b.bottom; - a.bottomItem = b.bottomItem; - } // otherwise b is totally enclosed in a -> nothing to do but drop b. - newRanges.removeAt(i); - } - - QItemSelection proxySelection; - for(int i = 0; i < newRanges.count(); i++) { - _RangeRect &r = newRanges[i]; - proxySelection << QItemSelectionRange(createIndex(r.top, r.left, r.topItem), createIndex(r.bottom, r.right, r.bottomItem)); - } - return proxySelection; -} - -QItemSelection FlatProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const { - QItemSelection sourceSelection; - - for(int i = 0; i < proxySelection.count(); i++) { - const QItemSelectionRange &range = proxySelection[i]; - - SourceItem *topLeftItem = 0; - SourceItem *bottomRightItem = 0; - SourceItem *currentItem = static_cast(range.topLeft().internalPointer()); - int row = range.topLeft().row(); - int left = range.topLeft().column(); - int right = range.bottomRight().column(); - while(currentItem && row <= range.bottomRight().row()) { - Q_ASSERT(currentItem->pos() == row); - if(!topLeftItem) - topLeftItem = currentItem; - - if(currentItem->parent() == topLeftItem->parent()) { - bottomRightItem = currentItem; - } else { - Q_ASSERT(topLeftItem && bottomRightItem); - sourceSelection << QItemSelectionRange(mapToSource(createIndex(topLeftItem->pos(), left, topLeftItem)), mapToSource(createIndex(bottomRightItem->pos(), right, bottomRightItem))); - topLeftItem = 0; - bottomRightItem = 0; - } - - // update loop vars - currentItem = currentItem->next(); - row++; - } - - Q_ASSERT(topLeftItem && bottomRightItem); // there should be one range left. - sourceSelection << QItemSelectionRange(mapToSource(createIndex(topLeftItem->pos(), left, topLeftItem)), mapToSource(createIndex(bottomRightItem->pos(), right, bottomRightItem))); - } - - return sourceSelection; -} - -void FlatProxyModel::setSourceModel(QAbstractItemModel *sourceModel) { - if(QAbstractProxyModel::sourceModel()) { - disconnect(QAbstractProxyModel::sourceModel(), 0, this, 0); - } - - QAbstractProxyModel::setSourceModel(sourceModel); - - emit layoutAboutToBeChanged(); - removeSubTree(QModelIndex(), false /* don't emit removeRows() */); - insertSubTree(QModelIndex(), false /* don't emit insertRows() */); - emit layoutChanged(); - - if(sourceModel) { - connect(sourceModel, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)), - this, SLOT(on_columnsAboutToBeInserted(const QModelIndex &, int, int))); - connect(sourceModel, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)), - this, SLOT(on_columnsAboutToBeRemoved(const QModelIndex &, int, int))); - connect(sourceModel, SIGNAL(columnsInserted(const QModelIndex &, int, int)), - this, SLOT(on_columnsInserted(const QModelIndex &, int, int))); - connect(sourceModel, SIGNAL(columnsRemoved(const QModelIndex &, int, int)), - this, SLOT(on_columnsRemoved(const QModelIndex &, int, int))); - - connect(sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), - this, SLOT(on_dataChanged(const QModelIndex &, const QModelIndex &))); - // on_headerDataChanged(Qt::Orientation orientation, int first, int last) - - connect(sourceModel, SIGNAL(layoutAboutToBeChanged()), - this, SLOT(on_layoutAboutToBeChanged())); - connect(sourceModel, SIGNAL(layoutChanged()), - this, SLOT(on_layoutChanged())); - - connect(sourceModel, SIGNAL(modelAboutToBeReset()), - this, SLOT(on_modelAboutToBeReset())); - // void on_modelReset() - - connect(sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), - this, SLOT(on_rowsAboutToBeInserted(const QModelIndex &, int, int))); - connect(sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), - this, SLOT(on_rowsAboutToBeRemoved(const QModelIndex &, int, int))); - connect(sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), - this, SLOT(on_rowsInserted(const QModelIndex &, int, int))); - connect(sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), - this, SLOT(on_rowsRemoved(const QModelIndex &, int, int))); - } - -} - -void FlatProxyModel::insertSubTree(const QModelIndex &source_idx, bool emitInsert) { - SourceItem *newSubTree = new SourceItem(source_idx.row(), sourceToInternal(sourceModel()->parent(source_idx))); - - if(newSubTree->parent()) { - newSubTree->setPos(newSubTree->parent()->pos() + source_idx.row() + 1); - } - SourceItem *lastItem = insertSubTreeHelper(newSubTree, newSubTree, source_idx); - - Q_ASSERT(lastItem); - Q_ASSERT(lastItem->next() == 0); - - if(emitInsert) - beginInsertRows(QModelIndex(), newSubTree->pos(), lastItem->pos()); - - if(newSubTree->parent()) { - if(newSubTree->parent()->childCount() > source_idx.row()) { - SourceItem *next = newSubTree->parent()->child(source_idx.row()); - lastItem->setNext(next); - int nextPos = lastItem->pos() + 1; - while(next) { - next->setPos(nextPos); - next = next->next(); + + SourceItem* nextItem = lastItem->next(); + while (nextItem) { + nextItem->setPos(nextPos); nextPos++; - } - } - if(source_idx.row() > 0) { - SourceItem *previous = newSubTree->parent()->child(source_idx.row() - 1); - while(previous->childCount() > 0) { - previous = previous->child(previous->childCount() - 1); - } - previous->setNext(newSubTree); - } else { - newSubTree->parent()->setNext(newSubTree); - } - } else { - _rootSourceItem = newSubTree; - } - - if(emitInsert) - endInsertRows(); -} + nextItem = nextItem->next(); + } -FlatProxyModel::SourceItem *FlatProxyModel::insertSubTreeHelper(SourceItem *parentItem, SourceItem *lastItem_, const QModelIndex &source_idx) { - SourceItem *lastItem = lastItem_; - SourceItem *newItem = 0; - for(int row = 0; row < sourceModel()->rowCount(source_idx); row++) { - newItem = new SourceItem(row, parentItem); - newItem->setPos(lastItem->pos() + 1); - lastItem->setNext(newItem); - lastItem = insertSubTreeHelper(newItem, newItem, sourceModel()->index(row, 0, source_idx)); - } - return lastItem; -} - -void FlatProxyModel::removeSubTree(const QModelIndex &source_idx, bool emitRemove) { - SourceItem *sourceItem = sourceToInternal(source_idx); - if(!sourceItem) - return; - - SourceItem *prevItem = sourceItem->parent(); - if(sourceItem->sourceRow() > 0) { - prevItem = prevItem->child(sourceItem->sourceRow() - 1); - while(prevItem->childCount() > 0) { - prevItem = prevItem->child(prevItem->childCount() - 1); - } - } - - SourceItem *lastItem = sourceItem; - while(lastItem->childCount() > 0) { - lastItem = lastItem->child(lastItem->childCount() - 1); - } - - if(emitRemove) - beginRemoveRows(QModelIndex(), sourceItem->pos(), lastItem->pos()); - - int nextPos = 0; - if(prevItem) { - prevItem->setNext(lastItem->next()); - nextPos = prevItem->pos() + 1; - } - - SourceItem *nextItem = lastItem->next(); - while(nextItem) { - nextItem->setPos(nextPos); - nextPos++; - nextItem = nextItem->next(); - } - - sourceItem->parent()->removeChild(sourceItem); - delete sourceItem; - - if(emitRemove) - endRemoveRows(); + sourceItem->parent()->removeChild(sourceItem); + delete sourceItem; + + if (emitRemove) + endRemoveRows(); } -QModelIndex FlatProxyModel::index(int row, int column, const QModelIndex &parent) const { - if(parent.isValid()) { - qWarning() << "FlatProxyModel::index() called with valid parent:" << parent; - return QModelIndex(); - } +QModelIndex FlatProxyModel::index(int row, int column, const QModelIndex& parent) const +{ + if (parent.isValid()) { + qWarning() << "FlatProxyModel::index() called with valid parent:" << parent; + return {}; + } - if(!_rootSourceItem) { - qWarning() << "FlatProxyModel::index() while model has no root Item"; - return QModelIndex(); - } + if (!_rootSourceItem) { + qWarning() << "FlatProxyModel::index() while model has no root Item"; + return {}; + } - SourceItem *item = _rootSourceItem; - while(item->pos() != row) { - item = item->findChild(row); - if(!item) { - qWarning() << "FlatProxyModel::index() no such row:" << row; - return QModelIndex(); + SourceItem* item = _rootSourceItem; + while (item->pos() != row) { + item = item->findChild(row); + if (!item) { + qWarning() << "FlatProxyModel::index() no such row:" << row; + return {}; + } } - } - Q_ASSERT(item->pos() == row); - return createIndex(row, column, item); + Q_ASSERT(item->pos() == row); + return createIndex(row, column, item); } -QModelIndex FlatProxyModel::parent(const QModelIndex &index) const { - Q_UNUSED(index) - // this is a flat model - return QModelIndex(); +QModelIndex FlatProxyModel::parent(const QModelIndex& index) const +{ + Q_UNUSED(index) + // this is a flat model + return {}; } -int FlatProxyModel::rowCount(const QModelIndex &index) const { - if(!_rootSourceItem) - return 0; +int FlatProxyModel::rowCount(const QModelIndex& index) const +{ + if (!_rootSourceItem) + return 0; - if(index.isValid()) - return 0; + if (index.isValid()) + return 0; - SourceItem *item = _rootSourceItem; - while(item->childCount() > 0) { - item = item->child(item->childCount() - 1); - } - return item->pos() + 1; + SourceItem* item = _rootSourceItem; + while (item->childCount() > 0) { + item = item->child(item->childCount() - 1); + } + return item->pos() + 1; } -int FlatProxyModel::columnCount(const QModelIndex &index) const { - Q_UNUSED(index) - if(!sourceModel()) { - return 0; - } else { - return sourceModel()->columnCount(QModelIndex()); - } +int FlatProxyModel::columnCount(const QModelIndex& index) const +{ + Q_UNUSED(index) + if (!sourceModel()) { + return 0; + } + else { + return sourceModel()->columnCount(QModelIndex()); + } } +FlatProxyModel::SourceItem* FlatProxyModel::sourceToInternal(const QModelIndex& sourceIndex) const +{ + QList childPath; + for (QModelIndex idx = sourceIndex; idx.isValid(); idx = sourceModel()->parent(idx)) { + childPath.prepend(idx.row()); + } -FlatProxyModel::SourceItem *FlatProxyModel::sourceToInternal(const QModelIndex &sourceIndex) const { - QList childPath; - for(QModelIndex idx = sourceIndex; idx.isValid(); idx = sourceModel()->parent(idx)) { - childPath.prepend(idx.row()); - } - - Q_ASSERT(!sourceIndex.isValid() || !childPath.isEmpty()); + Q_ASSERT(!sourceIndex.isValid() || !childPath.isEmpty()); - SourceItem *item = _rootSourceItem; - for(int i = 0; i < childPath.count(); i++) { - item = item->child(childPath[i]); - } - return item; + SourceItem* item = _rootSourceItem; + for (int i = 0; i < childPath.count(); i++) { + item = item->child(childPath[i]); + } + return item; } -void FlatProxyModel::on_columnsAboutToBeInserted(const QModelIndex &parent, int start, int end) { - Q_UNUSED(parent); - beginInsertColumns(QModelIndex(), start, end); +void FlatProxyModel::on_columnsAboutToBeInserted(const QModelIndex& parent, int start, int end) +{ + Q_UNUSED(parent); + beginInsertColumns(QModelIndex(), start, end); } -void FlatProxyModel::on_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - Q_UNUSED(parent); - beginRemoveColumns(QModelIndex(), start, end); +void FlatProxyModel::on_columnsAboutToBeRemoved(const QModelIndex& parent, int start, int end) +{ + Q_UNUSED(parent); + beginRemoveColumns(QModelIndex(), start, end); } -void FlatProxyModel::on_columnsInserted(const QModelIndex &parent, int start, int end) { - Q_UNUSED(parent); - Q_UNUSED(start); - Q_UNUSED(end); - endInsertColumns(); +void FlatProxyModel::on_columnsInserted(const QModelIndex& parent, int start, int end) +{ + Q_UNUSED(parent); + Q_UNUSED(start); + Q_UNUSED(end); + endInsertColumns(); } - -void FlatProxyModel::on_columnsRemoved(const QModelIndex &parent, int start, int end) { - Q_UNUSED(parent); - Q_UNUSED(start); - Q_UNUSED(end); - endRemoveRows(); +void FlatProxyModel::on_columnsRemoved(const QModelIndex& parent, int start, int end) +{ + Q_UNUSED(parent); + Q_UNUSED(start); + Q_UNUSED(end); + endRemoveRows(); } -void FlatProxyModel::on_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { - Q_ASSERT(sourceModel()); - Q_ASSERT(sourceModel()->parent(topLeft) == sourceModel()->parent(bottomRight)); +void FlatProxyModel::on_dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + Q_ASSERT(sourceModel()); + Q_ASSERT(sourceModel()->parent(topLeft) == sourceModel()->parent(bottomRight)); - SourceItem *topLeftItem = sourceToInternal(topLeft); - Q_ASSERT(topLeftItem); - Q_ASSERT(topLeftItem->parent()->childCount() > bottomRight.row()); + SourceItem* topLeftItem = sourceToInternal(topLeft); + Q_ASSERT(topLeftItem); + Q_ASSERT(topLeftItem->parent()->childCount() > bottomRight.row()); - QModelIndex proxyTopLeft = createIndex(topLeftItem->pos(), topLeft.column(), topLeftItem); - QModelIndex proxyBottomRight = createIndex(topLeftItem->pos() + bottomRight.row() - topLeft.row(), bottomRight.column(), topLeftItem->parent()->child(bottomRight.row())); - emit dataChanged(proxyTopLeft, proxyBottomRight); + QModelIndex proxyTopLeft = createIndex(topLeftItem->pos(), topLeft.column(), topLeftItem); + QModelIndex proxyBottomRight = createIndex(topLeftItem->pos() + bottomRight.row() - topLeft.row(), + bottomRight.column(), + topLeftItem->parent()->child(bottomRight.row())); + emit dataChanged(proxyTopLeft, proxyBottomRight); } -void FlatProxyModel::on_layoutAboutToBeChanged() { - emit layoutAboutToBeChanged(); - removeSubTree(QModelIndex(), false /* don't emit removeRows() */); +void FlatProxyModel::on_layoutAboutToBeChanged() +{ + emit layoutAboutToBeChanged(); + removeSubTree(QModelIndex(), false /* don't emit removeRows() */); } -void FlatProxyModel::on_layoutChanged() { - insertSubTree(QModelIndex(), false /* don't emit insertRows() */); - emit layoutChanged(); +void FlatProxyModel::on_layoutChanged() +{ + insertSubTree(QModelIndex(), false /* don't emit insertRows() */); + emit layoutChanged(); } -void FlatProxyModel::on_rowsAboutToBeInserted(const QModelIndex &parent, int start, int end) { - Q_ASSERT(sourceModel()); - Q_ASSERT(_rootSourceItem); +void FlatProxyModel::on_rowsAboutToBeInserted(const QModelIndex& parent, int start, int end) +{ + Q_ASSERT(sourceModel()); + Q_ASSERT(_rootSourceItem); - SourceItem *sourceItem = sourceToInternal(parent); - Q_ASSERT(sourceItem); + SourceItem* sourceItem = sourceToInternal(parent); + Q_ASSERT(sourceItem); - beginInsertRows(QModelIndex(), sourceItem->pos() + start + 1, sourceItem->pos() + end + 1); + beginInsertRows(QModelIndex(), sourceItem->pos() + start + 1, sourceItem->pos() + end + 1); - SourceItem *prevItem = sourceItem; - if(start > 0) { - prevItem = sourceItem->child(start - 1); - while(prevItem->childCount() > 0) { - prevItem = prevItem->child(prevItem->childCount() - 1); + SourceItem* prevItem = sourceItem; + if (start > 0) { + prevItem = sourceItem->child(start - 1); + while (prevItem->childCount() > 0) { + prevItem = prevItem->child(prevItem->childCount() - 1); + } } - } - Q_ASSERT(prevItem); - - SourceItem *nextItem = prevItem->next(); - - SourceItem *newItem = 0; - int newPos = prevItem->pos() + 1; - for(int row = start; row <= end; row++) { - newItem = new SourceItem(row, sourceItem); - newItem->setPos(newPos); - newPos++; - prevItem->setNext(newItem); - prevItem = newItem; - } - prevItem->setNext(nextItem); - - while(nextItem) { - nextItem->setPos(newPos); - newPos++; - nextItem = nextItem->next(); - } + Q_ASSERT(prevItem); + + SourceItem* nextItem = prevItem->next(); + + SourceItem* newItem = nullptr; + int newPos = prevItem->pos() + 1; + for (int row = start; row <= end; row++) { + newItem = new SourceItem(row, sourceItem); + newItem->setPos(newPos); + newPos++; + prevItem->setNext(newItem); + prevItem = newItem; + } + prevItem->setNext(nextItem); + while (nextItem) { + nextItem->setPos(newPos); + newPos++; + nextItem = nextItem->next(); + } } -void FlatProxyModel::on_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - Q_ASSERT(sourceModel()); - Q_ASSERT(_rootSourceItem); - - SourceItem *sourceItem = sourceToInternal(parent); - beginRemoveRows(QModelIndex(), sourceItem->pos() + start + 1, sourceItem->pos() + end + 1); - - // sanity check - if that check fails our indexes would be messed up - for(int row = start; row <= end; row++) { - if(sourceItem->child(row)->childCount() > 0) { - qWarning() << "on_rowsAboutToBeRemoved(): sourceModel() removed rows which have childs on their own!" << sourceModel()->index(row, 0, parent); - Q_ASSERT(false); +void FlatProxyModel::on_rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) +{ + Q_ASSERT(sourceModel()); + Q_ASSERT(_rootSourceItem); + + SourceItem* sourceItem = sourceToInternal(parent); + beginRemoveRows(QModelIndex(), sourceItem->pos() + start + 1, sourceItem->pos() + end + 1); + + // sanity check - if that check fails our indexes would be messed up + for (int row = start; row <= end; row++) { + if (sourceItem->child(row)->childCount() > 0) { + qWarning() << "on_rowsAboutToBeRemoved(): sourceModel() removed rows which have children on their own!" + << sourceModel()->index(row, 0, parent); + Q_ASSERT(false); + } } - } } -void FlatProxyModel::on_rowsInserted(const QModelIndex &parent, int start, int end) { - Q_ASSERT(sourceModel()); - Q_ASSERT(_rootSourceItem); +void FlatProxyModel::on_rowsInserted(const QModelIndex& parent, int start, int end) +{ + Q_ASSERT(sourceModel()); + Q_ASSERT(_rootSourceItem); + + SourceItem* sourceItem = sourceToInternal(parent); + Q_ASSERT(sourceItem); + Q_UNUSED(sourceItem); + + // sanity check - if that check fails our indexes would be messed up + for (int row = start; row <= end; row++) { + QModelIndex child = sourceModel()->index(row, 0, parent); + if (sourceModel()->rowCount(child) > 0) { + qWarning() << "on_rowsInserted(): sourceModel() inserted rows which already have children on their own!" << child; + Q_ASSERT(false); + } + } - SourceItem *sourceItem = sourceToInternal(parent); - Q_ASSERT(sourceItem); + endInsertRows(); +} - // sanity check - if that check fails our indexes would be messed up - for(int row = start; row <= end; row++) { - QModelIndex child = sourceModel()->index(row, 0, parent); - if(sourceModel()->rowCount(child) > 0) { - qWarning() << "on_rowsInserted(): sourceModel() inserted rows which already have childs on their own!" << child; - Q_ASSERT(false); +void FlatProxyModel::on_rowsRemoved(const QModelIndex& parent, int start, int end) +{ + Q_ASSERT(sourceModel()); + Q_ASSERT(_rootSourceItem); + + SourceItem* sourceItem = sourceToInternal(parent); + Q_ASSERT(sourceItem); + + SourceItem* prevItem = sourceItem; + if (start > 0) { + prevItem = sourceItem->child(start - 1); + while (prevItem->childCount() > 0) { + prevItem = prevItem->child(prevItem->childCount() - 1); + } } - } + Q_ASSERT(prevItem); - endInsertRows(); -} + SourceItem* nextItem = sourceItem->child(end)->next(); -void FlatProxyModel::on_rowsRemoved(const QModelIndex &parent, int start, int end) { - Q_ASSERT(sourceModel()); - Q_ASSERT(_rootSourceItem); + int newPos = prevItem->pos() + 1; + prevItem->setNext(nextItem); - SourceItem *sourceItem = sourceToInternal(parent); - Q_ASSERT(sourceItem); + while (nextItem) { + nextItem->setPos(newPos); + newPos++; + nextItem = nextItem->next(); + } - SourceItem *prevItem = sourceItem; - if(start > 0) { - prevItem = sourceItem->child(start - 1); - while(prevItem->childCount() > 0) { - prevItem = prevItem->child(prevItem->childCount() - 1); + SourceItem* childItem; + for (int row = start; row <= end; row++) { + childItem = sourceItem->_childs.takeAt(start); + delete childItem; } - } - Q_ASSERT(prevItem); - SourceItem *nextItem = sourceItem->child(end)->next(); + endRemoveRows(); +} - int newPos = prevItem->pos() + 1; - prevItem->setNext(nextItem); +// integrity Tets +void FlatProxyModel::linkTest() const +{ + qDebug() << "Checking FlatProxyModel for linklist integrity"; + if (!_rootSourceItem) + return; + + int pos = -1; + SourceItem* item = _rootSourceItem; + while (true) { + qDebug() << item << ":" << item->pos() << "==" << pos; + Q_ASSERT(item->pos() == pos); + pos++; + if (!item->next()) + break; + item = item->next(); + } + qDebug() << "Last item in linklist:" << item << item->pos(); - while(nextItem) { - nextItem->setPos(newPos); - newPos++; - nextItem = nextItem->next(); - } + int lastPos = item->pos(); + item = _rootSourceItem; + while (item->childCount() > 0) { + item = item->child(item->childCount() - 1); + } + qDebug() << "Last item in tree:" << item << item->pos(); + Q_ASSERT(lastPos == item->pos()); + Q_UNUSED(lastPos); - SourceItem *childItem; - for(int row = start; row <= end; row++) { - childItem = sourceItem->_childs.takeAt(start); - delete childItem; - } + qDebug() << "success!"; +} - endRemoveRows(); +void FlatProxyModel::completenessTest() const +{ + qDebug() << "Checking FlatProxyModel for Completeness:"; + int pos = -1; + checkChildCount(QModelIndex(), _rootSourceItem, pos); + qDebug() << "success!"; } -// integrity Tets -void FlatProxyModel::linkTest() const { - qDebug() << "Checking FlatProxyModel for linklist integrity"; - if(!_rootSourceItem) - return; - - int pos = -1; - SourceItem *item = _rootSourceItem; - while(true) { - qDebug() << item << ":" << item->pos() << "==" << pos; - Q_ASSERT(item->pos() == pos); - pos++; - if(!item->next()) - break; - item = item->next(); - } - qDebug() << "Last item in linklist:" << item << item->pos(); - - int lastPos = item->pos(); - item = _rootSourceItem; - while(item->childCount() > 0) { - item = item->child(item->childCount() - 1); - } - qDebug() << "Last item in tree:" << item << item->pos(); - Q_ASSERT(lastPos == item->pos()); - - qDebug() << "success!"; -} - -void FlatProxyModel::completenessTest() const { - qDebug() << "Checking FlatProxyModel for Completeness:"; - int pos = -1; - checkChildCount(QModelIndex(), _rootSourceItem, pos); - qDebug() << "success!"; -} - -void FlatProxyModel::checkChildCount(const QModelIndex &index, const SourceItem *item, int &pos) const { - if(!sourceModel()) - return; - - qDebug() << index << "(Item:" << item << "):" << sourceModel()->rowCount(index) << "==" << item->childCount(); - qDebug() << "ProxyPos:" << item->pos() << "==" << pos; - Q_ASSERT(sourceModel()->rowCount(index) == item->childCount()); - - for(int row = 0; row < sourceModel()->rowCount(index); row++) { - pos++; - checkChildCount(sourceModel()->index(row, 0, index), item->child(row), pos); - } +void FlatProxyModel::checkChildCount(const QModelIndex& index, const SourceItem* item, int& pos) const +{ + if (!sourceModel()) + return; + + qDebug() << index << "(Item:" << item << "):" << sourceModel()->rowCount(index) << "==" << item->childCount(); + qDebug() << "ProxyPos:" << item->pos() << "==" << pos; + Q_ASSERT(sourceModel()->rowCount(index) == item->childCount()); + + for (int row = 0; row < sourceModel()->rowCount(index); row++) { + pos++; + checkChildCount(sourceModel()->index(row, 0, index), item->child(row), pos); + } } // ======================================== // SourceItem // ======================================== -FlatProxyModel::SourceItem::SourceItem(int row, SourceItem *parent) - : _parent(parent), - _pos(-1), - _next(0) -{ - if(parent) { - parent->_childs.insert(row, this); - } -} - -FlatProxyModel::SourceItem::~SourceItem() { - for(int i = 0; i < childCount(); i++) { - delete child(i); - } - _childs.clear(); -} - -int FlatProxyModel::SourceItem::sourceRow() const { - if(!parent()) - return -1; - else - return parent()->_childs.indexOf(const_cast(this)); -} - -FlatProxyModel::SourceItem *FlatProxyModel::SourceItem::findChild(int proxyPos) const { - Q_ASSERT(proxyPos > pos()); - Q_ASSERT(_childs.count() > 0); - Q_ASSERT(proxyPos >= _childs[0]->pos()); - - int start = 0; - int end = _childs.count() - 1; - int pivot; - while(end - start != 1) { - pivot = (end + start) / 2; - if(_childs[pivot]->pos() > proxyPos) - end = pivot; +FlatProxyModel::SourceItem::SourceItem(int row, SourceItem* parent) + : _parent(parent) +{ + if (parent) { + parent->_childs.insert(row, this); + } +} + +FlatProxyModel::SourceItem::~SourceItem() +{ + for (int i = 0; i < childCount(); i++) { + delete child(i); + } + _childs.clear(); +} + +int FlatProxyModel::SourceItem::sourceRow() const +{ + if (!parent()) + return -1; else - start = pivot; - } + return parent()->_childs.indexOf(const_cast(this)); +} + +FlatProxyModel::SourceItem* FlatProxyModel::SourceItem::findChild(int proxyPos) const +{ + Q_ASSERT(proxyPos > pos()); + Q_ASSERT(_childs.count() > 0); + Q_ASSERT(proxyPos >= _childs[0]->pos()); + + int start = 0; + int end = _childs.count() - 1; + int pivot; + while (end - start > 1) { + pivot = (end + start) / 2; + if (_childs[pivot]->pos() > proxyPos) + end = pivot; + else + start = pivot; + } - if(_childs[end]->pos() <= proxyPos) - return _childs[end]; - else - return _childs[start]; + if (_childs[end]->pos() <= proxyPos) + return _childs[end]; + else + return _childs[start]; }