libtaskmanager: Fix dragging launcher icon when separateLaunchers is false

When separateLaunchers is false and there are two opened pinned tasks
and one launcher icon, dragging the launcher icon to a position between
the two pinned tasks always fails for the first time.

The general idea of this fix is to make sure after every move operation,
pinned launhcer item and the corresponding opened window still stay
together.

BUG: 448912
FIXED-IN: 5.26
wilder-5.26
Fushan Wen 4 years ago
parent 300f491d7f
commit a85eaedaae
No known key found for this signature in database
GPG Key ID: 2E48D1487C91DCAA
  1. 43
      libtaskmanager/launchertasksmodel.cpp
  2. 92
      libtaskmanager/tasksmodel.cpp

@ -446,23 +446,42 @@ void LauncherTasksModel::setLauncherList(const QStringList &serializedLaunchers)
} }
if (newLaunchersOrder != d->launchersOrder) { if (newLaunchersOrder != d->launchersOrder) {
// Use Remove/Insert to update the manual sort map in TasksModel const bool isOrderChanged = std::all_of(newLaunchersOrder.cbegin(),
if (!d->launchersOrder.empty()) { newLaunchersOrder.cend(),
beginRemoveRows(QModelIndex(), 0, d->launchersOrder.size() - 1); [this](const QUrl &url) {
return d->launchersOrder.contains(url);
})
&& newLaunchersOrder.size() == d->launchersOrder.size();
if (isOrderChanged) {
for (int i = 0; i < newLaunchersOrder.size(); i++) {
int oldRow = d->launchersOrder.indexOf(newLaunchersOrder.at(i));
if (oldRow != i) {
beginMoveRows(QModelIndex(), oldRow, oldRow, QModelIndex(), i);
d->launchersOrder.move(oldRow, i);
endMoveRows();
}
}
} else {
// Use Remove/Insert to update the manual sort map in TasksModel
if (!d->launchersOrder.empty()) {
beginRemoveRows(QModelIndex(), 0, d->launchersOrder.size() - 1);
d->launchersOrder.clear(); d->launchersOrder.clear();
d->activitiesForLauncher.clear(); d->activitiesForLauncher.clear();
endRemoveRows(); endRemoveRows();
} }
if (!newLaunchersOrder.empty()) { if (!newLaunchersOrder.empty()) {
beginInsertRows(QModelIndex(), 0, newLaunchersOrder.size() - 1); beginInsertRows(QModelIndex(), 0, newLaunchersOrder.size() - 1);
d->launchersOrder = newLaunchersOrder; d->launchersOrder = newLaunchersOrder;
d->activitiesForLauncher = newActivitiesForLauncher; d->activitiesForLauncher = newActivitiesForLauncher;
endInsertRows(); endInsertRows();
}
} }
Q_EMIT launcherListChanged(); Q_EMIT launcherListChanged();

@ -1715,32 +1715,75 @@ bool TasksModel::move(int row, int newPos, const QModelIndex &parent)
// Resort. // Resort.
d->forceResort(); d->forceResort();
if (!d->separateLaunchers && isLauncherMove) { if (!d->separateLaunchers) {
const QModelIndex &idx = d->concatProxyModel->index(d->sortedPreFilterRows.at(newPos), 0); if (isLauncherMove) {
const QUrl &launcherUrl = idx.data(AbstractTasksModel::LauncherUrlWithoutIcon).toUrl(); const QModelIndex &idx = d->concatProxyModel->index(d->sortedPreFilterRows.at(newPos), 0);
const QUrl &launcherUrl = idx.data(AbstractTasksModel::LauncherUrlWithoutIcon).toUrl();
// Move launcher for launcher-backed task along with task if launchers
// are not being kept separate.
// We don't need to resort again because the launcher is implicitly hidden
// at this time.
if (!idx.data(AbstractTasksModel::IsLauncher).toBool()) {
const int launcherPos = d->launcherTasksModel->launcherPosition(launcherUrl);
const QModelIndex &launcherIndex = d->launcherTasksModel->index(launcherPos, 0);
const int sortIndex = d->sortedPreFilterRows.indexOf(d->concatProxyModel->mapFromSource(launcherIndex).row());
d->sortedPreFilterRows.move(sortIndex, newPos);
// Otherwise move matching windows to after the launcher task (they are
// currently hidden but might be on another virtual desktop).
} else {
for (int i = (d->sortedPreFilterRows.count() - 1); i >= 0; --i) {
const QModelIndex &concatProxyIndex = d->concatProxyModel->index(d->sortedPreFilterRows.at(i), 0);
if (launcherUrl == concatProxyIndex.data(AbstractTasksModel::LauncherUrlWithoutIcon).toUrl()) { // Move launcher for launcher-backed task along with task if launchers
d->sortedPreFilterRows.move(i, newPos); // are not being kept separate.
// We don't need to resort again because the launcher is implicitly hidden
// at this time.
if (!idx.data(AbstractTasksModel::IsLauncher).toBool()) {
const int launcherPos = d->launcherTasksModel->launcherPosition(launcherUrl);
const QModelIndex &launcherIndex = d->launcherTasksModel->index(launcherPos, 0);
const int sortIndex = d->sortedPreFilterRows.indexOf(d->concatProxyModel->mapFromSource(launcherIndex).row());
d->sortedPreFilterRows.move(sortIndex, newPos);
/*
* Before moving:
* [pinned 2 (launcher)] [pinned 2 (window)] [pinned 1 (launcher)] [pinned 1 (window)]
* After moving [pinned 1], sortedPreFilterRows may become:
* - row > newPos: [pinned 2 (launcher)] [pinned 1 (launcher)] [pinned 1 (window)] [pinned 2 (window)]
* - row < newPos: [pinned 2 (window)] [pinned 1 (window)] [pinned 1 (launcher)] [pinned 2 (launcher)]
* We need to move [pinned 2 (launcher)] to the left of [pinned 2 (window)]
*/
if (row > newPos && newPos - 1 >= 0 && newPos + 2 < d->sortedPreFilterRows.size()) {
const QModelIndex beforeIdx = d->concatProxyModel->index(d->sortedPreFilterRows.at(newPos - 1), 0); // [pinned 2 (launcher)]
const QModelIndex afterIdx = d->concatProxyModel->index(d->sortedPreFilterRows.at(newPos + 2), 0); // [pinned 2 (window)]
if (appsMatch(beforeIdx, afterIdx)) {
// Move [pinned 2 (launcher)] before [pinned 2 (window)]
d->sortedPreFilterRows.move(newPos - 1, newPos + 2);
}
} else if (row < newPos && newPos - 2 >= 0 && newPos + 1 < d->sortedPreFilterRows.size()) {
const QModelIndex beforeIdx = d->concatProxyModel->index(d->sortedPreFilterRows.at(newPos - 2), 0); // [pinned 2 (window)]
const QModelIndex afterIdx = d->concatProxyModel->index(d->sortedPreFilterRows.at(newPos + 1), 0); // [pinned 2 (launcher)]
if (newPos > i) { if (appsMatch(beforeIdx, afterIdx)) {
--newPos; // Move [pinned 2 (launcher)] before [pinned 2 (window)]
d->sortedPreFilterRows.move(newPos + 1, newPos - 2);
} }
} }
// Otherwise move matching windows to after the launcher task (they are
// currently hidden but might be on another virtual desktop).
} else {
for (int i = (d->sortedPreFilterRows.count() - 1); i >= 0; --i) {
const QModelIndex &concatProxyIndex = d->concatProxyModel->index(d->sortedPreFilterRows.at(i), 0);
if (launcherUrl == concatProxyIndex.data(AbstractTasksModel::LauncherUrlWithoutIcon).toUrl()) {
d->sortedPreFilterRows.move(i, newPos);
if (newPos > i) {
--newPos;
}
}
}
}
} else if (newPos > 0 && newPos < d->sortedPreFilterRows.size() - 1) {
/*
* When dragging an unpinned task, a pinned task can also be moved.
* In this case, sortedPreFilterRows is like:
* - before moving: [pinned 1 (launcher item)] [pinned 1 (window)] [unpinned]
* - after moving: [pinned 1 (launcher item)] [unpinned] [pinned 1 (window)]
* So also check the indexes before and after the unpinned task.
*/
const QModelIndex beforeIdx = d->concatProxyModel->index(d->sortedPreFilterRows.at(newPos - 1), 0);
const QModelIndex afterIdx = d->concatProxyModel->index(d->sortedPreFilterRows.at(newPos + 1), 0);
if (appsMatch(beforeIdx, afterIdx)) {
// after adjusting: [unpinned] [pinned 1 (launcher item)] [pinned 1]
d->sortedPreFilterRows.move(newPos, newPos + (row < newPos ? 1 : -1));
} }
} }
} }
@ -1818,6 +1861,11 @@ void TasksModel::syncLaunchers()
} }
setLauncherList(sortedShownLaunchers.values() + sortedHiddenLaunchers); setLauncherList(sortedShownLaunchers.values() + sortedHiddenLaunchers);
// The accepted rows are outdated after the item order is changed
invalidateFilter();
d->forceResort();
d->launcherSortingDirty = false; d->launcherSortingDirty = false;
} }

Loading…
Cancel
Save