diff --git a/libtaskmanager/taskgroupingproxymodel.cpp b/libtaskmanager/taskgroupingproxymodel.cpp --- a/libtaskmanager/taskgroupingproxymodel.cpp +++ b/libtaskmanager/taskgroupingproxymodel.cpp @@ -31,14 +31,15 @@ { public: Private(TaskGroupingProxyModel *q); + ~Private(); AbstractTasksModelIface *abstractTasksSourceModel = nullptr; TasksModel::GroupMode groupMode = TasksModel::GroupApplications; bool groupDemandingAttention = false; int windowTasksThreshold = -1; - QVector> rowMap; + QVector *> rowMap; QSet blacklistedAppIds; QSet blacklistedLauncherUrls; @@ -74,13 +75,18 @@ { } +TaskGroupingProxyModel::Private::~Private() +{ + qDeleteAll(rowMap); +} + bool TaskGroupingProxyModel::Private::isGroup(int row) { if (row < 0 || row >= rowMap.count()) { return false; } - return (rowMap.at(row).count() > 1); + return (rowMap.at(row)->count() > 1); } bool TaskGroupingProxyModel::Private::any(const QModelIndex &parent, int role) @@ -130,7 +136,7 @@ for (int i = start; i <= end; ++i) { if (!shouldGroup || !tryToGroup(q->sourceModel()->index(i, 0))) { q->beginInsertRows(QModelIndex(), rowMap.count(), rowMap.count()); - rowMap.append(QVector{i}); + rowMap.append(new QVector{i}); q->endInsertRows(); } } @@ -147,53 +153,29 @@ for (int i = first; i <= last; ++i) { for (int j = 0; j < rowMap.count(); ++j) { - const QVector &sourceRows = rowMap.at(j); - const int mapIndex = sourceRows.indexOf(i); + const QVector *sourceRows = rowMap.at(j); + const int mapIndex = sourceRows->indexOf(i); if (mapIndex != -1) { // Remove top-level item. - if (sourceRows.count() == 1) { + if (sourceRows->count() == 1) { q->beginRemoveRows(QModelIndex(), j, j); - rowMap.remove(j); - - // index() encodes parent row numbers in indices returned for group - // members. endRemoveRows() is not aware of this scheme, and so won't - // update any persistent indices with new row values. We're now going - // to do it ourselves. - foreach (const QModelIndex &idx, q->persistentIndexList()) { - // internalId() for group members is parent row + 1, so the first - // id after j is (j + 2). - if (idx.internalId() > ((uint)j + 1)) { - q->changePersistentIndex(idx, q->createIndex(idx.row(), 0, idx.internalId() - 1)); - } - } - + delete rowMap.takeAt(j); q->endRemoveRows(); // Dissolve group. - } else if (sourceRows.count() == 2) { + } else if (sourceRows->count() == 2) { const QModelIndex parent = q->index(j, 0); q->beginRemoveRows(parent, 0, 1); - rowMap[j].remove(mapIndex); - - // index() encodes parent row numbers in indices returned for group - // members. endRemoveRows() is not aware of this scheme, and so won't - // invalidate persistent indices for the members of the group we're - // dissolving. We're now going to do it ourselves. - foreach (const QModelIndex &idx, q->persistentIndexList()) { - if (idx.internalId() == ((uint)j + 1)) { - q->changePersistentIndex(idx, QModelIndex()); - } - } - + rowMap[j]->remove(mapIndex); q->endRemoveRows(); // We're no longer a group parent. q->dataChanged(parent, parent); // Remove group member. } else { const QModelIndex parent = q->index(j, 0); q->beginRemoveRows(parent, mapIndex, mapIndex); - rowMap[j].remove(mapIndex); + rowMap[j]->remove(mapIndex); q->endRemoveRows(); // Various roles of the parent evaluate child data, and the @@ -260,7 +242,7 @@ if (shouldGroupTasks() && tryToGroup(sourceIndex)) { q->beginRemoveRows(QModelIndex(), proxyIndex.row(), proxyIndex.row()); - rowMap.remove(proxyIndex.row()); + delete rowMap.takeAt(proxyIndex.row()); q->endRemoveRows(); } else { q->dataChanged(proxyIndex, proxyIndex, roles); @@ -274,35 +256,30 @@ void TaskGroupingProxyModel::Private::adjustMap(int anchor, int delta) { for (int i = 0; i < rowMap.count(); ++i) { - bool changed = false; - QVector sourceRows = rowMap.at(i); - QMutableVectorIterator it(sourceRows); + QVector *sourceRows = rowMap.at(i); + QMutableVectorIterator it(*sourceRows); while (it.hasNext()) { it.next(); if (it.value() >= anchor) { it.setValue(it.value() + delta); - changed = true; } } - - if (changed) { - rowMap.replace(i, sourceRows); - } } } void TaskGroupingProxyModel::Private::rebuildMap() { + qDeleteAll(rowMap); rowMap.clear(); const int rows = q->sourceModel()->rowCount(); rowMap.reserve(rows); for (int i = 0; i < rows; ++i) { - rowMap.append(QVector{i}); + rowMap.append(new QVector{i}); } checkGrouping(true /* silent */); @@ -345,9 +322,9 @@ continue; } - if (tryToGroup(q->sourceModel()->index(rowMap.at(i).constFirst(), 0), silent)) { + if (tryToGroup(q->sourceModel()->index(rowMap.at(i)->constFirst(), 0), silent)) { q->beginRemoveRows(QModelIndex(), i, i); - rowMap.remove(i); // Safe since we're iterating backwards. + delete rowMap.takeAt(i); // Safe since we're iterating backwards. q->endRemoveRows(); } } @@ -405,7 +382,7 @@ // Meat of the matter: Try to add this source row to a sub-list with source rows // associated with the same application. for (int i = 0; i < rowMap.count(); ++i) { - const QModelIndex &groupRep = q->sourceModel()->index(rowMap.at(i).constFirst(), 0); + const QModelIndex &groupRep = q->sourceModel()->index(rowMap.at(i)->constFirst(), 0); // Don't match a row with itself. if (sourceIndex == groupRep) { @@ -421,16 +398,16 @@ const QModelIndex parent = q->index(i, 0); if (!silent) { - const int newIndex = rowMap.at(i).count(); + const int newIndex = rowMap.at(i)->count(); if (newIndex == 1) { q->beginInsertRows(parent, 0, 1); } else { q->beginInsertRows(parent, newIndex, newIndex); } } - rowMap[i].append(sourceIndex.row()); + rowMap[i]->append(sourceIndex.row()); if (!silent) { q->endInsertRows(); @@ -457,15 +434,15 @@ const QModelIndex &sourceTarget = q->mapToSource(index); for (int i = (rowMap.count() - 1); i >= 0; --i) { - const QModelIndex &sourceIndex = q->sourceModel()->index(rowMap.at(i).constFirst(), 0); + const QModelIndex &sourceIndex = q->sourceModel()->index(rowMap.at(i)->constFirst(), 0); if (!appsMatch(sourceTarget, sourceIndex)) { continue; } if (tryToGroup(sourceIndex)) { q->beginRemoveRows(QModelIndex(), i, i); - rowMap.remove(i); // Safe since we're iterating backwards. + delete rowMap.takeAt(i); // Safe since we're iterating backwards. q->endRemoveRows(); } } @@ -480,7 +457,7 @@ } // The first child will move up to the top level. - QVector extraChildren = rowMap.at(row).mid(1); + QVector extraChildren = rowMap.at(row)->mid(1); // NOTE: We're going to do remove+insert transactions instead of a // single reparenting move transaction to save on complexity in the @@ -491,17 +468,7 @@ q->beginRemoveRows(index, 0, extraChildren.count()); } - rowMap[row].resize(1); - - // index() encodes parent row numbers in indices returned for group - // members. endRemoveRows() is not aware of this scheme, and so won't - // invalidate persistent indices for the members of the group we're - // dissolving. We're now going to do it ourselves. - foreach (const QModelIndex &idx, q->persistentIndexList()) { - if (idx.internalId() == ((uint)row + 1)) { - q->changePersistentIndex(idx, QModelIndex()); - } - } + rowMap[row]->resize(1); if (!silent) { q->endRemoveRows(); @@ -514,7 +481,7 @@ } for (int i = 0; i < extraChildren.count(); ++i) { - rowMap.append(QVector{extraChildren.at(i)}); + rowMap.append(new QVector{extraChildren.at(i)}); } if (!silent) { @@ -537,20 +504,34 @@ return QModelIndex(); } - if (parent.isValid() && row < d->rowMap.at(parent.row()).count()) { - return createIndex(row, column, parent.row() + 1); + if (parent.isValid() && row < d->rowMap.at(parent.row())->count()) { + return createIndex(row, column, d->rowMap.at(parent.row())); } if (row < d->rowMap.count()) { - return createIndex(row, column, (quintptr)0); + return createIndex(row, column, nullptr); } return QModelIndex(); } QModelIndex TaskGroupingProxyModel::parent(const QModelIndex &child) const { - return (child.internalId() == 0) ? QModelIndex() : index(child.internalId() - 1, 0); + if (child.internalPointer() == nullptr) { + return QModelIndex(); + } else { + const int parentRow = d->rowMap.indexOf(static_cast *>(child.internalPointer())); + + if (parentRow != -1) { + return index(parentRow, 0); + } + + // If we were asked to find the parent for an internalPointer we can't + // locate, we have corrupted data: This should not happen. + Q_ASSERT(parentRow != -1); + } + + return QModelIndex(); } QModelIndex TaskGroupingProxyModel::mapFromSource(const QModelIndex &sourceIndex) const @@ -560,8 +541,8 @@ } for (int i = 0; i < d->rowMap.count(); ++i) { - const QVector &sourceRows = d->rowMap.at(i); - const int childIndex = sourceRows.indexOf(sourceIndex.row()); + const QVector *sourceRows = d->rowMap.at(i); + const int childIndex = sourceRows->indexOf(sourceIndex.row()); const QModelIndex parent = index(i, 0); if (childIndex == 0) { @@ -596,15 +577,15 @@ return QModelIndex(); } - return sourceModel()->index(d->rowMap.at(parent.row()).at(proxyIndex.row()), 0); + return sourceModel()->index(d->rowMap.at(parent.row())->at(proxyIndex.row()), 0); } else { // Group parents items therefore equate to the first child item; the source // row logically appears twice in the proxy. // mapFromSource() is not required to handle this well (consider proxies can // filter out rows, too) and opts to map to the child item, as the group parent // has its Qt::DisplayRole mangled by data(), and it's more useful for trans- // lating dataChanged() from the source model. - return sourceModel()->index(d->rowMap.at(proxyIndex.row()).at(0), 0); + return sourceModel()->index(d->rowMap.at(proxyIndex.row())->at(0), 0); } return QModelIndex(); @@ -627,7 +608,7 @@ return 0; } - const uint rowCount = d->rowMap.at(parent.row()).count(); + const uint rowCount = d->rowMap.at(parent.row())->count(); // If this sub-list in the map only has one entry, it's a plain item, not // parent to a group.