From 9f2ede30d24e4c987437e79ac64005e2907eadb3 Mon Sep 17 00:00:00 2001 From: wjyrich Date: Wed, 4 Mar 2026 17:41:44 +0800 Subject: [PATCH] fix: improve window grouping and drag reordering in dock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Fixed window grouping logic to correctly group windows by application after drag reordering 2. Enhanced window insertion algorithm to find the last window of an app even when windows are not consecutive 3. Added moveItem() method to properly handle item movement in the model 4. Connected windowSplitChanged signal to trigger re-grouping when window split mode changes 5. Updated QML drag handlers to use moveItem() when window split is enabled Log: Fixed dock task manager window grouping issues after drag reordering Influence: 1. Test dragging windows in dock when window split is disabled - windows should stay grouped by application 2. Test dragging windows in dock when window split is enabled - windows should move independently 3. Verify that window grouping is maintained after toggling window split mode 4. Test drag and drop reordering of both individual windows and application groups 5. Verify that the dock maintains correct ordering after multiple drag operations fix: 修复任务管理器停靠栏窗口分组和拖拽重排序问题 1. 修复窗口分组逻辑,确保拖拽重排序后窗口能正确按应用程序分组 2. 改进窗口插入算法,即使窗口不连续也能找到应用程序的最后一个窗口 3. 添加 moveItem() 方法以正确处理模型中的项目移动 4. 连接 windowSplitChanged 信号,在窗口分割模式更改时触发重新分组 5. 更新 QML 拖拽处理程序,在窗口分割启用时使用 moveItem() 方法 Log: 修复停靠栏任务管理器拖拽重排序后的窗口分组问题 Influence: 1. 测试在窗口分割禁用时拖拽停靠栏中的窗口 - 窗口应按应用程序保持分组 2. 测试在窗口分割启用时拖拽停靠栏中的窗口 - 窗口应独立移动 3. 验证切换窗口分割模式后窗口分组是否保持正确 4. 测试单个窗口和应用程序组的拖拽重排序功能 5. 验证多次拖拽操作后停靠栏是否保持正确的排序 PMS: BUG-343469 --- .../taskmanager/dockglobalelementmodel.cpp | 59 ++++++++++++++++++- .../dock/taskmanager/dockglobalelementmodel.h | 5 +- panels/dock/taskmanager/dockitemmodel.cpp | 7 +++ .../dock/taskmanager/package/TaskManager.qml | 12 +++- panels/dock/taskmanager/taskmanager.cpp | 8 ++- panels/dock/taskmanager/taskmanager.h | 3 +- 6 files changed, 86 insertions(+), 8 deletions(-) diff --git a/panels/dock/taskmanager/dockglobalelementmodel.cpp b/panels/dock/taskmanager/dockglobalelementmodel.cpp index 0d452b43f..2f0656af3 100644 --- a/panels/dock/taskmanager/dockglobalelementmodel.cpp +++ b/panels/dock/taskmanager/dockglobalelementmodel.cpp @@ -29,6 +29,8 @@ DockGlobalElementModel::DockGlobalElementModel(QAbstractItemModel *appsModel, Do , m_activeAppModel(activeAppModel) { connect(TaskManagerSettings::instance(), &TaskManagerSettings::dockedElementsChanged, this, &DockGlobalElementModel::loadDockedElements); + connect(TaskManagerSettings::instance(), &TaskManagerSettings::windowSplitChanged, this, &DockGlobalElementModel::groupItemsByApp); + connect( m_appsModel, &QAbstractItemModel::rowsRemoved, @@ -96,10 +98,13 @@ DockGlobalElementModel::DockGlobalElementModel(QAbstractItemModel *appsModel, Do } // There are already windows for this app: insert the new window - // right after the last existing one so that all windows stay together. + // right after the last (rightmost) existing one. + // Search the entire list since windows may not be consecutive after drag reorder. auto lastIt = firstIt; - while (lastIt + 1 != m_data.end() && std::get<0>(*(lastIt + 1)) == desktopId) { - ++lastIt; + for (auto it = firstIt + 1; it != m_data.end(); ++it) { + if (std::get<0>(*it) == desktopId) { + lastIt = it; + } } auto insertRow = (lastIt - m_data.begin()) + 1; @@ -487,4 +492,52 @@ void DockGlobalElementModel::requestWindowsView(const QModelIndexList &indexes) { Q_UNUSED(indexes) } + +void DockGlobalElementModel::moveItem(int from, int to) +{ + if (from < 0 || from >= m_data.size() || to < 0 || to >= m_data.size() || from == to) + return; + + int destRow = from < to ? to + 1 : to; + + if (!beginMoveRows(QModelIndex(), from, from, QModelIndex(), destRow)) + return; + + m_data.move(from, to); + endMoveRows(); +} + +void DockGlobalElementModel::groupItemsByApp() +{ + if (m_data.isEmpty()) + return; + + if (TaskManagerSettings::instance()->isWindowSplit()) + return; + + for (int i = 0; i < m_data.size(); ++i) { + const QString currentId = std::get<0>(m_data.at(i)); + + int insertPos = i + 1; + + while (insertPos < m_data.size() && std::get<0>(m_data.at(insertPos)) == currentId) { + ++insertPos; + } + + for (int j = insertPos; j < m_data.size(); ++j) { + if (std::get<0>(m_data.at(j)) != currentId) + continue; + + int destRow = insertPos < j ? insertPos : insertPos + 1; + if (!beginMoveRows(QModelIndex(), j, j, QModelIndex(), destRow)) + continue; + m_data.move(j, insertPos); + endMoveRows(); + + ++insertPos; + } + + i = insertPos - 1; + } +} } diff --git a/panels/dock/taskmanager/dockglobalelementmodel.h b/panels/dock/taskmanager/dockglobalelementmodel.h index 15db77425..64a991bcf 100644 --- a/panels/dock/taskmanager/dockglobalelementmodel.h +++ b/panels/dock/taskmanager/dockglobalelementmodel.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once @@ -36,12 +36,15 @@ class DockGlobalElementModel : public QAbstractListModel, public AbstractTaskMan void requestWindowsView(const QModelIndexList &indexes) const override; + void moveItem(int from, int to); + public slots: void initDockedElements(bool unused); private: void loadDockedElements(); QString getMenus(const QModelIndex &index) const; + void groupItemsByApp(); private: // id, model, and pos diff --git a/panels/dock/taskmanager/dockitemmodel.cpp b/panels/dock/taskmanager/dockitemmodel.cpp index 3c12128ee..d05965260 100644 --- a/panels/dock/taskmanager/dockitemmodel.cpp +++ b/panels/dock/taskmanager/dockitemmodel.cpp @@ -79,6 +79,13 @@ void DockItemModel::setSourceModel(QAbstractItemModel *model) auto last = bottomRight.row(); Q_EMIT dataChanged(index(first, 0), index(last, 0), roles); }); + connect(sourceModel(), &QAbstractItemModel::rowsMoved, this, [this](const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row) { + Q_UNUSED(destination) + if (parent.isValid() || m_isUpdating) + return; + beginMoveRows(QModelIndex(), start, end, QModelIndex(), row); + endMoveRows(); + }); auto bottomRight = this->index(std::min(currentCount, newCount), 0); Q_EMIT dataChanged(index(0, 0), bottomRight); diff --git a/panels/dock/taskmanager/package/TaskManager.qml b/panels/dock/taskmanager/package/TaskManager.qml index 82740dfea..f4f82d2c6 100644 --- a/panels/dock/taskmanager/package/TaskManager.qml +++ b/panels/dock/taskmanager/package/TaskManager.qml @@ -262,7 +262,11 @@ ContainmentItem { let appId = taskmanager.Applet.desktopIdToAppId(launcherDndDesktopId) let currentIndex = taskmanager.Applet.windowSplit ? taskmanager.findAppIndexByWindow(appId, launcherDndWinId) : taskmanager.findAppIndex(appId) if (currentIndex !== -1 && targetIndex !== -1 && currentIndex !== targetIndex) { - visualModel.items.move(currentIndex, targetIndex) + if (taskmanager.Applet.windowSplit) { + taskmanager.Applet.moveItem(currentIndex, targetIndex) + } else { + visualModel.items.move(currentIndex, targetIndex) + } } } @@ -273,7 +277,11 @@ ContainmentItem { let appId = taskmanager.Applet.desktopIdToAppId(launcherDndDesktopId) let currentIndex = taskmanager.Applet.windowSplit ? taskmanager.findAppIndexByWindow(appId, launcherDndWinId) : taskmanager.findAppIndex(appId) if (currentIndex !== -1 && targetIndex !== -1 && currentIndex !== targetIndex) { - visualModel.items.move(currentIndex, targetIndex) + if (taskmanager.Applet.windowSplit) { + taskmanager.Applet.moveItem(currentIndex, targetIndex) + } else { + visualModel.items.move(currentIndex, targetIndex) + } } let appIds = [] for (let i = 0; i < visualModel.items.count; i++) { diff --git a/panels/dock/taskmanager/taskmanager.cpp b/panels/dock/taskmanager/taskmanager.cpp index ea9ac23b3..7d644e460 100644 --- a/panels/dock/taskmanager/taskmanager.cpp +++ b/panels/dock/taskmanager/taskmanager.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -484,6 +484,12 @@ void TaskManager::saveDockElementsOrder(const QStringList &appIds) TaskManagerSettings::instance()->setDockedElements(newDockedElements); } +void TaskManager::moveItem(int from, int to) +{ + if (m_dockGlobalElementModel) + m_dockGlobalElementModel->moveItem(from, to); +} + QString TaskManager::getTrashTipText() { const auto count = queryTrashCount(); diff --git a/panels/dock/taskmanager/taskmanager.h b/panels/dock/taskmanager/taskmanager.h index ac24158d4..07079746e 100644 --- a/panels/dock/taskmanager/taskmanager.h +++ b/panels/dock/taskmanager/taskmanager.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -100,6 +100,7 @@ class TaskManager : public DS_NAMESPACE::DContainment, public AbstractTaskManage Q_INVOKABLE void activateWindow(uint32_t windowID); Q_INVOKABLE void saveDockElementsOrder(const QStringList &appIds); + Q_INVOKABLE void moveItem(int from, int to); Q_INVOKABLE QString getTrashTipText(); Q_INVOKABLE bool isTrashEmpty() const;