diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a0479f..98ed6d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ set(SOURCE_FILES src/model/model-manager.cpp src/model/model-manager.h src/appdata/app-icon-provider.cpp src/appdata/app-icon-provider.h src/windows/menu-main-window.cpp src/windows/menu-main-window.h + src/appdata/app-folder-helper.cpp src/appdata/app-folder-helper.h src/extension/menu-extension.cpp src/extension/menu-extension.h src/extension/menu-extension-iface.h src/appdata/data-provider-plugin-iface.h diff --git a/src/appdata/app-folder-helper.cpp b/src/appdata/app-folder-helper.cpp new file mode 100644 index 0000000..276203e --- /dev/null +++ b/src/appdata/app-folder-helper.cpp @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2022, 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-folder-helper.h" + +#include +#include +#include +#include +#include +#include + +#define FOLDER_FILE_PATH ".config/ukui-menu/" +#define FOLDER_FILE_NAME "folder.json" + +namespace UkuiMenu { + +QString AppFolderHelper::s_folderConfigFile = QDir::homePath() + "/" + FOLDER_FILE_PATH + FOLDER_FILE_NAME; + +AppFolderHelper *AppFolderHelper::instance() +{ + static AppFolderHelper appFolderHelper; + return &appFolderHelper; +} + +AppFolderHelper::AppFolderHelper() +{ + if (!QFile::exists(s_folderConfigFile)) { + QDir dir; + QString folderConfigDir(QDir::homePath() + "/" + FOLDER_FILE_PATH); + if (!dir.exists(folderConfigDir)) { + if (!dir.mkdir(folderConfigDir)) { + qWarning() << "Unable to create profile folder."; + return; + } + } + + QFile file(s_folderConfigFile); + file.open(QFile::WriteOnly); + file.close(); + } + + readData(); +} + +AppFolderHelper::~AppFolderHelper() +{ + saveData(); +} + +void AppFolderHelper::insertFolder(const Folder &folder) +{ + QMutexLocker locker(&m_mutex); + m_folders.append(folder); +} + +void AppFolderHelper::addAppToFolder(const QString& appName, const QString& folderName) +{ + if (appName.isEmpty() || folderName.isEmpty()) { + return; + } + + { + QMutexLocker locker(&m_mutex); + Folder *folder = findFolder(folderName); + if (folder) { + if (!folder->apps.contains(appName)) { + folder->apps.append(appName); + } + return; + } + } + + // 新文件夹放最后 + Folder folder; + folder.name = folderName; + folder.apps.append(appName); + if (m_folders.isEmpty()) { + folder.index = 1; + } else { + folder.index = m_folders.last().index + 1; + } + + insertFolder(folder); +} + +void AppFolderHelper::removeAppFromFolder(const QString &appName, const QString &folderName) +{ + if (appName.isEmpty() || folderName.isEmpty()) { + return; + } + + QMutexLocker locker(&m_mutex); + Folder *folder = findFolder(folderName); + if (!folder) { + return; + } + + if (folder->apps.contains(appName)) { + folder->apps.removeOne(appName); + } +} + +bool AppFolderHelper::deleteFolder(const QString &folderName) +{ + if (folderName.isEmpty()) { + return false; + } + + QMutexLocker locker(&m_mutex); + QVector::iterator iterator = m_folders.begin(); + for (; iterator != m_folders.end(); ++iterator) { + if (folderName == iterator->name) { + m_folders.erase(iterator); + return true; + } + } + + return false; +} + +QVector AppFolderHelper::folderData() +{ + QMutexLocker locker(&m_mutex); + return m_folders; +} + +const Folder *AppFolderHelper::searchFolder(const QString &folderName) +{ + QMutexLocker locker(&m_mutex); + return findFolder(folderName); +} + +const Folder *AppFolderHelper::searchFolderByAppName(const QString &appName) +{ + QMutexLocker locker(&m_mutex); + return findFolderByAppName(appName); +} + +Folder *AppFolderHelper::findFolder(const QString &folderName) +{ + if (m_folders.empty()) { + return nullptr; + } + + QVector::iterator iterator = m_folders.begin(); + for (; iterator != m_folders.end(); ++iterator) { + if (folderName == iterator->name) { + // 如果定义了 QT_STRICT_ITERATORS 宏,那么迭代器为:class iterator; 否则迭代器为:typedef T* iterator; + // kylin上的qt库没有定义QT_STRICT_ITERATORS宏,需要注意该处可能出现的编译错误,参见QVector源码。 + // return &*iterator; + return iterator; + } + } + + return nullptr; +} + +Folder *AppFolderHelper::findFolderByAppName(const QString &appName) +{ + if (m_folders.empty()) { + return nullptr; + } + + QVector::iterator iterator = m_folders.begin(); + for (; iterator != m_folders.end(); ++iterator) { + if (iterator->apps.contains(appName)) { + return iterator; + } + } + + return nullptr; +} + +void AppFolderHelper::forceSync() +{ + saveData(); + //readData(); +} + +void AppFolderHelper::readData() +{ + QFile file(s_folderConfigFile); + if (!file.open(QFile::ReadOnly)) { + return; + } + + // 读取json数据 + QByteArray byteArray = file.readAll(); + file.close(); + + QJsonDocument jsonDocument(QJsonDocument::fromJson(byteArray)); + if (jsonDocument.isNull() || jsonDocument.isEmpty() || !jsonDocument.isArray()) { + qWarning() << "AppFolderHelper: Incorrect configuration files are ignored."; + return; + } + + { + QMutexLocker locker(&m_mutex); + m_folders.clear(); + } + + // 遍历json数据节点 + QJsonArray jsonArray = jsonDocument.array(); + QJsonArray::iterator iterator = jsonArray.begin(); + while (iterator != jsonArray.end()) { + QJsonObject object = (*iterator).toObject(); + + if (object.contains("name") && object.contains("index") && object.contains("apps")) { + Folder folder; + + folder.name = object.value(QLatin1String("name")).toString(); + folder.index = object.value(QLatin1String("index")).toInt(); + + QJsonArray apps = object.value(QLatin1String("apps")).toArray(); + for (const auto &app : apps) { + folder.apps.append(app.toString()); + } + + if (!folder.apps.isEmpty()) { + insertFolder(folder); + } + } + + ++iterator; + } +} + +void AppFolderHelper::saveData() +{ + QFile file(s_folderConfigFile); + if (!file.open(QFile::WriteOnly)) { + return; + } + + // 读取json数据 + QJsonDocument jsonDocument; + QJsonArray folderArray; + + { + QMutexLocker locker(&m_mutex); + for (const auto &folder : m_folders) { + QJsonObject object; + QJsonArray apps; + + for (const auto &app : folder.apps) { + apps.append(app); + } + + object.insert("name", folder.name); + object.insert("index", folder.index); + object.insert("apps", apps); + + folderArray.append(object); + } + } + + jsonDocument.setArray(folderArray); + + if (file.write(jsonDocument.toJson()) == -1) { + qWarning() << "Error saving configuration file."; + } + file.flush(); + file.close(); +} + +} // UkuiMenu diff --git a/src/appdata/app-folder-helper.h b/src/appdata/app-folder-helper.h new file mode 100644 index 0000000..775fd74 --- /dev/null +++ b/src/appdata/app-folder-helper.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022, 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_FOLDER_HELPER_H +#define UKUI_MENU_APP_FOLDER_HELPER_H + +#include +#include +#include +#include +#include +#include + +namespace UkuiMenu { + +class Folder +{ + Q_GADGET + Q_PROPERTY(QString index READ getIndex) + Q_PROPERTY(QString name READ getName) + Q_PROPERTY(QStringList apps READ getApps) +public: + int getIndex() { return index; } + QString getName() { return name; } + QStringList getApps() { return apps; } + +public: + int index; + QString name; + QStringList apps; +}; + +class AppFolderHelper : public QObject +{ + Q_OBJECT +public: + static AppFolderHelper *instance(); + ~AppFolderHelper() override; + + AppFolderHelper(const AppFolderHelper& obj) = delete; + AppFolderHelper &operator=(const AppFolderHelper& obj) = delete; + AppFolderHelper(AppFolderHelper&& obj) = delete; + AppFolderHelper &operator=(AppFolderHelper&& obj) = delete; + + // TODO 修改文件夹信息 + // xxxx + const Folder *searchFolder(const QString& folderName); + const Folder *searchFolderByAppName(const QString& appName); + QVector folderData(); + + void addAppToFolder(const QString& appName, const QString& folderName); + void removeAppFromFolder(const QString& appName, const QString& folderName); + bool deleteFolder(const QString& folderName); + + void forceSync(); + +Q_SIGNALS: + void folderDataChanged(); + +private: + AppFolderHelper(); + void readData(); + void saveData(); + void insertFolder(const Folder& folder); + Folder *findFolder(const QString& folderName); + Folder *findFolderByAppName(const QString& appName); + // TODO 配置文件监听 + +private: + QMutex m_mutex; + QVector m_folders; + static QString s_folderConfigFile; +}; + +} // UkuiMenu + +#endif //UKUI_MENU_APP_FOLDER_HELPER_H