diff --git a/qml/FullscreenFrame.qml b/qml/FullscreenFrame.qml index 310dc229..9bae78fc 100644 --- a/qml/FullscreenFrame.qml +++ b/qml/FullscreenFrame.qml @@ -657,7 +657,7 @@ InputEventItem { folderGridViewPopup.startPointX = itemPos.x + width / 2 folderGridViewPopup.startPointY = itemPos.y + height / 2 folderGridViewPopup.open() - folderGridViewPopup.folderName = model.display.startsWith("internal/category/") ? getCategoryName(model.display.substring(18)) : model.display + folderGridViewPopup.folderName = model.display console.log("open folder id:" + idNum) } onMenuTriggered: { diff --git a/qml/IconItemDelegate.qml b/qml/IconItemDelegate.qml index 189335f9..09953f58 100644 --- a/qml/IconItemDelegate.qml +++ b/qml/IconItemDelegate.qml @@ -24,7 +24,7 @@ Control { // So we give the max sourceSize and use scale to solve it. property int maxIconSize: 128 property int maxIconSizeInFolder: 64 - readonly property string text: display.startsWith("internal/category/") ? getCategoryName(display.substring(18)) : display + readonly property string text: display property string iconSource property bool dndEnabled: false diff --git a/qml/Main.qml b/qml/Main.qml index 1276629e..1c6234f8 100644 --- a/qml/Main.qml +++ b/qml/Main.qml @@ -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 @@ -16,33 +16,6 @@ import org.deepin.launchpad.models 1.0 import org.deepin.launchpad.windowed 1.0 QtObject { - function getCategoryName(section) { - switch (Number(section)) { - case AppItem.Internet: - return qsTr("Internet"); - case AppItem.Chat: - return qsTr("Chat"); - case AppItem.Music: - return qsTr("Music"); - case AppItem.Video: - return qsTr("Video"); - case AppItem.Graphics: - return qsTr("Graphics"); - case AppItem.Game: - return qsTr("Games"); - case AppItem.Office: - return qsTr("Office"); - case AppItem.Reading: - return qsTr("Reading"); - case AppItem.Development: - return qsTr("Development"); - case AppItem.System: - return qsTr("System"); - default: - return qsTr("Others"); - } - } - function launchApp(desktopId) { if (DebugHelper.avoidLaunchApp) { DTK.sendSystemMessage("dde-launchpad (debug)", diff --git a/qml/windowed/AppListView.qml b/qml/windowed/AppListView.qml index c4dcef0a..d5c6aee3 100644 --- a/qml/windowed/AppListView.qml +++ b/qml/windowed/AppListView.qml @@ -106,7 +106,7 @@ FocusScope { if (CategorizedSortProxyModel.categoryType === CategorizedSortProxyModel.Alphabetary) { return section.toUpperCase(); } else { - return getCategoryName(section) + return ItemArrangementProxyModel.categoryDisplayName(section) } } @@ -295,7 +295,7 @@ FocusScope { model: ddeCategoryMenu.existingSections delegate: MenuItem { id: menuItem - text: getCategoryName(modelData) + text: ItemArrangementProxyModel.categoryDisplayName(modelData) textColor: DStyle.Style.menu.itemText font: DTK.fontManager.t6 onTriggered: { diff --git a/qml/windowed/FreeSortListView.qml b/qml/windowed/FreeSortListView.qml index 3bb6a2a4..0ae94cfe 100644 --- a/qml/windowed/FreeSortListView.qml +++ b/qml/windowed/FreeSortListView.qml @@ -200,7 +200,7 @@ Item { console.log("freesort view folder clicked:", desktopId); let idStr = model.desktopId let strFolderId = Number(idStr.replace("internal/folders/", "")) - let strFolderName = model.display.startsWith("internal/category/") ? getCategoryName(model.display.substring(18)) : model.display + let strFolderName = model.display let offset = height / 2 folderClicked(strFolderId, strFolderName, mapToItem(listView, offset, offset)) } else { @@ -260,7 +260,7 @@ Item { ItemDelegate { id: itemDelegate - text: model.display.startsWith("internal/category/") ? getCategoryName(model.display.substring(18)) : model.display + text: model.display checkable: false icon.name: itemType === ItemArrangementProxyModel.FolderItemType ? "folder" : iconName DciIcon.mode: DTK.NormalState diff --git a/qml/windowed/IconItemDelegate.qml b/qml/windowed/IconItemDelegate.qml index d5fa0ea7..73d783bc 100644 --- a/qml/windowed/IconItemDelegate.qml +++ b/qml/windowed/IconItemDelegate.qml @@ -14,7 +14,7 @@ Control { id: root opacity: Drag.active ? 0 : 1 - property string text: display.startsWith("internal/category/") ? getCategoryName(display.substring(18)) : display + property string text: display property string iconSource property bool dndEnabled: false diff --git a/shell-launcher-applet/CMakeLists.txt b/shell-launcher-applet/CMakeLists.txt index 73039e47..8e7f5eb2 100644 --- a/shell-launcher-applet/CMakeLists.txt +++ b/shell-launcher-applet/CMakeLists.txt @@ -20,4 +20,7 @@ PACKAGE org.deepin.ds.dock.launcherapplet QML_FILES ${QML_FILES_NEED_TRANSLATION} ${CMAKE_CURRENT_LIST_DIR}/package/launcheritem.qml +SOURCE_FILES + ${CMAKE_CURRENT_LIST_DIR}/launcheritem.cpp + ${PROJECT_SOURCE_DIR}/src/models/itemarrangementproxymodel.cpp ) diff --git a/shell-launcher-applet/launcheritem.cpp b/shell-launcher-applet/launcheritem.cpp index 45186803..ee3fee44 100644 --- a/shell-launcher-applet/launcheritem.cpp +++ b/shell-launcher-applet/launcheritem.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 @@ -6,6 +6,9 @@ #include "pluginfactory.h" #include "../launchercontroller.h" #include +#include +#include +#include #include #include @@ -16,6 +19,18 @@ DS_USE_NAMESPACE namespace { Q_LOGGING_CATEGORY(logApplet, "org.deepin.dde.launchpad.applet") + +constexpr QLatin1StringView groupIdPrefix("internal/folders/"); + +int folderIdFromGroupId(const QString &groupId) +{ + if (!groupId.startsWith(groupIdPrefix)) + return -1; + + bool ok = false; + const int folderId = QStringView(groupId).sliced(groupIdPrefix.size()).toInt(&ok); + return ok && folderId > 0 ? folderId : -1; +} } namespace dock { @@ -42,6 +57,48 @@ bool LauncherItem::init() return true; } +QAbstractItemModel *LauncherItem::itemArrangementModel() const +{ + return &ItemArrangementProxyModel::instance(); +} + +QString LauncherItem::groupDisplayName(const QString &groupId) const +{ + if (folderIdFromGroupId(groupId) < 0) + return {}; + + auto &model = ItemArrangementProxyModel::instance(); + const auto matches = model.match(model.index(0, 0), AppItem::DesktopIdRole, + groupId, 1, Qt::MatchExactly); + if (matches.isEmpty()) + return {}; + + return matches.constFirst().data(Qt::DisplayRole).toString(); +} + +QVariantList LauncherItem::groupItemDetails(const QString &groupId) const +{ + const int folderId = folderIdFromGroupId(groupId); + if (folderId < 0) + return {}; + + const auto desktopIds = ItemArrangementProxyModel::instance().folderItems(folderId); + QVariantList details; + details.reserve(desktopIds.size()); + for (const auto &desktopId : desktopIds) { + const auto item = AppsModel::instance().itemFromDesktopId(desktopId); + if (!item) + continue; + + details.append(QVariantMap{ + {QStringLiteral("desktopId"), desktopId}, + {QStringLiteral("name"), item->name()}, + {QStringLiteral("iconName"), item->iconName()}, + }); + } + return details; +} + D_APPLET_CLASS(LauncherItem) } diff --git a/shell-launcher-applet/launcheritem.h b/shell-launcher-applet/launcheritem.h index 229258ed..5e1f41aa 100644 --- a/shell-launcher-applet/launcheritem.h +++ b/shell-launcher-applet/launcheritem.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 @@ -7,16 +7,24 @@ #include "applet.h" #include "dsglobal.h" +#include +#include + namespace dock { class LauncherItem : public DS_NAMESPACE::DApplet { Q_OBJECT Q_PROPERTY(QString iconName MEMBER m_iconName NOTIFY iconNameChanged FINAL) + Q_PROPERTY(QAbstractItemModel *itemArrangementModel READ itemArrangementModel CONSTANT FINAL) public: explicit LauncherItem(QObject *parent = nullptr); virtual bool init() override; + QAbstractItemModel *itemArrangementModel() const; + Q_INVOKABLE QString groupDisplayName(const QString &groupId) const; + Q_INVOKABLE QVariantList groupItemDetails(const QString &groupId) const; + Q_SIGNALS: void iconNameChanged(); diff --git a/shell-launcher-applet/package/launcheritem.qml b/shell-launcher-applet/package/launcheritem.qml index 17201c99..8c759357 100644 --- a/shell-launcher-applet/package/launcheritem.qml +++ b/shell-launcher-applet/package/launcheritem.qml @@ -124,33 +124,6 @@ AppletItem { } } - function getCategoryName(section) { - switch (Number(section)) { - case AppItem.Internet: - return qsTr("Internet"); - case AppItem.Chat: - return qsTr("Chat"); - case AppItem.Music: - return qsTr("Music"); - case AppItem.Video: - return qsTr("Video"); - case AppItem.Graphics: - return qsTr("Graphics"); - case AppItem.Game: - return qsTr("Games"); - case AppItem.Office: - return qsTr("Office"); - case AppItem.Reading: - return qsTr("Reading"); - case AppItem.Development: - return qsTr("Development"); - case AppItem.System: - return qsTr("System"); - default: - return qsTr("Others"); - } - } - function launchApp(desktopId) { DesktopIntegration.launchByDesktopId(desktopId); LauncherController.visible = false; diff --git a/src/models/itemarrangementproxymodel.cpp b/src/models/itemarrangementproxymodel.cpp index 56ab91c4..5846df6e 100644 --- a/src/models/itemarrangementproxymodel.cpp +++ b/src/models/itemarrangementproxymodel.cpp @@ -7,6 +7,7 @@ #include "appsmodel.h" #include "categoryutils.h" +#include #include #include #include @@ -15,11 +16,53 @@ Q_DECLARE_LOGGING_CATEGORY(logModels) +namespace { +constexpr QLatin1StringView categoryNamePrefix("internal/category/"); +} + ItemArrangementProxyModel::~ItemArrangementProxyModel() { qCDebug(logModels) << "Destroying ItemArrangementProxyModel"; } +QString ItemArrangementProxyModel::categoryDisplayName(int category) const +{ + switch (category) { + case AppItem::Internet: + return QCoreApplication::translate("launcheritem", "Internet"); + case AppItem::Chat: + return QCoreApplication::translate("launcheritem", "Chat"); + case AppItem::Music: + return QCoreApplication::translate("launcheritem", "Music"); + case AppItem::Video: + return QCoreApplication::translate("launcheritem", "Video"); + case AppItem::Graphics: + return QCoreApplication::translate("launcheritem", "Graphics"); + case AppItem::Game: + return QCoreApplication::translate("launcheritem", "Games"); + case AppItem::Office: + return QCoreApplication::translate("launcheritem", "Office"); + case AppItem::Reading: + return QCoreApplication::translate("launcheritem", "Reading"); + case AppItem::Development: + return QCoreApplication::translate("launcheritem", "Development"); + case AppItem::System: + return QCoreApplication::translate("launcheritem", "System"); + default: + return QCoreApplication::translate("launcheritem", "Others"); + } +} + +QString ItemArrangementProxyModel::localizedFolderName(const QString &folderName) const +{ + if (!folderName.startsWith(categoryNamePrefix)) + return folderName; + + bool ok = false; + const int category = QStringView(folderName).sliced(categoryNamePrefix.size()).toInt(&ok); + return categoryDisplayName(ok ? category : AppItem::Others); +} + int ItemArrangementProxyModel::pageCount(int folderId) const { if (folderId == 0) return m_topLevel->pageCount(); @@ -248,7 +291,7 @@ QVariant ItemArrangementProxyModel::data(const QModelIndex &index, int role) con switch (role) { case Qt::DisplayRole: - return m_folders.value(id)->name(); + return localizedFolderName(m_folders.value(id)->name()); case AppItem::DesktopIdRole: return id; case AppItem::IsAutoStartRole: @@ -502,13 +545,19 @@ void ItemArrangementProxyModel::removeFolder(const QString &idNumber) } // get folder by id. 0 is top level, >=1 is folder -ItemsPage *ItemArrangementProxyModel::folderById(int id) +ItemsPage *ItemArrangementProxyModel::folderById(int id) const { if (id == 0) return m_topLevel; const QString folderId("internal/folders/" + QString::number(id)); return m_folders.value(folderId); } +QStringList ItemArrangementProxyModel::folderItems(int folderId) const +{ + const auto page = folderById(folderId); + return page ? page->allArrangedItems() : QStringList{}; +} + QStringList ItemArrangementProxyModel::allArrangedItems() const { return m_topLevel->allArrangedItems(); diff --git a/src/models/itemarrangementproxymodel.h b/src/models/itemarrangementproxymodel.h index 5b70564e..e9ac1383 100644 --- a/src/models/itemarrangementproxymodel.h +++ b/src/models/itemarrangementproxymodel.h @@ -60,8 +60,10 @@ class ItemArrangementProxyModel : public QConcatenateTablesProxyModel Q_INVOKABLE void commitDndOperation(const QString & dragId, const QString & dropId, const DndOperation op, int pageHint = -1); Q_INVOKABLE int creatEmptyPage(int folderId = 0) const; Q_INVOKABLE void removeEmptyPage() const; + Q_INVOKABLE QString categoryDisplayName(int category) const; ItemsPage *itemsPage() { return m_topLevel; } + QStringList folderItems(int folderId) const; // QAbstractItemModel interface public: @@ -85,7 +87,8 @@ class ItemArrangementProxyModel : public QConcatenateTablesProxyModel QString findAvailableFolderId(); ItemsPage * createFolder(const QString & id); void removeFolder(const QString & idNumber); - ItemsPage * folderById(int id); + QString localizedFolderName(const QString &folderName) const; + ItemsPage * folderById(int id) const; QStringList allArrangedItems() const; // folder-id: internal/folder/