From 5b09444a72879fd8c235f79407066f2fc036bf3b Mon Sep 17 00:00:00 2001 From: wjyrich Date: Fri, 7 Aug 2026 14:05:16 +0800 Subject: [PATCH] refactor: optimize AM appitem property update handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Refactor onPropertyChanged to handle individual property changes instead of fetching all properties on every D-Bus signal 2. Add vendor and genericName data roles to AppItem with corresponding accessors 3. Introduce Environ role for storing application environment data 4. Remove QtConcurrent dependency by simplifying async loading logic 5. Fix isOnDesktop property name mismatch (was OnDesktop) 6. Optimize duplicate check during managed objects loading 7. Replace ready property with proper readyChanged signal emission 8. Expose DDE categories as a QVariantMap property for QML usage 9. Clean up updateActions to properly handle empty action lists Log: Optimized app item property updates and added vendor/genericName/ Environ data roles Influence: 1. Verify application display names and generic names still display correctly in launcher 2. Test that application icons update properly when changed at runtime 3. Verify app model readiness signal works correctly with QML bindings 4. Test category filtering still functions with new DDE categories property 5. Verify duplicate desktop entries are properly filtered during loading 6. Test action menus still work correctly for applications with defined actions 7. Verify apps are correctly filtered by vendor (deepin vs other) refactor: 优化AM应用项属性更新处理 1. 重构onPropertyChanged,针对单个属性变化进行处理,而不是每次D-Bus信号 都获取所有属性 2. 为AppItem添加vendor和genericName数据角色及对应的访问器 3. 新增Environ角色用于存储应用环境数据 4. 简化异步加载逻辑,移除QtConcurrent依赖 5. 修复isOnDesktop属性名称不匹配问题(原为OnDesktop) 6. 优化加载托管对象时的重复检查逻辑 7. 用proper readyChanged信号替代原ready属性 8. 将DDE分类暴露为QVariantMap属性供QML使用 9. 清理updateActions以正确处理空操作列表 Log: 优化应用项属性更新,新增vendor/genericName/Environ数据角色 Influence: 1. 验证启动器中应用显示名称和通用名称是否仍然正确显示 2. 测试应用图标在运行时更改后是否能正确更新 3. 验证应用模型就绪信号与QML绑定的正常工作 4. 测试分类过滤功能在新DDE分类属性下是否正常 5. 验证加载过程中重复桌面条目的过滤是否正常 6. 测试已定义动作的应用的右键菜单是否正常工作 7. 验证应用是否能按供应商正确筛选(deepin与其他) PMS: TASK-393709 --- applets/dde-apps/CMakeLists.txt | 3 +- applets/dde-apps/amappitem.cpp | 122 ++++++++++++++++++++-------- applets/dde-apps/amappitemmodel.cpp | 32 ++++---- applets/dde-apps/appitem.cpp | 22 ++++- applets/dde-apps/appitem.h | 6 ++ applets/dde-apps/appitemmodel.cpp | 4 +- applets/dde-apps/appitemmodel.h | 4 + applets/dde-apps/appsapplet.cpp | 25 +++--- applets/dde-apps/appsapplet.h | 12 ++- 9 files changed, 157 insertions(+), 73 deletions(-) diff --git a/applets/dde-apps/CMakeLists.txt b/applets/dde-apps/CMakeLists.txt index e21172bd5..bf67ebc8a 100644 --- a/applets/dde-apps/CMakeLists.txt +++ b/applets/dde-apps/CMakeLists.txt @@ -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 @@ -59,7 +59,6 @@ add_library(dde-apps SHARED ${DBUS_INTERFACES} target_link_libraries(dde-apps PRIVATE dde-shell-frame - Qt${QT_VERSION_MAJOR}::Concurrent yaml-cpp ) diff --git a/applets/dde-apps/amappitem.cpp b/applets/dde-apps/amappitem.cpp index 17eb7cb3a..5e658e48b 100644 --- a/applets/dde-apps/amappitem.cpp +++ b/applets/dde-apps/amappitem.cpp @@ -14,6 +14,8 @@ namespace apps { // AM static string static const QString AM_DBUS_SERVICE = "org.desktopspec.ApplicationManager1"; +static const QString AM_APPLICATION_INTERFACE = "org.desktopspec.ApplicationManager1.Application"; +static const QString DBUS_PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties"; static const QString DESKTOP_ENTRY_ICON_KEY = "Desktop Entry"; static const QString DEFAULT_KEY = "default"; static QString locale = QLocale::system().name(); @@ -22,6 +24,13 @@ AMAppItem::AMAppItem(const QDBusObjectPath &path, QObject *parent) : Application(AM_DBUS_SERVICE, path.path(), QDBusConnection::sessionBus(), parent) , AppItem(DUtil::unescapeFromObjectPath(path.path().split('/').last()), AppItemModel::AppItemType) { + QDBusConnection::sessionBus().connect(AM_DBUS_SERVICE, + path.path(), + DBUS_PROPERTIES_INTERFACE, + QStringLiteral("PropertiesChanged"), + QStringLiteral("sa{sv}as"), + this, + SLOT(onPropertyChanged(const QDBusMessage &))); } AMAppItem::AMAppItem(const QDBusObjectPath &path, const ObjectInterfaceMap &source, QObject *parent) @@ -34,6 +43,8 @@ AMAppItem::AMAppItem(const QDBusObjectPath &path, const ObjectInterfaceMap &sour auto name = getLocaleOrDefaultValue(qdbus_cast(appInfo.value(u8"Name")), locale, DEFAULT_KEY); auto genericName = getLocaleOrDefaultValue(qdbus_cast(appInfo.value(u8"GenericName")), locale, DEFAULT_KEY); auto xDeepinVendor = appInfo.value(u8"X_Deepin_Vendor").toString(); + AppItem::setGenericName(genericName); + AppItem::setVendor(xDeepinVendor); if (QStringLiteral("deepin") == xDeepinVendor && !genericName.isEmpty()) { AppItem::setAppName(genericName); @@ -63,7 +74,7 @@ AMAppItem::AMAppItem(const QDBusObjectPath &path, const ObjectInterfaceMap &sour auto autoStart = appInfo.value(u8"AutoStart").toBool(); AppItem::setAutoStart(autoStart); - auto isOnDesktop = appInfo.value(u8"OnDesktop").toBool(); + auto isOnDesktop = appInfo.value(u8"isOnDesktop").toBool(); AppItem::setOnDesktop(isOnDesktop); PropMap actionName; @@ -127,42 +138,87 @@ QString AMAppItem::getLocaleOrDefaultValue(const QStringMap &value, const QStrin void AMAppItem::onPropertyChanged(const QDBusMessage &msg) { - QList arguments = msg.arguments(); - if (3 != arguments.count()) + const QList arguments = msg.arguments(); + if (arguments.count() != 3) return; - QString interfaceName = msg.arguments().at(0).toString(); - if (interfaceName != QStringLiteral("org.desktopspec.ApplicationManager1.Application")) + if (arguments.at(0).toString() != AM_APPLICATION_INTERFACE) return; - // AM send changed signal together - auto name = getLocaleOrDefaultValue(Application::name(), locale, DEFAULT_KEY); - auto genericName = getLocaleOrDefaultValue(Application::genericName(), locale, DEFAULT_KEY); - auto xDeepinVendor = Application::x_Deepin_Vendor(); - if (QStringLiteral("deepin") == xDeepinVendor && !genericName.isEmpty()) { - AppItem::setAppName(genericName); - } else { - AppItem::setAppName(name); + QVariantMap changedProperties = qdbus_cast(arguments.at(1)); + + const auto value = [&changedProperties](QLatin1StringView name) { + return changedProperties.value(name); + }; + const auto contains = [&changedProperties](QLatin1StringView name) { + return changedProperties.contains(name); + }; + + if (contains(QLatin1String("Name")) || contains(QLatin1String("GenericName")) + || contains(QLatin1String("X_Deepin_Vendor"))) { + const QString name = getLocaleOrDefaultValue( + contains(QLatin1String("Name")) + ? qdbus_cast(value(QLatin1String("Name"))) + : Application::name(), + locale, + DEFAULT_KEY); + const QString genericName = getLocaleOrDefaultValue( + contains(QLatin1String("GenericName")) + ? qdbus_cast(value(QLatin1String("GenericName"))) + : Application::genericName(), + locale, + DEFAULT_KEY); + const QString vendor = contains(QLatin1String("X_Deepin_Vendor")) + ? value(QLatin1String("X_Deepin_Vendor")).toString() + : Application::x_Deepin_Vendor(); + AppItem::setGenericName(genericName); + AppItem::setVendor(vendor); + AppItem::setAppName(vendor == QLatin1String("deepin") && !genericName.isEmpty() ? genericName : name); } - auto iconName = Application::icons().value(DESKTOP_ENTRY_ICON_KEY); - AppItem::setAppIconName(iconName); - - AppItem::setNoDisPlay(Application::noDisplay()); - AppItem::setDDECategories(AppItemModel::DDECategories(CategoryUtils::parseBestMatchedCategory(Application::categories()))); - AppItem::setLastLaunchedTime(Application::lastLaunchedTime()); - AppItem::setInstalledTime(Application::installedTime()); - AppItem::setStartupWMclass(Application::startupWMClass()); - AppItem::setAutoStart(Application::autoStart()); - AppItem::setOnDesktop(Application::isOnDesktop()); - AppItem::setXLingLong(Application::x_linglong()); - AppItem::setId(Application::iD()); - AppItem::setXCreatedBy(Application::x_CreatedBy()); - AppItem::setExecs(Application::execs()); - - auto actions = Application::actions(); - auto actionName = Application::actionName(); - updateActions(actions, actionName); + if (contains(QLatin1String("Icons"))) { + const auto icons = qdbus_cast(value(QLatin1String("Icons"))); + AppItem::setAppIconName(icons.value(DESKTOP_ENTRY_ICON_KEY)); + } + if (contains(QLatin1String("NoDisplay"))) + AppItem::setNoDisPlay(value(QLatin1String("NoDisplay")).toBool()); + if (contains(QLatin1String("Categories"))) { + const auto categories = value(QLatin1String("Categories")).toStringList(); + AppItem::setDDECategories(AppItemModel::DDECategories(CategoryUtils::parseBestMatchedCategory(categories))); + AppItem::setCategories(categories); + } + if (contains(QLatin1String("LastLaunchedTime"))) + AppItem::setLastLaunchedTime(value(QLatin1String("LastLaunchedTime")).toULongLong()); + if (contains(QLatin1String("LaunchedTimes"))) + AppItem::setData(value(QLatin1String("LaunchedTimes")).toULongLong(), AppItemModel::LaunchedTimesRole); + if (contains(QLatin1String("InstalledTime"))) + AppItem::setInstalledTime(value(QLatin1String("InstalledTime")).toULongLong()); + if (contains(QLatin1String("StartupWMClass"))) + AppItem::setStartupWMclass(value(QLatin1String("StartupWMClass")).toString()); + if (contains(QLatin1String("AutoStart"))) + AppItem::setAutoStart(value(QLatin1String("AutoStart")).toBool()); + if (contains(QLatin1String("isOnDesktop"))) + AppItem::setOnDesktop(value(QLatin1String("isOnDesktop")).toBool()); + if (contains(QLatin1String("X_linglong"))) + AppItem::setXLingLong(value(QLatin1String("X_linglong")).toBool()); + if (contains(QLatin1String("ID"))) + AppItem::setId(value(QLatin1String("ID")).toString()); + if (contains(QLatin1String("X_CreatedBy"))) + AppItem::setXCreatedBy(value(QLatin1String("X_CreatedBy")).toString()); + if (contains(QLatin1String("Execs"))) + AppItem::setExecs(qdbus_cast(value(QLatin1String("Execs")))); + if (contains(QLatin1String("DesktopSourcePath"))) + AppItem::setDesktopSourcePath(value(QLatin1String("DesktopSourcePath")).toString()); + + if (contains(QLatin1String("Actions")) || contains(QLatin1String("ActionName"))) { + const QStringList actions = contains(QLatin1String("Actions")) + ? value(QLatin1String("Actions")).toStringList() + : Application::actions(); + const PropMap actionNames = contains(QLatin1String("ActionName")) + ? qdbus_cast(value(QLatin1String("ActionName"))) + : Application::actionName(); + updateActions(actions, actionNames); + } } void AMAppItem::updateActions(const QStringList &actions, const PropMap &actionName) @@ -175,8 +231,6 @@ void AMAppItem::updateActions(const QStringList &actions, const PropMap &actionN actionObject.insert(QStringLiteral("name"), getLocaleOrDefaultValue(localeNames, locale, DEFAULT_KEY)); actionsArray.append(actionObject); } - if (actions.size() > 0) { - AppItem::setActions(QJsonDocument(actionsArray).toJson()); - } + AppItem::setActions(actions.isEmpty() ? QString() : QJsonDocument(actionsArray).toJson()); } } diff --git a/applets/dde-apps/amappitemmodel.cpp b/applets/dde-apps/amappitemmodel.cpp index 38291a6d9..5801dea82 100644 --- a/applets/dde-apps/amappitemmodel.cpp +++ b/applets/dde-apps/amappitemmodel.cpp @@ -8,8 +8,6 @@ #include "objectmanager1interface.h" #include -#include -#include Q_LOGGING_CATEGORY(appsLog, "org.deepin.dde.shell.dde-apps.amappitemmodel") @@ -50,25 +48,29 @@ AMAppItemModel::AMAppItemModel(QObject *parent) removeRow(res.first().row()); }); - // load static desktop info from am asynchronously - auto reply = m_manager->GetManagedObjects(); - auto *watcher = new QDBusPendingCallWatcher(reply, this); + auto watcher = new QDBusPendingCallWatcher(m_manager->GetManagedObjects(), this); connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher]() { - watcher->deleteLater(); QDBusPendingReply reply = *watcher; + watcher->deleteLater(); if (reply.isError()) { - qCWarning(appsLog()) << "Failed to get managed objects:" << reply.error().message(); + qCWarning(appsLog) << "Failed to load applications from ApplicationManager:" << reply.error(); return; } - auto apps = reply.value(); - for (auto app = apps.cbegin(); app != apps.cend(); app++) { - auto path = app.key(); - if (!path.path().isEmpty()) { - auto c = new AMAppItem(path, app.value()); - appendRow(c); - } + + const auto apps = reply.value(); + for (auto app = apps.cbegin(); app != apps.cend(); ++app) { + const auto path = app.key(); + if (path.path().isEmpty()) + continue; + + const auto desktopId = DUtil::unescapeFromObjectPath(path.path().split('/').last()); + if (!match(index(0, 0), AppItemModel::DesktopIdRole, desktopId, 1, Qt::MatchExactly).isEmpty()) + continue; + appendRow(new AMAppItem(path, app.value())); } - setProperty("ready", true); + + m_ready = true; + Q_EMIT readyChanged(true); qCDebug(appsLog) << "AMAppItemModel is now ready with apps counts:" << rowCount(); }); } diff --git a/applets/dde-apps/appitem.cpp b/applets/dde-apps/appitem.cpp index 9ef29c124..9dd1a6803 100644 --- a/applets/dde-apps/appitem.cpp +++ b/applets/dde-apps/appitem.cpp @@ -230,4 +230,24 @@ void AppItem::setDesktopSourcePath(const QString &desktopSourcePath) { setData(desktopSourcePath, AppItemModel::DesktopSourcePathRole); } -} \ No newline at end of file + +QString AppItem::vendor() const +{ + return data(AppItemModel::VendorRole).toString(); +} + +void AppItem::setVendor(const QString &vendor) +{ + setData(vendor, AppItemModel::VendorRole); +} + +QString AppItem::genericName() const +{ + return data(AppItemModel::GenericNameRole).toString(); +} + +void AppItem::setGenericName(const QString &genericName) +{ + setData(genericName, AppItemModel::GenericNameRole); +} +} diff --git a/applets/dde-apps/appitem.h b/applets/dde-apps/appitem.h index cdd48b1d0..4a1ac5981 100644 --- a/applets/dde-apps/appitem.h +++ b/applets/dde-apps/appitem.h @@ -78,5 +78,11 @@ class AppItem : public QStandardItem QString desktopSourcePath() const; void setDesktopSourcePath(const QString &desktopSourcePath); + + QString vendor() const; + void setVendor(const QString &vendor); + + QString genericName() const; + void setGenericName(const QString &genericName); }; } diff --git a/applets/dde-apps/appitemmodel.cpp b/applets/dde-apps/appitemmodel.cpp index d26c41c9a..e208f4d7c 100644 --- a/applets/dde-apps/appitemmodel.cpp +++ b/applets/dde-apps/appitemmodel.cpp @@ -32,6 +32,8 @@ QHash AppItemModel::roleNames() const {AppItemModel::IdRole, QByteArrayLiteral("id")}, {AppItemModel::XCreatedByRole, QByteArrayLiteral("xCreatedBy")}, {AppItemModel::ExecsRole, QByteArrayLiteral("execs")}, - {AppItemModel::DesktopSourcePathRole, QByteArrayLiteral("desktopSourcePath")}}; + {AppItemModel::DesktopSourcePathRole, QByteArrayLiteral("desktopSourcePath")}, + {AppItemModel::VendorRole, QByteArrayLiteral("vendor")}, + {AppItemModel::GenericNameRole, QByteArrayLiteral("genericName")}}; } } diff --git a/applets/dde-apps/appitemmodel.h b/applets/dde-apps/appitemmodel.h index ef3d3ace1..356b63c92 100644 --- a/applets/dde-apps/appitemmodel.h +++ b/applets/dde-apps/appitemmodel.h @@ -10,6 +10,8 @@ namespace apps { class AppItemModel : public QStandardItemModel { + Q_OBJECT + public: enum Roles { DesktopIdRole = AppGroupManager::ExtendRole, @@ -32,6 +34,8 @@ class AppItemModel : public QStandardItemModel ExecsRole, CategoriesRole, DesktopSourcePathRole, + VendorRole, + GenericNameRole, }; Q_ENUM(Roles) diff --git a/applets/dde-apps/appsapplet.cpp b/applets/dde-apps/appsapplet.cpp index aeaf6bfcf..7404e3e74 100644 --- a/applets/dde-apps/appsapplet.cpp +++ b/applets/dde-apps/appsapplet.cpp @@ -1,14 +1,14 @@ -// 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 #include "appsapplet.h" #include "amappitemmodel.h" #include "appgroupmanager.h" +#include "appitemmodel.h" #include "pluginfactory.h" -#include -#include +#include namespace apps { @@ -20,16 +20,6 @@ AppsApplet::AppsApplet(QObject *parent) connect(m_appModel, &AMAppItemModel::readyChanged, this, &AppsApplet::appModelReadyChanged); } -AppsApplet::~AppsApplet() -{ - -} - -bool AppsApplet::load() -{ - return true; -} - QAbstractItemModel *AppsApplet::groupModel() const { return m_groupModel; @@ -45,6 +35,15 @@ bool AppsApplet::appModelReady() const return m_appModel->ready(); } +QVariantMap AppsApplet::ddeCategories() const +{ + QVariantMap categories; + const QMetaEnum metaEnum = QMetaEnum::fromType(); + for (int i = 0; i < metaEnum.keyCount(); ++i) + categories.insert(QString::fromLatin1(metaEnum.key(i)), metaEnum.value(i)); + return categories; +} + D_APPLET_CLASS(AppsApplet) } diff --git a/applets/dde-apps/appsapplet.h b/applets/dde-apps/appsapplet.h index 6c81d73ee..65d08f4d4 100644 --- a/applets/dde-apps/appsapplet.h +++ b/applets/dde-apps/appsapplet.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 @@ -7,36 +7,34 @@ #include "applet.h" #include "dsglobal.h" -#include +#include +#include DS_USE_NAMESPACE namespace apps { class AMAppItemModel; -class AppItem; class AppsApplet : public DApplet { Q_OBJECT Q_PROPERTY(QAbstractItemModel *appModel READ appModel CONSTANT FINAL) Q_PROPERTY(bool appModelReady READ appModelReady NOTIFY appModelReadyChanged FINAL) Q_PROPERTY(QAbstractItemModel *appGroupModel READ groupModel CONSTANT FINAL) + Q_PROPERTY(QVariantMap ddeCategories READ ddeCategories CONSTANT FINAL) public: explicit AppsApplet(QObject *parent = nullptr); - ~AppsApplet(); - - bool load() override; QAbstractItemModel *appModel() const; QAbstractItemModel *groupModel() const; bool appModelReady() const; + QVariantMap ddeCategories() const; signals: void appModelReadyChanged(bool ready); private: - bool m_appModelReady; AMAppItemModel *m_appModel; QAbstractItemModel *m_groupModel; };