--- /dev/null
+# SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
+# SPDX-License-Identifier: LGPL-3.0-or-later
+
+include(MacroAddFileDependencies)
+include(CMakeParseArguments)
+
+# Define the helper function
+function(dtk_add_config_to_cpp OUTPUT_VAR JSON_FILE)
+ if(NOT EXISTS ${JSON_FILE})
+ message(FATAL_ERROR "JSON file ${JSON_FILE} does not exist.")
+ endif()
+
+ cmake_parse_arguments(
+ "arg"
+ ""
+ "OUTPUT_FILE_NAME;CLASS_NAME;USE_QPROPERTY"
+ ""
+ ${ARGN}
+ )
+
+ # Generate the output header file name
+ get_filename_component(FILE_NAME_WLE ${JSON_FILE} NAME_WLE)
+ if(DEFINED arg_OUTPUT_FILE_NAME)
+ set(OUTPUT_HEADER "${CMAKE_CURRENT_BINARY_DIR}/${arg_OUTPUT_FILE_NAME}")
+ else()
+ set(OUTPUT_HEADER "${CMAKE_CURRENT_BINARY_DIR}/dconfig_${FILE_NAME_WLE}.hpp")
+ endif()
+
+ # Check if CLASS_NAME is set
+ if(DEFINED arg_CLASS_NAME)
+ set(CLASS_NAME_ARG -c ${arg_CLASS_NAME})
+ else()
+ set(CLASS_NAME_ARG "")
+ endif()
+
+ if(NOT DEFINED arg_USE_QPROPERTY)
+ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
+ set(arg_USE_QPROPERTY ON)
+ endif()
+ endif()
+
+ if (arg_USE_QPROPERTY)
+ set(USE_QPROPERTY_ARG "--use-qproperty")
+ else()
+ set(USE_QPROPERTY_ARG "")
+ endif()
+
+ # Add a custom command to run dconfig2cpp
+ add_custom_command(
+ OUTPUT ${OUTPUT_HEADER}
+ COMMAND ${DTK_DCONFIG2CPP} -o ${OUTPUT_HEADER} ${CLASS_NAME_ARG} ${USE_QPROPERTY_ARG} ${JSON_FILE}
+ DEPENDS ${JSON_FILE} ${DTK_XML2CPP}
+ COMMENT "Generating ${OUTPUT_HEADER} from ${JSON_FILE}"
+ VERBATIM
+ )
+
+ # Add the generated header to the specified output variable
+ set(${OUTPUT_VAR} ${${OUTPUT_VAR}} ${OUTPUT_HEADER} PARENT_SCOPE)
+endfunction()
include("${CMAKE_CURRENT_LIST_DIR}/Dtk@DTK_VERSION_MAJOR@SettingsToolsMacros.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/Dtk@DTK_VERSION_MAJOR@ToolsTargets.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/DtkDBusMacros.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/DtkDConfigMacros.cmake")
get_target_property(DTK_XML2CPP Dtk@DTK_VERSION_MAJOR@::Xml2Cpp LOCATION)
+get_target_property(DTK_DCONFIG2CPP Dtk@DTK_VERSION_MAJOR@::DConfig2Cpp LOCATION)
+dtkcore (5.7.11) unstable; urgency=medium
+
+ * feat: dconfig2cpp generated codes supports qml
+ * feat: export ProductType for QML
+ * feat: async get dconfig value for DLog
+ * feat: support auto generate the Qt code from a dconfig's json
+
+ -- YeShanShan <yeshanshan@uniontech.com> Thu, 27 Feb 2025 20:47:22 +0800
+
+dtkcore (5.7.10) unstable; urgency=medium
+
+ * Release 5.7.10
+
+ -- YeShanShan <yeshanshan@uniontech.com> Thu, 13 Feb 2025 17:18:04 +0800
+
dtkcore (5.7.9) unstable; urgency=medium
[ root ]
@param[in] appId 配置文件所属的应用Id
@note 需要在QCoreApplication构造前设置。
+@fn static void DConfig::globalThread()
+@brief 一个服务于 DConfig 的公用线程,一般用于 dconfig2cpp 生成的代码,此线程在构造时会自动调用 QThread::start 以满足 dconfig2cpp 的需求。
+@return 此线程默认为 running 状态
+@note 请不要析构它,它会在应用程序退出时释放
+
@fn QString Dtk::Core::DConfig::backendName()
@brief 配置策略后端名称
@return 配置策略后端名称
install(FILES cmake/DtkTools/DtkDBusMacros.cmake
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools")
+install(FILES ${CMAKE_SOURCE_DIR}/cmake/DtkTools/DtkDConfigMacros.cmake
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools")
+
if (NOT DTK_VERSION_MAJOR)
set(DCONFIG_DEPRECATED_FUNCS [=[
# deprecated since dtk6
Q_OBJECT
D_DECLARE_PRIVATE(DConfig)
- Q_PROPERTY(QStringList keyList READ keyList FINAL)
+ Q_PROPERTY(QStringList keyList READ keyList CONSTANT FINAL)
public:
explicit DConfig(const QString &name, const QString &subpath = QString(),
QObject *parent = nullptr);
static void setAppId(const QString &appId);
+ static QThread *globalThread();
QString backendName() const;
NixOS
};
+ Q_ENUM(ProductType)
+
enum DeepinType {
UnknownDeepin = 0,
DeepinDesktop,
@fn QString DConfigBackend::name() const = 0
@brief The unique identity of the backend configuration
+ */
/*!
@~english
qCDebug(cfLog, "Explicitly specify application Id as appId=%s for config.", qPrintable(appId));
}
+class DConfigThread : public QThread
+{
+public:
+ DConfigThread() {
+ setObjectName("DConfigGlobalThread");
+ start();
+ }
+
+ ~DConfigThread() override {
+ if (isRunning()) {
+ quit();
+ wait();
+ }
+ }
+};
+
+Q_GLOBAL_STATIC(DConfigThread, _globalThread)
+
+QThread *DConfig::globalThread()
+{
+ return _globalThread;
+}
+
/*!
@~english
* @brief Use custom configuration policy backend to construct objects
#include <QtCore>
#include "LogManager.h"
-#include "dconfig.h"
#include <DSGApplication>
#include <Logger.h>
#include <ConsoleAppender.h>
#include <RollingFileAppender.h>
#include <JournalAppender.h>
+
#include "dstandardpaths.h"
+#include "dconfig_org_deepin_dtk_preference.hpp"
DCORE_BEGIN_NAMESPACE
{
}
- DConfig *createDConfig(const QString &appId);
+ dconfig_org_deepin_dtk_preference *createDConfig(const QString &appId);
void initLoggingRules();
void updateLoggingRules();
ConsoleAppender* m_consoleAppender = nullptr;
RollingFileAppender* m_rollingFileAppender = nullptr;
JournalAppender* m_journalAppender = nullptr;
- QScopedPointer<DConfig> m_dsgConfig;
- QScopedPointer<DConfig> m_fallbackConfig;
+ QScopedPointer<dconfig_org_deepin_dtk_preference> m_dsgConfig;
+ QScopedPointer<dconfig_org_deepin_dtk_preference> m_fallbackConfig;
DLogManager *q_ptr = nullptr;
Q_DECLARE_PUBLIC(DLogManager)
};
-DConfig *DLogManagerPrivate::createDConfig(const QString &appId)
+dconfig_org_deepin_dtk_preference *DLogManagerPrivate::createDConfig(const QString &appId)
{
if (appId.isEmpty())
return nullptr;
- DConfig *config = DConfig::create(appId, "org.deepin.dtk.preference");
- if (!config->isValid()) {
- qWarning() << "Logging rules config is invalid, please check `appId` [" << appId << "]arg is correct";
- delete config;
- config = nullptr;
- return nullptr;
- }
-
- QObject::connect(config, &DConfig::valueChanged, config, [this](const QString &key) {
- if (key != RULES_KEY)
- return;
-
- updateLoggingRules();
- });
+ auto config = dconfig_org_deepin_dtk_preference::create(appId);
+ QObject::connect(config, &dconfig_org_deepin_dtk_preference::rulesChanged,
+ config, [this](){ updateLoggingRules(); });
return config;
}
QString dsgAppId = DSGApplication::id();
m_dsgConfig.reset(createDConfig(dsgAppId));
+ if (m_dsgConfig) {
+ QObject::connect(m_dsgConfig.data(), &dconfig_org_deepin_dtk_preference::configInitializeSucceed,
+ m_dsgConfig.data(), [this](){ updateLoggingRules(); });
+ QObject::connect(m_dsgConfig.data(), &dconfig_org_deepin_dtk_preference::configInitializeFailed,
+ m_dsgConfig.data(), [this, dsgAppId] {
+ m_dsgConfig.reset();
+ qWarning() << "Logging rules config is invalid, please check `appId` [" << dsgAppId << "]arg is correct";
+ });
+ }
+
QString fallbackId = qgetenv("DTK_LOGGING_FALLBACK_APPID");
// 2. fallbackId 和 dsgAppId 非空且不等时,都创建和监听变化
if (!fallbackId.isEmpty() && fallbackId != dsgAppId)
m_fallbackConfig.reset(createDConfig(fallbackId));
- // 3. 默认值和非默认值时,非默认值优先
- updateLoggingRules();
+ // 3. 默认值和非默认值时,非默认值优先
+ if (m_fallbackConfig) {
+ QObject::connect(m_fallbackConfig.data(), &dconfig_org_deepin_dtk_preference::configInitializeSucceed,
+ m_fallbackConfig.data(), [this](){ updateLoggingRules(); });
+ QObject::connect(m_fallbackConfig.data(), &dconfig_org_deepin_dtk_preference::configInitializeFailed,
+ m_fallbackConfig.data(), [this, fallbackId] {
+ m_fallbackConfig.reset();
+ qWarning() << "Logging rules config is invalid, please check `appId` [" << fallbackId << "]arg is correct";
+ });
+ }
}
void DLogManagerPrivate::updateLoggingRules()
{
QVariant var;
// 4. 优先看 dsgConfig 是否默认值,其次 fallback 是否默认值
- if (m_dsgConfig && !m_dsgConfig->isDefaultValue(RULES_KEY)) {
- var = m_dsgConfig->value(RULES_KEY);
- } else if (m_fallbackConfig && !m_fallbackConfig->isDefaultValue(RULES_KEY)) {
- var = m_fallbackConfig->value(RULES_KEY);
- } else if (m_dsgConfig) {
- var = m_dsgConfig->value(RULES_KEY);
+ if (m_dsgConfig && m_dsgConfig->isInitializeSucceed() && !m_dsgConfig->rulesIsDefaultValue()) {
+ var = m_dsgConfig->rules();
+ } else if (m_fallbackConfig && m_dsgConfig->isInitializeSucceed() && !m_fallbackConfig->rulesIsDefaultValue()) {
+ var = m_fallbackConfig->rules();
+ } else if (m_dsgConfig && m_dsgConfig->isInitializeSucceed()) {
+ var = m_dsgConfig->rules();
}
if (var.isValid())
--- /dev/null
+/**
+ * This file is generated by dconfig2cpp.
+ * Command line arguments: /home/zccrs/projects/dtkcore/build/unknown-Debug/tools/dconfig2cpp/dconfig2cpp /home/zccrs/projects/dtkcommon/configs/org.deepin.dtk.preference.json
+ * Generation time: 2025-02-21T13:49:21
+ * JSON file version: 1.0
+ *
+ * WARNING: DO NOT MODIFY THIS FILE MANUALLY.
+ * If you need to change the content, please modify the dconfig2cpp tool.
+ */
+
+#ifndef DCONFIG_ORG_DEEPIN_DTK_PREFERENCE_H
+#define DCONFIG_ORG_DEEPIN_DTK_PREFERENCE_H
+
+#include <QThread>
+#include <QVariant>
+#include <QDebug>
+#include <QAtomicPointer>
+#include <QAtomicInteger>
+#include <DConfig>
+
+class dconfig_org_deepin_dtk_preference : public QObject {
+ Q_OBJECT
+
+ Q_PROPERTY(bool autoDisplayFeature READ autoDisplayFeature WRITE setAutoDisplayFeature NOTIFY autoDisplayFeatureChanged RESET resetAutoDisplayFeature)
+ Q_PROPERTY(bool featureUpdated READ featureUpdated WRITE setFeatureUpdated NOTIFY featureUpdatedChanged RESET resetFeatureUpdated)
+ Q_PROPERTY(bool keyboardsearchDisabled READ keyboardsearchDisabled WRITE setKeyboardsearchDisabled NOTIFY keyboardsearchDisabledChanged RESET resetKeyboardsearchDisabled)
+ Q_PROPERTY(QString rules READ rules WRITE setRules NOTIFY rulesChanged RESET resetRules)
+ Q_PROPERTY(qlonglong themeType READ themeType WRITE setThemeType NOTIFY themeTypeChanged RESET resetThemeType)
+ Q_PROPERTY(qlonglong titlebarHeight READ titlebarHeight WRITE setTitlebarHeight NOTIFY titlebarHeightChanged RESET resetTitlebarHeight)
+ Q_PROPERTY(bool underlineShortcut READ underlineShortcut WRITE setUnderlineShortcut NOTIFY underlineShortcutChanged RESET resetUnderlineShortcut)
+ Q_CLASSINFO("DConfigKeyList", "autoDisplayFeature;featureUpdated;keyboardsearchDisabled;rules;themeType;titlebarHeight;underlineShortcut")
+ Q_CLASSINFO("DConfigFileName", "org.deepin.dtk.preference")
+ Q_CLASSINFO("DConfigFileVersion", "1.0")
+
+public:
+ explicit dconfig_org_deepin_dtk_preference(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId, const QString &subpath, QObject *parent)
+ : QObject(parent) {
+ if (!thread->isRunning()) {
+ qWarning() << QLatin1String("Warning: The provided thread is not running.");
+ }
+ Q_ASSERT(QThread::currentThread() != thread);
+ auto worker = new QObject();
+ worker->moveToThread(thread);
+ QMetaObject::invokeMethod(worker, [=, this]() {
+ DTK_CORE_NAMESPACE::DConfig *config = nullptr;
+ if (backend) {
+ if (appId.isNull()) {
+ config = DTK_CORE_NAMESPACE::DConfig::create(backend, name, subpath, nullptr);
+ } else {
+ config = DTK_CORE_NAMESPACE::DConfig::create(backend, appId, name, subpath, nullptr);
+ }
+ } else {
+ if (appId.isNull()) {
+ config = DTK_CORE_NAMESPACE::DConfig::create(name, subpath, nullptr);
+ } else {
+ config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr);
+ }
+ }
+ if (!config) {
+ qWarning() << QLatin1String("Failed to create DConfig instance.");
+ worker->deleteLater();
+ return;
+ }
+ config->moveToThread(QThread::currentThread());
+ initializeInConfigThread(config);
+ worker->deleteLater();
+ });
+ }
+ static dconfig_org_deepin_dtk_preference* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())
+ { return new dconfig_org_deepin_dtk_preference(thread, nullptr, QStringLiteral(u"\u006f\u0072\u0067\u002e\u0064\u0065\u0065\u0070\u0069\u006e\u002e\u0064\u0074\u006b\u002e\u0070\u0072\u0065\u0066\u0065\u0072\u0065\u006e\u0063\u0065"), appId, subpath, parent); }
+ static dconfig_org_deepin_dtk_preference* create(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())
+ { return new dconfig_org_deepin_dtk_preference(thread, backend, QStringLiteral(u"\u006f\u0072\u0067\u002e\u0064\u0065\u0065\u0070\u0069\u006e\u002e\u0064\u0074\u006b\u002e\u0070\u0072\u0065\u0066\u0065\u0072\u0065\u006e\u0063\u0065"), appId, subpath, parent); }
+ static dconfig_org_deepin_dtk_preference* createByName(const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())
+ { return new dconfig_org_deepin_dtk_preference(thread, nullptr, name, appId, subpath, parent); }
+ static dconfig_org_deepin_dtk_preference* createByName(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())
+ { return new dconfig_org_deepin_dtk_preference(thread, backend, name, appId, subpath, parent); }
+ ~dconfig_org_deepin_dtk_preference() {
+ if (m_config.loadRelaxed()) {
+ m_config.loadRelaxed()->deleteLater();
+ }
+ }
+
+ Q_INVOKABLE DTK_CORE_NAMESPACE::DConfig *config() const {
+ return m_config.loadRelaxed();
+ }
+
+ Q_INVOKABLE bool isInitializeSucceed() const {
+ return m_status.loadRelaxed() == static_cast<int>(Status::Succeed);
+ }
+
+ Q_INVOKABLE bool isInitializeFailed() const {
+ return m_status.loadRelaxed() == static_cast<int>(Status::Failed);
+ }
+
+ Q_INVOKABLE bool isInitializing() const {
+ return m_status.loadRelaxed() == static_cast<int>(Status::Invalid);
+ }
+
+ Q_INVOKABLE QStringList keyList() const {
+ return { QStringLiteral(u"\u0061\u0075\u0074\u006f\u0044\u0069\u0073\u0070\u006c\u0061\u0079\u0046\u0065\u0061\u0074\u0075\u0072\u0065"),
+ QStringLiteral(u"\u0066\u0065\u0061\u0074\u0075\u0072\u0065\u0055\u0070\u0064\u0061\u0074\u0065\u0064"),
+ QStringLiteral(u"\u006b\u0065\u0079\u0062\u006f\u0061\u0072\u0064\u0073\u0065\u0061\u0072\u0063\u0068\u0044\u0069\u0073\u0061\u0062\u006c\u0065\u0064"),
+ QStringLiteral(u"\u0072\u0075\u006c\u0065\u0073"),
+ QStringLiteral(u"\u0074\u0068\u0065\u006d\u0065\u0054\u0079\u0070\u0065"),
+ QStringLiteral(u"\u0074\u0069\u0074\u006c\u0065\u0062\u0061\u0072\u0048\u0065\u0069\u0067\u0068\u0074"),
+ QStringLiteral(u"\u0075\u006e\u0064\u0065\u0072\u006c\u0069\u006e\u0065\u0053\u0068\u006f\u0072\u0074\u0063\u0075\u0074")};
+ }
+
+ Q_INVOKABLE bool isDefaultValue(const QString &key) const {
+ if (key == QStringLiteral(u"\u0061\u0075\u0074\u006f\u0044\u0069\u0073\u0070\u006c\u0061\u0079\u0046\u0065\u0061\u0074\u0075\u0072\u0065"))
+ return autoDisplayFeatureIsDefaultValue();
+ if (key == QStringLiteral(u"\u0066\u0065\u0061\u0074\u0075\u0072\u0065\u0055\u0070\u0064\u0061\u0074\u0065\u0064"))
+ return featureUpdatedIsDefaultValue();
+ if (key == QStringLiteral(u"\u006b\u0065\u0079\u0062\u006f\u0061\u0072\u0064\u0073\u0065\u0061\u0072\u0063\u0068\u0044\u0069\u0073\u0061\u0062\u006c\u0065\u0064"))
+ return keyboardsearchDisabledIsDefaultValue();
+ if (key == QStringLiteral(u"\u0072\u0075\u006c\u0065\u0073"))
+ return rulesIsDefaultValue();
+ if (key == QStringLiteral(u"\u0074\u0068\u0065\u006d\u0065\u0054\u0079\u0070\u0065"))
+ return themeTypeIsDefaultValue();
+ if (key == QStringLiteral(u"\u0074\u0069\u0074\u006c\u0065\u0062\u0061\u0072\u0048\u0065\u0069\u0067\u0068\u0074"))
+ return titlebarHeightIsDefaultValue();
+ if (key == QStringLiteral(u"\u0075\u006e\u0064\u0065\u0072\u006c\u0069\u006e\u0065\u0053\u0068\u006f\u0072\u0074\u0063\u0075\u0074"))
+ return underlineShortcutIsDefaultValue();
+ return false;
+ }
+
+ bool autoDisplayFeature() const {
+ return p_autoDisplayFeature;
+ }
+ void setAutoDisplayFeature(const bool &value) {
+ auto oldValue = p_autoDisplayFeature;
+ p_autoDisplayFeature = value;
+ markPropertySet(0);
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this, value]() {
+ m_config.loadRelaxed()->setValue(QStringLiteral(u"\u0061\u0075\u0074\u006f\u0044\u0069\u0073\u0070\u006c\u0061\u0079\u0046\u0065\u0061\u0074\u0075\u0072\u0065"), value);
+ });
+ }
+ if (p_autoDisplayFeature != oldValue) {
+ Q_EMIT autoDisplayFeatureChanged();
+ Q_EMIT valueChanged(QStringLiteral(u"\u0061\u0075\u0074\u006f\u0044\u0069\u0073\u0070\u006c\u0061\u0079\u0046\u0065\u0061\u0074\u0075\u0072\u0065"), value);
+ }
+ }
+ void resetAutoDisplayFeature() {
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this]() {
+ m_config.loadRelaxed()->reset(QStringLiteral(u"\u0061\u0075\u0074\u006f\u0044\u0069\u0073\u0070\u006c\u0061\u0079\u0046\u0065\u0061\u0074\u0075\u0072\u0065"));
+ });
+ }
+ }
+ Q_INVOKABLE bool autoDisplayFeatureIsDefaultValue() const {
+ return !testPropertySet(0);
+ }
+ bool featureUpdated() const {
+ return p_featureUpdated;
+ }
+ void setFeatureUpdated(const bool &value) {
+ auto oldValue = p_featureUpdated;
+ p_featureUpdated = value;
+ markPropertySet(1);
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this, value]() {
+ m_config.loadRelaxed()->setValue(QStringLiteral(u"\u0066\u0065\u0061\u0074\u0075\u0072\u0065\u0055\u0070\u0064\u0061\u0074\u0065\u0064"), value);
+ });
+ }
+ if (p_featureUpdated != oldValue) {
+ Q_EMIT featureUpdatedChanged();
+ Q_EMIT valueChanged(QStringLiteral(u"\u0066\u0065\u0061\u0074\u0075\u0072\u0065\u0055\u0070\u0064\u0061\u0074\u0065\u0064"), value);
+ }
+ }
+ void resetFeatureUpdated() {
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this]() {
+ m_config.loadRelaxed()->reset(QStringLiteral(u"\u0066\u0065\u0061\u0074\u0075\u0072\u0065\u0055\u0070\u0064\u0061\u0074\u0065\u0064"));
+ });
+ }
+ }
+ Q_INVOKABLE bool featureUpdatedIsDefaultValue() const {
+ return !testPropertySet(1);
+ }
+ bool keyboardsearchDisabled() const {
+ return p_keyboardsearchDisabled;
+ }
+ void setKeyboardsearchDisabled(const bool &value) {
+ auto oldValue = p_keyboardsearchDisabled;
+ p_keyboardsearchDisabled = value;
+ markPropertySet(2);
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this, value]() {
+ m_config.loadRelaxed()->setValue(QStringLiteral(u"\u006b\u0065\u0079\u0062\u006f\u0061\u0072\u0064\u0073\u0065\u0061\u0072\u0063\u0068\u0044\u0069\u0073\u0061\u0062\u006c\u0065\u0064"), value);
+ });
+ }
+ if (p_keyboardsearchDisabled != oldValue) {
+ Q_EMIT keyboardsearchDisabledChanged();
+ Q_EMIT valueChanged(QStringLiteral(u"\u006b\u0065\u0079\u0062\u006f\u0061\u0072\u0064\u0073\u0065\u0061\u0072\u0063\u0068\u0044\u0069\u0073\u0061\u0062\u006c\u0065\u0064"), value);
+ }
+ }
+ void resetKeyboardsearchDisabled() {
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this]() {
+ m_config.loadRelaxed()->reset(QStringLiteral(u"\u006b\u0065\u0079\u0062\u006f\u0061\u0072\u0064\u0073\u0065\u0061\u0072\u0063\u0068\u0044\u0069\u0073\u0061\u0062\u006c\u0065\u0064"));
+ });
+ }
+ }
+ Q_INVOKABLE bool keyboardsearchDisabledIsDefaultValue() const {
+ return !testPropertySet(2);
+ }
+ QString rules() const {
+ return p_rules;
+ }
+ void setRules(const QString &value) {
+ auto oldValue = p_rules;
+ p_rules = value;
+ markPropertySet(3);
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this, value]() {
+ m_config.loadRelaxed()->setValue(QStringLiteral(u"\u0072\u0075\u006c\u0065\u0073"), value);
+ });
+ }
+ if (p_rules != oldValue) {
+ Q_EMIT rulesChanged();
+ Q_EMIT valueChanged(QStringLiteral(u"\u0072\u0075\u006c\u0065\u0073"), value);
+ }
+ }
+ void resetRules() {
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this]() {
+ m_config.loadRelaxed()->reset(QStringLiteral(u"\u0072\u0075\u006c\u0065\u0073"));
+ });
+ }
+ }
+ Q_INVOKABLE bool rulesIsDefaultValue() const {
+ return !testPropertySet(3);
+ }
+ qlonglong themeType() const {
+ return p_themeType;
+ }
+ void setThemeType(const qlonglong &value) {
+ auto oldValue = p_themeType;
+ p_themeType = value;
+ markPropertySet(4);
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this, value]() {
+ m_config.loadRelaxed()->setValue(QStringLiteral(u"\u0074\u0068\u0065\u006d\u0065\u0054\u0079\u0070\u0065"), value);
+ });
+ }
+ if (p_themeType != oldValue) {
+ Q_EMIT themeTypeChanged();
+ Q_EMIT valueChanged(QStringLiteral(u"\u0074\u0068\u0065\u006d\u0065\u0054\u0079\u0070\u0065"), value);
+ }
+ }
+ void resetThemeType() {
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this]() {
+ m_config.loadRelaxed()->reset(QStringLiteral(u"\u0074\u0068\u0065\u006d\u0065\u0054\u0079\u0070\u0065"));
+ });
+ }
+ }
+ Q_INVOKABLE bool themeTypeIsDefaultValue() const {
+ return !testPropertySet(4);
+ }
+ qlonglong titlebarHeight() const {
+ return p_titlebarHeight;
+ }
+ void setTitlebarHeight(const qlonglong &value) {
+ auto oldValue = p_titlebarHeight;
+ p_titlebarHeight = value;
+ markPropertySet(5);
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this, value]() {
+ m_config.loadRelaxed()->setValue(QStringLiteral(u"\u0074\u0069\u0074\u006c\u0065\u0062\u0061\u0072\u0048\u0065\u0069\u0067\u0068\u0074"), value);
+ });
+ }
+ if (p_titlebarHeight != oldValue) {
+ Q_EMIT titlebarHeightChanged();
+ Q_EMIT valueChanged(QStringLiteral(u"\u0074\u0069\u0074\u006c\u0065\u0062\u0061\u0072\u0048\u0065\u0069\u0067\u0068\u0074"), value);
+ }
+ }
+ void resetTitlebarHeight() {
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this]() {
+ m_config.loadRelaxed()->reset(QStringLiteral(u"\u0074\u0069\u0074\u006c\u0065\u0062\u0061\u0072\u0048\u0065\u0069\u0067\u0068\u0074"));
+ });
+ }
+ }
+ Q_INVOKABLE bool titlebarHeightIsDefaultValue() const {
+ return !testPropertySet(5);
+ }
+ bool underlineShortcut() const {
+ return p_underlineShortcut;
+ }
+ void setUnderlineShortcut(const bool &value) {
+ auto oldValue = p_underlineShortcut;
+ p_underlineShortcut = value;
+ markPropertySet(6);
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this, value]() {
+ m_config.loadRelaxed()->setValue(QStringLiteral(u"\u0075\u006e\u0064\u0065\u0072\u006c\u0069\u006e\u0065\u0053\u0068\u006f\u0072\u0074\u0063\u0075\u0074"), value);
+ });
+ }
+ if (p_underlineShortcut != oldValue) {
+ Q_EMIT underlineShortcutChanged();
+ Q_EMIT valueChanged(QStringLiteral(u"\u0075\u006e\u0064\u0065\u0072\u006c\u0069\u006e\u0065\u0053\u0068\u006f\u0072\u0074\u0063\u0075\u0074"), value);
+ }
+ }
+ void resetUnderlineShortcut() {
+ if (auto config = m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [this]() {
+ m_config.loadRelaxed()->reset(QStringLiteral(u"\u0075\u006e\u0064\u0065\u0072\u006c\u0069\u006e\u0065\u0053\u0068\u006f\u0072\u0074\u0063\u0075\u0074"));
+ });
+ }
+ }
+ Q_INVOKABLE bool underlineShortcutIsDefaultValue() const {
+ return !testPropertySet(6);
+ }
+Q_SIGNALS:
+ void configInitializeFailed(DTK_CORE_NAMESPACE::DConfig *config);
+ void configInitializeSucceed(DTK_CORE_NAMESPACE::DConfig *config);
+ void valueChanged(const QString &key, const QVariant &value);
+
+ void autoDisplayFeatureChanged();
+ void featureUpdatedChanged();
+ void keyboardsearchDisabledChanged();
+ void rulesChanged();
+ void themeTypeChanged();
+ void titlebarHeightChanged();
+ void underlineShortcutChanged();
+private:
+ void initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config) {
+ Q_ASSERT(!m_config.loadRelaxed());
+ m_config.storeRelaxed(config);
+ if (!config->isValid()) {
+ m_status.storeRelaxed(static_cast<int>(Status::Failed));
+ Q_EMIT configInitializeFailed(config);
+ return;
+ }
+
+ if (testPropertySet(0)) {
+ config->setValue(QStringLiteral(u"\u0061\u0075\u0074\u006f\u0044\u0069\u0073\u0070\u006c\u0061\u0079\u0046\u0065\u0061\u0074\u0075\u0072\u0065"), QVariant::fromValue(p_autoDisplayFeature));
+ } else {
+ updateValue(QStringLiteral(u"\u0061\u0075\u0074\u006f\u0044\u0069\u0073\u0070\u006c\u0061\u0079\u0046\u0065\u0061\u0074\u0075\u0072\u0065"), QVariant::fromValue(p_autoDisplayFeature));
+ }
+ if (testPropertySet(1)) {
+ config->setValue(QStringLiteral(u"\u0066\u0065\u0061\u0074\u0075\u0072\u0065\u0055\u0070\u0064\u0061\u0074\u0065\u0064"), QVariant::fromValue(p_featureUpdated));
+ } else {
+ updateValue(QStringLiteral(u"\u0066\u0065\u0061\u0074\u0075\u0072\u0065\u0055\u0070\u0064\u0061\u0074\u0065\u0064"), QVariant::fromValue(p_featureUpdated));
+ }
+ if (testPropertySet(2)) {
+ config->setValue(QStringLiteral(u"\u006b\u0065\u0079\u0062\u006f\u0061\u0072\u0064\u0073\u0065\u0061\u0072\u0063\u0068\u0044\u0069\u0073\u0061\u0062\u006c\u0065\u0064"), QVariant::fromValue(p_keyboardsearchDisabled));
+ } else {
+ updateValue(QStringLiteral(u"\u006b\u0065\u0079\u0062\u006f\u0061\u0072\u0064\u0073\u0065\u0061\u0072\u0063\u0068\u0044\u0069\u0073\u0061\u0062\u006c\u0065\u0064"), QVariant::fromValue(p_keyboardsearchDisabled));
+ }
+ if (testPropertySet(3)) {
+ config->setValue(QStringLiteral(u"\u0072\u0075\u006c\u0065\u0073"), QVariant::fromValue(p_rules));
+ } else {
+ updateValue(QStringLiteral(u"\u0072\u0075\u006c\u0065\u0073"), QVariant::fromValue(p_rules));
+ }
+ if (testPropertySet(4)) {
+ config->setValue(QStringLiteral(u"\u0074\u0068\u0065\u006d\u0065\u0054\u0079\u0070\u0065"), QVariant::fromValue(p_themeType));
+ } else {
+ updateValue(QStringLiteral(u"\u0074\u0068\u0065\u006d\u0065\u0054\u0079\u0070\u0065"), QVariant::fromValue(p_themeType));
+ }
+ if (testPropertySet(5)) {
+ config->setValue(QStringLiteral(u"\u0074\u0069\u0074\u006c\u0065\u0062\u0061\u0072\u0048\u0065\u0069\u0067\u0068\u0074"), QVariant::fromValue(p_titlebarHeight));
+ } else {
+ updateValue(QStringLiteral(u"\u0074\u0069\u0074\u006c\u0065\u0062\u0061\u0072\u0048\u0065\u0069\u0067\u0068\u0074"), QVariant::fromValue(p_titlebarHeight));
+ }
+ if (testPropertySet(6)) {
+ config->setValue(QStringLiteral(u"\u0075\u006e\u0064\u0065\u0072\u006c\u0069\u006e\u0065\u0053\u0068\u006f\u0072\u0074\u0063\u0075\u0074"), QVariant::fromValue(p_underlineShortcut));
+ } else {
+ updateValue(QStringLiteral(u"\u0075\u006e\u0064\u0065\u0072\u006c\u0069\u006e\u0065\u0053\u0068\u006f\u0072\u0074\u0063\u0075\u0074"), QVariant::fromValue(p_underlineShortcut));
+ }
+
+ connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) {
+ updateValue(key);
+ }, Qt::DirectConnection);
+
+ m_status.storeRelaxed(static_cast<int>(Status::Succeed));
+ Q_EMIT configInitializeSucceed(config);
+ }
+ void updateValue(const QString &key, const QVariant &fallback = QVariant()) {
+ Q_ASSERT(QThread::currentThread() == m_config.loadRelaxed()->thread());
+ const QVariant &value = m_config.loadRelaxed()->value(key, fallback);
+ if (key == QStringLiteral(u"\u0061\u0075\u0074\u006f\u0044\u0069\u0073\u0070\u006c\u0061\u0079\u0046\u0065\u0061\u0074\u0075\u0072\u0065")) {
+ markPropertySet(0, !m_config.loadRelaxed()->isDefaultValue(key));
+ auto newValue = qvariant_cast<bool>(value);
+ QMetaObject::invokeMethod(this, [this, newValue, key, value]() {
+ Q_ASSERT(QThread::currentThread() == this->thread());
+ if (p_autoDisplayFeature != newValue) {
+ p_autoDisplayFeature = newValue;
+ Q_EMIT autoDisplayFeatureChanged();
+ Q_EMIT valueChanged(key, value);
+ }
+ });
+ return;
+ }
+ if (key == QStringLiteral(u"\u0066\u0065\u0061\u0074\u0075\u0072\u0065\u0055\u0070\u0064\u0061\u0074\u0065\u0064")) {
+ markPropertySet(1, !m_config.loadRelaxed()->isDefaultValue(key));
+ auto newValue = qvariant_cast<bool>(value);
+ QMetaObject::invokeMethod(this, [this, newValue, key, value]() {
+ Q_ASSERT(QThread::currentThread() == this->thread());
+ if (p_featureUpdated != newValue) {
+ p_featureUpdated = newValue;
+ Q_EMIT featureUpdatedChanged();
+ Q_EMIT valueChanged(key, value);
+ }
+ });
+ return;
+ }
+ if (key == QStringLiteral(u"\u006b\u0065\u0079\u0062\u006f\u0061\u0072\u0064\u0073\u0065\u0061\u0072\u0063\u0068\u0044\u0069\u0073\u0061\u0062\u006c\u0065\u0064")) {
+ markPropertySet(2, !m_config.loadRelaxed()->isDefaultValue(key));
+ auto newValue = qvariant_cast<bool>(value);
+ QMetaObject::invokeMethod(this, [this, newValue, key, value]() {
+ Q_ASSERT(QThread::currentThread() == this->thread());
+ if (p_keyboardsearchDisabled != newValue) {
+ p_keyboardsearchDisabled = newValue;
+ Q_EMIT keyboardsearchDisabledChanged();
+ Q_EMIT valueChanged(key, value);
+ }
+ });
+ return;
+ }
+ if (key == QStringLiteral(u"\u0072\u0075\u006c\u0065\u0073")) {
+ markPropertySet(3, !m_config.loadRelaxed()->isDefaultValue(key));
+ auto newValue = qvariant_cast<QString>(value);
+ QMetaObject::invokeMethod(this, [this, newValue, key, value]() {
+ Q_ASSERT(QThread::currentThread() == this->thread());
+ if (p_rules != newValue) {
+ p_rules = newValue;
+ Q_EMIT rulesChanged();
+ Q_EMIT valueChanged(key, value);
+ }
+ });
+ return;
+ }
+ if (key == QStringLiteral(u"\u0074\u0068\u0065\u006d\u0065\u0054\u0079\u0070\u0065")) {
+ markPropertySet(4, !m_config.loadRelaxed()->isDefaultValue(key));
+ auto newValue = qvariant_cast<qlonglong>(value);
+ QMetaObject::invokeMethod(this, [this, newValue, key, value]() {
+ Q_ASSERT(QThread::currentThread() == this->thread());
+ if (p_themeType != newValue) {
+ p_themeType = newValue;
+ Q_EMIT themeTypeChanged();
+ Q_EMIT valueChanged(key, value);
+ }
+ });
+ return;
+ }
+ if (key == QStringLiteral(u"\u0074\u0069\u0074\u006c\u0065\u0062\u0061\u0072\u0048\u0065\u0069\u0067\u0068\u0074")) {
+ markPropertySet(5, !m_config.loadRelaxed()->isDefaultValue(key));
+ auto newValue = qvariant_cast<qlonglong>(value);
+ QMetaObject::invokeMethod(this, [this, newValue, key, value]() {
+ Q_ASSERT(QThread::currentThread() == this->thread());
+ if (p_titlebarHeight != newValue) {
+ p_titlebarHeight = newValue;
+ Q_EMIT titlebarHeightChanged();
+ Q_EMIT valueChanged(key, value);
+ }
+ });
+ return;
+ }
+ if (key == QStringLiteral(u"\u0075\u006e\u0064\u0065\u0072\u006c\u0069\u006e\u0065\u0053\u0068\u006f\u0072\u0074\u0063\u0075\u0074")) {
+ markPropertySet(6, !m_config.loadRelaxed()->isDefaultValue(key));
+ auto newValue = qvariant_cast<bool>(value);
+ QMetaObject::invokeMethod(this, [this, newValue, key, value]() {
+ Q_ASSERT(QThread::currentThread() == this->thread());
+ if (p_underlineShortcut != newValue) {
+ p_underlineShortcut = newValue;
+ Q_EMIT underlineShortcutChanged();
+ Q_EMIT valueChanged(key, value);
+ }
+ });
+ return;
+ }
+ }
+ inline void markPropertySet(const int index, bool on = true) {
+ if (index < 32) {
+ if (on)
+ m_propertySetStatus0.fetchAndOrOrdered(1 << (index - 0));
+ else
+ m_propertySetStatus0.fetchAndAndOrdered(1 << (index - 0));
+ return;
+ }
+ Q_UNREACHABLE();
+ }
+ inline bool testPropertySet(const int index) const {
+ if (index < 32) {
+ return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0)));
+ }
+ Q_UNREACHABLE();
+ }
+
+ QAtomicPointer<DTK_CORE_NAMESPACE::DConfig> m_config = nullptr;
+
+public:
+ enum class Status {
+ Invalid = 0,
+ Succeed = 1,
+ Failed = 2
+ };
+private:
+ QAtomicInteger<int> m_status = static_cast<int>(Status::Invalid);
+
+ bool p_autoDisplayFeature { false };
+ bool p_featureUpdated { false };
+ bool p_keyboardsearchDisabled { false };
+ // Default value: ""
+ QString p_rules { QLatin1String("") };
+ qlonglong p_themeType { 0 };
+ qlonglong p_titlebarHeight { -1 };
+ bool p_underlineShortcut { false };
+ QAtomicInteger<quint32> m_propertySetStatus0 = 0;
+};
+
+#endif // DCONFIG_ORG_DEEPIN_DTK_PREFERENCE_H
)
set(LOG_SOURCE
${CMAKE_CURRENT_LIST_DIR}/LogManager.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/dconfig_org_deepin_dtk_preference.hpp
)
set(log_SRCS
add_subdirectory(qdbusxml2cpp)
add_subdirectory(settings)
add_subdirectory(ch2py)
+add_subdirectory(dconfig2cpp)
--- /dev/null
+set(TARGET_NAME dconfig2cpp)
+set(BIN_NAME ${TARGET_NAME}${DTK_VERSION_MAJOR})
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)
+
+add_executable(${BIN_NAME}
+ main.cpp
+)
+
+target_link_libraries(
+ ${BIN_NAME} PRIVATE
+ Qt${QT_VERSION_MAJOR}::Core
+)
+
+set_target_properties(
+ ${BIN_NAME} PROPERTIES
+ OUTPUT_NAME ${TARGET_NAME}
+ EXPORT_NAME DConfig2Cpp
+)
+
+install(
+ TARGETS ${BIN_NAME}
+ EXPORT Dtk${DTK_VERSION_MAJOR}ToolsTargets
+ DESTINATION ${TOOL_INSTALL_DIR}
+)
--- /dev/null
+// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+
+#include <QCoreApplication>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonValue>
+#include <QJsonArray>
+#include <QFile>
+#include <QDebug>
+#include <QCommandLineParser>
+#include <QFileInfo>
+
+static QString toUnicodeEscape(const QString& input) {
+ QString result;
+ for (QChar ch : input) {
+ result += QString("\\u%1").arg(ch.unicode(), 4, 16, QChar('0'));
+ }
+ return result;
+}
+
+// Converts a QJsonValue to a corresponding C++ code representation
+static QString jsonValueToCppCode(const QJsonValue &value){
+ if (value.isBool()) {
+ return value.toBool() ? QLatin1String("true") : QLatin1String("false");
+ } else if (value.isDouble()) {
+ const auto variantValue = value.toVariant();
+ if (variantValue.userType() == QVariant(static_cast<int>(1)).userType()) {
+ return QString::number(value.toInt());
+ } else if (variantValue.userType() == QVariant(static_cast<qint64>(1)).userType()) {
+ return QString::number(variantValue.toLongLong());
+ }
+
+ return QString::number(value.toDouble());
+ } else if (value.isString()) {
+ const auto string = value.toString();
+ if (string.isEmpty()) {
+ return QLatin1String("QLatin1String(\"\")");
+ }
+ return QString("QStringLiteral(u\"%1\")").arg(toUnicodeEscape(string));
+ } else if (value.isNull()) {
+ return "QVariant::fromValue(nullptr)";
+ } else if (value.isArray()) {
+ QStringList elements;
+ const auto array = value.toArray();
+ for (const QJsonValue &element : array) {
+ elements << "QVariant(" + jsonValueToCppCode(element) + ")";
+ }
+ return "QList<QVariant>{" + elements.join(", ") + "}";
+ } else if (value.isObject()) {
+ QStringList elements;
+ QJsonObject obj = value.toObject();
+ for (auto it = obj.begin(); it != obj.end(); ++it) {
+ elements << QString("{QStringLiteral(u\"%1\"), QVariant(%2)}")
+ .arg(toUnicodeEscape(it.key()),
+ jsonValueToCppCode(it.value()));
+ }
+ return "QVariantMap{" + elements.join(", ") + "}";
+ } else {
+ return "QVariant()";
+ }
+}
+
+int main(int argc, char *argv[]) {
+ QCoreApplication app(argc, argv);
+ QCommandLineParser parser;
+ parser.setApplicationDescription(QLatin1String("DConfig to C++ class generator"));
+ parser.addHelpOption();
+
+ // Define command line options
+ QCommandLineOption classNameOption(QStringList() << QLatin1String("c") << QLatin1String("class-name"),
+ QLatin1String("Name of the generated class"),
+ QLatin1String("className"));
+ parser.addOption(classNameOption);
+
+ QCommandLineOption sourceFileOption(QStringList() << QLatin1String("o") << QLatin1String("output"),
+ QLatin1String("Path to the output source(header only) file"),
+ QLatin1String("sourceFile"));
+ parser.addOption(sourceFileOption);
+
+ QCommandLineOption cppPropertyOption(QStringList() << QLatin1String("use-qproperty"),
+ QLatin1String("Generate Qt/C++ properties use QProperty"));
+ parser.addOption(cppPropertyOption);
+
+ QCommandLineOption forceRequestThread(QStringList() << QLatin1String("force-request-thread"),
+ QLatin1String("Force request thread to create DConfig instance"));
+ parser.addOption(forceRequestThread);
+
+ QCommandLineOption noComment(QStringList() << QLatin1String("no-comment"),
+ QLatin1String("Do not generate comments in the generated code"));
+ parser.addOption(noComment);
+
+ parser.addPositionalArgument(QLatin1String("json-file"), QLatin1String("Path to the input JSON file"));
+ parser.process(app);
+
+ const QStringList args = parser.positionalArguments();
+ if (args.size() != 1) {
+ parser.showHelp(-1);
+ }
+
+ QString className = parser.value(classNameOption);
+ const QString jsonFileName = QFileInfo(args.first()).completeBaseName();
+ if (className.isEmpty()) {
+ className = QLatin1String("dconfig_") + QString(jsonFileName).replace('.', '_');
+ }
+
+ QString sourceFilePath = parser.value(sourceFileOption);
+ if (sourceFilePath.isEmpty()) {
+ sourceFilePath = className.toLower() + QLatin1String(".hpp");
+ }
+
+ QFile file(args.first());
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning() << QLatin1String("Failed to open file:") << args.first();
+ return -1;
+ }
+
+ QByteArray data = file.readAll();
+ QJsonDocument doc = QJsonDocument::fromJson(data);
+ QJsonObject root = doc.object();
+
+ // Check magic value
+ if (root[QLatin1String("magic")].toString() != QLatin1String("dsg.config.meta")) {
+ qWarning() << QLatin1String("Invalid magic value in JSON file");
+ return -1;
+ }
+
+ // Generate header and source files
+ QFile headerFile(sourceFilePath);
+ if (!headerFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ qWarning() << QLatin1String("Failed to open file for writing:") << sourceFilePath;
+ return -1;
+ }
+
+ QTextStream headerStream(&headerFile);
+
+ // Extract version and add it as a comment in the generated code
+ QString version = root[QLatin1String("version")].toString();
+
+ // Generate header and source file comments
+ QString commandLineArgs = QCoreApplication::arguments().join(QLatin1String(" "));
+ QString generationTime = QDateTime::currentDateTime().toString(Qt::ISODate);
+
+ if (!parser.isSet(noComment)) {
+ QString headerComment = QString(
+ "/**\n"
+ " * This file is generated by dconfig2cpp.\n"
+ " * Command line arguments: %1\n"
+ " * Generation time: %2\n"
+ " * JSON file version: %3\n"
+ " *\n"
+ " * WARNING: DO NOT MODIFY THIS FILE MANUALLY.\n"
+ " * If you need to change the content, please modify the dconfig2cpp tool.\n"
+ " */\n\n"
+ ).arg(commandLineArgs, generationTime, version);
+
+ headerStream << headerComment;
+ }
+
+ QJsonObject contents = root[QLatin1String("contents")].toObject();
+
+ // Write header file content
+ headerStream << "#ifndef " << className.toUpper() << "_H\n";
+ headerStream << "#define " << className.toUpper() << "_H\n\n";
+ headerStream << "#include <QThread>\n";
+ headerStream << "#include <QVariant>\n";
+ headerStream << "#include <QDebug>\n";
+ headerStream << "#include <QAtomicPointer>\n";
+ headerStream << "#include <QAtomicInteger>\n";
+
+ if (parser.isSet(cppPropertyOption)) {
+ headerStream << "#include <QProperty>\n";
+ }
+
+ headerStream << "#include <DConfig>\n\n";
+ headerStream << "class " << className << " : public QObject {\n";
+ headerStream << " Q_OBJECT\n\n";
+
+ struct Property {
+ QString typeName;
+ QString propertyName;
+ QString capitalizedPropertyName;
+ QString propertyNameString;
+ QJsonValue defaultValue;
+ };
+ QList<Property> properties;
+ QStringList propertyNames;
+ QStringList propertyNameStrings;
+
+ static QStringList usedKeywords = {
+ className,
+ "create",
+ "createByName",
+ "config",
+ "keyList",
+ "isInitializeSucceed",
+ "isInitializeFailed",
+ "isInitializing",
+ "isDefaultValue",
+ "m_config",
+ "m_status",
+ };
+
+ for (int i = 0; i <= (contents.size()) / 32; ++i) {
+ usedKeywords << QLatin1String("m_propertySetStatus") + QString::number(i);
+ }
+
+ // Iterate over JSON contents to extract properties
+ for (auto it = contents.begin(); it != contents.end(); ++it) {
+ QJsonObject obj = it.value().toObject();
+ QString propertyName = it.key();
+ QString typeName;
+ const auto value = obj[QLatin1String("value")];
+ if (value.isBool()) {
+ typeName = "bool";
+ } else if (value.isArray()) {
+ typeName = "QList<QVariant>";
+ } else if (value.isObject()) {
+ typeName = "QVariantMap";
+ } else if (value.isDouble()) {
+ const auto variantValue = value.toVariant();
+ typeName = QString::fromLatin1(variantValue.typeName());
+ } else if (value.isString()) {
+ typeName = "QString";
+ } else {
+ typeName = "QVariant";
+ }
+
+ QString capitalizedPropertyName = propertyName;
+ if (!capitalizedPropertyName.isEmpty() && capitalizedPropertyName[0].isLower()) {
+ capitalizedPropertyName[0] = capitalizedPropertyName[0].toUpper();
+ }
+
+ propertyNames << propertyName;
+ properties.append(Property({
+ typeName,
+ propertyName,
+ capitalizedPropertyName,
+ "QStringLiteral(u\"" + toUnicodeEscape(propertyName) + "\")",
+ obj[QLatin1String("value")]
+ }));
+ propertyNameStrings << properties.last().propertyNameString;
+
+ const QString readFunction = usedKeywords.contains(propertyName) ? QLatin1String(" READ get") + capitalizedPropertyName
+ : QLatin1String(" READ ") + propertyName;
+ headerStream << " Q_PROPERTY(" << typeName << " " << propertyName << readFunction
+ << " WRITE set" << capitalizedPropertyName << " NOTIFY " << propertyName << "Changed"
+ << " RESET reset" << capitalizedPropertyName << ")\n";
+ }
+
+ headerStream << " Q_CLASSINFO(\"DConfigKeyList\", \"" << propertyNames.join(";") <<"\")\n"
+ << " Q_CLASSINFO(\"DConfigFileName\", \"" << QString(jsonFileName).replace("\n", "\\n").replace("\r", "\\r") <<"\")\n"
+ << " Q_CLASSINFO(\"DConfigFileVersion\", \"" << version <<"\")\n\n"
+ << "public:\n"
+ << " explicit " << className
+ << R"((QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId, const QString &subpath, QObject *parent)
+ : QObject(parent) {
+ if (!thread->isRunning()) {
+ qWarning() << QLatin1String("Warning: The provided thread is not running.");
+ }
+ Q_ASSERT(QThread::currentThread() != thread);
+ auto worker = new QObject();
+ worker->moveToThread(thread);
+ QMetaObject::invokeMethod(worker, [=, this]() {
+ DTK_CORE_NAMESPACE::DConfig *config = nullptr;
+ if (backend) {
+ if (appId.isNull()) {
+ config = DTK_CORE_NAMESPACE::DConfig::create(backend, name, subpath, nullptr);
+ } else {
+ config = DTK_CORE_NAMESPACE::DConfig::create(backend, appId, name, subpath, nullptr);
+ }
+ } else {
+ if (appId.isNull()) {
+ config = DTK_CORE_NAMESPACE::DConfig::create(name, subpath, nullptr);
+ } else {
+ config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr);
+ }
+ }
+ if (!config) {
+ qWarning() << QLatin1String("Failed to create DConfig instance.");
+ worker->deleteLater();
+ return;
+ }
+ config->moveToThread(QThread::currentThread());
+ initializeInConfigThread(config);
+ worker->deleteLater();
+ });
+ }
+)";
+
+ const QString jsonFileString = "QStringLiteral(u\"" + toUnicodeEscape(jsonFileName) + "\")";
+ // Generate constructors
+ if (parser.isSet(forceRequestThread))
+ headerStream << " static " << className << "* create(QThread *thread, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr)\n";
+ else
+ headerStream << " static " << className << "* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n";
+ headerStream << " { return new " << className << "(thread, nullptr, " << jsonFileString << ", appId, subpath, parent); }\n";
+ if (parser.isSet(forceRequestThread))
+ headerStream << " static " << className << "* create(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr)\n";
+ else
+ headerStream << " static " << className << "* create(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n";
+ headerStream << " { return new " << className << "(thread, backend, " << jsonFileString << ", appId, subpath, parent); }\n";
+ if (parser.isSet(forceRequestThread))
+ headerStream << " static " << className << "* createByName(QThread *thread, const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr)\n";
+ else
+ headerStream << " static " << className << "* createByName(const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n";
+ headerStream << " { return new " << className << "(thread, nullptr, name, appId, subpath, parent); }\n";
+ if (parser.isSet(forceRequestThread))
+ headerStream << " static " << className << "* createByName(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr)\n";
+ else
+ headerStream << " static " << className << "* createByName(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n";
+ headerStream << " { return new " << className << "(thread, backend, name, appId, subpath, parent); }\n";
+
+ // Destructor
+ headerStream << " ~" << className << R"(() {
+ if (m_config.loadRelaxed()) {
+ m_config.loadRelaxed()->deleteLater();
+ }
+ }
+
+ Q_INVOKABLE DTK_CORE_NAMESPACE::DConfig *config() const {
+ return m_config.loadRelaxed();
+ }
+
+ Q_INVOKABLE bool isInitializeSucceed() const {
+ return m_status.loadRelaxed() == static_cast<int>(Status::Succeed);
+ }
+
+ Q_INVOKABLE bool isInitializeFailed() const {
+ return m_status.loadRelaxed() == static_cast<int>(Status::Failed);
+ }
+
+ Q_INVOKABLE bool isInitializing() const {
+ return m_status.loadRelaxed() == static_cast<int>(Status::Invalid);
+ }
+
+)";
+
+ headerStream << " Q_INVOKABLE QStringList keyList() const {\n"
+ << " return { " << propertyNameStrings.join(",\n ") << "};\n"
+ << " }\n\n";
+
+ headerStream << " Q_INVOKABLE bool isDefaultValue(const QString &key) const {\n";
+ for (int i = 0; i < properties.size(); ++i) {
+ headerStream << " if (key == " << properties.at(i).propertyNameString << ")\n"
+ << " return " << properties.at(i).propertyName << "IsDefaultValue();\n";
+ }
+ headerStream << " return false;\n"
+ << " }\n\n";
+
+ // Generate property getter and setter methods
+ for (int i = 0; i < properties.size(); ++i) {
+ const Property &property = properties[i];
+ const QString readFunction = usedKeywords.contains(property.propertyName)
+ ? "get" + property.capitalizedPropertyName
+ : property.propertyName;
+ assert(!usedKeywords.contains(readFunction));
+
+ headerStream << " " << property.typeName << " " << readFunction << "() const {\n"
+ << " return p_" << property.propertyName << ";\n }\n";
+ headerStream << " void set" << property.capitalizedPropertyName << "(const " << property.typeName << " &value) {\n"
+ << " auto oldValue = p_" << property.propertyName << ";\n"
+ << " p_" << property.propertyName << " = value;\n"
+ << " markPropertySet(" << i << ");\n"
+ << " if (auto config = m_config.loadRelaxed()) {\n"
+ << " QMetaObject::invokeMethod(config, [this, value]() {\n"
+ << " m_config.loadRelaxed()->setValue(" << property.propertyNameString << ", value);\n"
+ << " });\n"
+ << " }\n"
+ << " if (p_" << property.propertyName << " != oldValue) {\n"
+ << " Q_EMIT " << property.propertyName << "Changed();\n"
+ << " Q_EMIT valueChanged(" << property.propertyNameString << ", value);\n"
+ << " }\n"
+ << " }\n"
+ << " void reset" << property.capitalizedPropertyName << "() {\n"
+ << " if (auto config = m_config.loadRelaxed()) {\n"
+ << " QMetaObject::invokeMethod(config, [this]() {\n"
+ << " m_config.loadRelaxed()->reset(" << property.propertyNameString << ");\n"
+ << " });\n"
+ << " }\n"
+ << " }\n";
+ if (parser.isSet(cppPropertyOption)) {
+ headerStream << " QBindable<" << property.typeName << "> bindable" << property.capitalizedPropertyName << "() {\n"
+ << " return QBindable<" << property.typeName << ">(this, " << property.propertyNameString << ");\n"
+ << " }\n";
+ }
+
+ headerStream << " Q_INVOKABLE bool " << property.propertyName << "IsDefaultValue() const {\n"
+ << " return !testPropertySet(" << i << ");\n"
+ << " }\n";
+ }
+
+ // Generate signals for property changes
+ headerStream << "Q_SIGNALS:\n"
+ << " void configInitializeFailed(DTK_CORE_NAMESPACE::DConfig *config);\n"
+ << " void configInitializeSucceed(DTK_CORE_NAMESPACE::DConfig *config);\n"
+ << " void valueChanged(const QString &key, const QVariant &value);\n\n";
+ for (const Property &property : std::as_const(properties)) {
+ headerStream << " void " << property.propertyName << "Changed();\n";
+ }
+
+ // Generate private methods and members
+ headerStream << "private:\n";
+
+ headerStream << " void initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config) {\n"
+ << " Q_ASSERT(!m_config.loadRelaxed());\n"
+ << " m_config.storeRelaxed(config);\n"
+ << " if (!config->isValid()) {\n"
+ << " m_status.storeRelaxed(static_cast<int>(Status::Failed));\n"
+ << " Q_EMIT configInitializeFailed(config);\n"
+ << " return;\n"
+ << " }\n\n";
+ for (int i = 0; i < properties.size(); ++i) {
+ const Property &property = properties[i];
+ headerStream << " if (testPropertySet(" << i << ")) {\n";
+ headerStream << " config->setValue(" << property.propertyNameString << ", QVariant::fromValue(p_" << property.propertyName << "));\n";
+ headerStream << " } else {\n";
+ headerStream << " updateValue(" << property.propertyNameString << ", QVariant::fromValue(p_" << property.propertyName << "));\n";
+ headerStream << " }\n";
+ }
+ headerStream << R"(
+ connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) {
+ updateValue(key);
+ }, Qt::DirectConnection);
+
+ m_status.storeRelaxed(static_cast<int>(Status::Succeed));
+ Q_EMIT configInitializeSucceed(config);
+ }
+ void updateValue(const QString &key, const QVariant &fallback = QVariant()) {
+ Q_ASSERT(QThread::currentThread() == m_config.loadRelaxed()->thread());
+ const QVariant &value = m_config.loadRelaxed()->value(key, fallback);
+)";
+ for (int i = 0; i < properties.size(); ++i) {
+ const Property &property = properties.at(i);
+ headerStream << " if (key == " << property.propertyNameString << ") {\n";
+
+ headerStream << " markPropertySet(" << i << ", !m_config.loadRelaxed()->isDefaultValue(key));\n";
+
+ headerStream << " auto newValue = qvariant_cast<" << property.typeName << ">(value);\n"
+ << " QMetaObject::invokeMethod(this, [this, newValue, key, value]() {\n"
+ << " Q_ASSERT(QThread::currentThread() == this->thread());\n"
+ << " if (p_" << property.propertyName << " != newValue) {\n"
+ << " p_" << property.propertyName << " = newValue;\n"
+ << " Q_EMIT " << property.propertyName << "Changed();\n"
+ << " Q_EMIT valueChanged(key, value);\n"
+ << " }\n"
+ << " });\n"
+ << " return;\n"
+ << " }\n";
+ }
+ headerStream << " }\n";
+
+ // Mark property as set
+ headerStream << " inline void markPropertySet(const int index, bool on = true) {\n";
+ for (int i = 0; i <= (properties.size()) / 32; ++i) {
+ headerStream << " if (index < " << (i + 1) * 32 << ") {\n"
+ << " if (on)\n"
+ << " m_propertySetStatus" << QString::number(i) << ".fetchAndOrOrdered(1 << (index - " << i * 32 << "));\n"
+ << " else\n"
+ << " m_propertySetStatus" << QString::number(i) << ".fetchAndAndOrdered(1 << (index - " << i * 32 << "));\n"
+ << " return;\n"
+ << " }\n";
+ }
+ headerStream << " Q_UNREACHABLE();\n }\n";
+
+ // Test if property is set
+ headerStream << " inline bool testPropertySet(const int index) const {\n";
+ for (int i = 0; i <= (properties.size()) / 32; ++i) {
+ headerStream << " if (index < " << (i + 1) * 32 << ") {\n";
+ headerStream << " return (m_propertySetStatus" << QString::number(i) << ".loadRelaxed() & (1 << (index - " << i * 32 << ")));\n";
+ headerStream << " }\n";
+ }
+ headerStream << " Q_UNREACHABLE();\n"
+ << " }\n";
+
+ // Member variables
+ headerStream << R"(
+ QAtomicPointer<DTK_CORE_NAMESPACE::DConfig> m_config = nullptr;
+
+public:
+ enum class Status {
+ Invalid = 0,
+ Succeed = 1,
+ Failed = 2
+ };
+private:
+ QAtomicInteger<int> m_status = static_cast<int>(Status::Invalid);
+
+)";
+
+ // Property variables
+ for (const Property &property : std::as_const(properties)) {
+ if (property.typeName == QLatin1String("int") || property.typeName == QLatin1String("qint64")) {
+ headerStream << " // Note: If you expect a double type, add 'e' to the number in the JSON value field, e.g., \"value\": 1.0e, not just 1.0\n";
+ } else if (property.typeName == QLatin1String("QString")) {
+ headerStream << " // Default value: \"" << property.defaultValue.toString().replace("\n", "\\n").replace("\r", "\\r") << "\"\n";
+ }
+ headerStream << " " << property.typeName << " p_" << property.propertyName << " { ";
+ headerStream << jsonValueToCppCode(property.defaultValue) << " };\n";
+ }
+
+ // Property set status variables
+ for (int i = 0; i <= (properties.size()) / 32; ++i) {
+ headerStream << " QAtomicInteger<quint32> m_propertySetStatus" << QString::number(i) << " = 0;\n";
+ }
+ headerStream << "};\n\n";
+ headerStream << "#endif // " << className.toUpper() << "_H\n";
+
+ return 0;
+}