diff --git a/libtaskmanager/tasksmodel.cpp b/libtaskmanager/tasksmodel.cpp index 0cb932006..128b566f7 100644 --- a/libtaskmanager/tasksmodel.cpp +++ b/libtaskmanager/tasksmodel.cpp @@ -49,6 +49,8 @@ public: int launcherCount = 0; + bool switchingFromActiveTask = false; + QTimer *reorderTimer = nullptr; SortMode sortMode = SortAlpha; bool separateLaunchers = true; bool launchInPlace = false; @@ -78,7 +80,6 @@ public: void updateGroupInline(); QModelIndex preFilterIndex(const QModelIndex &sourceIndex) const; void updateActivityTaskCounts(); - void forceResort(); bool lessThan(const QModelIndex &left, const QModelIndex &right, bool sortOnlyLaunchers = false) const; private: @@ -139,6 +140,8 @@ TasksModel::Private::~Private() virtualDesktopInfo = nullptr; delete activityInfo; activityInfo = nullptr; + delete reorderTimer; + reorderTimer = nullptr; } } @@ -165,7 +168,7 @@ void TasksModel::Private::initModels() QObject::connect(windowTasksModel, &QAbstractItemModel::rowsRemoved, q, [this]() { if (sortMode == SortActivity) { updateActivityTaskCounts(); - forceResort(); + q->invalidate(); } // the active task may have potentially changed, so signal that so that users // will recompute it @@ -690,7 +693,7 @@ void TasksModel::Private::updateGroupInline() q->setSourceModel(flattenGroupsProxyModel); if (sortMode == SortManual) { - forceResort(); + q->invalidate(); } } else { if (hadSourceModel && !flattenGroupsProxyModel) { @@ -707,7 +710,7 @@ void TasksModel::Private::updateGroupInline() flattenGroupsProxyModel = nullptr; if (hadSourceModel && sortMode == SortManual) { - forceResort(); + q->invalidate(); } } @@ -767,14 +770,6 @@ void TasksModel::Private::updateActivityTaskCounts() } } -void TasksModel::Private::forceResort() -{ - // HACK: This causes QSortFilterProxyModel to run all rows through - // our lessThan() implementation again. - q->setDynamicSortFilter(false); - q->setDynamicSortFilter(true); -} - bool TasksModel::Private::lessThan(const QModelIndex &left, const QModelIndex &right, bool sortOnlyLaunchers) const { // Launcher tasks go first. @@ -827,6 +822,25 @@ bool TasksModel::Private::lessThan(const QModelIndex &left, const QModelIndex &r // Sort other cases by sort mode. switch (sortMode) { + case SortLastActivated: { + QTime leftSortTime = left.data(AbstractTasksModel::LastActivated).toTime(); + + if (!leftSortTime.isValid()) { + leftSortTime = left.data(Qt::DisplayRole).toTime(); + } + + QTime rightSortTime = right.data(AbstractTasksModel::LastActivated).toTime(); + + if (!rightSortTime.isValid()) { + rightSortTime = right.data(Qt::DisplayRole).toTime(); + } + + if (leftSortTime == rightSortTime) { + return left.row() < right.row(); + } + + return (leftSortTime < rightSortTime); + } case SortVirtualDesktop: { const bool leftAll = left.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool(); const bool rightAll = right.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool(); @@ -872,8 +886,8 @@ bool TasksModel::Private::lessThan(const QModelIndex &left, const QModelIndex &r return true; } } + Q_FALLTHROUGH(); } - // fall through case SortActivity: { // updateActivityTaskCounts() counts the number of window tasks on each // activity. This will sort tasks by comparing a cumulative score made @@ -913,13 +927,12 @@ bool TasksModel::Private::lessThan(const QModelIndex &left, const QModelIndex &r if (leftScore != rightScore) { return (leftScore > rightScore); } + + Q_FALLTHROUGH(); } - // Fall through to source order if sorting is disabled or manual, or alphabetical by app name otherwise. - // This marker comment makes gcc/clang happy: - // fall through default: { if (sortMode == SortDisabled) { - return (left.row() < right.row()); + return left.row() < right.row(); } else { // The overall goal of alphabetic sorting is to sort tasks belonging to the // same app together, while sorting the resulting sets alphabetically among @@ -953,7 +966,7 @@ bool TasksModel::Private::lessThan(const QModelIndex &left, const QModelIndex &r // If the string are identical fall back to source model (creation/append) order. if (sortResult == 0) { - return (left.row() < right.row()); + return left.row() < right.row(); } return (sortResult < 0); @@ -1209,10 +1222,38 @@ void TasksModel::setSortMode(SortMode mode) d->activityTaskCounts.clear(); setSortRole(Qt::DisplayRole); } + if (mode == SortLastActivated) { + setDynamicSortFilter(false); + + if (!d->reorderTimer) { + d->reorderTimer = new QTimer(this); + } + + d->reorderTimer->setSingleShot(true); + + QObject::connect(this, &TasksModel::activeTaskChanged, this, [this] { + if (activeTask().data(AbstractTasksModel::AppId).isValid() + && activeTask().data(AbstractTasksModel::AppId).toString() != "org.kde.plasmashell.desktop") { + if (!d->switchingFromActiveTask) { + d->reorderTimer->stop(); + invalidate(); + } else { + d->reorderTimer->start(); + } + } + }); + + QObject::connect(d->reorderTimer, &QTimer::timeout, this, [this] { + if (d->switchingFromActiveTask) { + d->switchingFromActiveTask = false; + invalidate(); + } + }); + } d->sortMode = mode; - d->forceResort(); + invalidate(); Q_EMIT sortModeChanged(); } @@ -1229,7 +1270,7 @@ void TasksModel::setSeparateLaunchers(bool separate) d->separateLaunchers = separate; d->updateManualSortMap(); - d->forceResort(); + invalidate(); Q_EMIT separateLaunchersChanged(); } @@ -1245,7 +1286,7 @@ void TasksModel::setLaunchInPlace(bool launchInPlace) if (d->launchInPlace != launchInPlace) { d->launchInPlace = launchInPlace; - d->forceResort(); + invalidate(); Q_EMIT launchInPlaceChanged(); } @@ -1365,7 +1406,7 @@ bool TasksModel::requestAddLauncher(const QUrl &url) // their launcher position now. if (added && d->sortMode == SortManual && (d->launchInPlace || !d->separateLaunchers)) { d->updateManualSortMap(); - d->forceResort(); + invalidate(); } return added; @@ -1381,7 +1422,7 @@ bool TasksModel::requestRemoveLauncher(const QUrl &url) // longer backed by a launcher out of the launcher area. if (removed && d->sortMode == SortManual && (d->launchInPlace || !d->separateLaunchers)) { d->updateManualSortMap(); - d->forceResort(); + invalidate(); } return removed; @@ -1401,7 +1442,7 @@ bool TasksModel::requestAddLauncherToActivity(const QUrl &url, const QString &ac // their launcher position now. if (added && d->sortMode == SortManual && (d->launchInPlace || !d->separateLaunchers)) { d->updateManualSortMap(); - d->forceResort(); + invalidate(); } return added; @@ -1417,7 +1458,7 @@ bool TasksModel::requestRemoveLauncherFromActivity(const QUrl &url, const QStrin // longer backed by a launcher out of the launcher area. if (removed && d->sortMode == SortManual && (d->launchInPlace || !d->separateLaunchers)) { d->updateManualSortMap(); - d->forceResort(); + invalidate(); } return removed; @@ -1549,6 +1590,21 @@ void TasksModel::requestActivities(const QModelIndex &index, const QStringList & } } +void TasksModel::requestLastActivatedReorderDelay(int delay) +{ + if (d->sortMode == SortMode::SortLastActivated) { + if (delay > 0) { + if (d->reorderTimer->interval() != delay) { + d->reorderTimer->setInterval(delay); + } + + d->switchingFromActiveTask = true; + } else { + d->switchingFromActiveTask = false; + } + } +} + void TasksModel::requestPublishDelegateGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate) { if (index.isValid() && index.model() == this) { @@ -1672,7 +1728,7 @@ bool TasksModel::move(int row, int newPos, const QModelIndex &parent) } // Resort. - d->forceResort(); + invalidate(); if (!d->separateLaunchers && isLauncherMove) { const QModelIndex &idx = d->concatProxyModel->index(d->sortedPreFilterRows.at(newPos), 0); diff --git a/libtaskmanager/tasksmodel.h b/libtaskmanager/tasksmodel.h index 6f4e8f5cc..fd5593203 100644 --- a/libtaskmanager/tasksmodel.h +++ b/libtaskmanager/tasksmodel.h @@ -81,6 +81,7 @@ public: SortAlpha, /**< Tasks are sorted alphabetically, by AbstractTasksModel::AppName and Qt::DisplayRole. */ SortVirtualDesktop, /**< Tasks are sorted by the virtual desktop they are on. */ SortActivity, /**< Tasks are sorted by the number of tasks on the activities they're on. */ + SortLastActivated, /**< Tasks are sorted by the last time they were active. */ }; Q_ENUM(SortMode) @@ -770,6 +771,15 @@ public: **/ Q_INVOKABLE void requestActivities(const QModelIndex &index, const QStringList &activities) override; + /** + * Request setting or disabling a delay before the reorder phase. + * + * If the current sort mode is not SortLastActivated this function does nothing. + * + * @param delay delay interval in ms, delay disabled if 0 + **/ + Q_INVOKABLE void requestLastActivatedReorderDelay(int delay); + /** * Request informing the window manager of new geometry for a visual * delegate for the task at the given index. The geometry should be in