diff --git a/panels/dock/taskmanager/CMakeLists.txt b/panels/dock/taskmanager/CMakeLists.txt index 3c3d291a3..190804e32 100644 --- a/panels/dock/taskmanager/CMakeLists.txt +++ b/panels/dock/taskmanager/CMakeLists.txt @@ -66,6 +66,14 @@ add_library(dock-taskmanager SHARED ${DBUS_INTERFACES} desktopfileamparser.cpp desktopfileamparser.h desktopfileparserfactory.h + dockcombinemodel.cpp + dockcombinemodel.h + dockitemmodel.cpp + dockitemmodel.h + dockglobalelementmodel.cpp + dockglobalelementmodel.h + dockgroupmodel.cpp + dockgroupmodel.h taskmanager.cpp taskmanager.h treelandwindow.cpp diff --git a/panels/dock/taskmanager/abstracttaskmanagerinterface.h b/panels/dock/taskmanager/abstracttaskmanagerinterface.h new file mode 100644 index 000000000..182b3804e --- /dev/null +++ b/panels/dock/taskmanager/abstracttaskmanagerinterface.h @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include +#include + +namespace dock +{ +class AbstractTaskManagerInterface +{ +protected: + template + void callInterfaceMethod(const QModelIndex &index, Func func, Args &&...args) const + { + if (nullptr == m_model) { + return; + } + auto interface = dynamic_cast(m_model->sourceModel()); + if (interface != nullptr) { + (interface->*func)(m_model->mapToSource(index), std::forward(args)...); + } + } + + template + void callInterfaceMethod(const QModelIndexList &indexes, Func func, Args &&...args) const + { + if (nullptr == m_model) { + return; + } + QModelIndexList sourceModelIndexes; + std::transform(indexes.begin(), indexes.end(), std::back_inserter(sourceModelIndexes), [this](const auto &index) { + return m_model->mapToSource(index); + }); + auto interface = dynamic_cast(m_model->sourceModel()); + if (interface != nullptr) { + (interface->*func)(sourceModelIndexes, std::forward(args)...); + } + } + +public: + AbstractTaskManagerInterface(QAbstractProxyModel *model) + : m_model(model){}; + + virtual void requestActivate(const QModelIndex &index) const + { + callInterfaceMethod(index, &AbstractTaskManagerInterface::requestActivate); + } + virtual void requestNewInstance(const QModelIndex &index, const QString &action) const + { + callInterfaceMethod(index, &AbstractTaskManagerInterface::requestNewInstance, action); + } + virtual void requestOpenUrls(const QModelIndex &index, const QList &urls) const + { + callInterfaceMethod(index, &AbstractTaskManagerInterface::requestOpenUrls, urls); + } + virtual void requestClose(const QModelIndex &index, bool force = false) const + { + callInterfaceMethod(index, &AbstractTaskManagerInterface::requestClose, force); + } + virtual void requestUpdateWindowGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate = nullptr) const + { + callInterfaceMethod(index, &AbstractTaskManagerInterface::requestUpdateWindowGeometry, geometry, delegate); + } + + virtual void + requestPreview(const QModelIndexList &indexes, QObject *relativePositionItem, int32_t previewXoffset, int32_t previewYoffset, uint32_t direction) const + { + callInterfaceMethod(indexes, &AbstractTaskManagerInterface::requestPreview, relativePositionItem, previewXoffset, previewYoffset, direction); + } + virtual void requestWindowsView(const QModelIndexList &indexes) const + { + callInterfaceMethod(indexes, &AbstractTaskManagerInterface::requestWindowsView); + } + +protected: + QAbstractProxyModel *m_model; +}; +} diff --git a/panels/dock/taskmanager/dconfig/org.deepin.ds.dock.taskmanager.json b/panels/dock/taskmanager/dconfig/org.deepin.ds.dock.taskmanager.json index 3b605f8b3..be0b854aa 100644 --- a/panels/dock/taskmanager/dconfig/org.deepin.ds.dock.taskmanager.json +++ b/panels/dock/taskmanager/dconfig/org.deepin.ds.dock.taskmanager.json @@ -42,6 +42,16 @@ "description": "The default apps which is docked when dock is started.", "permissions": "readwrite", "visibility": "private" + }, + "dockedElements": { + "value": ["desktop/dde-file-manager", "desktop/deepin-app-storedesktop", "desktop/org.deepin.browser", "desktop/deepin-mail", "desktop/deepin-terminal", "desktop/dde-calendar", "desktop/deepin-music", "desktop/deepin-editor", "desktop/deepin-calculator", "desktop/org.deepin.dde.control-center", "desktop/dde-trash"], + "serial": 0, + "flags": [], + "name": "dockedElements", + "name[zh_CN]": "任务栏驻留项目", + "description": "The items which is docked when dock is started.", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/panels/dock/taskmanager/dockcombinemodel.cpp b/panels/dock/taskmanager/dockcombinemodel.cpp new file mode 100644 index 000000000..a53ccc705 --- /dev/null +++ b/panels/dock/taskmanager/dockcombinemodel.cpp @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dockcombinemodel.h" +#include "abstracttaskmanagerinterface.h" +#include "globals.h" +#include "rolecombinemodel.h" +#include "taskmanager.h" + +namespace dock +{ +DockCombineModel::DockCombineModel(QAbstractItemModel *major, QAbstractItemModel *minor, int majorRoles, CombineFunc func, QObject *parent) + : RoleCombineModel(major, minor, majorRoles, func, parent) + , AbstractTaskManagerInterface(this) +{ + // due to role has changed by RoleGroupModel, so we redirect role to TaskManager::Roles. + m_roleMaps = {{TaskManager::ActiveRole, RoleCombineModel::roleNames().key(MODEL_ACTIVE)}, + {TaskManager::AttentionRole, RoleCombineModel::roleNames().key(MODEL_ATTENTION)}, + {TaskManager::DesktopIdRole, RoleCombineModel::roleNames().key(MODEL_DESKTOPID)}, + {TaskManager::IconNameRole, RoleCombineModel::roleNames().key(MODEL_ICONNAME)}, + {TaskManager::IdentityRole, RoleCombineModel::roleNames().key(MODEL_IDENTIFY)}, + {TaskManager::ActionsRole, RoleCombineModel::roleNames().key(MODEL_ACTIONS)}, + {TaskManager::NameRole, RoleCombineModel::roleNames().key(MODEL_NAME)}, + {TaskManager::WinIdRole, RoleCombineModel::roleNames().key(MODEL_WINID)}, + {TaskManager::WinTitleRole, RoleCombineModel::roleNames().key(MODEL_TITLE)}}; +} + +QHash DockCombineModel::roleNames() const +{ + return {{TaskManager::ActiveRole, MODEL_ACTIVE}, + {TaskManager::AttentionRole, MODEL_ATTENTION}, + {TaskManager::DesktopIdRole, MODEL_DESKTOPID}, + {TaskManager::IconNameRole, MODEL_ICONNAME}, + {TaskManager::IdentityRole, MODEL_IDENTIFY}, + {TaskManager::ActionsRole, MODEL_ACTIONS}, + {TaskManager::NameRole, MODEL_NAME}, + {TaskManager::WinIdRole, MODEL_WINID}, + {TaskManager::WinTitleRole, MODEL_TITLE}}; +} + +QVariant DockCombineModel::data(const QModelIndex &index, int role) const +{ + switch (role) { + case TaskManager::DesktopIdRole: { + auto res = RoleCombineModel::data(index, m_roleMaps.value(TaskManager::DesktopIdRole)).toString(); + if (res.isEmpty()) { + auto data = RoleCombineModel::data(index, m_roleMaps.value(TaskManager::IdentityRole)).toStringList(); + res = data.value(0, ""); + } + return res; + } + case TaskManager::IconNameRole: { + auto icon = RoleCombineModel::data(index, m_roleMaps.value(TaskManager::IconNameRole)).toString(); + if (icon.isEmpty()) { + icon = RoleCombineModel::data(index, m_roleMaps.value(TaskManager::WinIconRole)).toString(); + } + return icon; + } + default: { + auto newRole = m_roleMaps.value(role, -1); + if (newRole == -1) { + return QVariant(); + } + + return RoleCombineModel::data(index, newRole); + } + } + + return QVariant(); +} +} diff --git a/panels/dock/taskmanager/dockcombinemodel.h b/panels/dock/taskmanager/dockcombinemodel.h new file mode 100644 index 000000000..d91af1379 --- /dev/null +++ b/panels/dock/taskmanager/dockcombinemodel.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "abstracttaskmanagerinterface.h" +#include "rolecombinemodel.h" + +namespace dock +{ +class DockCombineModel : public RoleCombineModel, public AbstractTaskManagerInterface +{ + Q_OBJECT + +public: + DockCombineModel(QAbstractItemModel *major, QAbstractItemModel *minor, int majorRoles, CombineFunc func, QObject *parent = nullptr); + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override; + +private: + QHash m_roleMaps; +}; +} diff --git a/panels/dock/taskmanager/dockglobalelementmodel.cpp b/panels/dock/taskmanager/dockglobalelementmodel.cpp new file mode 100644 index 000000000..a1140bcaa --- /dev/null +++ b/panels/dock/taskmanager/dockglobalelementmodel.cpp @@ -0,0 +1,373 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dockglobalelementmodel.h" +#include "globals.h" +#include "taskmanager.h" +#include "taskmanagersettings.h" + +#include +#include +#include +#include + +#include +#include + +namespace dock +{ +DockGlobalElementModel::DockGlobalElementModel(QAbstractItemModel *appsModel, DockCombineModel *activeAppModel, QObject *parent) + : QAbstractListModel(parent) + , AbstractTaskManagerInterface(nullptr) + , m_appsModel(appsModel) + , m_activeAppModel(activeAppModel) +{ + connect(TaskManagerSettings::instance(), &TaskManagerSettings::dockedElementsChanged, this, &DockGlobalElementModel::loadDockedElements); + connect(m_appsModel, &QAbstractItemModel::rowsRemoved, this, [this](const QModelIndex &parent, int first, int last) { + for (int i = first; i <= last; ++i) { + auto it = std::find_if(m_data.begin(), m_data.end(), [this, &i](auto data) { + return std::get<1>(data) == m_appsModel && std::get<2>(data) == i; + }); + if (it != m_data.end()) { + auto pos = it - m_data.end(); + beginRemoveRows(QModelIndex(), pos, pos); + m_data.remove(pos); + endRemoveRows(); + } + } + std::for_each(m_data.begin(), m_data.end(), [this, first, last](auto &data) { + if (std::get<1>(data) == m_appsModel && std::get<2>(data) >= first) { + data = std::make_tuple(std::get<0>(data), std::get<1>(data), std::get<2>(data) - -((last - first) + 1)); + } + }); + }); + + connect(m_activeAppModel, &QAbstractItemModel::rowsInserted, this, [this](const QModelIndex &parent, int first, int last) { + for (int i = first; i <= last; ++i) { + auto index = m_activeAppModel->index(i, 0); + auto desktopId = index.data(TaskManager::DesktopIdRole).toString(); + + auto it = std::find_if(m_data.begin(), m_data.end(), [this, &desktopId](auto &data) { + return m_appsModel == std::get<1>(data) && desktopId == std::get<0>(data); + }); + + if (it != m_data.end()) { + *it = std::make_tuple(desktopId, m_activeAppModel, i); + auto pIndex = this->index(it - m_data.begin(), 0); + Q_EMIT dataChanged(pIndex, pIndex, {TaskManager::ActiveRole, TaskManager::AttentionRole, TaskManager::WindowsRole, TaskManager::MenusRole}); + + } else { + beginInsertRows(QModelIndex(), m_data.size(), m_data.size()); + m_data.append(std::make_tuple(desktopId, m_activeAppModel, first)); + endInsertRows(); + } + } + + std::for_each(m_data.begin(), m_data.end(), [this, first, last](auto &data) { + if (std::get<1>(data) == m_activeAppModel && std::get<2>(data) > first) { + data = std::make_tuple(std::get<0>(data), std::get<1>(data), std::get<2>(data) + ((last - first) + 1)); + } + }); + }); + + connect(m_activeAppModel, &QAbstractItemModel::rowsRemoved, this, [this](const QModelIndex &parent, int first, int last) { + for (int i = first; i <= last; ++i) { + auto it = std::find_if(m_data.begin(), m_data.end(), [this, i](auto data) { + return std::get<1>(data) == m_activeAppModel && std::get<2>(data) == i; + }); + + if (it == m_data.end()) { + qWarning() << "failed to find a running apps on dock" << i; + continue; + } + + auto pos = it - m_data.begin(); + auto id = std::get<0>(*it); + + auto oit = std::find_if(m_data.constBegin(), m_data.constEnd(), [this, &id, i](auto &data) { + return std::get<0>(data) == id && std::get<1>(data) == m_activeAppModel && std::get<2>(data) != i; + }); + + if (oit == m_data.constEnd() && m_dockedElements.contains(std::make_tuple("desktop", id))) { + auto pIndex = this->index(pos, 0); + auto res = m_appsModel->match(m_appsModel->index(0, 0), TaskManager::DesktopIdRole, id, 1, Qt::MatchExactly); + if (res.isEmpty()) { + beginRemoveRows(QModelIndex(), pos, pos); + m_data.remove(pos); + endRemoveRows(); + } else { + auto row = res.first().row(); + *it = std::make_tuple(id, m_appsModel, row); + Q_EMIT dataChanged(pIndex, pIndex, {TaskManager::ActiveRole, TaskManager::AttentionRole, TaskManager::WindowsRole, TaskManager::MenusRole}); + } + } else { + beginRemoveRows(QModelIndex(), pos, pos); + m_data.remove(pos); + endRemoveRows(); + } + } + std::for_each(m_data.begin(), m_data.end(), [this, first, last](auto &data) { + if (std::get<1>(data) == m_activeAppModel && std::get<2>(data) >= first) { + data = std::make_tuple(std::get<0>(data), std::get<1>(data), std::get<2>(data) - ((last - first) + 1)); + } + }); + }); + + connect(m_activeAppModel, + &QAbstractItemModel::dataChanged, + this, + [this](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList &roles) { + int first = topLeft.row(), last = bottomRight.row(); + for (int i = first; i <= last; i++) { + auto it = std::find_if(m_data.constBegin(), m_data.constEnd(), [this, i](auto data) { + return std::get<1>(data) == m_activeAppModel && std::get<2>(data) == i; + }); + + if (it == m_data.end()) + return; + auto pos = it - m_data.constBegin(); + + auto oldRoles = roles; + auto desktopId = roles.indexOf(TaskManager::DesktopIdRole); + auto identifyId = roles.indexOf(TaskManager::IdentityRole); + if (desktopId != -1 || identifyId != -1) { + oldRoles.append(TaskManager::ItemIdRole); + } + Q_EMIT dataChanged(index(pos, 0), index(pos, 0), oldRoles); + } + }); + + QMetaObject::invokeMethod(this, &DockGlobalElementModel::loadDockedElements, Qt::QueuedConnection); +} + +QHash DockGlobalElementModel::roleNames() const +{ + return { + {TaskManager::ItemIdRole, MODEL_ITEMID}, + {TaskManager::NameRole, MODEL_NAME}, + {TaskManager::IconNameRole, MODEL_ICONNAME}, + {TaskManager::ActiveRole, MODEL_ACTIVE}, + {TaskManager::AttentionRole, MODEL_ATTENTION}, + {TaskManager::MenusRole, MODEL_MENUS}, + {TaskManager::DockedRole, MODEL_DOCKED}, + {TaskManager::WindowsRole, MODEL_WINDOWS}, + {TaskManager::WinTitleRole, MODEL_TITLE}, + {TaskManager::WinIconRole, MODEL_WINICON}, + {TaskManager::WinIdRole, MODEL_WINID}, + }; +} + +QModelIndex DockGlobalElementModel::index(int row, int column, const QModelIndex &parent) const +{ + return createIndex(row, column); +} + +QModelIndex DockGlobalElementModel::parent(const QModelIndex &child) const +{ + return QModelIndex(); +} + +int DockGlobalElementModel::columnCount(const QModelIndex &parent) const +{ + return 1; +} + +void DockGlobalElementModel::loadDockedElements() +{ + QList> newDocked; + for (auto elementInfo : TaskManagerSettings::instance()->dockedElements()) { + auto pair = elementInfo.split('/'); + if (pair.size() != 2) + continue; + + auto type = pair[0]; + auto id = pair[1]; + + auto tmp = std::make_tuple(type, id); + + // check desktop is installed + QAbstractItemModel *model = nullptr; + int row = 0; + if (type == "desktop") { + model = m_appsModel; + auto res = m_appsModel->match(m_appsModel->index(0, 0), TaskManager::DesktopIdRole, id, 1, Qt::MatchExactly).value(0); + if (!res.isValid()) + continue; + row = res.row(); + } + + newDocked.append(tmp); + if (m_dockedElements.contains(tmp)) + continue; + + auto isRunning = std::any_of(m_data.constBegin(), m_data.constEnd(), [this, &id](const auto &data) { + return std::get<0>(data) == id; + }); + + if (!isRunning) { + beginInsertRows(QModelIndex(), m_data.size(), m_data.size()); + m_data.append(std::make_tuple(id, model, row)); + endInsertRows(); + } + } + + for (auto it = m_dockedElements.begin(); it < m_dockedElements.end(); ++it) { + if (newDocked.contains(*it)) + continue; + auto type = std::get<0>(*it), id = std::get<1>(*it); + auto dataIt = std::find_if(m_data.begin(), m_data.end(), [this, &id](const auto &data) { + return std::get<0>(data) == id && std::get<1>(data) == m_appsModel; + }); + if (dataIt != m_data.end()) { + auto pos = (dataIt - m_data.begin()); + beginRemoveRows(QModelIndex(), pos, pos); + m_data.remove(pos); + endRemoveRows(); + } + } + + m_dockedElements = newDocked; +} + +QString DockGlobalElementModel::getMenus(const QModelIndex &index) const +{ + auto data = m_data.value(index.row()); + auto id = std::get<0>(data); + auto model = std::get<1>(data); + auto row = std::get<2>(data); + + QJsonArray menusArray; + menusArray.append(QJsonObject{{"id", ""}, {"name", model == m_activeAppModel ? index.data(TaskManager::WinTitleRole).toString() : tr("Open")}}); + + auto actions = model->index(row, 0).data(TaskManager::ActionsRole).toByteArray(); + for (auto action : QJsonDocument::fromJson(actions).array()) { + menusArray.append(action); + } + + bool isDocked = (model == nullptr) || m_dockedElements.contains(std::make_tuple("desktop", id)); + menusArray.append(QJsonObject{{"id", DOCK_ACTION_DOCK}, {"name", isDocked ? tr("Undock") : tr("Dock")}}); + + if (model == m_activeAppModel) { + if (TaskManagerSettings::instance()->isAllowedForceQuit()) { + menusArray.append(QJsonObject{{"id", DOCK_ACTION_FORCEQUIT}, {"name", tr("Force Quit")}}); + } + menusArray.append(QJsonObject{{"id", DOCK_ACTION_CLOSEALL}, {"name", tr("Close All")}}); + } + + return QJsonDocument(menusArray).toJson(); +} + +int DockGlobalElementModel::rowCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : m_data.size(); +} + +QVariant DockGlobalElementModel::data(const QModelIndex &index, int role) const +{ + if (index.row() > m_data.size()) + return {}; + + auto data = m_data.value(index.row()); + auto id = std::get<0>(data); + auto model = std::get<1>(data); + auto row = std::get<2>(data); + + switch (role) { + case TaskManager::ItemIdRole: + return id; + case TaskManager::WindowsRole: { + if (model == m_activeAppModel) { + return QStringList{model->index(row, 0).data(TaskManager::WinIdRole).toString()}; + } + return QVariant(); + } + case TaskManager::MenusRole: { + return getMenus(index); + } + + default: { + if (model) { + return model->index(row, 0).data(role); + } + return {}; + } + } +} + +void DockGlobalElementModel::requestActivate(const QModelIndex &index) const +{ + auto data = m_data.value(index.row()); + auto id = std::get<0>(data); + auto sourceModel = std::get<1>(data); + auto sourceRow = std::get<2>(data); + + if (sourceModel == m_activeAppModel) { + auto sourceIndex = sourceModel->index(sourceRow, 0); + m_activeAppModel->requestActivate(sourceIndex); + } else { + this->requestNewInstance(index, ""); + } +} + +void DockGlobalElementModel::requestOpenUrls(const QModelIndex &index, const QList &urls) const +{ +} + +void DockGlobalElementModel::requestNewInstance(const QModelIndex &index, const QString &action) const +{ + if (action == DOCK_ACTION_DOCK) { + } else if (action == DOCK_ACTION_FORCEQUIT) { + } else if (action == DOCK_ACTION_CLOSEALL) { + } else { + auto data = m_data.value(index.row()); + auto id = std::get<0>(data); + QProcess process; + process.setProcessChannelMode(QProcess::MergedChannels); + process.start("dde-am", {"--by-user", id, action}); + process.waitForFinished(); + return; + } +} +void DockGlobalElementModel::requestClose(const QModelIndex &index, bool force) const +{ + auto data = m_data.value(index.row()); + auto id = std::get<0>(data); + auto sourceModel = std::get<1>(data); + auto sourceRow = std::get<2>(data); + + if (sourceModel == m_activeAppModel) { + auto sourceIndex = sourceModel->index(sourceRow, 0); + m_activeAppModel->requestClose(sourceIndex, force); + return; + } + + qWarning() << "unable to close app not running"; +} +void DockGlobalElementModel::requestUpdateWindowGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate) const +{ +} + +void DockGlobalElementModel::requestPreview(const QModelIndexList &indexes, + QObject *relativePositionItem, + int32_t previewXoffset, + int32_t previewYoffset, + uint32_t direction) const +{ + QModelIndexList sourceIndexes; + for (auto index : indexes) { + auto data = m_data.value(index.row()); + auto id = std::get<0>(data); + auto sourceModel = std::get<1>(data); + auto sourceRow = std::get<2>(data); + if (sourceModel == m_activeAppModel) { + sourceIndexes.append(sourceModel->index(sourceRow, 0)); + } + } + m_activeAppModel->requestPreview(sourceIndexes, relativePositionItem, previewXoffset, previewYoffset, direction); +} + +void DockGlobalElementModel::requestWindowsView(const QModelIndexList &indexes) const +{ +} +} diff --git a/panels/dock/taskmanager/dockglobalelementmodel.h b/panels/dock/taskmanager/dockglobalelementmodel.h new file mode 100644 index 000000000..bb3267f5d --- /dev/null +++ b/panels/dock/taskmanager/dockglobalelementmodel.h @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "abstracttaskmanagerinterface.h" +#include "dockcombinemodel.h" +#include +#include +#include + +namespace dock +{ +class DockGlobalElementModel : public QAbstractListModel, public AbstractTaskManagerInterface +{ + Q_OBJECT +public: + explicit DockGlobalElementModel(QAbstractItemModel *appsModel, DockCombineModel *activeAppModel, QObject *parent = nullptr); + + QHash roleNames() const override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &child) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + + inline int mapToSourceModelRole(QAbstractItemModel *model, int role) const; + + void requestActivate(const QModelIndex &index) const override; + void requestNewInstance(const QModelIndex &index, const QString &action) const override; + + void requestOpenUrls(const QModelIndex &index, const QList &urls) const override; + void requestClose(const QModelIndex &index, bool force = false) const override; + void requestUpdateWindowGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate = nullptr) const override; + + void requestPreview(const QModelIndexList &indexes, + QObject *relativePositionItem, + int32_t previewXoffset, + int32_t previewYoffset, + uint32_t direction) const override; + void requestWindowsView(const QModelIndexList &indexes) const override; + +private: + void loadDockedElements(); + QString getMenus(const QModelIndex &index) const; + +private: + // id, model, and pos + QList> m_data; + + // type, id + QList> m_dockedElements; + QAbstractItemModel *m_appsModel; + DockCombineModel *m_activeAppModel; +}; +} diff --git a/panels/dock/taskmanager/dockgroupmodel.cpp b/panels/dock/taskmanager/dockgroupmodel.cpp new file mode 100644 index 000000000..20becac6e --- /dev/null +++ b/panels/dock/taskmanager/dockgroupmodel.cpp @@ -0,0 +1,165 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dockgroupmodel.h" +#include "abstracttaskmanagerinterface.h" +#include "rolegroupmodel.h" +#include "taskmanager.h" + +namespace dock +{ +DockGroupModel::DockGroupModel(QAbstractItemModel *sourceModel, int role, QObject *parent) + : RoleGroupModel(sourceModel, role, parent) + , AbstractTaskManagerInterface(this) + , m_roleForDeduplication(role) +{ + connect(this, &QAbstractItemModel::rowsInserted, this, [this](const QModelIndex &parent, int first, int last) { + if (!parent.isValid()) + return; + Q_EMIT dataChanged(index(parent.row(), 0), index(parent.row(), 0), {TaskManager::WindowsRole}); + }); + connect(this, &QAbstractItemModel::rowsRemoved, this, [this](const QModelIndex &parent, int first, int last) { + if (!parent.isValid()) + return; + Q_EMIT dataChanged(index(parent.row(), 0), index(parent.row(), 0), {TaskManager::WindowsRole}); + }); + + connect(this, &QAbstractItemModel::dataChanged, this, [this](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList &roles) { + if (!topLeft.parent().isValid()) + return; + auto parentRow = topLeft.parent().row(); + Q_EMIT dataChanged(index(parentRow, 0), index(parentRow, 0), roles); + + if (roles.contains(TaskManager::ActiveRole)) + m_currentActiveWindow.insert(parentRow, topLeft.row()); + }); +} + +QVariant DockGroupModel::data(const QModelIndex &index, int role) const +{ + if (role == m_roleForDeduplication) { + return RoleGroupModel::data(index, role); + } + + if (TaskManager::WindowsRole == role) { + QStringList stringList; + auto variantList = all(index, role); + std::transform(variantList.begin(), variantList.end(), std::back_inserter(stringList), [](const QVariant &var) { + return var.toString(); + }); + return stringList; + } else if (TaskManager::ActiveRole == role || TaskManager::AttentionRole == role) { + return any(index, role); + } + + return RoleGroupModel::data(index, role); +} + +int DockGroupModel::rowCount(const QModelIndex &index) const +{ + return index.isValid() ? 0 : RoleGroupModel::rowCount(); +} + +QModelIndex DockGroupModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid()) + return QModelIndex(); + + return RoleGroupModel::index(row, column); +} + +bool DockGroupModel::any(const QModelIndex &index, int role) const +{ + auto rowCount = RoleGroupModel::rowCount(index); + for (int i = 0; i < rowCount; i++) { + auto cIndex = RoleGroupModel::index(i, 0, index); + if (RoleGroupModel::data(cIndex, role).toBool()) + return true; + } + + return false; +} + +QVariantList DockGroupModel::all(const QModelIndex &index, int role) const +{ + QVariantList res; + auto rowCount = RoleGroupModel::rowCount(index); + for (int i = 0; i < rowCount; i++) { + auto cIndex = RoleGroupModel::index(i, 0, index); + auto window = RoleGroupModel::data(index, role); + if (window.isValid()) + res.append(window); + } + + return res; +} + +void DockGroupModel::requestActivate(const QModelIndex &index) const +{ + auto interface = dynamic_cast(sourceModel()); + if (nullptr == interface) + return; + + QModelIndex sourceIndex; + if (index.data(TaskManager::ActiveRole).toBool()) { + auto next = (m_currentActiveWindow.value(index.row()) + 1) % RoleGroupModel::rowCount(index); + sourceIndex = mapToSource(createIndex(next, 0, index.row())); + } else { + auto current = m_currentActiveWindow.value(index.row()); + sourceIndex = mapToSource(createIndex(current, 0, index.row())); + } + + interface->requestActivate(sourceIndex); +} + +void DockGroupModel::requestOpenUrls(const QModelIndex &index, const QList &urls) const +{ +} + +void DockGroupModel::requestClose(const QModelIndex &index, bool force) const +{ + auto interface = dynamic_cast(sourceModel()); + if (nullptr == interface) + return; + + auto indexRowCount = RoleGroupModel::rowCount(index); + for (int i = 0; i < indexRowCount; i++) { + auto cIndex = RoleGroupModel::index(i, 0, index); + callInterfaceMethod(cIndex, &AbstractTaskManagerInterface::requestClose, force); + } +} + +void DockGroupModel::requestUpdateWindowGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate) const +{ +} + +void DockGroupModel::requestPreview(const QModelIndexList &indexes, + QObject *relativePositionItem, + int32_t previewXoffset, + int32_t previewYoffset, + uint32_t direction) const +{ + QModelIndexList proxyIndexes; + for (auto index : indexes) { + for (int i = 0; i < RoleGroupModel::rowCount(index); ++i) { + auto proxyIndex = createIndex(i, 0, index.row()); + proxyIndexes.append(proxyIndex); + } + } + + callInterfaceMethod(proxyIndexes, &AbstractTaskManagerInterface::requestPreview, relativePositionItem, previewXoffset, previewYoffset, direction); +} + +void DockGroupModel::requestWindowsView(const QModelIndexList &indexes) const +{ + QModelIndexList sourceIndexes; + for (auto index : indexes) { + for (int i = 0; i < RoleGroupModel::rowCount(index); i++) { + sourceIndexes.append(mapToSource(createIndex(i, 0, index.row()))); + } + } + + callInterfaceMethod(sourceIndexes, &AbstractTaskManagerInterface::requestWindowsView); +} +} \ No newline at end of file diff --git a/panels/dock/taskmanager/dockgroupmodel.h b/panels/dock/taskmanager/dockgroupmodel.h new file mode 100644 index 000000000..f3a6d1ed1 --- /dev/null +++ b/panels/dock/taskmanager/dockgroupmodel.h @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "abstracttaskmanagerinterface.h" +#include "rolegroupmodel.h" + +namespace dock +{ +class DockGroupModel : public RoleGroupModel, public AbstractTaskManagerInterface +{ + Q_OBJECT + +public: + explicit DockGroupModel(QAbstractItemModel *sourceModel, int role, QObject *parent = nullptr); + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex &index = QModelIndex()) const override; + Q_INVOKABLE virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + + void requestActivate(const QModelIndex &index) const override; + void requestOpenUrls(const QModelIndex &index, const QList &urls) const override; + void requestClose(const QModelIndex &index, bool force = false) const override; + void requestUpdateWindowGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate = nullptr) const override; + void requestPreview(const QModelIndexList &indexes, + QObject *relativePositionItem, + int32_t previewXoffset, + int32_t previewYoffset, + uint32_t direction) const override; + void requestWindowsView(const QModelIndexList &indexes) const override; + +private: + bool any(const QModelIndex &index, int role) const; + QVariantList all(const QModelIndex &index, int role) const; + +private: + int m_roleForDeduplication; + QHash m_currentActiveWindow; +}; +} diff --git a/panels/dock/taskmanager/dockitemmodel.cpp b/panels/dock/taskmanager/dockitemmodel.cpp new file mode 100644 index 000000000..30ddcbab6 --- /dev/null +++ b/panels/dock/taskmanager/dockitemmodel.cpp @@ -0,0 +1,148 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dockitemmodel.h" +#include "abstracttaskmanagerinterface.h" +#include "dockgroupmodel.h" +#include "globals.h" +#include "taskmanager.h" +#include "taskmanagersettings.h" + +namespace dock +{ +DockItemModel::DockItemModel(QAbstractItemModel *globalModel, QObject *parent) + : QAbstractProxyModel(parent) + , AbstractTaskManagerInterface(this) + , m_globalModel(globalModel) + , m_split(!TaskManagerSettings::instance()->isWindowSplit()) + , m_isUpdating(false) +{ + auto updateSourceModel = [this]() { + if (TaskManagerSettings::instance()->isWindowSplit() == m_split) + return; + + m_split = TaskManagerSettings::instance()->isWindowSplit(); + if (m_split) { + setSourceModel(m_globalModel); + m_groupModel.reset(nullptr); + } else { + m_groupModel.reset(new DockGroupModel(m_globalModel, TaskManager::DesktopIdRole)); + setSourceModel(m_groupModel.get()); + } + }; + + connect(TaskManagerSettings::instance(), &TaskManagerSettings::windowSplitChanged, this, updateSourceModel); + QMetaObject::invokeMethod(this, updateSourceModel, Qt::QueuedConnection); +} + +void DockItemModel::setSourceModel(QAbstractItemModel *model) +{ + if (sourceModel() == model) + return; + + m_isUpdating = true; + if (sourceModel()) { + sourceModel()->disconnect(this); + } + + auto currentCount = this->rowCount(); + auto newCount = model->rowCount(); + QAbstractProxyModel::setSourceModel(model); + + if (newCount > currentCount) { + beginInsertRows(QModelIndex(), currentCount, newCount - 1); + endInsertRows(); + } else if (newCount < currentCount) { + beginRemoveRows(QModelIndex(), newCount, currentCount); + endRemoveRows(); + } + + connect(sourceModel(), &QAbstractItemModel::rowsInserted, this, [this](const QModelIndex &parent, int first, int last) { + if (parent.isValid() || m_isUpdating) + return; + beginInsertRows(QModelIndex(), first, last); + endInsertRows(); + }); + connect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, [this](const QModelIndex &parent, int first, int last) { + if (parent.isValid() || m_isUpdating) + return; + beginRemoveRows(QModelIndex(), first, last); + endRemoveRows(); + }); + connect(sourceModel(), &QAbstractItemModel::dataChanged, this, [this](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList &roles) { + if (m_isUpdating) + return; + auto first = topLeft.row(); + auto last = bottomRight.row(); + Q_EMIT dataChanged(index(first, 0), index(last, 0), roles); + }); + + connect(sourceModel(), &QAbstractItemModel::destroyed, this, [this]() { + if (m_isUpdating) + return; + + beginResetModel(); + endResetModel(); + }); + + auto bottomRight = this->index(std::min(currentCount, newCount), 0); + Q_EMIT dataChanged(index(0, 0), bottomRight); + m_isUpdating = false; +} + +void DockItemModel::dumpItemInfo(const QModelIndex &index) +{ + qDebug() << "Index in DockItemModel:" << index << "DesktopIdRole:" << data(index, TaskManager::DesktopIdRole) + << "ItemIdRole:" << data(index, TaskManager::ItemIdRole) << "DockedRole:" << data(index, TaskManager::DockedRole); +} + +QHash DockItemModel::roleNames() const +{ + return m_globalModel->roleNames(); +} + +QModelIndex DockItemModel::index(int row, int column, const QModelIndex &parent) const +{ + return createIndex(row, column); +} + +QModelIndex DockItemModel::parent(const QModelIndex &child) const +{ + return QModelIndex(); +} + +int DockItemModel::columnCount(const QModelIndex &parent) const +{ + return 1; +} + +int DockItemModel::rowCount(const QModelIndex &parent) const +{ + auto sourceModel = this->sourceModel(); + return sourceModel == nullptr ? 0 : sourceModel->rowCount(); +} + +QVariant DockItemModel::data(const QModelIndex &index, int role) const +{ + auto sourceModel = this->sourceModel(); + auto data = sourceModel->data(sourceModel->index(index.row(), index.column()), role); + if (role == TaskManager::IconNameRole) { + if (data.toString().isEmpty()) { + return DEFAULT_APP_ICONNAME; + } + } + + return data; +} + +QModelIndex DockItemModel::mapToSource(const QModelIndex &proxyIndex) const +{ + return sourceModel()->index(proxyIndex.row(), proxyIndex.column()); +} + +QModelIndex DockItemModel::mapFromSource(const QModelIndex &sourceIndex) const +{ + return index(sourceIndex.row(), sourceIndex.column()); +} +} diff --git a/panels/dock/taskmanager/dockitemmodel.h b/panels/dock/taskmanager/dockitemmodel.h new file mode 100644 index 000000000..e17d3c246 --- /dev/null +++ b/panels/dock/taskmanager/dockitemmodel.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "abstracttaskmanagerinterface.h" + +#include + +namespace dock +{ +class DockItemModel : public QAbstractProxyModel, public AbstractTaskManagerInterface +{ +public: + explicit DockItemModel(QAbstractItemModel *globalModel, QObject *parent = nullptr); + QHash roleNames() const override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &child) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + void setSourceModel(QAbstractItemModel *model) override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + + QModelIndex mapToSource(const QModelIndex &proxyIndex) const override; + QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override; + + void dumpItemInfo(const QModelIndex &index); + +private: + QAbstractItemModel *m_globalModel; + QScopedPointer m_groupModel; + bool m_split; + bool m_isUpdating; +}; +} diff --git a/panels/dock/taskmanager/globals.h b/panels/dock/taskmanager/globals.h index 1e40ad9bc..2006de935 100644 --- a/panels/dock/taskmanager/globals.h +++ b/panels/dock/taskmanager/globals.h @@ -9,15 +9,41 @@ namespace dock { +// actions static inline const QString DOCK_ACTION_ALLWINDOW = "dock-action-allWindow"; static inline const QString DOCK_ACTION_FORCEQUIT = "dock-action-forceQuit"; static inline const QString DOCK_ACTION_CLOSEALL = "dock-action-closeAll"; static inline const QString DOCK_ACTIN_LAUNCH = "dock-action-launch"; static inline const QString DOCK_ACTION_DOCK = "dock-action-dock"; +// setting keys static inline const QString TASKMANAGER_ALLOWFOCEQUIT_KEY = "Allow_Force_Quit"; -static inline const QString TASKMANAGER_WINDOWSPLIT_KEY = "Window_Split"; +static inline const QString TASKMANAGER_WINDOWSPLIT_KEY = "noTaskGrouping"; static inline const QString TASKMANAGER_DOCKEDITEMS_KEY = "Docked_Items"; +constexpr auto TASKMANAGER_DOCKEDELEMENTS_KEY = "dockedElements"; + +// model roleNames +constexpr auto MODEL_WINID = "winId"; +constexpr auto MODEL_PID = "pid"; +constexpr auto MODEL_IDENTIFY = "identity"; +constexpr auto MODEL_WINICON = "icon"; +constexpr auto MODEL_TITLE = "title"; +constexpr auto MODEL_ACTIVE = "active"; +constexpr auto MODEL_ATTENTION = "attention"; +constexpr auto MODEL_SHOULDSKIP = "shouldSkip"; + +constexpr auto MODEL_DESKTOPID = "desktopId"; +constexpr auto MODEL_ICONNAME = "iconName"; +constexpr auto MODEL_ITEMID = "itemId"; +constexpr auto MODEL_NAME = "name"; +constexpr auto MODEL_STARTUPWMCLASS = "startupWMClass"; +constexpr auto MODEL_ACTIONS = "actions"; +constexpr auto MODEL_MENUS = "menus"; +constexpr auto MODEL_DOCKED = "docked"; +constexpr auto MODEL_WINDOWS = "windows"; + +// default item icon +constexpr auto DEFAULT_APP_ICONNAME = "application-default-icon"; // copy from application-manager diff --git a/panels/dock/taskmanager/taskmanager.cpp b/panels/dock/taskmanager/taskmanager.cpp index 294f453cf..f3a0a16ab 100644 --- a/panels/dock/taskmanager/taskmanager.cpp +++ b/panels/dock/taskmanager/taskmanager.cpp @@ -2,17 +2,19 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +#include "abstracttaskmanagerinterface.h" #include "appitem.h" #include "abstractwindow.h" #include "abstractwindowmonitor.h" #include "desktopfileamparser.h" #include "desktopfileparserfactory.h" +#include "dockcombinemodel.h" +#include "dockglobalelementmodel.h" #include "dsglobal.h" #include "globals.h" #include "itemmodel.h" #include "pluginfactory.h" -#include "rolecombinemodel.h" #include "taskmanager.h" #include "taskmanageradaptor.h" #include "taskmanagersettings.h" @@ -38,8 +40,35 @@ Q_LOGGING_CATEGORY(taskManagerLog, "dde.shell.dock.taskmanager", QtDebugMsg) namespace dock { -TaskManager::TaskManager(QObject* parent) +class BoolFilterModel : public QSortFilterProxyModel, public AbstractTaskManagerInterface +{ + Q_OBJECT +public: + explicit BoolFilterModel(QAbstractItemModel *sourceModel, int role, QObject *parent = nullptr) + : QSortFilterProxyModel(parent) + , AbstractTaskManagerInterface(this) + , m_role(role) + { + setSourceModel(sourceModel); + } + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override + { + if (sourceRow >= sourceModel()->rowCount()) + return false; + + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + return !sourceModel()->data(index, m_role).toBool(); + } + +private: + int m_role; +}; + +TaskManager::TaskManager(QObject *parent) : DContainment(parent) + , AbstractTaskManagerInterface(nullptr) , m_windowFullscreen(false) { qRegisterMetaType(); @@ -83,31 +112,36 @@ bool TaskManager::init() DApplet::init(); DS_NAMESPACE::DAppletBridge bridge("org.deepin.ds.dde-apps"); + BoolFilterModel *leftModel = new BoolFilterModel(m_windowMonitor.data(), m_windowMonitor->roleNames().key("shouldSkip"), this); if (auto applet = bridge.applet()) { auto model = applet->property("appModel").value(); Q_ASSERT(model); - m_activeAppModel = - new RoleCombineModel(m_windowMonitor.data(), model, AbstractWindow::identityRole, [](QVariant data, QAbstractItemModel *model) -> QModelIndex { - auto roleNames = model->roleNames(); - QList identifiedOrders = {"desktopId", "startupWMClass", "name", "iconName"}; - - auto indentifies = data.toStringList(); - for (auto id : indentifies) { - if (id.isEmpty()) { - continue; - } + m_activeAppModel = new DockCombineModel(leftModel, model, TaskManager::IdentityRole, [](QVariant data, QAbstractItemModel *model) -> QModelIndex { + auto roleNames = model->roleNames(); + QList identifiedOrders = {MODEL_DESKTOPID, MODEL_STARTUPWMCLASS, MODEL_NAME, MODEL_ICONNAME}; + + auto identifies = data.toStringList(); + for (auto id : identifies) { + if (id.isEmpty()) { + continue; + } - for (auto identifiedOrder : identifiedOrders) { - auto res = model->match(model->index(0, 0), roleNames.key(identifiedOrder), id, 1, Qt::MatchFixedString | Qt::MatchWrap); - if (res.size() > 0 && res.first().isValid()) { - qCDebug(taskManagerLog()) << "Window match id:" << id << "role:" << identifiedOrder << "data:" << res.first().data() << "desktop id:" << res.first().data(roleNames.key("desktopId")); - return res.first(); - } + for (auto identifiedOrder : identifiedOrders) { + auto res = model->match(model->index(0, 0), roleNames.key(identifiedOrder), id, 1, Qt::MatchFixedString | Qt::MatchWrap).value(0); + if (res.isValid()) { + qCDebug(taskManagerLog) << "matched" << res; + return res; } } + } - return QModelIndex(); - }); + auto res = model->match(model->index(0, 0), roleNames.key(MODEL_DESKTOPID), identifies.value(0), 1, Qt::MatchEndsWith); + qCDebug(taskManagerLog) << "matched" << res.value(0); + return res.value(0); + }); + + m_dockGlobalElementModel = new DockGlobalElementModel(model, m_activeAppModel, this); + m_itemModel = new DockItemModel(m_dockGlobalElementModel, this); } if (m_windowMonitor) @@ -120,11 +154,52 @@ bool TaskManager::init() return true; } -ItemModel* TaskManager::dataModel() +ItemModel *TaskManager::dataModel() { return ItemModel::instance(); } +void TaskManager::requestActivate(const QModelIndex &index) const +{ + m_itemModel->requestActivate(index); +} + +void TaskManager::requestOpenUrls(const QModelIndex &index, const QList &urls) const +{ + m_itemModel->requestOpenUrls(index, urls); +} + +void TaskManager::requestNewInstance(const QModelIndex &index, const QString &action) const +{ + m_itemModel->requestNewInstance(index, action); +} + +void TaskManager::requestClose(const QModelIndex &index, bool force) const +{ + m_itemModel->requestClose(index, force); +} + +void TaskManager::requestUpdateWindowGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate) const +{ + m_itemModel->requestUpdateWindowGeometry(index, geometry, delegate); +} + +void TaskManager::requestPreview(const QModelIndexList &indexes, + QObject *relativePositionItem, + int32_t previewXoffset, + int32_t previewYoffset, + uint32_t direction) const +{ + for (auto index : indexes) { + qDebug() << "requestPreview" << index << index.model() << (index.model() == m_itemModel); + } + m_itemModel->requestPreview(indexes, relativePositionItem, previewXoffset, previewYoffset, direction); +} +void TaskManager::requestWindowsView(const QModelIndexList &indexes) const +{ + m_itemModel->requestWindowsView(indexes); +} + void TaskManager::handleWindowAdded(QPointer window) { if (!window || window->shouldSkip() || window->getAppItem() != nullptr) return; @@ -132,7 +207,7 @@ void TaskManager::handleWindowAdded(QPointer window) // TODO: remove below code and use use model replaced. QModelIndexList res; if (m_activeAppModel) { - res = m_activeAppModel->match(m_activeAppModel->index(0, 0), AbstractWindow::winIdRole, window->id()); + res = m_activeAppModel->match(m_activeAppModel->index(0, 0), TaskManager::WinIdRole, window->id()); } QSharedPointer desktopfile = nullptr; @@ -192,13 +267,17 @@ void TaskManager::dropFilesOnItem(const QString& itemId, const QStringList& urls item->handleFileDrop(urls); } -void TaskManager::showItemPreview(const QString &itemId, QObject* relativePositionItem, int32_t previewXoffset, int32_t previewYoffset, uint32_t direction) +void TaskManager::showItemPreview(const QString &itemId, QObject *relativePositionItem, int32_t previewXoffset, int32_t previewYoffset, uint32_t direction) { auto item = ItemModel::instance()->getItemById(itemId).get(); - if (!item) return; + if (!item) { + return; + } - QPointer pItem = reinterpret_cast(item); - if (pItem.isNull()) return; + QPointer pItem = reinterpret_cast(item); + if (pItem.isNull()) { + return; + } m_windowMonitor->showItemPreview(pItem, relativePositionItem, previewXoffset, previewYoffset, direction); } diff --git a/panels/dock/taskmanager/taskmanager.h b/panels/dock/taskmanager/taskmanager.h index f9226379b..13e8e052c 100644 --- a/panels/dock/taskmanager/taskmanager.h +++ b/panels/dock/taskmanager/taskmanager.h @@ -4,27 +4,64 @@ #pragma once +#include "abstracttaskmanagerinterface.h" #include "abstractwindow.h" #include "abstractwindowmonitor.h" #include "containment.h" +#include "dockcombinemodel.h" +#include "dockglobalelementmodel.h" +#include "dockitemmodel.h" #include "itemmodel.h" -#include "rolecombinemodel.h" #include namespace dock { class AppItem; -class TaskManager : public DS_NAMESPACE::DContainment +class TaskManager : public DS_NAMESPACE::DContainment, public AbstractTaskManagerInterface { Q_OBJECT - Q_PROPERTY(ItemModel* dataModel READ dataModel NOTIFY dataModelChanged) + Q_PROPERTY(QAbstractItemModel *dataModel READ dataModel NOTIFY dataModelChanged) Q_PROPERTY(bool windowSplit READ windowSplit NOTIFY windowSplitChanged) Q_PROPERTY(bool windowFullscreen READ windowFullscreen NOTIFY windowFullscreenChanged) Q_PROPERTY(bool allowForceQuit READ allowForceQuit NOTIFY allowedForceQuitChanged) public: + enum Roles { + // abstract window + WinIdRole = Qt::UserRole + 1, + PidRole, + IdentityRole, + WinIconRole, + WinTitleRole, + ActiveRole, + ShouldSkipRole, + AttentionRole, + + // item + ItemIdRole, + MenusRole, + WindowsRole, + + // from dde-apps + DesktopIdRole = 0x1000, + NameRole, + IconNameRole, + StartUpWMClassRole, + NoDisplayRole, + ActionsRole, + DDECategoryRole, + InstalledTimeRole, + LastLaunchedTimeRole, + LaunchedTimesRole, + DockedRole, + OnDesktopRole, + AutoStartRole, + AppTypeRole, + }; + Q_ENUM(Roles) + explicit TaskManager(QObject* parent = nullptr); ItemModel* dataModel(); @@ -36,6 +73,19 @@ class TaskManager : public DS_NAMESPACE::DContainment bool windowFullscreen(); bool allowForceQuit(); + Q_INVOKABLE void requestActivate(const QModelIndex &index) const override; + Q_INVOKABLE void requestNewInstance(const QModelIndex &index, const QString &action = QString()) const override; + + Q_INVOKABLE void requestOpenUrls(const QModelIndex &index, const QList &urls) const override; + Q_INVOKABLE void requestClose(const QModelIndex &index, bool force = false) const override; + Q_INVOKABLE void requestUpdateWindowGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate = nullptr) const override; + Q_INVOKABLE void requestPreview(const QModelIndexList &indexes, + QObject *relativePositionItem, + int32_t previewXoffset, + int32_t previewYoffset, + uint32_t direction) const override; + Q_INVOKABLE void requestWindowsView(const QModelIndexList &indexes) const override; + Q_INVOKABLE QString desktopIdToAppId(const QString& desktopId); Q_INVOKABLE bool requestDockByDesktopId(const QString& desktopID); Q_INVOKABLE bool requestUndockByDesktopId(const QString& desktopID); @@ -64,8 +114,10 @@ private Q_SLOTS: private: QScopedPointer m_windowMonitor; - RoleCombineModel *m_activeAppModel = nullptr; bool m_windowFullscreen; + DockCombineModel *m_activeAppModel = nullptr; + DockGlobalElementModel *m_dockGlobalElementModel = nullptr; + DockItemModel *m_itemModel = nullptr; }; } diff --git a/panels/dock/taskmanager/taskmanagersettings.cpp b/panels/dock/taskmanager/taskmanagersettings.cpp index 2baec7551..39a66ae62 100644 --- a/panels/dock/taskmanager/taskmanagersettings.cpp +++ b/panels/dock/taskmanager/taskmanagersettings.cpp @@ -41,16 +41,21 @@ TaskManagerSettings::TaskManagerSettings(QObject *parent) m_allowForceQuit = enableStr2Bool(m_taskManagerDconfig->value(TASKMANAGER_ALLOWFOCEQUIT_KEY).toString()); Q_EMIT allowedForceQuitChanged(); } else if (TASKMANAGER_WINDOWSPLIT_KEY == key) { - m_windowSplit = enableStr2Bool(m_taskManagerDconfig->value(TASKMANAGER_WINDOWSPLIT_KEY).toString()); + m_windowSplit = m_taskManagerDconfig->value(TASKMANAGER_WINDOWSPLIT_KEY).toBool(); Q_EMIT windowSplitChanged(); } else if (TASKMANAGER_DOCKEDITEMS_KEY == key) { loadDockedItems(); Q_EMIT dockedItemsChanged(); + Q_EMIT dockedElementsChanged(); + } else if (TASKMANAGER_DOCKEDELEMENTS_KEY == key) { + m_dockedElements = m_taskManagerDconfig->value(TASKMANAGER_DOCKEDELEMENTS_KEY, {}).toStringList(); + Q_EMIT dockedElementsChanged(); } }); m_allowForceQuit = enableStr2Bool(m_taskManagerDconfig->value(TASKMANAGER_ALLOWFOCEQUIT_KEY).toString()); - m_windowSplit = enableStr2Bool(m_taskManagerDconfig->value(TASKMANAGER_WINDOWSPLIT_KEY).toString()); + m_windowSplit = m_taskManagerDconfig->value(TASKMANAGER_WINDOWSPLIT_KEY).toBool(); + m_dockedElements = m_taskManagerDconfig->value(TASKMANAGER_DOCKEDELEMENTS_KEY, {}).toStringList(); loadDockedItems(); } @@ -73,7 +78,12 @@ bool TaskManagerSettings::isWindowSplit() void TaskManagerSettings::setWindowSplit(bool split) { m_windowSplit = split; - m_taskManagerDconfig->setValue(TASKMANAGER_WINDOWSPLIT_KEY, bool2EnableStr(m_windowSplit)); + m_taskManagerDconfig->setValue(TASKMANAGER_WINDOWSPLIT_KEY, m_windowSplit); +} + +QStringList TaskManagerSettings::dockedElements() +{ + return m_dockedElements; } void TaskManagerSettings::dockedItemsPersisted() @@ -81,7 +91,9 @@ void TaskManagerSettings::dockedItemsPersisted() QStringList list; for (auto dockedDesktopFile : m_dockedItems) { - if (!dockedDesktopFile.isObject()) continue; + if (!dockedDesktopFile.isObject()) { + continue; + } YAML::Node node; auto dockedDesktopFileObj = dockedDesktopFile.toObject(); for (auto key : dockedDesktopFileObj.keys()) { @@ -116,6 +128,19 @@ void TaskManagerSettings::loadDockedItems() } m_dockedItems.append(dockedItem); } + + // Migrate data under the new dconfig setting entry + if (!m_dockedItems.isEmpty() && m_dockedElements.isEmpty()) { + for (auto dockedDesktopFile : m_dockedItems) { + if (!dockedDesktopFile.isObject()) { + continue; + } + auto dockedDesktopFileObj = dockedDesktopFile.toObject(); + if (dockedDesktopFileObj.contains(QStringLiteral("id")) && dockedDesktopFileObj.contains(QStringLiteral("type"))) { + m_dockedElements.append(QStringLiteral("desktop/%1").arg(dockedDesktopFileObj[QStringLiteral("id")].toString())); + } + } + } } void TaskManagerSettings::setDockedDesktopFiles(QJsonArray items) diff --git a/panels/dock/taskmanager/taskmanagersettings.h b/panels/dock/taskmanager/taskmanagersettings.h index 50c0f2bf1..62dacf5a0 100644 --- a/panels/dock/taskmanager/taskmanagersettings.h +++ b/panels/dock/taskmanager/taskmanagersettings.h @@ -33,6 +33,7 @@ class TaskManagerSettings : public QObject void appnedDockedDesktopfiles(QJsonObject desktopfile); void removeDockedDesktopfile(QJsonObject desktopfile); QJsonArray dockedDesktopFiles(); + QStringList dockedElements(); private: explicit TaskManagerSettings(QObject *parent = nullptr); @@ -43,6 +44,7 @@ class TaskManagerSettings : public QObject void allowedForceQuitChanged(); void windowSplitChanged(); void dockedItemsChanged(); + void dockedElementsChanged(); private: DConfig* m_taskManagerDconfig; @@ -50,5 +52,6 @@ class TaskManagerSettings : public QObject bool m_allowForceQuit; bool m_windowSplit; QJsonArray m_dockedItems; + QStringList m_dockedElements; }; }