Changeset View
Changeset View
Standalone View
Standalone View
libtaskmanager/tasksmodel.cpp
Show All 15 Lines | |||||
16 | 16 | | |||
17 | You should have received a copy of the GNU Lesser General Public | 17 | You should have received a copy of the GNU Lesser General Public | ||
18 | License along with this library. If not, see <http://www.gnu.org/licenses/>. | 18 | License along with this library. If not, see <http://www.gnu.org/licenses/>. | ||
19 | *********************************************************************/ | 19 | *********************************************************************/ | ||
20 | 20 | | |||
21 | #include "tasksmodel.h" | 21 | #include "tasksmodel.h" | ||
22 | #include "activityinfo.h" | 22 | #include "activityinfo.h" | ||
23 | #include "concatenatetasksproxymodel.h" | 23 | #include "concatenatetasksproxymodel.h" | ||
24 | #include "flattentaskgroupsproxymodel.h" | ||||
24 | #include "taskfilterproxymodel.h" | 25 | #include "taskfilterproxymodel.h" | ||
25 | #include "taskgroupingproxymodel.h" | 26 | #include "taskgroupingproxymodel.h" | ||
26 | #include "tasktools.h" | 27 | #include "tasktools.h" | ||
27 | 28 | | |||
28 | #include <config-X11.h> | 29 | #include <config-X11.h> | ||
29 | 30 | | |||
30 | #include "launchertasksmodel.h" | 31 | #include "launchertasksmodel.h" | ||
31 | #include "waylandtasksmodel.h" | 32 | #include "waylandtasksmodel.h" | ||
Show All 26 Lines | 55 | public: | |||
58 | static int instanceCount; | 59 | static int instanceCount; | ||
59 | 60 | | |||
60 | static AbstractTasksModel* windowTasksModel; | 61 | static AbstractTasksModel* windowTasksModel; | ||
61 | static StartupTasksModel* startupTasksModel; | 62 | static StartupTasksModel* startupTasksModel; | ||
62 | LauncherTasksModel* launcherTasksModel = nullptr; | 63 | LauncherTasksModel* launcherTasksModel = nullptr; | ||
63 | ConcatenateTasksProxyModel* concatProxyModel = nullptr; | 64 | ConcatenateTasksProxyModel* concatProxyModel = nullptr; | ||
64 | TaskFilterProxyModel* filterProxyModel = nullptr; | 65 | TaskFilterProxyModel* filterProxyModel = nullptr; | ||
65 | TaskGroupingProxyModel* groupingProxyModel = nullptr; | 66 | TaskGroupingProxyModel* groupingProxyModel = nullptr; | ||
67 | FlattenTaskGroupsProxyModel* flattenGroupsProxyModel = nullptr; | ||||
68 | AbstractTasksModelIface *abstractTasksSourceModel = nullptr; | ||||
66 | 69 | | |||
67 | bool anyTaskDemandsAttention = false; | 70 | bool anyTaskDemandsAttention = false; | ||
68 | 71 | | |||
69 | int launcherCount = 0; | 72 | int launcherCount = 0; | ||
70 | int virtualDesktop = -1; | 73 | int virtualDesktop = -1; | ||
71 | int screen = -1; | 74 | int screen = -1; | ||
72 | QString activity; | 75 | QString activity; | ||
73 | 76 | | |||
74 | SortMode sortMode = SortAlpha; | 77 | SortMode sortMode = SortAlpha; | ||
75 | bool separateLaunchers = true; | 78 | bool separateLaunchers = true; | ||
76 | bool launchInPlace = false; | 79 | bool launchInPlace = false; | ||
77 | bool launcherSortingDirty = false; | 80 | bool launcherSortingDirty = false; | ||
78 | QList<int> sortedPreFilterRows; | 81 | QList<int> sortedPreFilterRows; | ||
79 | QVector<int> sortRowInsertQueue; | 82 | QVector<int> sortRowInsertQueue; | ||
80 | QHash<QString, int> activityTaskCounts; | 83 | QHash<QString, int> activityTaskCounts; | ||
81 | static ActivityInfo* activityInfo; | 84 | static ActivityInfo* activityInfo; | ||
82 | static int activityInfoUsers; | 85 | static int activityInfoUsers; | ||
83 | 86 | | |||
87 | bool groupInline = false; | ||||
88 | int groupingWindowTasksThreshold = -1; | ||||
89 | | ||||
84 | void initModels(); | 90 | void initModels(); | ||
85 | void updateAnyTaskDemandsAttention(); | 91 | void updateAnyTaskDemandsAttention(); | ||
86 | void updateManualSortMap(); | 92 | void updateManualSortMap(); | ||
87 | void syncManualSortMapForGroup(const QModelIndex &parent); | 93 | void consolidateManualSortMapForGroup(const QModelIndex &groupingProxyIndex); | ||
94 | void updateGroupInline(); | ||||
88 | QModelIndex preFilterIndex(const QModelIndex &sourceIndex) const; | 95 | QModelIndex preFilterIndex(const QModelIndex &sourceIndex) const; | ||
89 | void updateActivityTaskCounts(); | 96 | void updateActivityTaskCounts(); | ||
90 | void forceResort(); | 97 | void forceResort(); | ||
91 | bool lessThan(const QModelIndex &left, const QModelIndex &right, | 98 | bool lessThan(const QModelIndex &left, const QModelIndex &right, | ||
92 | bool sortOnlyLaunchers = false) const; | 99 | bool sortOnlyLaunchers = false) const; | ||
93 | 100 | | |||
94 | private: | 101 | private: | ||
95 | TasksModel *q; | 102 | TasksModel *q; | ||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Line(s) | 144 | if (!instanceCount) { | |||
143 | activityInfo = nullptr; | 150 | activityInfo = nullptr; | ||
144 | } | 151 | } | ||
145 | } | 152 | } | ||
146 | 153 | | |||
147 | void TasksModel::Private::initModels() | 154 | void TasksModel::Private::initModels() | ||
148 | { | 155 | { | ||
149 | // NOTE: Overview over the entire model chain assembled here: | 156 | // NOTE: Overview over the entire model chain assembled here: | ||
150 | // {X11,Wayland}WindowTasksModel, StartupTasksModel, LauncherTasksModel | 157 | // {X11,Wayland}WindowTasksModel, StartupTasksModel, LauncherTasksModel | ||
151 | // -> ConcatenateTasksProxyModel concatenates them into a single list. | 158 | // -> concatProxyModel concatenates them into a single list. | ||
152 | // -> TaskFilterProxyModel filters by state (e.g. virtual desktop). | 159 | // -> filterProxyModel filters by state (e.g. virtual desktop). | ||
153 | // -> TaskGroupingProxyModel groups by application (we go from flat list to tree). | 160 | // -> groupingProxyModel groups by application (we go from flat list to tree). | ||
154 | // -> TasksModel collapses top-level items into task lifecycle abstraction, sorts. | 161 | // -> flattenGroupsProxyModel (optionally, if groupInline == true) flattens groups out. | ||
162 | // -> TasksModel collapses (top-level) items into task lifecycle abstraction; sorts. | ||||
155 | 163 | | |||
156 | if (!windowTasksModel && QGuiApplication::platformName().startsWith(QLatin1String("wayland"))) { | 164 | if (!windowTasksModel && QGuiApplication::platformName().startsWith(QLatin1String("wayland"))) { | ||
157 | windowTasksModel = new WaylandTasksModel(); | 165 | windowTasksModel = new WaylandTasksModel(); | ||
158 | } | 166 | } | ||
159 | 167 | | |||
160 | #if HAVE_X11 | 168 | #if HAVE_X11 | ||
161 | if (!windowTasksModel && QX11Info::isPlatformX11()) { | 169 | if (!windowTasksModel && QX11Info::isPlatformX11()) { | ||
162 | windowTasksModel = new XWindowTasksModel(); | 170 | windowTasksModel = new XWindowTasksModel(); | ||
▲ Show 20 Lines • Show All 134 Lines • ▼ Show 20 Line(s) | 304 | QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByActivityChanged, | |||
297 | q, &TasksModel::filterByActivityChanged); | 305 | q, &TasksModel::filterByActivityChanged); | ||
298 | QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterNotMinimizedChanged, | 306 | QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterNotMinimizedChanged, | ||
299 | q, &TasksModel::filterNotMinimizedChanged); | 307 | q, &TasksModel::filterNotMinimizedChanged); | ||
300 | 308 | | |||
301 | groupingProxyModel = new TaskGroupingProxyModel(q); | 309 | groupingProxyModel = new TaskGroupingProxyModel(q); | ||
302 | groupingProxyModel->setSourceModel(filterProxyModel); | 310 | groupingProxyModel->setSourceModel(filterProxyModel); | ||
303 | QObject::connect(groupingProxyModel, &TaskGroupingProxyModel::groupModeChanged, | 311 | QObject::connect(groupingProxyModel, &TaskGroupingProxyModel::groupModeChanged, | ||
304 | q, &TasksModel::groupModeChanged); | 312 | q, &TasksModel::groupModeChanged); | ||
305 | QObject::connect(groupingProxyModel, &TaskGroupingProxyModel::windowTasksThresholdChanged, | | |||
306 | q, &TasksModel::groupingWindowTasksThresholdChanged); | | |||
307 | QObject::connect(groupingProxyModel, &TaskGroupingProxyModel::blacklistedAppIdsChanged, | 313 | QObject::connect(groupingProxyModel, &TaskGroupingProxyModel::blacklistedAppIdsChanged, | ||
308 | q, &TasksModel::groupingAppIdBlacklistChanged); | 314 | q, &TasksModel::groupingAppIdBlacklistChanged); | ||
309 | QObject::connect(groupingProxyModel, &TaskGroupingProxyModel::blacklistedLauncherUrlsChanged, | 315 | QObject::connect(groupingProxyModel, &TaskGroupingProxyModel::blacklistedLauncherUrlsChanged, | ||
310 | q, &TasksModel::groupingLauncherUrlBlacklistChanged); | 316 | q, &TasksModel::groupingLauncherUrlBlacklistChanged); | ||
311 | 317 | | |||
312 | QObject::connect(groupingProxyModel, &QAbstractItemModel::rowsInserted, q, | 318 | QObject::connect(groupingProxyModel, &QAbstractItemModel::rowsInserted, q, | ||
313 | [this](const QModelIndex &parent, int first, int last) { | 319 | [this](const QModelIndex &parent, int first, int last) { | ||
314 | // We can ignore group members. | | |||
315 | if (parent.isValid()) { | 320 | if (parent.isValid()) { | ||
321 | consolidateManualSortMapForGroup(parent); | ||||
322 | | ||||
323 | // Existence of a group means everything below this has already been done. | ||||
316 | return; | 324 | return; | ||
317 | } | 325 | } | ||
318 | 326 | | |||
319 | for (int i = first; i <= last; ++i) { | 327 | for (int i = first; i <= last; ++i) { | ||
320 | const QModelIndex &sourceIndex = groupingProxyModel->index(i, 0); | 328 | const QModelIndex &sourceIndex = groupingProxyModel->index(i, 0); | ||
321 | const QString &appId = sourceIndex.data(AbstractTasksModel::AppId).toString(); | 329 | const QString &appId = sourceIndex.data(AbstractTasksModel::AppId).toString(); | ||
322 | 330 | | |||
323 | if (sourceIndex.data(AbstractTasksModel::IsDemandingAttention).toBool()) { | 331 | if (sourceIndex.data(AbstractTasksModel::IsDemandingAttention).toBool()) { | ||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Line(s) | |||||
395 | ); | 403 | ); | ||
396 | 404 | | |||
397 | // Update anyTaskDemandsAttention on source data changes. | 405 | // Update anyTaskDemandsAttention on source data changes. | ||
398 | QObject::connect(groupingProxyModel, &QAbstractItemModel::dataChanged, q, | 406 | QObject::connect(groupingProxyModel, &QAbstractItemModel::dataChanged, q, | ||
399 | [this](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) { | 407 | [this](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) { | ||
400 | Q_UNUSED(bottomRight) | 408 | Q_UNUSED(bottomRight) | ||
401 | 409 | | |||
402 | // We can ignore group members. | 410 | // We can ignore group members. | ||
403 | if (topLeft.isValid()) { | 411 | if (topLeft.parent().isValid()) { | ||
404 | return; | 412 | return; | ||
405 | } | 413 | } | ||
406 | 414 | | |||
407 | if (roles.isEmpty() || roles.contains(AbstractTasksModel::IsDemandingAttention)) { | 415 | if (roles.isEmpty() || roles.contains(AbstractTasksModel::IsDemandingAttention)) { | ||
408 | updateAnyTaskDemandsAttention(); | 416 | updateAnyTaskDemandsAttention(); | ||
409 | } | 417 | } | ||
410 | } | 418 | } | ||
411 | ); | 419 | ); | ||
412 | 420 | | |||
413 | // Update anyTaskDemandsAttention on source model resets. | 421 | // Update anyTaskDemandsAttention on source model resets. | ||
414 | QObject::connect(groupingProxyModel, &QAbstractItemModel::modelReset, q, | 422 | QObject::connect(groupingProxyModel, &QAbstractItemModel::modelReset, q, | ||
415 | [this]() { updateAnyTaskDemandsAttention(); } | 423 | [this]() { updateAnyTaskDemandsAttention(); } | ||
416 | ); | 424 | ); | ||
417 | 425 | | |||
426 | abstractTasksSourceModel = groupingProxyModel; | ||||
418 | q->setSourceModel(groupingProxyModel); | 427 | q->setSourceModel(groupingProxyModel); | ||
419 | 428 | | |||
420 | QObject::connect(q, &QAbstractItemModel::rowsInserted, q, | 429 | QObject::connect(q, &QAbstractItemModel::rowsInserted, q, &TasksModel::countChanged); | ||
421 | [this](const QModelIndex &parent, int first, int last) { | | |||
422 | Q_UNUSED(first) | | |||
423 | Q_UNUSED(last) | | |||
424 | | ||||
425 | q->countChanged(); | | |||
426 | | ||||
427 | // If we're in manual sort mode, we need to consolidate new children | | |||
428 | // of a group in the manual sort map to prepare for when a group | | |||
429 | // gets dissolved. | | |||
430 | // This is done after we've already had a chance to sort the new child | | |||
431 | // in alphabetically in this proxy. | | |||
432 | if (sortMode == SortManual && parent.isValid()) { | | |||
433 | syncManualSortMapForGroup(parent); | | |||
434 | } | | |||
435 | } | | |||
436 | ); | | |||
437 | | ||||
438 | | ||||
439 | QObject::connect(q, &QAbstractItemModel::rowsRemoved, q, &TasksModel::countChanged); | 430 | QObject::connect(q, &QAbstractItemModel::rowsRemoved, q, &TasksModel::countChanged); | ||
440 | QObject::connect(q, &QAbstractItemModel::modelReset, q, &TasksModel::countChanged); | 431 | QObject::connect(q, &QAbstractItemModel::modelReset, q, &TasksModel::countChanged); | ||
441 | } | 432 | } | ||
442 | 433 | | |||
443 | void TasksModel::Private::updateAnyTaskDemandsAttention() | 434 | void TasksModel::Private::updateAnyTaskDemandsAttention() | ||
444 | { | 435 | { | ||
445 | bool taskFound = false; | 436 | bool taskFound = false; | ||
446 | 437 | | |||
Show All 19 Lines | 454 | if (sortedPreFilterRows.isEmpty()) { | |||
466 | for (int i = 0; i < concatProxyModel->rowCount(); ++i) { | 457 | for (int i = 0; i < concatProxyModel->rowCount(); ++i) { | ||
467 | sortedPreFilterRows.append(i); | 458 | sortedPreFilterRows.append(i); | ||
468 | } | 459 | } | ||
469 | 460 | | |||
470 | // Full sort. | 461 | // Full sort. | ||
471 | TasksModelLessThan lt(concatProxyModel, q, false); | 462 | TasksModelLessThan lt(concatProxyModel, q, false); | ||
472 | std::stable_sort(sortedPreFilterRows.begin(), sortedPreFilterRows.end(), lt); | 463 | std::stable_sort(sortedPreFilterRows.begin(), sortedPreFilterRows.end(), lt); | ||
473 | 464 | | |||
465 | // Consolidate sort map entries for groups. | ||||
466 | if (q->groupMode() != GroupDisabled) { | ||||
467 | for (int i = 0; i < groupingProxyModel->rowCount(); ++i) { | ||||
468 | const QModelIndex &groupingIndex = groupingProxyModel->index(i, 0); | ||||
469 | | ||||
470 | if (groupingIndex.data(AbstractTasksModel::IsGroupParent).toBool()) { | ||||
471 | consolidateManualSortMapForGroup(groupingIndex); | ||||
472 | } | ||||
473 | } | ||||
474 | } | ||||
475 | | ||||
474 | return; | 476 | return; | ||
475 | } | 477 | } | ||
476 | 478 | | |||
477 | // Existing map; check whether launchers need sorting by launcher list position. | 479 | // Existing map; check whether launchers need sorting by launcher list position. | ||
478 | if (separateLaunchers) { | 480 | if (separateLaunchers) { | ||
479 | // Sort only launchers. | 481 | // Sort only launchers. | ||
480 | TasksModelLessThan lt(concatProxyModel, q, true); | 482 | TasksModelLessThan lt(concatProxyModel, q, true); | ||
481 | std::stable_sort(sortedPreFilterRows.begin(), sortedPreFilterRows.end(), lt); | 483 | std::stable_sort(sortedPreFilterRows.begin(), sortedPreFilterRows.end(), lt); | ||
Show All 32 Lines | 513 | if (appsMatch(concatProxyIndex, idx)) { | |||
514 | break; | 516 | break; | ||
515 | } | 517 | } | ||
516 | } | 518 | } | ||
517 | } | 519 | } | ||
518 | } | 520 | } | ||
519 | } | 521 | } | ||
520 | } | 522 | } | ||
521 | 523 | | |||
522 | void TasksModel::Private::syncManualSortMapForGroup(const QModelIndex &parent) | 524 | void TasksModel::Private::consolidateManualSortMapForGroup(const QModelIndex &groupingProxyIndex) | ||
523 | { | 525 | { | ||
524 | const int childCount = q->rowCount(parent); | 526 | // Consolidates sort map entries for a group's items to be contiguous | ||
527 | // after the group's first item and the same order as in groupingProxyModel. | ||||
528 | | ||||
529 | const int childCount = groupingProxyModel->rowCount(groupingProxyIndex); | ||||
525 | 530 | | |||
526 | if (childCount != -1) { | 531 | if (!childCount) { | ||
527 | const QModelIndex &preFilterParent = preFilterIndex(q->mapToSource(parent)); | 532 | return; | ||
533 | } | ||||
534 | | ||||
535 | const QModelIndex &leader = groupingProxyIndex.child(0, 0); | ||||
536 | const QModelIndex &preFilterLeader = filterProxyModel->mapToSource(groupingProxyModel->mapToSource(leader)); | ||||
528 | 537 | | |||
529 | // We're moving the trailing children to the sort map position of | 538 | // We're moving the trailing children to the sort map position of | ||
530 | // the first child, so we're skipping the first child. | 539 | // the first child, so we're skipping the first child. | ||
531 | for (int i = 1; i < childCount; ++i) { | 540 | for (int i = 1; i < childCount; ++i) { | ||
532 | const QModelIndex &preFilterChildIndex = preFilterIndex(q->mapToSource(parent.child(i, 0))); | 541 | const QModelIndex &child = groupingProxyIndex.child(i, 0); | ||
533 | const int childSortIndex = sortedPreFilterRows.indexOf(preFilterChildIndex.row()); | 542 | const QModelIndex &preFilterChild = filterProxyModel->mapToSource(groupingProxyModel->mapToSource(child)); | ||
534 | const int parentSortIndex = sortedPreFilterRows.indexOf(preFilterParent.row()); | 543 | const int leaderPos = sortedPreFilterRows.indexOf(preFilterLeader.row()); | ||
535 | const int insertPos = (parentSortIndex + i) + ((parentSortIndex + i) > childSortIndex ? -1 : 0); | 544 | const int childPos = sortedPreFilterRows.indexOf(preFilterChild.row()); | ||
536 | sortedPreFilterRows.move(childSortIndex, insertPos); | 545 | const int insertPos = (leaderPos + i) + ((leaderPos + i) > childPos ? -1 : 0); | ||
546 | sortedPreFilterRows.move(childPos, insertPos); | ||||
547 | } | ||||
548 | } | ||||
549 | | ||||
550 | void TasksModel::Private::updateGroupInline() | ||||
551 | { | ||||
552 | if (q->groupMode() != GroupDisabled && groupInline) { | ||||
553 | if (flattenGroupsProxyModel) { | ||||
554 | return; | ||||
555 | } | ||||
556 | | ||||
557 | // Exempting tasks which demand attention from grouping is not | ||||
558 | // necessary when all group children are shown inline anyway | ||||
559 | // and would interfere with our sort-tasks-together goals. | ||||
560 | groupingProxyModel->setGroupDemandingAttention(true); | ||||
561 | | ||||
562 | // Likewise, ignore the window tasks threshold when making | ||||
563 | // grouping decisions. | ||||
564 | groupingProxyModel->setWindowTasksThreshold(-1); | ||||
565 | | ||||
566 | flattenGroupsProxyModel = new FlattenTaskGroupsProxyModel(q); | ||||
567 | flattenGroupsProxyModel->setSourceModel(groupingProxyModel); | ||||
568 | | ||||
569 | abstractTasksSourceModel = flattenGroupsProxyModel; | ||||
570 | q->setSourceModel(flattenGroupsProxyModel); | ||||
571 | | ||||
572 | if (sortMode == SortManual) { | ||||
573 | forceResort(); | ||||
574 | } | ||||
575 | } else { | ||||
576 | if (!flattenGroupsProxyModel) { | ||||
577 | return; | ||||
578 | } | ||||
579 | | ||||
580 | groupingProxyModel->setGroupDemandingAttention(false); | ||||
581 | groupingProxyModel->setWindowTasksThreshold(groupingWindowTasksThreshold); | ||||
582 | | ||||
583 | abstractTasksSourceModel = groupingProxyModel; | ||||
584 | q->setSourceModel(groupingProxyModel); | ||||
585 | | ||||
586 | delete flattenGroupsProxyModel; | ||||
587 | flattenGroupsProxyModel = nullptr; | ||||
588 | | ||||
589 | if (sortMode == SortManual) { | ||||
590 | forceResort(); | ||||
537 | } | 591 | } | ||
538 | } | 592 | } | ||
539 | } | 593 | } | ||
540 | 594 | | |||
541 | QModelIndex TasksModel::Private::preFilterIndex(const QModelIndex &sourceIndex) const { | 595 | QModelIndex TasksModel::Private::preFilterIndex(const QModelIndex &sourceIndex) const { | ||
596 | // Only in inline grouping mode, we have an additional proxy layer. | ||||
597 | if (flattenGroupsProxyModel) { | ||||
598 | return filterProxyModel->mapToSource(groupingProxyModel->mapToSource(flattenGroupsProxyModel->mapToSource(sourceIndex))); | ||||
599 | } else { | ||||
542 | return filterProxyModel->mapToSource(groupingProxyModel->mapToSource(sourceIndex)); | 600 | return filterProxyModel->mapToSource(groupingProxyModel->mapToSource(sourceIndex)); | ||
543 | } | 601 | } | ||
602 | } | ||||
544 | 603 | | |||
545 | void TasksModel::Private::updateActivityTaskCounts() | 604 | void TasksModel::Private::updateActivityTaskCounts() | ||
546 | { | 605 | { | ||
547 | // Collects the number of window tasks on each activity. | 606 | // Collects the number of window tasks on each activity. | ||
548 | 607 | | |||
549 | activityTaskCounts.clear(); | 608 | activityTaskCounts.clear(); | ||
550 | 609 | | |||
551 | if (!windowTasksModel || !activityInfo) { | 610 | if (!windowTasksModel || !activityInfo) { | ||
▲ Show 20 Lines • Show All 180 Lines • ▼ Show 20 Line(s) | |||||
732 | { | 791 | { | ||
733 | return QSortFilterProxyModel::rowCount(parent); | 792 | return QSortFilterProxyModel::rowCount(parent); | ||
734 | } | 793 | } | ||
735 | 794 | | |||
736 | void TasksModel::updateLauncherCount() | 795 | void TasksModel::updateLauncherCount() | ||
737 | { | 796 | { | ||
738 | QList<QUrl> launchers = QUrl::fromStringList(d->launcherTasksModel->launcherList()); | 797 | QList<QUrl> launchers = QUrl::fromStringList(d->launcherTasksModel->launcherList()); | ||
739 | 798 | | |||
740 | for(int i = 0; i < d->filterProxyModel->rowCount(); ++i) { | 799 | for (int i = 0; i < d->filterProxyModel->rowCount(); ++i) { | ||
741 | const QModelIndex &filterIndex = d->filterProxyModel->index(i, 0); | 800 | const QModelIndex &filterIndex = d->filterProxyModel->index(i, 0); | ||
742 | 801 | | |||
743 | if (!filterIndex.data(AbstractTasksModel::IsLauncher).toBool()) { | 802 | if (!filterIndex.data(AbstractTasksModel::IsLauncher).toBool()) { | ||
744 | // TODO: It would be much faster if we didn't ask for a URL with serialized PNG data in it, just to discard it a few lines below | 803 | // TODO: It would be much faster if we didn't ask for a URL with serialized PNG | ||
804 | // data in it, just to discard it a few lines below. | ||||
745 | const QUrl &launcherUrl = filterIndex.data(AbstractTasksModel::LauncherUrl).toUrl(); | 805 | const QUrl &launcherUrl = filterIndex.data(AbstractTasksModel::LauncherUrl).toUrl(); | ||
746 | 806 | | |||
747 | QMutableListIterator<QUrl> it(launchers); | 807 | QMutableListIterator<QUrl> it(launchers); | ||
748 | 808 | | |||
749 | while(it.hasNext()) { | 809 | while(it.hasNext()) { | ||
750 | it.next(); | 810 | it.next(); | ||
751 | 811 | | |||
752 | if (launcherUrlsMatch(launcherUrl, it.value(), IgnoreQueryItems)) { | 812 | if (launcherUrlsMatch(launcherUrl, it.value(), IgnoreQueryItems)) { | ||
▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Line(s) | |||||
892 | 952 | | |||
893 | void TasksModel::setSeparateLaunchers(bool separate) | 953 | void TasksModel::setSeparateLaunchers(bool separate) | ||
894 | { | 954 | { | ||
895 | return; // FIXME TODO: Disable until done. | 955 | return; // FIXME TODO: Disable until done. | ||
896 | 956 | | |||
897 | if (d->separateLaunchers != separate) { | 957 | if (d->separateLaunchers != separate) { | ||
898 | d->separateLaunchers = separate; | 958 | d->separateLaunchers = separate; | ||
899 | 959 | | |||
960 | d->updateManualSortMap(); | ||||
900 | d->forceResort(); | 961 | d->forceResort(); | ||
901 | 962 | | |||
902 | emit separateLaunchersChanged(); | 963 | emit separateLaunchersChanged(); | ||
903 | } | 964 | } | ||
904 | } | 965 | } | ||
905 | 966 | | |||
906 | bool TasksModel::launchInPlace() const | 967 | bool TasksModel::launchInPlace() const | ||
907 | { | 968 | { | ||
Show All 18 Lines | 984 | { | |||
926 | } | 987 | } | ||
927 | 988 | | |||
928 | return d->groupingProxyModel->groupMode(); | 989 | return d->groupingProxyModel->groupMode(); | ||
929 | } | 990 | } | ||
930 | 991 | | |||
931 | void TasksModel::setGroupMode(GroupMode mode) | 992 | void TasksModel::setGroupMode(GroupMode mode) | ||
932 | { | 993 | { | ||
933 | if (d->groupingProxyModel) { | 994 | if (d->groupingProxyModel) { | ||
995 | if (mode == GroupDisabled && d->flattenGroupsProxyModel) { | ||||
996 | d->flattenGroupsProxyModel->setSourceModel(nullptr); | ||||
997 | } | ||||
998 | | ||||
934 | d->groupingProxyModel->setGroupMode(mode); | 999 | d->groupingProxyModel->setGroupMode(mode); | ||
1000 | d->updateGroupInline(); | ||||
935 | } | 1001 | } | ||
936 | } | 1002 | } | ||
937 | 1003 | | |||
938 | int TasksModel::groupingWindowTasksThreshold() const | 1004 | bool TasksModel::groupInline() const | ||
939 | { | 1005 | { | ||
940 | if (!d->groupingProxyModel) { | 1006 | return d->groupInline; | ||
941 | return -1; | | |||
942 | } | 1007 | } | ||
943 | 1008 | | |||
944 | return d->groupingProxyModel->windowTasksThreshold(); | 1009 | void TasksModel::setGroupInline(bool groupInline) | ||
1010 | { | ||||
1011 | if (d->groupInline != groupInline) { | ||||
1012 | d->groupInline = groupInline; | ||||
1013 | | ||||
1014 | d->updateGroupInline(); | ||||
1015 | | ||||
1016 | emit groupInlineChanged(); | ||||
1017 | } | ||||
1018 | } | ||||
1019 | | ||||
1020 | int TasksModel::groupingWindowTasksThreshold() const | ||||
1021 | { | ||||
1022 | return d->groupingWindowTasksThreshold; | ||||
945 | } | 1023 | } | ||
946 | 1024 | | |||
947 | void TasksModel::setGroupingWindowTasksThreshold(int threshold) | 1025 | void TasksModel::setGroupingWindowTasksThreshold(int threshold) | ||
948 | { | 1026 | { | ||
949 | if (d->groupingProxyModel) { | 1027 | if (d->groupingWindowTasksThreshold != threshold) { | ||
1028 | d->groupingWindowTasksThreshold = threshold; | ||||
1029 | | ||||
1030 | if (!d->groupInline && d->groupingProxyModel) { | ||||
950 | d->groupingProxyModel->setWindowTasksThreshold(threshold); | 1031 | d->groupingProxyModel->setWindowTasksThreshold(threshold); | ||
951 | } | 1032 | } | ||
1033 | | ||||
1034 | emit groupingWindowTasksThresholdChanged(); | ||||
1035 | } | ||||
952 | } | 1036 | } | ||
953 | 1037 | | |||
954 | QStringList TasksModel::groupingAppIdBlacklist() const | 1038 | QStringList TasksModel::groupingAppIdBlacklist() const | ||
955 | { | 1039 | { | ||
956 | if (!d->groupingProxyModel) { | 1040 | if (!d->groupingProxyModel) { | ||
957 | return QStringList(); | 1041 | return QStringList(); | ||
958 | } | 1042 | } | ||
959 | 1043 | | |||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Line(s) | 1115 | { | |||
1034 | } | 1118 | } | ||
1035 | 1119 | | |||
1036 | return -1; | 1120 | return -1; | ||
1037 | } | 1121 | } | ||
1038 | 1122 | | |||
1039 | void TasksModel::requestActivate(const QModelIndex &index) | 1123 | void TasksModel::requestActivate(const QModelIndex &index) | ||
1040 | { | 1124 | { | ||
1041 | if (index.isValid() && index.model() == this) { | 1125 | if (index.isValid() && index.model() == this) { | ||
1042 | d->groupingProxyModel->requestActivate(mapToSource(index)); | 1126 | d->abstractTasksSourceModel->requestActivate(mapToSource(index)); | ||
1043 | } | 1127 | } | ||
1044 | } | 1128 | } | ||
1045 | 1129 | | |||
1046 | void TasksModel::requestNewInstance(const QModelIndex &index) | 1130 | void TasksModel::requestNewInstance(const QModelIndex &index) | ||
1047 | { | 1131 | { | ||
1048 | if (index.isValid() && index.model() == this) { | 1132 | if (index.isValid() && index.model() == this) { | ||
1049 | d->groupingProxyModel->requestNewInstance(mapToSource(index)); | 1133 | d->abstractTasksSourceModel->requestNewInstance(mapToSource(index)); | ||
1050 | } | 1134 | } | ||
1051 | } | 1135 | } | ||
1052 | 1136 | | |||
1053 | void TasksModel::requestClose(const QModelIndex &index) | 1137 | void TasksModel::requestClose(const QModelIndex &index) | ||
1054 | { | 1138 | { | ||
1055 | if (index.isValid() && index.model() == this) { | 1139 | if (index.isValid() && index.model() == this) { | ||
1056 | d->groupingProxyModel->requestClose(mapToSource(index)); | 1140 | d->abstractTasksSourceModel->requestClose(mapToSource(index)); | ||
1057 | } | 1141 | } | ||
1058 | } | 1142 | } | ||
1059 | 1143 | | |||
1060 | void TasksModel::requestMove(const QModelIndex &index) | 1144 | void TasksModel::requestMove(const QModelIndex &index) | ||
1061 | { | 1145 | { | ||
1062 | if (index.isValid() && index.model() == this) { | 1146 | if (index.isValid() && index.model() == this) { | ||
1063 | d->groupingProxyModel->requestMove(mapToSource(index)); | 1147 | d->abstractTasksSourceModel->requestMove(mapToSource(index)); | ||
1064 | } | 1148 | } | ||
1065 | } | 1149 | } | ||
1066 | 1150 | | |||
1067 | void TasksModel::requestResize(const QModelIndex &index) | 1151 | void TasksModel::requestResize(const QModelIndex &index) | ||
1068 | { | 1152 | { | ||
1069 | if (index.isValid() && index.model() == this) { | 1153 | if (index.isValid() && index.model() == this) { | ||
1070 | d->groupingProxyModel->requestResize(mapToSource(index)); | 1154 | d->abstractTasksSourceModel->requestResize(mapToSource(index)); | ||
1071 | } | 1155 | } | ||
1072 | } | 1156 | } | ||
1073 | 1157 | | |||
1074 | void TasksModel::requestToggleMinimized(const QModelIndex &index) | 1158 | void TasksModel::requestToggleMinimized(const QModelIndex &index) | ||
1075 | { | 1159 | { | ||
1076 | if (index.isValid() && index.model() == this) { | 1160 | if (index.isValid() && index.model() == this) { | ||
1077 | d->groupingProxyModel->requestToggleMinimized(mapToSource(index)); | 1161 | d->abstractTasksSourceModel->requestToggleMinimized(mapToSource(index)); | ||
1078 | } | 1162 | } | ||
1079 | } | 1163 | } | ||
1080 | 1164 | | |||
1081 | void TasksModel::requestToggleMaximized(const QModelIndex &index) | 1165 | void TasksModel::requestToggleMaximized(const QModelIndex &index) | ||
1082 | { | 1166 | { | ||
1083 | if (index.isValid() && index.model() == this) { | 1167 | if (index.isValid() && index.model() == this) { | ||
1084 | d->groupingProxyModel->requestToggleMaximized(mapToSource(index)); | 1168 | d->abstractTasksSourceModel->requestToggleMaximized(mapToSource(index)); | ||
1085 | } | 1169 | } | ||
1086 | } | 1170 | } | ||
1087 | 1171 | | |||
1088 | void TasksModel::requestToggleKeepAbove(const QModelIndex &index) | 1172 | void TasksModel::requestToggleKeepAbove(const QModelIndex &index) | ||
1089 | { | 1173 | { | ||
1090 | if (index.isValid() && index.model() == this) { | 1174 | if (index.isValid() && index.model() == this) { | ||
1091 | d->groupingProxyModel->requestToggleKeepAbove(mapToSource(index)); | 1175 | d->abstractTasksSourceModel->requestToggleKeepAbove(mapToSource(index)); | ||
1092 | } | 1176 | } | ||
1093 | } | 1177 | } | ||
1094 | 1178 | | |||
1095 | void TasksModel::requestToggleKeepBelow(const QModelIndex &index) | 1179 | void TasksModel::requestToggleKeepBelow(const QModelIndex &index) | ||
1096 | { | 1180 | { | ||
1097 | if (index.isValid() && index.model() == this) { | 1181 | if (index.isValid() && index.model() == this) { | ||
1098 | d->groupingProxyModel->requestToggleKeepBelow(mapToSource(index)); | 1182 | d->abstractTasksSourceModel->requestToggleKeepBelow(mapToSource(index)); | ||
1099 | } | 1183 | } | ||
1100 | } | 1184 | } | ||
1101 | 1185 | | |||
1102 | void TasksModel::requestToggleFullScreen(const QModelIndex &index) | 1186 | void TasksModel::requestToggleFullScreen(const QModelIndex &index) | ||
1103 | { | 1187 | { | ||
1104 | if (index.isValid() && index.model() == this) { | 1188 | if (index.isValid() && index.model() == this) { | ||
1105 | d->groupingProxyModel->requestToggleFullScreen(mapToSource(index)); | 1189 | d->abstractTasksSourceModel->requestToggleFullScreen(mapToSource(index)); | ||
1106 | } | 1190 | } | ||
1107 | } | 1191 | } | ||
1108 | 1192 | | |||
1109 | void TasksModel::requestToggleShaded(const QModelIndex &index) | 1193 | void TasksModel::requestToggleShaded(const QModelIndex &index) | ||
1110 | { | 1194 | { | ||
1111 | if (index.isValid() && index.model() == this) { | 1195 | if (index.isValid() && index.model() == this) { | ||
1112 | d->groupingProxyModel->requestToggleShaded(mapToSource(index)); | 1196 | d->abstractTasksSourceModel->requestToggleShaded(mapToSource(index)); | ||
1113 | } | 1197 | } | ||
1114 | } | 1198 | } | ||
1115 | 1199 | | |||
1116 | void TasksModel::requestVirtualDesktop(const QModelIndex &index, qint32 desktop) | 1200 | void TasksModel::requestVirtualDesktop(const QModelIndex &index, qint32 desktop) | ||
1117 | { | 1201 | { | ||
1118 | if (index.isValid() && index.model() == this) { | 1202 | if (index.isValid() && index.model() == this) { | ||
1119 | d->groupingProxyModel->requestVirtualDesktop(mapToSource(index), desktop); | 1203 | d->abstractTasksSourceModel->requestVirtualDesktop(mapToSource(index), desktop); | ||
1120 | } | 1204 | } | ||
1121 | } | 1205 | } | ||
1122 | 1206 | | |||
1123 | void TasksModel::requestPublishDelegateGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate) | 1207 | void TasksModel::requestPublishDelegateGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate) | ||
1124 | { | 1208 | { | ||
1125 | if (index.isValid() && index.model() == this) { | 1209 | if (index.isValid() && index.model() == this) { | ||
1126 | d->groupingProxyModel->requestPublishDelegateGeometry(mapToSource(index), geometry, delegate); | 1210 | d->abstractTasksSourceModel->requestPublishDelegateGeometry(mapToSource(index), geometry, delegate); | ||
1127 | } | 1211 | } | ||
1128 | } | 1212 | } | ||
1129 | 1213 | | |||
1130 | void TasksModel::requestToggleGrouping(const QModelIndex &index) | 1214 | void TasksModel::requestToggleGrouping(const QModelIndex &index) | ||
1131 | { | 1215 | { | ||
1132 | if (index.isValid() && index.model() == this) { | 1216 | if (index.isValid() && index.model() == this) { | ||
1133 | d->groupingProxyModel->requestToggleGrouping(mapToSource(index)); | 1217 | const QModelIndex &target = (d->flattenGroupsProxyModel | ||
1218 | ? d->flattenGroupsProxyModel->mapToSource(mapToSource(index)) : mapToSource(index)); | ||||
1219 | d->groupingProxyModel->requestToggleGrouping(target); | ||||
1134 | } | 1220 | } | ||
1135 | } | 1221 | } | ||
1136 | 1222 | | |||
1137 | bool TasksModel::move(int row, int newPos) | 1223 | bool TasksModel::move(int row, int newPos) | ||
1138 | { | 1224 | { | ||
1139 | if (d->sortMode != SortManual || row == newPos || newPos < 0 || newPos >= rowCount()) { | 1225 | if (d->sortMode != SortManual || row == newPos || newPos < 0 || newPos >= rowCount()) { | ||
1140 | return false; | 1226 | return false; | ||
1141 | } | 1227 | } | ||
Show All 28 Lines | 1250 | if (d->separateLaunchers) { | |||
1170 | } | 1256 | } | ||
1171 | 1257 | | |||
1172 | // Don't allow tasks to be moved into the launchers. | 1258 | // Don't allow tasks to be moved into the launchers. | ||
1173 | if (!isLauncherMove && newPos < firstTask) { | 1259 | if (!isLauncherMove && newPos < firstTask) { | ||
1174 | return false; | 1260 | return false; | ||
1175 | } | 1261 | } | ||
1176 | } | 1262 | } | ||
1177 | 1263 | | |||
1264 | // Treat flattened-out groups as single items. | ||||
1265 | if (d->flattenGroupsProxyModel) { | ||||
1266 | QModelIndex groupingRowIndex = d->flattenGroupsProxyModel->mapToSource(mapToSource(index(row, 0))); | ||||
1267 | const QModelIndex &groupingRowIndexParent = groupingRowIndex.parent(); | ||||
1268 | QModelIndex groupingNewPosIndex = d->flattenGroupsProxyModel->mapToSource(mapToSource(index(newPos, 0))); | ||||
1269 | const QModelIndex &groupingNewPosIndexParent = groupingNewPosIndex.parent(); | ||||
1270 | | ||||
1271 | // Disallow moves within a flattened-out group (TODO: for now, anyway). | ||||
1272 | if (groupingRowIndexParent.isValid() | ||||
1273 | && (groupingRowIndexParent == groupingNewPosIndex | ||||
1274 | || groupingRowIndexParent == groupingNewPosIndexParent)) { | ||||
1275 | return false; | ||||
1276 | } | ||||
1277 | | ||||
1278 | int offset = 0; | ||||
1279 | int extraChildCount = 0; | ||||
1280 | | ||||
1281 | if (groupingRowIndexParent.isValid()) { | ||||
1282 | offset = groupingRowIndex.row(); | ||||
1283 | extraChildCount = d->groupingProxyModel->rowCount(groupingRowIndexParent) - 1; | ||||
1284 | groupingRowIndex = groupingRowIndexParent; | ||||
1285 | } | ||||
1286 | | ||||
1287 | if (groupingNewPosIndexParent.isValid()) { | ||||
1288 | groupingNewPosIndex = groupingNewPosIndexParent; | ||||
1289 | } | ||||
1290 | | ||||
1291 | beginMoveRows(QModelIndex(), (row - offset), (row - offset) + extraChildCount, | ||||
1292 | QModelIndex(), (newPos > row) ? newPos + 1 : newPos); | ||||
1293 | | ||||
1294 | row = d->sortedPreFilterRows.indexOf(d->filterProxyModel->mapToSource(d->groupingProxyModel->mapToSource(groupingRowIndex)).row()); | ||||
1295 | newPos = d->sortedPreFilterRows.indexOf(d->filterProxyModel->mapToSource(d->groupingProxyModel->mapToSource(groupingNewPosIndex)).row()); | ||||
1296 | | ||||
1297 | // Update sort mappings. | ||||
1298 | d->sortedPreFilterRows.move(row, newPos); | ||||
1299 | | ||||
1300 | if (groupingRowIndexParent.isValid()) { | ||||
1301 | d->consolidateManualSortMapForGroup(groupingRowIndexParent); | ||||
1302 | } | ||||
1303 | | ||||
1304 | if (groupingNewPosIndexParent.isValid()) { | ||||
1305 | d->consolidateManualSortMapForGroup(groupingNewPosIndexParent); | ||||
1306 | } | ||||
1307 | | ||||
1308 | endMoveRows(); | ||||
1309 | } else { | ||||
1178 | beginMoveRows(QModelIndex(), row, row, QModelIndex(), (newPos >row) ? newPos + 1 : newPos); | 1310 | beginMoveRows(QModelIndex(), row, row, QModelIndex(), (newPos >row) ? newPos + 1 : newPos); | ||
1179 | 1311 | | |||
1180 | // Translate to sort map indices. | 1312 | // Translate to sort map indices. | ||
1181 | const QModelIndex &rowIndex = index(row, 0); | 1313 | const QModelIndex &groupingRowIndex = mapToSource(index(row, 0)); | ||
1182 | const QModelIndex &preFilterRowIndex = d->preFilterIndex(mapToSource(rowIndex)); | 1314 | const QModelIndex &preFilterRowIndex = d->preFilterIndex(groupingRowIndex); | ||
1183 | row = d->sortedPreFilterRows.indexOf(preFilterRowIndex.row()); | 1315 | row = d->sortedPreFilterRows.indexOf(preFilterRowIndex.row()); | ||
1184 | newPos = d->sortedPreFilterRows.indexOf(d->preFilterIndex(mapToSource(index(newPos, 0))).row()); | 1316 | newPos = d->sortedPreFilterRows.indexOf(d->preFilterIndex(mapToSource(index(newPos, 0))).row()); | ||
1185 | 1317 | | |||
1186 | // Update sort mapping. | 1318 | // Update sort mapping. | ||
1187 | d->sortedPreFilterRows.move(row, newPos); | 1319 | d->sortedPreFilterRows.move(row, newPos); | ||
1188 | 1320 | | |||
1189 | endMoveRows(); | 1321 | // If we moved a group parent, consolidate sort map for children. | ||
1322 | if (groupMode() != GroupDisabled && d->groupingProxyModel->rowCount(groupingRowIndex)) { | ||||
1323 | d->consolidateManualSortMapForGroup(groupingRowIndex); | ||||
1324 | } | ||||
1190 | 1325 | | |||
1191 | // Move children along with the group. | 1326 | endMoveRows(); | ||
1192 | // This can be safely done after the row move transaction as the sort | | |||
1193 | // map isn't consulted for rows below the top level. | | |||
1194 | if (groupMode() != GroupDisabled && rowCount(rowIndex)) { | | |||
1195 | d->syncManualSortMapForGroup(rowIndex); | | |||
1196 | } | 1327 | } | ||
1197 | 1328 | | |||
1198 | // Resort. | 1329 | // Resort. | ||
1199 | d->forceResort(); | 1330 | d->forceResort(); | ||
1200 | 1331 | | |||
1201 | // Setup for syncLaunchers(). | 1332 | // Setup for syncLaunchers(). | ||
1202 | d->launcherSortingDirty = isLauncherMove; | 1333 | d->launcherSortingDirty = isLauncherMove; | ||
1203 | 1334 | | |||
Show All 25 Lines | 1349 | foreach(const QUrl &launcherUrl, launcherList()) { | |||
1229 | 1360 | | |||
1230 | if (row != -1) { | 1361 | if (row != -1) { | ||
1231 | sortedLaunchers.insert(row, launcherUrl); | 1362 | sortedLaunchers.insert(row, launcherUrl); | ||
1232 | } | 1363 | } | ||
1233 | } | 1364 | } | ||
1234 | 1365 | | |||
1235 | setLauncherList(QUrl::toStringList(sortedLaunchers.values())); | 1366 | setLauncherList(QUrl::toStringList(sortedLaunchers.values())); | ||
1236 | d->launcherSortingDirty = false; | 1367 | d->launcherSortingDirty = false; | ||
1368 | | ||||
1369 | d->updateManualSortMap(); | ||||
1370 | d->forceResort(); | ||||
1237 | } | 1371 | } | ||
1238 | 1372 | | |||
1239 | QModelIndex TasksModel::activeTask() const | 1373 | QModelIndex TasksModel::activeTask() const | ||
1240 | { | 1374 | { | ||
1241 | for (int i = 0; i < rowCount(); ++i) { | 1375 | for (int i = 0; i < rowCount(); ++i) { | ||
1242 | const QModelIndex &idx = index(i, 0); | 1376 | const QModelIndex &idx = index(i, 0); | ||
1243 | 1377 | | |||
1244 | if (idx.data(AbstractTasksModel::IsActive).toBool()) { | 1378 | if (idx.data(AbstractTasksModel::IsActive).toBool()) { | ||
Show All 32 Lines | 1406 | } else { | |||
1277 | } | 1411 | } | ||
1278 | } | 1412 | } | ||
1279 | 1413 | | |||
1280 | return QModelIndex(); | 1414 | return QModelIndex(); | ||
1281 | } | 1415 | } | ||
1282 | 1416 | | |||
1283 | bool TasksModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const | 1417 | bool TasksModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const | ||
1284 | { | 1418 | { | ||
1285 | // All our filtering occurs at the top-level; group children always go through. | 1419 | // All our filtering occurs at the top-level; anything below always | ||
1420 | // goes through. | ||||
1286 | if (sourceParent.isValid()) { | 1421 | if (sourceParent.isValid()) { | ||
1287 | return true; | 1422 | return true; | ||
1288 | } | 1423 | } | ||
1289 | 1424 | | |||
1290 | const QModelIndex &sourceIndex = sourceModel()->index(sourceRow, 0); | 1425 | const QModelIndex &sourceIndex = sourceModel()->index(sourceRow, 0); | ||
1426 | | ||||
1427 | // In inline grouping mode, filter out group parents. | ||||
1428 | if (d->flattenGroupsProxyModel && sourceIndex.data(AbstractTasksModel::IsGroupParent).toBool()) { | ||||
1429 | return false; | ||||
1430 | } | ||||
1431 | | ||||
1291 | const QString &appId = sourceIndex.data(AbstractTasksModel::AppId).toString(); | 1432 | const QString &appId = sourceIndex.data(AbstractTasksModel::AppId).toString(); | ||
1292 | const QString &appName = sourceIndex.data(AbstractTasksModel::AppName).toString(); | 1433 | const QString &appName = sourceIndex.data(AbstractTasksModel::AppName).toString(); | ||
1293 | 1434 | | |||
1294 | // Filter startup tasks we already have a window task for. | 1435 | // Filter startup tasks we already have a window task for. | ||
1295 | if (sourceIndex.data(AbstractTasksModel::IsStartup).toBool()) { | 1436 | if (sourceIndex.data(AbstractTasksModel::IsStartup).toBool()) { | ||
1296 | for (int i = 0; i < d->windowTasksModel->rowCount(); ++i) { | 1437 | for (int i = 0; i < d->windowTasksModel->rowCount(); ++i) { | ||
1297 | const QModelIndex &windowIndex = d->windowTasksModel->index(i, 0); | 1438 | const QModelIndex &windowIndex = d->windowTasksModel->index(i, 0); | ||
1298 | 1439 | | |||
Show All 17 Lines | 1455 | if (!filteredIndex.data(AbstractTasksModel::IsWindow).toBool() && | |||
1316 | continue; | 1457 | continue; | ||
1317 | } | 1458 | } | ||
1318 | 1459 | | |||
1319 | const QString &filteredAppId = filteredIndex.data(AbstractTasksModel::AppId).toString(); | 1460 | const QString &filteredAppId = filteredIndex.data(AbstractTasksModel::AppId).toString(); | ||
1320 | 1461 | | |||
1321 | if ((!appId.isEmpty() && appId == filteredAppId) | 1462 | if ((!appId.isEmpty() && appId == filteredAppId) | ||
1322 | || (launcherUrl.isValid() && launcherUrlsMatch(launcherUrl, | 1463 | || (launcherUrl.isValid() && launcherUrlsMatch(launcherUrl, | ||
1323 | filteredIndex.data(AbstractTasksModel::LauncherUrl).toUrl(), IgnoreQueryItems))) { | 1464 | filteredIndex.data(AbstractTasksModel::LauncherUrl).toUrl(), IgnoreQueryItems))) { | ||
1324 | // TODO: Do this outside of filterAcceptsRow, based on notification that something changed | 1465 | // TODO: Do this outside of filterAcceptsRow, based on notification that something changed. | ||
1325 | QMetaObject::invokeMethod(const_cast<TasksModel *>(this), "updateLauncherCount", Qt::QueuedConnection); | 1466 | QMetaObject::invokeMethod(const_cast<TasksModel *>(this), "updateLauncherCount", Qt::QueuedConnection); | ||
1326 | | ||||
1327 | return false; | 1467 | return false; | ||
1328 | } | 1468 | } | ||
1329 | } | 1469 | } | ||
1330 | } | 1470 | } | ||
1331 | 1471 | | |||
1332 | return true; | 1472 | return true; | ||
1333 | } | 1473 | } | ||
1334 | 1474 | | |||
1335 | bool TasksModel::lessThan(const QModelIndex &left, const QModelIndex &right) const | 1475 | bool TasksModel::lessThan(const QModelIndex &left, const QModelIndex &right) const | ||
1336 | { | 1476 | { | ||
1337 | // In manual sort mode we sort top-level items by referring to a map we keep. | 1477 | // In manual sort mode, sort by map. | ||
1338 | // Insertions into the map are placed using a combination of Private::lessThan | 1478 | if (d->sortMode == SortManual) { | ||
1339 | // and simple append behavior. Child items are sorted alphabetically. | | |||
1340 | if (d->sortMode == SortManual && !left.parent().isValid() && !right.parent().isValid()) { | | |||
1341 | return (d->sortedPreFilterRows.indexOf(d->preFilterIndex(left).row()) | 1479 | return (d->sortedPreFilterRows.indexOf(d->preFilterIndex(left).row()) | ||
1342 | < d->sortedPreFilterRows.indexOf(d->preFilterIndex(right).row())); | 1480 | < d->sortedPreFilterRows.indexOf(d->preFilterIndex(right).row())); | ||
1343 | } | 1481 | } | ||
1344 | 1482 | | |||
1345 | return d->lessThan(left, right); | 1483 | return d->lessThan(left, right); | ||
1346 | } | 1484 | } | ||
1347 | 1485 | | |||
1348 | } | 1486 | } |