From c1d45948a9d58127ab5f1eba33ec71124bcf297c Mon Sep 17 00:00:00 2001 From: l10n daemon script Date: Sat, 19 Aug 2017 06:49:33 +0200 Subject: [PATCH 1/2] SVN_SILENT made messages (.desktop file) - always resolve ours In case of conflict in i18n, keep the version of the branch "ours" To resolve a particular conflict, "git checkout --ours path/to/file.desktop" --- menu/desktop/kf5-utilities-accessibility.directory | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/menu/desktop/kf5-utilities-accessibility.directory b/menu/desktop/kf5-utilities-accessibility.directory index 083770f0b..cdb1a86e0 100644 --- a/menu/desktop/kf5-utilities-accessibility.directory +++ b/menu/desktop/kf5-utilities-accessibility.directory @@ -25,7 +25,7 @@ Name[en_GB]=Accessibility Name[eo]=Alirebleco Name[es]=Accesibilidad Name[et]=Hõlbustus -Name[eu]=Erabilerraztasuna +Name[eu]=Irisgarritasuna Name[fa]=دستیابی‌پذیری Name[fi]=Esteettömyys Name[fr]=Accessibilité @@ -119,7 +119,7 @@ Comment[en_GB]=Accessibility Comment[eo]=Alirebleco Comment[es]=Accesibilidad Comment[et]=Hõlbustus -Comment[eu]=Erabilerraztasuna +Comment[eu]=Irisgarritasuna Comment[fa]=دستیابی‌پذیری Comment[fi]=Esteettömyys Comment[fr]=Accessibilité From d2f722a82ebeb213a89efc209ec726a8188de6f0 Mon Sep 17 00:00:00 2001 From: Eike Hein Date: Sat, 5 Aug 2017 03:58:06 +0900 Subject: [PATCH 2/2] Fix QSortFilterProxyModelPrivate::updateChildrenMapping crash in libtaskmanager Summary: TaskGroupingProxyModel uses a simple QVector> populated with source model row indices to represent the task group tree. To implement QAbstractItemModel::parent(), its implementation of index() encodes row indices of the top-level vector into the internal ids of child item model indices. This allows parent() to produce the parent model index by simply decoding the parent row from the passed-in child index and call index() with that row. Top-level row indices shift up and down as the list of top-level items changes, invalidating those internal ids. QModelIndex is not meant to be stored, and the proxy model does take care of updating any persis- tent model indexes with new ids, so this should be fine. However, where it falls apart is that as internal ids are invalidated, a QSortFilterProxyModel on top of this proxy (i.e. TasksModel) may end up with multiple indexes with identical internal ids in its mappings, causing it to mess up its mappings as it uses them (e.g. taking things from them). This causes the often-reported crash/assert there. The fix is to refactor index()/parent() not to rely on row indices as internal ids, but instead use pointers to internal data structures instead. This patch achieves this by changing the map to QVector *>. This screams fugly, but the alternative would basically just be to create some wrapper struct to hide the fugly appeareance a little, which I don't think is worth it. On the flip side, it saves a QVector::replace() call as a multable vector iterator can work directly on a vector without making a copy, and it's now no longer necessary to manually update the persistent model indices beyond what endRemoveRows() does implicitly. BUG:381006 Reviewers: #plasma, davidedmundson Subscribers: plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D7139 --- libtaskmanager/taskgroupingproxymodel.cpp | 127 +++++++++------------- 1 file changed, 54 insertions(+), 73 deletions(-) diff --git a/libtaskmanager/taskgroupingproxymodel.cpp b/libtaskmanager/taskgroupingproxymodel.cpp index 46b92b9d6..bcad638ef 100644 --- a/libtaskmanager/taskgroupingproxymodel.cpp +++ b/libtaskmanager/taskgroupingproxymodel.cpp @@ -31,6 +31,7 @@ class TaskGroupingProxyModel::Private { public: Private(TaskGroupingProxyModel *q); + ~Private(); AbstractTasksModelIface *abstractTasksSourceModel = nullptr; @@ -38,7 +39,7 @@ public: bool groupDemandingAttention = false; int windowTasksThreshold = -1; - QVector> rowMap; + QVector *> rowMap; QSet blacklistedAppIds; QSet blacklistedLauncherUrls; @@ -74,13 +75,18 @@ TaskGroupingProxyModel::Private::Private(TaskGroupingProxyModel *q) { } +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 @@ void TaskGroupingProxyModel::Private::sourceRowsInserted(const QModelIndex &pare 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,44 +153,20 @@ void TaskGroupingProxyModel::Private::sourceRowsAboutToBeRemoved(const QModelInd 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. @@ -193,7 +175,7 @@ void TaskGroupingProxyModel::Private::sourceRowsAboutToBeRemoved(const QModelInd } 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 @@ void TaskGroupingProxyModel::Private::sourceDataChanged(QModelIndex topLeft, QMo 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,27 +256,22 @@ void TaskGroupingProxyModel::Private::sourceDataChanged(QModelIndex topLeft, QMo 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(); @@ -302,7 +279,7 @@ void TaskGroupingProxyModel::Private::rebuildMap() 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 @@ void TaskGroupingProxyModel::Private::checkGrouping(bool silent) 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 @@ bool TaskGroupingProxyModel::Private::tryToGroup(const QModelIndex &sourceIndex, // 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,7 +398,7 @@ bool TaskGroupingProxyModel::Private::tryToGroup(const QModelIndex &sourceIndex, 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); @@ -430,7 +407,7 @@ bool TaskGroupingProxyModel::Private::tryToGroup(const QModelIndex &sourceIndex, } } - rowMap[i].append(sourceIndex.row()); + rowMap[i]->append(sourceIndex.row()); if (!silent) { q->endInsertRows(); @@ -457,7 +434,7 @@ void TaskGroupingProxyModel::Private::formGroupFor(const QModelIndex &index) 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; @@ -465,7 +442,7 @@ void TaskGroupingProxyModel::Private::formGroupFor(const QModelIndex &index) 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 @@ void TaskGroupingProxyModel::Private::breakGroupFor(const QModelIndex &index, bo } // 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 @@ void TaskGroupingProxyModel::Private::breakGroupFor(const QModelIndex &index, bo 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 @@ void TaskGroupingProxyModel::Private::breakGroupFor(const QModelIndex &index, bo } for (int i = 0; i < extraChildren.count(); ++i) { - rowMap.append(QVector{extraChildren.at(i)}); + rowMap.append(new QVector{extraChildren.at(i)}); } if (!silent) { @@ -537,12 +504,12 @@ QModelIndex TaskGroupingProxyModel::index(int row, int column, const QModelIndex 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(); @@ -550,7 +517,21 @@ QModelIndex TaskGroupingProxyModel::index(int row, int column, const 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 @@ QModelIndex TaskGroupingProxyModel::mapFromSource(const QModelIndex &sourceIndex } 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,7 +577,7 @@ QModelIndex TaskGroupingProxyModel::mapToSource(const QModelIndex &proxyIndex) c 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. @@ -604,7 +585,7 @@ QModelIndex TaskGroupingProxyModel::mapToSource(const QModelIndex &proxyIndex) c // 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 @@ int TaskGroupingProxyModel::rowCount(const QModelIndex &parent) const 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.