ukui-notification/libukui-notification/notification-settings/settings-manager.cpp

372 lines
13 KiB
C++

/*
* 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 <https://www.gnu.org/licenses/>.
*
* Authors: iaom <zhangpengfei@kylinos.cn>
*/
#include "settings-manager.h"
#include "settings-manager-private.h"
#include <QFile>
#include <QDir>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QDebug>
#include <QList>
#include <QLockFile>
#include <QCoreApplication>
#include <mutex>
#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;
}