diff --git a/CMakeLists.txt b/CMakeLists.txt index d991a26..723fdee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ find_package(PkgConfig REQUIRED) set(UKUI_MENU_EXTERNAL_LIBS "") # glib-2.0 gio-unix-2.0 gsettings-qt x11 kysdk-waylandhelper -set(UKUI_MENU_PC_PKGS glib-2.0 gio-unix-2.0 gsettings-qt x11 kysdk-waylandhelper) +set(UKUI_MENU_PC_PKGS glib-2.0 gio-unix-2.0 gsettings-qt x11 kysdk-waylandhelper ukui-search) foreach(external_lib IN ITEMS ${UKUI_MENU_PC_PKGS}) pkg_check_modules(${external_lib} REQUIRED ${external_lib}) @@ -87,6 +87,7 @@ set(SOURCE_FILES src/extension/menu-extension.cpp src/extension/menu-extension.h src/extension/menu-extension-iface.h src/appdata/data-provider-plugin-iface.h + src/appdata/app-data-manager.cpp src/appdata/app-data-manager.h src/extension/extensions/folder-extension.cpp src/extension/extensions/folder-extension.h src/extension/extensions/recent-file-extension.cpp src/extension/extensions/recent-file-extension.h ) diff --git a/src/appdata/app-data-manager.cpp b/src/appdata/app-data-manager.cpp new file mode 100644 index 0000000..d5d6ece --- /dev/null +++ b/src/appdata/app-data-manager.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "app-data-manager.h" + +#include + +#define APP_ICON_PREFIX "image://appicon/" + +namespace UkuiMenu { + +class AppDataWorker : public QObject +{ + Q_OBJECT +public: + explicit AppDataWorker(AppDataManager *appManager = nullptr); + +Q_SIGNALS: + void appDataChanged(); + void favoriteAppChanged(); + void appDataBaseOpenFailed(); + +private Q_SLOTS: + void initAppData(); + void onAppAdded(const QVector &infos); + void onAppUpdated(QVector infos); + void onAppDeleted(QStringList infos); + +private: + void updateFavoriteApps(); + +private: + AppDataManager *m_appManager{nullptr}; + UkuiSearch::AppInfoTable *m_appInfoTable = nullptr; +}; + +AppDataWorker::AppDataWorker(AppDataManager *appManager) : QObject(nullptr), m_appManager(appManager) +{ + m_appInfoTable = new UkuiSearch::AppInfoTable(this); + if (!m_appInfoTable || !m_appManager) { + return; + } + + initAppData(); + + connect(m_appInfoTable, &UkuiSearch::AppInfoTable::appDBItems2BAdd, this, &AppDataWorker::onAppAdded); + connect(m_appInfoTable, &UkuiSearch::AppInfoTable::appDBItems2BUpdate, this, &AppDataWorker::onAppUpdated); + connect(m_appInfoTable, &UkuiSearch::AppInfoTable::appDBItems2BDelete, this, &AppDataWorker::onAppDeleted); + connect(m_appInfoTable, &UkuiSearch::AppInfoTable::DBOpenFailed, this, &AppDataWorker::appDataBaseOpenFailed); +} + +void AppDataWorker::initAppData() +{ + QVector appInfos; + if (!m_appInfoTable->getAppInfoResults(appInfos)) { + return; + } + + if (appInfos.isEmpty()) { + return; + } + + // parse app-info + QVector normalApps; + + for (const auto &info : appInfos) { + DataEntity app; + app.setTop(info.top); + app.setLock(info.lock == 1); + app.setFavorite(info.favorite); + app.setLaunchTimes(info.launchTimes); + + app.setId(info.desktopPath); + app.setIcon(APP_ICON_PREFIX + info.iconName); + app.setName(info.appLocalName); + app.setCategory(info.category); + app.setFirstLetter(info.firstLetter); + + normalApps.append(app); + } + + { + QMutexLocker locker(&m_appManager->m_mutex); + m_appManager->m_normalApps.swap(normalApps); + } + + updateFavoriteApps(); +} + +void AppDataWorker::updateFavoriteApps() +{ + QVector favoriteApps; + for (const auto &app : m_appManager->m_normalApps) { + if (app.favorite() > 0) { + favoriteApps.append(app); + } + } + + if (favoriteApps.isEmpty()) { + return; + } + + // 排序搜藏夹数据 + std::sort(favoriteApps.begin(), favoriteApps.end(), [](const DataEntity& a, const DataEntity &b) { + return a.favorite() < b.favorite(); + }); + + { + QMutexLocker locker(&m_appManager->m_mutex); + m_appManager->m_favoriteApps.swap(favoriteApps); + } + + Q_EMIT favoriteAppChanged(); +} + +void AppDataWorker::onAppAdded(const QVector &infos) +{ + if (infos.isEmpty()) { + return; + } + + { + QMutexLocker locker(&m_appManager->m_mutex); + for (const auto &info: infos) { + DataEntity app; + app.setTop(info.top); + app.setLock(info.lock == 1); + app.setFavorite(info.favorite); + app.setLaunchTimes(info.launchTimes); + app.setId(info.desktopPath); + app.setIcon(APP_ICON_PREFIX + info.iconName); + app.setName(info.appLocalName); + app.setCategory(info.category); + app.setFirstLetter(info.firstLetter); + + m_appManager->m_normalApps.append(app); + } + } + + Q_EMIT appDataChanged(); +} + +void AppDataWorker::onAppUpdated(QVector infos) +{ + if (infos.isEmpty()) { + return; + } + + for (auto &app : m_appManager->m_normalApps) { + if (infos.isEmpty()) { + break; + } + for (int i = 0; i < infos.size(); ++i) { + const UkuiSearch::AppInfoResult &info = infos.at(i); + if (info.desktopPath == app.id()) { + QMutexLocker locker(&m_appManager->m_mutex); + + app.setTop(info.top); + app.setLock(info.lock == 1); + app.setFavorite(info.favorite); + app.setLaunchTimes(info.launchTimes); + app.setIcon(APP_ICON_PREFIX + info.iconName); + app.setName(info.appLocalName); + app.setCategory(info.category); + app.setFirstLetter(info.firstLetter); + + infos.remove(i); + break; + } + } + } + + Q_EMIT appDataChanged(); + updateFavoriteApps(); +} + +void AppDataWorker::onAppDeleted(QStringList infos) +{ + if (infos.isEmpty()) { + return; + } + + QVector::iterator appIterator = m_appManager->m_normalApps.begin(); + for (; appIterator != m_appManager->m_normalApps.end(); ++appIterator) { + if (infos.isEmpty()) { + break; + } + + QStringList::iterator infoIterator = infos.begin(); + for (; infoIterator != infos.end(); ++infoIterator) { + if ((*appIterator).id() == *infoIterator) { + QMutexLocker locker(&m_appManager->m_mutex); + m_appManager->m_normalApps.erase(appIterator); + infos.erase(infoIterator); + break; + } + } + } + + Q_EMIT appDataChanged(); + updateFavoriteApps(); +} + +// ===== AppDataManager ===== // +AppDataManager *AppDataManager::instance() +{ + static AppDataManager appDataManager; + return &appDataManager; +} + +AppDataManager::AppDataManager() +{ + AppDataWorker *appDataWorker = new AppDataWorker(this); + appDataWorker->moveToThread(&m_workerThread); + + connect(&m_workerThread, &QThread::finished, appDataWorker, &QObject::deleteLater); + connect(appDataWorker, &AppDataWorker::appDataChanged, this, &AppDataManager::appDataChanged); + connect(appDataWorker, &AppDataWorker::favoriteAppChanged, this, &AppDataManager::favoriteAppChanged); + + m_workerThread.start(); +} + +AppDataManager::~AppDataManager() +{ + m_workerThread.quit(); + m_workerThread.wait(); +} + +QVector AppDataManager::normalApps() +{ + QMutexLocker locker(&m_mutex); + return m_normalApps; +} + +QVector AppDataManager::favoriteApps() +{ + QMutexLocker locker(&m_mutex); + return m_favoriteApps; +} + +} // UkuiMenu + +#include "app-data-manager.moc" diff --git a/src/appdata/app-data-manager.h b/src/appdata/app-data-manager.h new file mode 100644 index 0000000..4d01933 --- /dev/null +++ b/src/appdata/app-data-manager.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef UKUI_MENU_APP_DATA_MANAGER_H +#define UKUI_MENU_APP_DATA_MANAGER_H + +#include +#include +#include +#include +#include + +#include "commons.h" + +namespace UkuiMenu { + +class AppDataManager : public QObject +{ + friend class AppDataWorker; + Q_OBJECT +public: + static AppDataManager *instance(); + + ~AppDataManager() override; + + AppDataManager(const AppDataManager& obj) = delete; + AppDataManager &operator=(const AppDataManager& obj) = delete; + AppDataManager(AppDataManager&& obj) = delete; + AppDataManager &operator=(AppDataManager&& obj) = delete; + + QVector normalApps(); + QVector favoriteApps(); + +Q_SIGNALS: + void appDataChanged(); + void favoriteAppChanged(); + +private: + AppDataManager(); + +private: + QMutex m_mutex; + QThread m_workerThread; + QVector m_normalApps; + QVector m_favoriteApps; +}; + +} // UkuiMenu + +#endif //UKUI_MENU_APP_DATA_MANAGER_H diff --git a/src/commons.cpp b/src/commons.cpp index 5c645e5..10c740b 100644 --- a/src/commons.cpp +++ b/src/commons.cpp @@ -20,17 +20,128 @@ #include -UkuiMenu::DataEntity::DataEntity(const UkuiMenu::DataEntity &obj) -{ - m_type = obj.m_type; - m_name = obj.m_name; - m_icon = obj.m_icon; - m_comment = obj.m_comment; - m_extraData = obj.m_extraData; -} - UkuiMenu::DataEntity::DataEntity(UkuiMenu::DataType::Type type, QString name, QString icon, QString comment, QString extraData) : m_type(type), m_name(std::move(name)), m_icon(std::move(icon)), m_comment(std::move(comment)), m_extraData(std::move(extraData)) { } + +int UkuiMenu::DataEntity::top() const +{ + return m_top; +} + +void UkuiMenu::DataEntity::setTop(int top) +{ + m_top = top; +} + +bool UkuiMenu::DataEntity::isLock() const +{ + return m_lock; +} + +void UkuiMenu::DataEntity::setLock(bool lock) +{ + m_lock = lock; +} + +int UkuiMenu::DataEntity::favorite() const +{ + return m_favorite; +} + +void UkuiMenu::DataEntity::setFavorite(int favorite) +{ + m_favorite = favorite; +} + +int UkuiMenu::DataEntity::launchTimes() const +{ + return m_launchTimes; +} + +void UkuiMenu::DataEntity::setLaunchTimes(int launchTimes) +{ + m_launchTimes = launchTimes; +} + +QString UkuiMenu::DataEntity::id() const +{ + return m_id; +} + +void UkuiMenu::DataEntity::setId(const QString &id) +{ + m_id = id; +} + +void UkuiMenu::DataEntity::setCategory(const QString &category) +{ + m_category = category; +} + +QString UkuiMenu::DataEntity::category() const +{ + return m_category; +} + +void UkuiMenu::DataEntity::setFirstLetter(const QString &firstLetter) +{ + m_firstLetter = firstLetter; +} + +QString UkuiMenu::DataEntity::firstLetter() const +{ + return m_firstLetter; +} + +void UkuiMenu::DataEntity::setType(UkuiMenu::DataType::Type type) +{ + m_type = type; +} + +UkuiMenu::DataType::Type UkuiMenu::DataEntity::type() const +{ + return m_type; +} + +void UkuiMenu::DataEntity::setIcon(const QString &icon) +{ + m_icon = icon; +} + +QString UkuiMenu::DataEntity::icon() const +{ + return m_icon; +} + +void UkuiMenu::DataEntity::setName(const QString &name) +{ + m_name = name; +} + +QString UkuiMenu::DataEntity::name() const +{ + return m_name; +} + +void UkuiMenu::DataEntity::setComment(const QString &comment) +{ + m_comment = comment; +} + +QString UkuiMenu::DataEntity::comment() const +{ + return m_comment; +} + +void UkuiMenu::DataEntity::setExtraData(const QString &extraData) +{ + m_extraData = extraData; +} + +QString UkuiMenu::DataEntity::extraData() const +{ + return m_extraData; +} diff --git a/src/commons.h b/src/commons.h index 1b31b51..b472467 100644 --- a/src/commons.h +++ b/src/commons.h @@ -68,30 +68,57 @@ public: ExtraData }; DataEntity() = default; - DataEntity(const DataEntity& obj); DataEntity(DataType::Type type, QString name, QString icon, QString comment, QString extraData); - void setType(DataType::Type type) {m_type = type;} - DataType::Type type() {return m_type;} + int top() const; + void setTop(int top); - void setIcon(const QString& icon) {m_icon = icon;} - QString icon() {return m_icon;} + bool isLock() const; + void setLock(bool lock); - void setName(const QString& name) {m_name = name;} - QString name() {return m_name;} + int favorite() const; + void setFavorite(int favorite); - void setComment(const QString& comment) {m_comment = comment;} - QString comment() {return m_comment;} + int launchTimes() const; + void setLaunchTimes(int launchTimes); - void setExtraData(const QString& extraData) {m_extraData = extraData;} - QString extraData() {return m_extraData;} + QString id() const; + void setId(const QString& id); + + void setCategory(const QString& category); + QString category() const; + + void setFirstLetter(const QString& firstLetter); + QString firstLetter() const; + + void setType(DataType::Type type); + DataType::Type type() const; + + void setIcon(const QString& icon); + QString icon() const; + + void setName(const QString& name); + QString name() const; + + void setComment(const QString& comment); + QString comment() const; + + void setExtraData(const QString& extraData); + QString extraData() const; private: + bool m_lock{false}; // 应用锁定 + int m_top{0}; // 置顶状态及序号 + int m_favorite{0}; // 收藏状态及序号 + int m_launchTimes{0}; // 启动次数 + DataType::Type m_type {DataType::Normal}; + QString m_id; // 应用可执行文件路径 QString m_icon; QString m_name; - QString m_comment; // 应用描述 - QString m_extraData; // 额外的数据 - DataType::Type m_type {DataType::Normal}; + QString m_category; + QString m_firstLetter; + QString m_comment; // 应用描述 + QString m_extraData; // 额外的数据 }; class CommonsModule