/* * 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 . * * Authors: iaom */ #include "settings-manager.h" #include "settings-manager-private.h" #include #include #include #include #include #include #include #include #include #include #include "settings-properties-info.h" using namespace UkuiNotification; static const QString SETTINGS_FILE_PATH = QDir::homePath() + QStringLiteral("/.config/org.ukui/ukui-notification"); static const QString SETTINGS_FILE_PATH_NAME = SETTINGS_FILE_PATH + QStringLiteral("/ukui-notification-settings.json"); static std::once_flag flag; static SettingsManager *s_self; SettingsManagerPrivate::SettingsManagerPrivate(QObject* parent) : QObject(parent) { for(SettingsProperty::Property property : SINGLE_APPLICATION_SETTINGS) { SettingsPropertiesInfo info(property); m_applicationDefaultSettings.insert(info.name(), info.defaultValue()); } } SettingsManagerPrivate::~SettingsManagerPrivate() { } void SettingsManagerPrivate::init() { m_watcher = new QFileSystemWatcher(this); connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &SettingsManagerPrivate::checkAndLoad); //TODO 应用数据服务接口更新中 m_applicationInfo = new UkuiSearch::ApplicationInfo(this); if (qApp->property("IS_UKUI_NOTIFICATION_SERVER").toBool()) { connect(m_applicationInfo, &UkuiSearch::ApplicationInfo::appDBItems2BAdd, this,&SettingsManagerPrivate::desktopFileAdd); } connect(m_applicationInfo, &UkuiSearch::ApplicationInfo::appDBItems2BDelete, this, &SettingsManagerPrivate::desktopFileDelete); checkAndLoad(); } void SettingsManagerPrivate::checkAndLoad() { QLockFile lockFile(SETTINGS_FILE_PATH + QStringLiteral("ukui-notification-settings.json.lock")); lockFile.lock(); QFile settingsFile(SETTINGS_FILE_PATH_NAME); if (!settingsFile.exists()) { qDebug() << SETTINGS_FILE_PATH_NAME << " is not exist, start create settings file."; createSettingsFile(); lockFile.unlock(); return; } if (!settingsFile.open(QFile::ReadOnly)) { qWarning() << "SettingsManagerPrivate: configuration file " << settingsFile.fileName() << "open failed !"; m_watcher->addPath(SETTINGS_FILE_PATH_NAME); lockFile.unlock(); return; } // 读取json数据 QByteArray byteArray = settingsFile.readAll(); settingsFile.close(); QJsonParseError errRpt; QJsonDocument jsonDocument(QJsonDocument::fromJson(byteArray, &errRpt)); if (errRpt.error != QJsonParseError::NoError) { qWarning() << "SettingsManagerPrivate: Incorrect configuration files. JSON parse error"; createSettingsFile(); lockFile.unlock(); return; } // 读取配置文件 QJsonObject settingsData = jsonDocument.object(); QString version = settingsData.value("VERSION").toString(); if (version != QString(NOTIFICATION_SETTINGS_VERSION)) { qDebug() << "Notification settings version is different, need update! configFile:" << version << " new:" << NOTIFICATION_SETTINGS_VERSION; updateSettingsFile(); } else { if(m_needCheckApplist) { checkApplicationList(settingsData); m_needCheckApplist = false; } m_settingsData.swap(settingsData); Q_EMIT settingsUpdateFinished(); m_watcher->addPath(SETTINGS_FILE_PATH_NAME); } lockFile.unlock(); } void SettingsManagerPrivate::createSettingsFile() { initSettingsData(m_settingsData); save2SettingsFile(m_settingsData); Q_EMIT settingsUpdateFinished(); m_watcher->addPath(SETTINGS_FILE_PATH_NAME); } void SettingsManagerPrivate::updateSettingsFile() { m_watcher->removePath(SETTINGS_FILE_PATH_NAME); //初始化当前版本默认值 QJsonObject newData; initSettingsData(newData); //同步全局配置 QJsonObject newGlobalData = newData.value(QStringLiteral("Global")).toObject(); QJsonObject oldGlobalData = m_settingsData.value(QStringLiteral("Global")).toObject(); for(const QString &key : newGlobalData.keys()) { QJsonValue oldValue = oldGlobalData.value(key); if(!oldValue.isUndefined()) { newGlobalData.insert(key, oldValue); } } newData.insert(QStringLiteral("Global"), newGlobalData); //同步所有应用配置 QJsonObject newApplicationsData = newData.value(QStringLiteral("Applications")).toObject(); QJsonObject oldApplicationsData = m_settingsData.value(QStringLiteral("Applications")).toObject(); for(const QString &desktopEntry : newApplicationsData.keys()) { if(oldApplicationsData.contains(desktopEntry)) { QJsonObject oldSingleAppData = oldApplicationsData.value(desktopEntry).toObject(); QJsonObject newSingleAppData = newApplicationsData.value(desktopEntry).toObject(); for(const QString &key : newSingleAppData.keys()) { QJsonValue oldValue = oldSingleAppData.value(key); if(!oldValue.isUndefined()) { newSingleAppData.insert(key, oldValue); } } newApplicationsData.insert(desktopEntry, newSingleAppData); } } newData.insert(QStringLiteral("Applications"), newApplicationsData); //写入数据 m_settingsData.swap(newData); save2SettingsFile(m_settingsData); m_watcher->addPath(SETTINGS_FILE_PATH_NAME); Q_EMIT settingsUpdateFinished(); } QStringList SettingsManagerPrivate::getAppInfo() { // 过滤掉不需要显示的应用 UkuiSearch::ApplicationPropertyMap restrictions = { {UkuiSearch::ApplicationProperty::DontDisplay, 0} }; return m_applicationInfo->getInfo(UkuiSearch::ApplicationProperties{}, restrictions).keys(); } void SettingsManagerPrivate::initSettingsData(QJsonObject &data) { data.insert("VERSION", QString(NOTIFICATION_SETTINGS_VERSION)); //全局设置 QJsonObject globalSettings; for(SettingsProperty::Property property : GLOBAL_SETTINGS) { SettingsPropertiesInfo info(property); globalSettings.insert(info.name(), info.defaultValue()); } data.insert(QStringLiteral("Global"), globalSettings); //应用设置 QJsonObject applicationsSettings; for (const QString &desktopFile : getAppInfo()) { applicationsSettings.insert(desktopFile, m_applicationDefaultSettings); } data.insert(QStringLiteral("Applications"), applicationsSettings); } void SettingsManagerPrivate::desktopFileAdd(const QStringList &data) { QJsonObject applicationsSettings = m_settingsData.value(QStringLiteral("Applications")).toObject(); bool needUpdate = false; for (const QString &desktopPath : data) { if(m_applicationInfo->getInfo(desktopPath, UkuiSearch::ApplicationProperty::AutoStart).toInt() == 0) { applicationsSettings.insert(desktopPath, m_applicationDefaultSettings); needUpdate = true; } } if(!needUpdate) { return; } m_settingsData.insert(QStringLiteral("Applications"), applicationsSettings); QLockFile lockFile(SETTINGS_FILE_PATH + QStringLiteral("ukui-notification-settings.json.lock")); lockFile.lock(); m_watcher->removePath(SETTINGS_FILE_PATH_NAME); save2SettingsFile(m_settingsData); m_watcher->addPath(SETTINGS_FILE_PATH_NAME); lockFile.unlock(); Q_EMIT settingsUpdateFinished(); } void SettingsManagerPrivate::desktopFileDelete(const QStringList &data) { if (data.isEmpty()) { return; } if (qApp->property("IS_UKUI_NOTIFICATION_SERVER").toBool()) { QJsonObject applicationsSettings = m_settingsData.value(QStringLiteral("Applications")).toObject(); for (const QString &app : data) { applicationsSettings.remove(app); } m_settingsData.insert(QStringLiteral("Applications"), applicationsSettings); QLockFile lockFile(SETTINGS_FILE_PATH + QStringLiteral("ukui-notification-settings.json.lock")); lockFile.lock(); m_watcher->removePath(SETTINGS_FILE_PATH_NAME); save2SettingsFile(m_settingsData); m_watcher->addPath(SETTINGS_FILE_PATH_NAME); lockFile.unlock(); Q_EMIT settingsUpdateFinished(); } for(const QString &app : data) { Q_EMIT appUninstalled(app); } } void SettingsManagerPrivate::save2SettingsFile(const QJsonObject &jsonDocData) { QDir dir; QString configFileDir(SETTINGS_FILE_PATH); if (!dir.exists(configFileDir)) { if (!dir.mkdir(configFileDir)) { qWarning() << "Unable to create notification settings config file."; return; } } QFile settingsFile(SETTINGS_FILE_PATH_NAME); settingsFile.open(QIODevice::WriteOnly | QIODevice::Truncate); if (settingsFile.write(QJsonDocument(jsonDocData).toJson()) == -1) { qWarning() << "SettingsManagerPrivate: Error saving configuration file."; } settingsFile.flush(); settingsFile.close(); } void SettingsManagerPrivate::checkApplicationList(QJsonObject &data) { QStringList appList = getAppInfo(); QStringList appNeedRemoved; QJsonObject applicationSettings = data.value(QStringLiteral("Applications")).toObject(); for(const QString &desktopFile : applicationSettings.keys()) { if(appList.contains(desktopFile)) { appList.removeAll(desktopFile); } else { appNeedRemoved.append(desktopFile); } } //移除应用列表里已经不存在的应用 for(const QString &desktopFile : appNeedRemoved) { applicationSettings.remove(desktopFile); } //将配置文件中没有的应用插入 for(const QString &desktopFile : appList) { applicationSettings.insert(desktopFile, m_applicationDefaultSettings); } data.insert(QStringLiteral("Applications"), applicationSettings); save2SettingsFile(data); } SettingsManager::SettingsManager(QObject *parent) : QObject(parent), d(new SettingsManagerPrivate(this)) { connect(d, &SettingsManagerPrivate::settingsUpdateFinished, this, &SettingsManager::settingsDataChanged); connect(d, &SettingsManagerPrivate::appUninstalled, this, &SettingsManager::appUninstalled); d->init(); } QJsonObject SettingsManager::getGlobalSettings() { return d->m_settingsData.value(QStringLiteral("Global")).toObject(); } QJsonObject SettingsManager::getAllAppSettings() { return d->m_settingsData.value(QStringLiteral("Applications")).toObject(); } QJsonObject SettingsManager::getAppSettings(const QString &appDesktopName) { if(appDesktopName == QStringLiteral("default") || appDesktopName.isEmpty()) { return d->m_applicationDefaultSettings; } QJsonValue value = d->m_settingsData.value(QStringLiteral("Applications")).toObject().value(appDesktopName); if(value.isUndefined()) { return {}; } return value.toObject(); } QJsonObject SettingsManager::getAppDefaultSettings() { return d->m_applicationDefaultSettings; } SettingsManager *SettingsManager::self() { std::call_once(flag, [ & ] { s_self = new SettingsManager(); }); return s_self; } bool SettingsManager::setGlobalSettings(SettingsProperty::Property key, const QVariant &value) { if(!GLOBAL_SETTINGS.contains(key)) { return false; } auto info = SettingsPropertiesInfo(key); QString valueToSet = info.valueToString(value); QJsonObject data = d->m_settingsData.value(QStringLiteral("Global")).toObject(); data.insert(info.name(), valueToSet); d->m_settingsData.insert(QStringLiteral("Global"), data); QLockFile lockFile(SETTINGS_FILE_PATH + QStringLiteral("ukui-notification-settings.json.lock")); lockFile.lock(); d->save2SettingsFile(d->m_settingsData); lockFile.unlock(); return true; } bool SettingsManager::setAppSettings(const QString &appDesktopName, SettingsProperty::Property key, const QVariant &value) { if(!SINGLE_APPLICATION_SETTINGS.contains(key)) { return false; } QJsonObject appsData = d->m_settingsData.value(QStringLiteral("Applications")).toObject(); QJsonValue dataValue = appsData.value(appDesktopName); if(dataValue.isUndefined()) { return false; } QJsonObject oneAppData = dataValue.toObject(); auto info = SettingsPropertiesInfo(key); QString valueToSet = info.valueToString(value); oneAppData.insert(info.name(), valueToSet); appsData.insert(appDesktopName, oneAppData); d->m_settingsData.insert(QStringLiteral("Applications"), appsData); QLockFile lockFile(SETTINGS_FILE_PATH + QStringLiteral("ukui-notification-settings.json.lock")); lockFile.lock(); d->save2SettingsFile(d->m_settingsData); lockFile.unlock(); return true; }