diff --git a/src/log/dconfig_org_deepin_dtk_preference.hpp b/src/log/dconfig_org_deepin_dtk_preference.hpp index 4fea5196..a9b9c8ab 100644 --- a/src/log/dconfig_org_deepin_dtk_preference.hpp +++ b/src/log/dconfig_org_deepin_dtk_preference.hpp @@ -1,7 +1,7 @@ /** * This file is generated by dconfig2cpp. - * Command line arguments: ./build/tools/dconfig2cpp/dconfig2cpp /usr/share/dsg/configs/org.deepin.dtk.preference.json - * Generation time: 2025-08-20T15:40:55 + * Command line arguments: ./build/tools/dconfig2cpp/dconfig2cpp /usr/share/dsg/configs/org.deepin.dtk.preference.json -o ./src/log/dconfig_org_deepin_dtk_preference.hpp + * Generation time: 2026-01-16T21:21:45 * JSON file version: 1.0 * * WARNING: DO NOT MODIFY THIS FILE MANUALLY. @@ -20,6 +20,7 @@ #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #endif +#include #include #include @@ -27,6 +28,8 @@ class dconfig_org_deepin_dtk_preference : public QObject { Q_OBJECT Q_PROPERTY(bool autoDisplayFeature READ autoDisplayFeature WRITE setAutoDisplayFeature NOTIFY autoDisplayFeatureChanged RESET resetAutoDisplayFeature) + Q_PROPERTY(QString colorMode READ colorMode WRITE setColorMode NOTIFY colorModeChanged RESET resetColorMode) + Q_PROPERTY(QString defaultColorMode READ defaultColorMode WRITE setDefaultColorMode NOTIFY defaultColorModeChanged RESET resetDefaultColorMode) Q_PROPERTY(bool enableDtkAnimations READ enableDtkAnimations WRITE setEnableDtkAnimations NOTIFY enableDtkAnimationsChanged RESET resetEnableDtkAnimations) Q_PROPERTY(bool featureUpdated READ featureUpdated WRITE setFeatureUpdated NOTIFY featureUpdatedChanged RESET resetFeatureUpdated) Q_PROPERTY(bool keyboardsearchDisabled READ keyboardsearchDisabled WRITE setKeyboardsearchDisabled NOTIFY keyboardsearchDisabledChanged RESET resetKeyboardsearchDisabled) @@ -36,7 +39,7 @@ class dconfig_org_deepin_dtk_preference : public QObject { 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;enableDtkAnimations;featureUpdated;keyboardsearchDisabled;rules;scrollBarPolicy;sizeMode;themeType;titlebarHeight;underlineShortcut") + Q_CLASSINFO("DConfigKeyList", "autoDisplayFeature;colorMode;defaultColorMode;enableDtkAnimations;featureUpdated;keyboardsearchDisabled;rules;scrollBarPolicy;sizeMode;themeType;titlebarHeight;underlineShortcut") Q_CLASSINFO("DConfigFileName", "org.deepin.dtk.preference") Q_CLASSINFO("DConfigFileVersion", "1.0") @@ -44,15 +47,30 @@ class dconfig_org_deepin_dtk_preference : public QObject { explicit dconfig_org_deepin_dtk_preference(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId, const QString &subpath, bool isGeneric, QObject *parent) - : QObject(nullptr) { + : QObject(parent), m_data(new Data) { + m_data->m_userConfig = this; + m_data->moveToThread(thread); + if (!thread->isRunning()) { qWarning() << QLatin1String("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); - QPointer watcher(parent); - QMetaObject::invokeMethod(worker, [=, this]() { + + QPointer safeData(m_data); + + QMetaObject::invokeMethod(worker, [safeData, backend, name, appId, subpath, isGeneric, worker]() mutable { + delete worker; + worker = nullptr; + + if (!safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Invalid), + static_cast(Data::Status::Initializing))) { + // CAS failed, state already changed - userConfig destructor will handle cleanup + // Do not attempt to delete here as it would race with destructor + return; + } + DTK_CORE_NAMESPACE::DConfig *config = nullptr; if (isGeneric) { if (backend) { @@ -77,21 +95,46 @@ class dconfig_org_deepin_dtk_preference : public QObject { } } } - if (!config) { + + if (!config || !config->isValid()) { qWarning() << QLatin1String("Failed to create DConfig instance."); - worker->deleteLater(); + + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Failed))) { + if (safeData->m_userConfig) { + QPointer selfData = safeData; + QMetaObject::invokeMethod(selfData, [selfData]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->configInitializeFailed(); + } + }, Qt::QueuedConnection); + } + } + + if (config) + delete config; + return; } config->moveToThread(QThread::currentThread()); - initializeInConfigThread(config); - if (watcher != parent) { - // delete this if watcher is changed to nullptr. - deleteLater(); - } else if (!this->parent() && parent) { - // !parent() means that parent is not changed. - this->setParent(watcher); - } - worker->deleteLater(); + // Initialize through Data class + safeData->initializeInConfigThread(config); + + // Try to transition from Initializing to Succeeded + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Succeeded))) { + // CAS succeeded, connect destroyed signal + QPointer selfData = safeData; + QObject::connect(config, &QObject::destroyed, config, [selfData]() { + if (selfData) { + selfData->deleteLater(); } + }); + } else { + // CAS failed - state changed (e.g., set to Destroyed) + // We must clean up the config we just created + config->deleteLater(); + safeData->deleteLater(); + } }); } static dconfig_org_deepin_dtk_preference* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) @@ -111,44 +154,58 @@ class dconfig_org_deepin_dtk_preference : public QObject { static dconfig_org_deepin_dtk_preference* createGenericByName(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) { return new dconfig_org_deepin_dtk_preference(thread, backend, name, {}, subpath, true, parent); } ~dconfig_org_deepin_dtk_preference() { - if (m_config.loadRelaxed()) { - m_config.loadRelaxed()->deleteLater(); - m_config.storeRelaxed(nullptr); + int oldStatus = m_data->m_status.fetchAndStoreOrdered(static_cast(Data::Status::Destroyed)); + + if (oldStatus == static_cast(Data::Status::Succeeded)) { + // When Succeeded, release config object only + auto config = m_data->m_config.loadRelaxed(); + Q_ASSERT(config); + config->deleteLater(); + // m_data will be deleted by config's destroyed signal + } else if (oldStatus == static_cast(Data::Status::Failed) || + oldStatus == static_cast(Data::Status::Invalid)) { + // When Failed or Invalid, directly clean up Data object + m_data->deleteLater(); } } Q_INVOKABLE DTK_CORE_NAMESPACE::DConfig *config() const { - return m_config.loadRelaxed(); + return m_data->m_config.loadRelaxed(); } - Q_INVOKABLE bool isInitializeSucceed() const { - return m_status.loadRelaxed() == static_cast(Status::Succeed); + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Succeeded); } - Q_INVOKABLE bool isInitializeFailed() const { - return m_status.loadRelaxed() == static_cast(Status::Failed); + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Failed); } - Q_INVOKABLE bool isInitializing() const { - return m_status.loadRelaxed() == static_cast(Status::Invalid); + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Initializing); } Q_INVOKABLE QStringList keyList() const { - return { QStringLiteral("autoDisplayFeature"), - QStringLiteral("enableDtkAnimations"), - QStringLiteral("featureUpdated"), - QStringLiteral("keyboardsearchDisabled"), - QStringLiteral("rules"), - QStringLiteral("scrollBarPolicy"), - QStringLiteral("sizeMode"), - QStringLiteral("themeType"), - QStringLiteral("titlebarHeight"), - QStringLiteral("underlineShortcut")}; + return { + QStringLiteral("autoDisplayFeature"), + QStringLiteral("colorMode"), + QStringLiteral("defaultColorMode"), + QStringLiteral("enableDtkAnimations"), + QStringLiteral("featureUpdated"), + QStringLiteral("keyboardsearchDisabled"), + QStringLiteral("rules"), + QStringLiteral("scrollBarPolicy"), + QStringLiteral("sizeMode"), + QStringLiteral("themeType"), + QStringLiteral("titlebarHeight"), + QStringLiteral("underlineShortcut") + }; } Q_INVOKABLE bool isDefaultValue(const QString &key) const { if (key == QStringLiteral("autoDisplayFeature")) return autoDisplayFeatureIsDefaultValue(); + if (key == QStringLiteral("colorMode")) + return colorModeIsDefaultValue(); + if (key == QStringLiteral("defaultColorMode")) + return defaultColorModeIsDefaultValue(); if (key == QStringLiteral("enableDtkAnimations")) return enableDtkAnimationsIsDefaultValue(); if (key == QStringLiteral("featureUpdated")) @@ -170,332 +227,369 @@ class dconfig_org_deepin_dtk_preference : public QObject { return false; } - bool autoDisplayFeature() const { - return p_autoDisplayFeature; + bool autoDisplayFeature() const + { + return m_data->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("autoDisplayFeature"), value); + auto oldValue = m_data->p_autoDisplayFeature; + m_data->p_autoDisplayFeature = value; + m_data->markPropertySet(0); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("autoDisplayFeature"), value); }); } - if (p_autoDisplayFeature != oldValue) { + if (m_data->p_autoDisplayFeature != oldValue) { Q_EMIT autoDisplayFeatureChanged(); Q_EMIT valueChanged(QStringLiteral("autoDisplayFeature"), value); } } void resetAutoDisplayFeature() { - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this]() { - m_config.loadRelaxed()->reset(QStringLiteral("autoDisplayFeature")); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("autoDisplayFeature")); }); } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QBindable bindableAutoDisplayFeature() { - return QBindable(this, "autoDisplayFeature"); + Q_INVOKABLE bool autoDisplayFeatureIsDefaultValue() const + { + return !m_data->testPropertySet(0); } -#endif - Q_INVOKABLE bool autoDisplayFeatureIsDefaultValue() const { - return !testPropertySet(0); + QString colorMode() const + { + return m_data->p_colorMode; } - bool enableDtkAnimations() const { - return p_enableDtkAnimations; + void setColorMode(const QString &value) { + auto oldValue = m_data->p_colorMode; + m_data->p_colorMode = value; + m_data->markPropertySet(1); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("colorMode"), value); + }); + } + if (m_data->p_colorMode != oldValue) { + Q_EMIT colorModeChanged(); + Q_EMIT valueChanged(QStringLiteral("colorMode"), value); + } + } + void resetColorMode() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("colorMode")); + }); + } + } + Q_INVOKABLE bool colorModeIsDefaultValue() const + { + return !m_data->testPropertySet(1); + } + QString defaultColorMode() const + { + return m_data->p_defaultColorMode; + } + void setDefaultColorMode(const QString &value) { + auto oldValue = m_data->p_defaultColorMode; + m_data->p_defaultColorMode = value; + m_data->markPropertySet(2); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("defaultColorMode"), value); + }); + } + if (m_data->p_defaultColorMode != oldValue) { + Q_EMIT defaultColorModeChanged(); + Q_EMIT valueChanged(QStringLiteral("defaultColorMode"), value); + } + } + void resetDefaultColorMode() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("defaultColorMode")); + }); + } + } + Q_INVOKABLE bool defaultColorModeIsDefaultValue() const + { + return !m_data->testPropertySet(2); + } + bool enableDtkAnimations() const + { + return m_data->p_enableDtkAnimations; } void setEnableDtkAnimations(const bool &value) { - auto oldValue = p_enableDtkAnimations; - p_enableDtkAnimations = value; - markPropertySet(1); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("enableDtkAnimations"), value); + auto oldValue = m_data->p_enableDtkAnimations; + m_data->p_enableDtkAnimations = value; + m_data->markPropertySet(3); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("enableDtkAnimations"), value); }); } - if (p_enableDtkAnimations != oldValue) { + if (m_data->p_enableDtkAnimations != oldValue) { Q_EMIT enableDtkAnimationsChanged(); Q_EMIT valueChanged(QStringLiteral("enableDtkAnimations"), value); } } void resetEnableDtkAnimations() { - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this]() { - m_config.loadRelaxed()->reset(QStringLiteral("enableDtkAnimations")); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("enableDtkAnimations")); }); } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QBindable bindableEnableDtkAnimations() { - return QBindable(this, "enableDtkAnimations"); - } -#endif - Q_INVOKABLE bool enableDtkAnimationsIsDefaultValue() const { - return !testPropertySet(1); + Q_INVOKABLE bool enableDtkAnimationsIsDefaultValue() const + { + return !m_data->testPropertySet(3); } - bool featureUpdated() const { - return p_featureUpdated; + bool featureUpdated() const + { + return m_data->p_featureUpdated; } void setFeatureUpdated(const bool &value) { - auto oldValue = p_featureUpdated; - p_featureUpdated = value; - markPropertySet(2); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("featureUpdated"), value); + auto oldValue = m_data->p_featureUpdated; + m_data->p_featureUpdated = value; + m_data->markPropertySet(4); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("featureUpdated"), value); }); } - if (p_featureUpdated != oldValue) { + if (m_data->p_featureUpdated != oldValue) { Q_EMIT featureUpdatedChanged(); Q_EMIT valueChanged(QStringLiteral("featureUpdated"), value); } } void resetFeatureUpdated() { - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this]() { - m_config.loadRelaxed()->reset(QStringLiteral("featureUpdated")); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("featureUpdated")); }); } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QBindable bindableFeatureUpdated() { - return QBindable(this, "featureUpdated"); - } -#endif - Q_INVOKABLE bool featureUpdatedIsDefaultValue() const { - return !testPropertySet(2); + Q_INVOKABLE bool featureUpdatedIsDefaultValue() const + { + return !m_data->testPropertySet(4); } - bool keyboardsearchDisabled() const { - return p_keyboardsearchDisabled; + bool keyboardsearchDisabled() const + { + return m_data->p_keyboardsearchDisabled; } void setKeyboardsearchDisabled(const bool &value) { - auto oldValue = p_keyboardsearchDisabled; - p_keyboardsearchDisabled = value; - markPropertySet(3); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("keyboardsearchDisabled"), value); + auto oldValue = m_data->p_keyboardsearchDisabled; + m_data->p_keyboardsearchDisabled = value; + m_data->markPropertySet(5); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("keyboardsearchDisabled"), value); }); } - if (p_keyboardsearchDisabled != oldValue) { + if (m_data->p_keyboardsearchDisabled != oldValue) { Q_EMIT keyboardsearchDisabledChanged(); Q_EMIT valueChanged(QStringLiteral("keyboardsearchDisabled"), value); } } void resetKeyboardsearchDisabled() { - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this]() { - m_config.loadRelaxed()->reset(QStringLiteral("keyboardsearchDisabled")); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("keyboardsearchDisabled")); }); } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QBindable bindableKeyboardsearchDisabled() { - return QBindable(this, "keyboardsearchDisabled"); - } -#endif - Q_INVOKABLE bool keyboardsearchDisabledIsDefaultValue() const { - return !testPropertySet(3); + Q_INVOKABLE bool keyboardsearchDisabledIsDefaultValue() const + { + return !m_data->testPropertySet(5); } - QString rules() const { - return p_rules; + QString rules() const + { + return m_data->p_rules; } void setRules(const QString &value) { - auto oldValue = p_rules; - p_rules = value; - markPropertySet(4); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("rules"), value); + auto oldValue = m_data->p_rules; + m_data->p_rules = value; + m_data->markPropertySet(6); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("rules"), value); }); } - if (p_rules != oldValue) { + if (m_data->p_rules != oldValue) { Q_EMIT rulesChanged(); Q_EMIT valueChanged(QStringLiteral("rules"), value); } } void resetRules() { - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this]() { - m_config.loadRelaxed()->reset(QStringLiteral("rules")); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("rules")); }); } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QBindable bindableRules() { - return QBindable(this, "rules"); - } -#endif - Q_INVOKABLE bool rulesIsDefaultValue() const { - return !testPropertySet(4); + Q_INVOKABLE bool rulesIsDefaultValue() const + { + return !m_data->testPropertySet(6); } - qlonglong scrollBarPolicy() const { - return p_scrollBarPolicy; + qlonglong scrollBarPolicy() const + { + return m_data->p_scrollBarPolicy; } void setScrollBarPolicy(const qlonglong &value) { - auto oldValue = p_scrollBarPolicy; - p_scrollBarPolicy = value; - markPropertySet(5); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("scrollBarPolicy"), value); + auto oldValue = m_data->p_scrollBarPolicy; + m_data->p_scrollBarPolicy = value; + m_data->markPropertySet(7); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("scrollBarPolicy"), value); }); } - if (p_scrollBarPolicy != oldValue) { + if (m_data->p_scrollBarPolicy != oldValue) { Q_EMIT scrollBarPolicyChanged(); Q_EMIT valueChanged(QStringLiteral("scrollBarPolicy"), value); } } void resetScrollBarPolicy() { - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this]() { - m_config.loadRelaxed()->reset(QStringLiteral("scrollBarPolicy")); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("scrollBarPolicy")); }); } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QBindable bindableScrollBarPolicy() { - return QBindable(this, "scrollBarPolicy"); - } -#endif - Q_INVOKABLE bool scrollBarPolicyIsDefaultValue() const { - return !testPropertySet(5); + Q_INVOKABLE bool scrollBarPolicyIsDefaultValue() const + { + return !m_data->testPropertySet(7); } - qlonglong sizeMode() const { - return p_sizeMode; + qlonglong sizeMode() const + { + return m_data->p_sizeMode; } void setSizeMode(const qlonglong &value) { - auto oldValue = p_sizeMode; - p_sizeMode = value; - markPropertySet(6); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("sizeMode"), value); + auto oldValue = m_data->p_sizeMode; + m_data->p_sizeMode = value; + m_data->markPropertySet(8); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("sizeMode"), value); }); } - if (p_sizeMode != oldValue) { + if (m_data->p_sizeMode != oldValue) { Q_EMIT sizeModeChanged(); Q_EMIT valueChanged(QStringLiteral("sizeMode"), value); } } void resetSizeMode() { - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this]() { - m_config.loadRelaxed()->reset(QStringLiteral("sizeMode")); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("sizeMode")); }); } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QBindable bindableSizeMode() { - return QBindable(this, "sizeMode"); - } -#endif - Q_INVOKABLE bool sizeModeIsDefaultValue() const { - return !testPropertySet(6); + Q_INVOKABLE bool sizeModeIsDefaultValue() const + { + return !m_data->testPropertySet(8); } - qlonglong themeType() const { - return p_themeType; + qlonglong themeType() const + { + return m_data->p_themeType; } void setThemeType(const qlonglong &value) { - auto oldValue = p_themeType; - p_themeType = value; - markPropertySet(7); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("themeType"), value); + auto oldValue = m_data->p_themeType; + m_data->p_themeType = value; + m_data->markPropertySet(9); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("themeType"), value); }); } - if (p_themeType != oldValue) { + if (m_data->p_themeType != oldValue) { Q_EMIT themeTypeChanged(); Q_EMIT valueChanged(QStringLiteral("themeType"), value); } } void resetThemeType() { - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this]() { - m_config.loadRelaxed()->reset(QStringLiteral("themeType")); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("themeType")); }); } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QBindable bindableThemeType() { - return QBindable(this, "themeType"); - } -#endif - Q_INVOKABLE bool themeTypeIsDefaultValue() const { - return !testPropertySet(7); + Q_INVOKABLE bool themeTypeIsDefaultValue() const + { + return !m_data->testPropertySet(9); } - qlonglong titlebarHeight() const { - return p_titlebarHeight; + qlonglong titlebarHeight() const + { + return m_data->p_titlebarHeight; } void setTitlebarHeight(const qlonglong &value) { - auto oldValue = p_titlebarHeight; - p_titlebarHeight = value; - markPropertySet(8); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("titlebarHeight"), value); + auto oldValue = m_data->p_titlebarHeight; + m_data->p_titlebarHeight = value; + m_data->markPropertySet(10); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("titlebarHeight"), value); }); } - if (p_titlebarHeight != oldValue) { + if (m_data->p_titlebarHeight != oldValue) { Q_EMIT titlebarHeightChanged(); Q_EMIT valueChanged(QStringLiteral("titlebarHeight"), value); } } void resetTitlebarHeight() { - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this]() { - m_config.loadRelaxed()->reset(QStringLiteral("titlebarHeight")); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("titlebarHeight")); }); } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QBindable bindableTitlebarHeight() { - return QBindable(this, "titlebarHeight"); - } -#endif - Q_INVOKABLE bool titlebarHeightIsDefaultValue() const { - return !testPropertySet(8); + Q_INVOKABLE bool titlebarHeightIsDefaultValue() const + { + return !m_data->testPropertySet(10); } - bool underlineShortcut() const { - return p_underlineShortcut; + bool underlineShortcut() const + { + return m_data->p_underlineShortcut; } void setUnderlineShortcut(const bool &value) { - auto oldValue = p_underlineShortcut; - p_underlineShortcut = value; - markPropertySet(9); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("underlineShortcut"), value); + auto oldValue = m_data->p_underlineShortcut; + m_data->p_underlineShortcut = value; + m_data->markPropertySet(11); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("underlineShortcut"), value); }); } - if (p_underlineShortcut != oldValue) { + if (m_data->p_underlineShortcut != oldValue) { Q_EMIT underlineShortcutChanged(); Q_EMIT valueChanged(QStringLiteral("underlineShortcut"), value); } } void resetUnderlineShortcut() { - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this]() { - m_config.loadRelaxed()->reset(QStringLiteral("underlineShortcut")); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("underlineShortcut")); }); } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QBindable bindableUnderlineShortcut() { - return QBindable(this, "underlineShortcut"); + Q_INVOKABLE bool underlineShortcutIsDefaultValue() const + { + return !m_data->testPropertySet(11); } -#endif - Q_INVOKABLE bool underlineShortcutIsDefaultValue() const { - return !testPropertySet(9); +protected: + bool event(QEvent *e) override { + if (e->type() == QEvent::ThreadChange) { + Q_ASSERT_X(false, "dconfig_org_deepin_dtk_preference", "Moving dconfig_org_deepin_dtk_preference to another thread is forbidden!"); + } + return QObject::event(e); } + Q_SIGNALS: - void configInitializeFailed(DTK_CORE_NAMESPACE::DConfig *config); + void configInitializeFailed(); void configInitializeSucceed(DTK_CORE_NAMESPACE::DConfig *config); void valueChanged(const QString &key, const QVariant &value); - void autoDisplayFeatureChanged(); + void colorModeChanged(); + void defaultColorModeChanged(); void enableDtkAnimationsChanged(); void featureUpdatedChanged(); void keyboardsearchDisabledChanged(); @@ -505,252 +599,408 @@ class dconfig_org_deepin_dtk_preference : public QObject { 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(Status::Failed)); - Q_EMIT configInitializeFailed(config); - return; - } - - if (testPropertySet(0)) { - config->setValue(QStringLiteral("autoDisplayFeature"), QVariant::fromValue(p_autoDisplayFeature)); - } else { - updateValue(QStringLiteral("autoDisplayFeature"), QVariant::fromValue(p_autoDisplayFeature)); - } - if (testPropertySet(1)) { - config->setValue(QStringLiteral("enableDtkAnimations"), QVariant::fromValue(p_enableDtkAnimations)); - } else { - updateValue(QStringLiteral("enableDtkAnimations"), QVariant::fromValue(p_enableDtkAnimations)); - } - if (testPropertySet(2)) { - config->setValue(QStringLiteral("featureUpdated"), QVariant::fromValue(p_featureUpdated)); - } else { - updateValue(QStringLiteral("featureUpdated"), QVariant::fromValue(p_featureUpdated)); - } - if (testPropertySet(3)) { - config->setValue(QStringLiteral("keyboardsearchDisabled"), QVariant::fromValue(p_keyboardsearchDisabled)); - } else { - updateValue(QStringLiteral("keyboardsearchDisabled"), QVariant::fromValue(p_keyboardsearchDisabled)); - } - if (testPropertySet(4)) { - config->setValue(QStringLiteral("rules"), QVariant::fromValue(p_rules)); - } else { - updateValue(QStringLiteral("rules"), QVariant::fromValue(p_rules)); - } - if (testPropertySet(5)) { - config->setValue(QStringLiteral("scrollBarPolicy"), QVariant::fromValue(p_scrollBarPolicy)); - } else { - updateValue(QStringLiteral("scrollBarPolicy"), QVariant::fromValue(p_scrollBarPolicy)); - } - if (testPropertySet(6)) { - config->setValue(QStringLiteral("sizeMode"), QVariant::fromValue(p_sizeMode)); - } else { - updateValue(QStringLiteral("sizeMode"), QVariant::fromValue(p_sizeMode)); - } - if (testPropertySet(7)) { - config->setValue(QStringLiteral("themeType"), QVariant::fromValue(p_themeType)); - } else { - updateValue(QStringLiteral("themeType"), QVariant::fromValue(p_themeType)); - } - if (testPropertySet(8)) { - config->setValue(QStringLiteral("titlebarHeight"), QVariant::fromValue(p_titlebarHeight)); - } else { - updateValue(QStringLiteral("titlebarHeight"), QVariant::fromValue(p_titlebarHeight)); - } - if (testPropertySet(9)) { - config->setValue(QStringLiteral("underlineShortcut"), QVariant::fromValue(p_underlineShortcut)); - } else { - updateValue(QStringLiteral("underlineShortcut"), QVariant::fromValue(p_underlineShortcut)); - } - - if (!m_config.loadRelaxed()) - return; - connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) { - updateValue(key); - }, Qt::DirectConnection); - - m_status.storeRelaxed(static_cast(Status::Succeed)); - Q_EMIT configInitializeSucceed(config); - } - void updateValue(const QString &key, const QVariant &fallback = QVariant()) { - if (!m_config.loadRelaxed()) - return; - Q_ASSERT(QThread::currentThread() == m_config.loadRelaxed()->thread()); - const QVariant &value = m_config.loadRelaxed()->value(key, fallback); - if (key == QStringLiteral("autoDisplayFeature")) { - markPropertySet(0, !m_config.loadRelaxed()->isDefaultValue(key)); - auto newValue = qvariant_cast(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); - } + // Prevent external moveToThread calls + using QObject::moveToThread; + class Data : public QObject { + public: + enum class Status { + Invalid = 0, + Initializing = 1, + Succeeded = 2, + Failed = 3, + Destroyed = 4 + }; + + explicit Data() + : QObject(nullptr) {} + + QAtomicPointer m_config = nullptr; + QAtomicInteger m_status = static_cast(Status::Invalid); + QPointer m_userConfig = nullptr; + QAtomicInteger m_propertySetStatus0 = 0; + + // Property storage + bool p_autoDisplayFeature { false }; + // Default value: "" + QString p_colorMode { QLatin1String("") }; + // Default value: "color" + QString p_defaultColorMode { QStringLiteral(u"\u0063\u006f\u006c\u006f\u0072") }; + bool p_enableDtkAnimations { false }; + bool p_featureUpdated { false }; + bool p_keyboardsearchDisabled { false }; + // Default value: "*.debug=false" + QString p_rules { QStringLiteral(u"\u002a\u002e\u0064\u0065\u0062\u0075\u0067\u003d\u0066\u0061\u006c\u0073\u0065") }; + qlonglong p_scrollBarPolicy { 0 }; + qlonglong p_sizeMode { 0 }; + qlonglong p_themeType { 0 }; + qlonglong p_titlebarHeight { -1 }; + bool p_underlineShortcut { false }; + + inline void initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config) { + Q_ASSERT(!m_config.loadRelaxed()); + m_config.storeRelaxed(config); + // Connect signals early - use QPointer to protect Data lifetime + QPointer selfData(this); + QObject::connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, config, [selfData](const QString &key) { + if (selfData) selfData->updateValue(key); }); - return; - } - if (key == QStringLiteral("enableDtkAnimations")) { - markPropertySet(1, !m_config.loadRelaxed()->isDefaultValue(key)); - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue, key, value]() { - Q_ASSERT(QThread::currentThread() == this->thread()); - if (p_enableDtkAnimations != newValue) { - p_enableDtkAnimations = newValue; - Q_EMIT enableDtkAnimationsChanged(); - Q_EMIT valueChanged(key, value); + if (testPropertySet(0)) { + config->setValue(QStringLiteral("autoDisplayFeature"), QVariant::fromValue(p_autoDisplayFeature)); + } else { + updateValue(QStringLiteral("autoDisplayFeature"), QVariant::fromValue(p_autoDisplayFeature)); + } + if (testPropertySet(1)) { + config->setValue(QStringLiteral("colorMode"), QVariant::fromValue(p_colorMode)); + } else { + updateValue(QStringLiteral("colorMode"), QVariant::fromValue(p_colorMode)); + } + if (testPropertySet(2)) { + config->setValue(QStringLiteral("defaultColorMode"), QVariant::fromValue(p_defaultColorMode)); + } else { + updateValue(QStringLiteral("defaultColorMode"), QVariant::fromValue(p_defaultColorMode)); + } + if (testPropertySet(3)) { + config->setValue(QStringLiteral("enableDtkAnimations"), QVariant::fromValue(p_enableDtkAnimations)); + } else { + updateValue(QStringLiteral("enableDtkAnimations"), QVariant::fromValue(p_enableDtkAnimations)); + } + if (testPropertySet(4)) { + config->setValue(QStringLiteral("featureUpdated"), QVariant::fromValue(p_featureUpdated)); + } else { + updateValue(QStringLiteral("featureUpdated"), QVariant::fromValue(p_featureUpdated)); + } + if (testPropertySet(5)) { + config->setValue(QStringLiteral("keyboardsearchDisabled"), QVariant::fromValue(p_keyboardsearchDisabled)); + } else { + updateValue(QStringLiteral("keyboardsearchDisabled"), QVariant::fromValue(p_keyboardsearchDisabled)); + } + if (testPropertySet(6)) { + config->setValue(QStringLiteral("rules"), QVariant::fromValue(p_rules)); + } else { + updateValue(QStringLiteral("rules"), QVariant::fromValue(p_rules)); + } + if (testPropertySet(7)) { + config->setValue(QStringLiteral("scrollBarPolicy"), QVariant::fromValue(p_scrollBarPolicy)); + } else { + updateValue(QStringLiteral("scrollBarPolicy"), QVariant::fromValue(p_scrollBarPolicy)); + } + if (testPropertySet(8)) { + config->setValue(QStringLiteral("sizeMode"), QVariant::fromValue(p_sizeMode)); + } else { + updateValue(QStringLiteral("sizeMode"), QVariant::fromValue(p_sizeMode)); + } + if (testPropertySet(9)) { + config->setValue(QStringLiteral("themeType"), QVariant::fromValue(p_themeType)); + } else { + updateValue(QStringLiteral("themeType"), QVariant::fromValue(p_themeType)); + } + if (testPropertySet(10)) { + config->setValue(QStringLiteral("titlebarHeight"), QVariant::fromValue(p_titlebarHeight)); + } else { + updateValue(QStringLiteral("titlebarHeight"), QVariant::fromValue(p_titlebarHeight)); + } + if (testPropertySet(11)) { + config->setValue(QStringLiteral("underlineShortcut"), QVariant::fromValue(p_underlineShortcut)); + } else { + updateValue(QStringLiteral("underlineShortcut"), QVariant::fromValue(p_underlineShortcut)); + } + } + + inline void updateValue(const QString &key, const QVariant &fallback = QVariant()) { + auto config = m_config.loadRelaxed(); + if (!config) return; + const QVariant &v = config->value(key, fallback); + if (key == QStringLiteral("autoDisplayFeature")) { + markPropertySet(0, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("colorMode")) { + markPropertySet(1, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("defaultColorMode")) { + markPropertySet(2, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("enableDtkAnimations")) { + markPropertySet(3, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("featureUpdated")) { + markPropertySet(4, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("keyboardsearchDisabled")) { + markPropertySet(5, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("rules")) { + markPropertySet(6, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("scrollBarPolicy")) { + markPropertySet(7, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("sizeMode")) { + markPropertySet(8, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("themeType")) { + markPropertySet(9, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("titlebarHeight")) { + markPropertySet(10, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("underlineShortcut")) { + markPropertySet(11, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + } + + inline void updateProperty(const QString &key, const QVariant &v) { + if (key == QStringLiteral("autoDisplayFeature")) { + bool nv = qvariant_cast(v); + if (p_autoDisplayFeature != nv) { + p_autoDisplayFeature = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->autoDisplayFeatureChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("featureUpdated")) { - markPropertySet(2, !m_config.loadRelaxed()->isDefaultValue(key)); - auto newValue = qvariant_cast(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("colorMode")) { + QString nv = qvariant_cast(v); + if (p_colorMode != nv) { + p_colorMode = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->colorModeChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("keyboardsearchDisabled")) { - markPropertySet(3, !m_config.loadRelaxed()->isDefaultValue(key)); - auto newValue = qvariant_cast(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("defaultColorMode")) { + QString nv = qvariant_cast(v); + if (p_defaultColorMode != nv) { + p_defaultColorMode = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->defaultColorModeChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("rules")) { - markPropertySet(4, !m_config.loadRelaxed()->isDefaultValue(key)); - auto newValue = qvariant_cast(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("enableDtkAnimations")) { + bool nv = qvariant_cast(v); + if (p_enableDtkAnimations != nv) { + p_enableDtkAnimations = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->enableDtkAnimationsChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("scrollBarPolicy")) { - markPropertySet(5, !m_config.loadRelaxed()->isDefaultValue(key)); - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue, key, value]() { - Q_ASSERT(QThread::currentThread() == this->thread()); - if (p_scrollBarPolicy != newValue) { - p_scrollBarPolicy = newValue; - Q_EMIT scrollBarPolicyChanged(); - Q_EMIT valueChanged(key, value); + return; + } + if (key == QStringLiteral("featureUpdated")) { + bool nv = qvariant_cast(v); + if (p_featureUpdated != nv) { + p_featureUpdated = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->featureUpdatedChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("sizeMode")) { - markPropertySet(6, !m_config.loadRelaxed()->isDefaultValue(key)); - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue, key, value]() { - Q_ASSERT(QThread::currentThread() == this->thread()); - if (p_sizeMode != newValue) { - p_sizeMode = newValue; - Q_EMIT sizeModeChanged(); - Q_EMIT valueChanged(key, value); + return; + } + if (key == QStringLiteral("keyboardsearchDisabled")) { + bool nv = qvariant_cast(v); + if (p_keyboardsearchDisabled != nv) { + p_keyboardsearchDisabled = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->keyboardsearchDisabledChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("themeType")) { - markPropertySet(7, !m_config.loadRelaxed()->isDefaultValue(key)); - auto newValue = qvariant_cast(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("rules")) { + QString nv = qvariant_cast(v); + if (p_rules != nv) { + p_rules = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->rulesChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("titlebarHeight")) { - markPropertySet(8, !m_config.loadRelaxed()->isDefaultValue(key)); - auto newValue = qvariant_cast(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("scrollBarPolicy")) { + qlonglong nv = qvariant_cast(v); + if (p_scrollBarPolicy != nv) { + p_scrollBarPolicy = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->scrollBarPolicyChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("underlineShortcut")) { - markPropertySet(9, !m_config.loadRelaxed()->isDefaultValue(key)); - auto newValue = qvariant_cast(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; + } + if (key == QStringLiteral("sizeMode")) { + qlonglong nv = qvariant_cast(v); + if (p_sizeMode != nv) { + p_sizeMode = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->sizeModeChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - 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))); + return; + } + if (key == QStringLiteral("themeType")) { + qlonglong nv = qvariant_cast(v); + if (p_themeType != nv) { + p_themeType = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->themeTypeChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } + } + return; + } + if (key == QStringLiteral("titlebarHeight")) { + qlonglong nv = qvariant_cast(v); + if (p_titlebarHeight != nv) { + p_titlebarHeight = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->titlebarHeightChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } + } + return; + } + if (key == QStringLiteral("underlineShortcut")) { + bool nv = qvariant_cast(v); + if (p_underlineShortcut != nv) { + p_underlineShortcut = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->underlineShortcutChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } + } + return; + } } - Q_UNREACHABLE(); - } - QAtomicPointer m_config = nullptr; + 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(); + } -public: - enum class Status { - Invalid = 0, - Succeed = 1, - Failed = 2 + inline bool testPropertySet(const int index) const { + if (index < 32) { + return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0))); + } + Q_UNREACHABLE(); + } }; -private: - QAtomicInteger m_status = static_cast(Status::Invalid); - - bool p_autoDisplayFeature { false }; - bool p_enableDtkAnimations { false }; - bool p_featureUpdated { false }; - bool p_keyboardsearchDisabled { false }; - // Default value: "*.debug=false" - QString p_rules { QStringLiteral(u"\u002a\u002e\u0064\u0065\u0062\u0075\u0067\u003d\u0066\u0061\u006c\u0073\u0065") }; - qlonglong p_scrollBarPolicy { 0 }; - qlonglong p_sizeMode { 0 }; - qlonglong p_themeType { 0 }; - qlonglong p_titlebarHeight { -1 }; - bool p_underlineShortcut { false }; - QAtomicInteger m_propertySetStatus0 = 0; + + Data *m_data; }; #endif // DCONFIG_ORG_DEEPIN_DTK_PREFERENCE_H diff --git a/toolGenerate/dconfig2cpp/dconf-example_meta.hpp b/toolGenerate/dconfig2cpp/dconf-example_meta.hpp index 3ceef68c..499c9c67 100644 --- a/toolGenerate/dconfig2cpp/dconf-example_meta.hpp +++ b/toolGenerate/dconfig2cpp/dconf-example_meta.hpp @@ -1,322 +1,658 @@ /** * This file is generated by dconfig2cpp. - * Command line arguments: ./dconfig2cpp -p ./dtkcore/toolGenerate/dconfig2cpp ./dtkcore/tests/data/dconf-example.meta.json - * Generation time: 2025-01-14T10:54:59 + * Command line arguments: ./build/tools/dconfig2cpp/dconfig2cpp ./tests/data/dconf-example.meta.json -o ./toolGenerate/dconfig2cpp/dconf-example_meta.hpp + * Generation time: 2026-01-16T21:21:45 * 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 DCONF-EXAMPLE_META_H -#define DCONF-EXAMPLE_META_H +#ifndef DCONFIG_DCONF-EXAMPLE_META_H +#define DCONFIG_DCONF-EXAMPLE_META_H #include #include +#include #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#include +#endif +#include +#include #include -class dconf-example_meta : public QObject { +class dconfig_dconf-example_meta : public QObject { Q_OBJECT - Q_PROPERTY(QList array READ array WRITE setArray NOTIFY arrayChanged) - Q_PROPERTY(QList array_map READ array_map WRITE setArray_map NOTIFY array_mapChanged) - Q_PROPERTY(QList array_map_struct READ array_map_struct WRITE setArray_map_struct NOTIFY array_map_structChanged) - Q_PROPERTY(bool canExit READ canExit WRITE setCanExit NOTIFY canExitChanged) - Q_PROPERTY(QString key2 READ key2 WRITE setKey2 NOTIFY key2Changed) - Q_PROPERTY(QString key3 READ key3 WRITE setKey3 NOTIFY key3Changed) - Q_PROPERTY(QVariantMap map READ map WRITE setMap NOTIFY mapChanged) - Q_PROPERTY(QVariantMap map_array READ map_array WRITE setMap_array NOTIFY map_arrayChanged) - Q_PROPERTY(double number READ number WRITE setNumber NOTIFY numberChanged) - Q_PROPERTY(double numberDouble READ numberDouble WRITE setNumberDouble NOTIFY numberDoubleChanged) - Q_PROPERTY(bool publicConfig READ publicConfig WRITE setPublicConfig NOTIFY publicConfigChanged) - Q_PROPERTY(QVariantMap struct READ struct WRITE setStruct NOTIFY structChanged) + Q_PROPERTY(QList array READ array WRITE setArray NOTIFY arrayChanged RESET resetArray) + Q_PROPERTY(QList array_map READ array_map WRITE setArray_map NOTIFY array_mapChanged RESET resetArray_map) + Q_PROPERTY(QList array_map_struct READ array_map_struct WRITE setArray_map_struct NOTIFY array_map_structChanged RESET resetArray_map_struct) + Q_PROPERTY(bool canExit READ canExit WRITE setCanExit NOTIFY canExitChanged RESET resetCanExit) + Q_PROPERTY(QString key2 READ key2 WRITE setKey2 NOTIFY key2Changed RESET resetKey2) + Q_PROPERTY(QString key3 READ key3 WRITE setKey3 NOTIFY key3Changed RESET resetKey3) + Q_PROPERTY(QVariantMap map READ map WRITE setMap NOTIFY mapChanged RESET resetMap) + Q_PROPERTY(QVariantMap map_array READ map_array WRITE setMap_array NOTIFY map_arrayChanged RESET resetMap_array) + Q_PROPERTY(qlonglong number READ number WRITE setNumber NOTIFY numberChanged RESET resetNumber) + Q_PROPERTY(double numberDouble READ numberDouble WRITE setNumberDouble NOTIFY numberDoubleChanged RESET resetNumberDouble) + Q_PROPERTY(bool publicConfig READ publicConfig WRITE setPublicConfig NOTIFY publicConfigChanged RESET resetPublicConfig) + Q_PROPERTY(bool readonly READ readonly WRITE setReadonly NOTIFY readonlyChanged RESET resetReadonly) + Q_PROPERTY(bool readwrite READ readwrite WRITE setReadwrite NOTIFY readwriteChanged RESET resetReadwrite) + Q_PROPERTY(QVariantMap struct READ struct WRITE setStruct NOTIFY structChanged RESET resetStruct) + Q_CLASSINFO("DConfigKeyList", "array;array_map;array_map_struct;canExit;key2;key3;map;map_array;number;numberDouble;publicConfig;readonly;readwrite;struct") + Q_CLASSINFO("DConfigFileName", "dconf-example.meta") + Q_CLASSINFO("DConfigFileVersion", "1.0") + public: - explicit dconf-example_meta(QThread *thread, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { + explicit dconfig_dconf-example_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, + const QString &name, const QString &appId, const QString &subpath, + bool isGeneric, QObject *parent) + : QObject(parent), m_data(new Data) { + m_data->m_userConfig = this; + m_data->moveToThread(thread); if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); + qWarning() << QLatin1String("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); + + QPointer safeData(m_data); + + QMetaObject::invokeMethod(worker, [safeData, backend, name, appId, subpath, isGeneric, worker]() mutable { + delete worker; + worker = nullptr; + + if (!safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Invalid), + static_cast(Data::Status::Initializing))) { + // CAS failed, state already changed - userConfig destructor will handle cleanup + // Do not attempt to delete here as it would race with destructor return; } - config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); - }); - } - explicit dconf-example_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { - if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); - } - Q_ASSERT(QThread::currentThread() != thread); - auto worker = new QObject(); - worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, appId, name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); - return; + DTK_CORE_NAMESPACE::DConfig *config = nullptr; + if (isGeneric) { + if (backend) { + config = DTK_CORE_NAMESPACE::DConfig::createGeneric(backend, name, subpath, nullptr); + } else { + config = DTK_CORE_NAMESPACE::DConfig::createGeneric(name, subpath, nullptr); + } + } else { + if (backend) { + if (appId.isNull()) { + config = DTK_CORE_NAMESPACE::DConfig::create(backend, DTK_CORE_NAMESPACE::DSGApplication::id(), + 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(DTK_CORE_NAMESPACE::DSGApplication::id(), + name, subpath, nullptr); + } else { + config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); + } + } } - config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); - }); - } - explicit dconf-example_meta(QThread *thread, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { - if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); - } - Q_ASSERT(QThread::currentThread() != thread); - auto worker = new QObject(); - worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); + if (!config || !config->isValid()) { + qWarning() << QLatin1String("Failed to create DConfig instance."); + + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Failed))) { + if (safeData->m_userConfig) { + QPointer selfData = safeData; + QMetaObject::invokeMethod(selfData, [selfData]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->configInitializeFailed(); + } + }, Qt::QueuedConnection); + } + } + + if (config) + delete config; + return; } config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); - }); - } - explicit dconf-example_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { + // Initialize through Data class + safeData->initializeInConfigThread(config); - if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); - } - Q_ASSERT(QThread::currentThread() != thread); - auto worker = new QObject(); - worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); - return; + // Try to transition from Initializing to Succeeded + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Succeeded))) { + // CAS succeeded, connect destroyed signal + QPointer selfData = safeData; + QObject::connect(config, &QObject::destroyed, config, [selfData]() { + if (selfData) { + selfData->deleteLater(); } + }); + } else { + // CAS failed - state changed (e.g., set to Destroyed) + // We must clean up the config we just created + config->deleteLater(); + safeData->deleteLater(); } - config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); }); } - ~dconf-example_meta() { - if (m_config.loadRelaxed()) { - m_config.loadRelaxed()->deleteLater(); + static dconfig_dconf-example_meta* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_meta(thread, nullptr, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0065\u0078\u0061\u006d\u0070\u006c\u0065\u002e\u006d\u0065\u0074\u0061"), appId, subpath, false, parent); } + static dconfig_dconf-example_meta* 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_dconf-example_meta(thread, backend, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0065\u0078\u0061\u006d\u0070\u006c\u0065\u002e\u006d\u0065\u0074\u0061"), appId, subpath, false, parent); } + static dconfig_dconf-example_meta* createByName(const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_meta(thread, nullptr, name, appId, subpath, false, parent); } + static dconfig_dconf-example_meta* 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_dconf-example_meta(thread, backend, name, appId, subpath, false, parent); } + static dconfig_dconf-example_meta* createGeneric(const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_meta(thread, nullptr, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0065\u0078\u0061\u006d\u0070\u006c\u0065\u002e\u006d\u0065\u0074\u0061"), {}, subpath, true, parent); } + static dconfig_dconf-example_meta* create(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_meta(thread, backend, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0065\u0078\u0061\u006d\u0070\u006c\u0065\u002e\u006d\u0065\u0074\u0061"), {}, subpath, true, parent); } + static dconfig_dconf-example_meta* createGenericByName(const QString &name, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_meta(thread, nullptr, name, {}, subpath, true, parent); } + static dconfig_dconf-example_meta* createGenericByName(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_meta(thread, backend, name, {}, subpath, true, parent); } + ~dconfig_dconf-example_meta() { + int oldStatus = m_data->m_status.fetchAndStoreOrdered(static_cast(Data::Status::Destroyed)); + + if (oldStatus == static_cast(Data::Status::Succeeded)) { + // When Succeeded, release config object only + auto config = m_data->m_config.loadRelaxed(); + Q_ASSERT(config); + config->deleteLater(); + // m_data will be deleted by config's destroyed signal + } else if (oldStatus == static_cast(Data::Status::Failed) || + oldStatus == static_cast(Data::Status::Invalid)) { + // When Failed or Invalid, directly clean up Data object + m_data->deleteLater(); } } - QList array() const { - return p_array; + Q_INVOKABLE DTK_CORE_NAMESPACE::DConfig *config() const { + return m_data->m_config.loadRelaxed(); + } + Q_INVOKABLE bool isInitializeSucceed() const { + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Succeeded); + } + Q_INVOKABLE bool isInitializeFailed() const { + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Failed); + } + Q_INVOKABLE bool isInitializing() const { + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Initializing); + } + + Q_INVOKABLE QStringList keyList() const { + return { + QStringLiteral("array"), + QStringLiteral("array_map"), + QStringLiteral("array_map_struct"), + QStringLiteral("canExit"), + QStringLiteral("key2"), + QStringLiteral("key3"), + QStringLiteral("map"), + QStringLiteral("map_array"), + QStringLiteral("number"), + QStringLiteral("numberDouble"), + QStringLiteral("publicConfig"), + QStringLiteral("readonly"), + QStringLiteral("readwrite"), + QStringLiteral("struct") + }; + } + + Q_INVOKABLE bool isDefaultValue(const QString &key) const { + if (key == QStringLiteral("array")) + return arrayIsDefaultValue(); + if (key == QStringLiteral("array_map")) + return array_mapIsDefaultValue(); + if (key == QStringLiteral("array_map_struct")) + return array_map_structIsDefaultValue(); + if (key == QStringLiteral("canExit")) + return canExitIsDefaultValue(); + if (key == QStringLiteral("key2")) + return key2IsDefaultValue(); + if (key == QStringLiteral("key3")) + return key3IsDefaultValue(); + if (key == QStringLiteral("map")) + return mapIsDefaultValue(); + if (key == QStringLiteral("map_array")) + return map_arrayIsDefaultValue(); + if (key == QStringLiteral("number")) + return numberIsDefaultValue(); + if (key == QStringLiteral("numberDouble")) + return numberDoubleIsDefaultValue(); + if (key == QStringLiteral("publicConfig")) + return publicConfigIsDefaultValue(); + if (key == QStringLiteral("readonly")) + return readonlyIsDefaultValue(); + if (key == QStringLiteral("readwrite")) + return readwriteIsDefaultValue(); + if (key == QStringLiteral("struct")) + return structIsDefaultValue(); + return false; + } + + QList array() const + { + return m_data->p_array; } void setArray(const QList &value) { - auto oldValue = p_array; - p_array = value; - markPropertySet(0); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("array"), value); + auto oldValue = m_data->p_array; + m_data->p_array = value; + m_data->markPropertySet(0); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("array"), value); }); } - if (p_array != oldValue) { + if (m_data->p_array != oldValue) { Q_EMIT arrayChanged(); + Q_EMIT valueChanged(QStringLiteral("array"), value); + } + } + void resetArray() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("array")); + }); } } - QList array_map() const { - return p_array_map; + Q_INVOKABLE bool arrayIsDefaultValue() const + { + return !m_data->testPropertySet(0); + } + QList array_map() const + { + return m_data->p_array_map; } void setArray_map(const QList &value) { - auto oldValue = p_array_map; - p_array_map = value; - markPropertySet(1); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("array_map"), value); + auto oldValue = m_data->p_array_map; + m_data->p_array_map = value; + m_data->markPropertySet(1); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("array_map"), value); }); } - if (p_array_map != oldValue) { + if (m_data->p_array_map != oldValue) { Q_EMIT array_mapChanged(); + Q_EMIT valueChanged(QStringLiteral("array_map"), value); + } + } + void resetArray_map() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("array_map")); + }); } } - QList array_map_struct() const { - return p_array_map_struct; + Q_INVOKABLE bool array_mapIsDefaultValue() const + { + return !m_data->testPropertySet(1); + } + QList array_map_struct() const + { + return m_data->p_array_map_struct; } void setArray_map_struct(const QList &value) { - auto oldValue = p_array_map_struct; - p_array_map_struct = value; - markPropertySet(2); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("array_map_struct"), value); + auto oldValue = m_data->p_array_map_struct; + m_data->p_array_map_struct = value; + m_data->markPropertySet(2); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("array_map_struct"), value); }); } - if (p_array_map_struct != oldValue) { + if (m_data->p_array_map_struct != oldValue) { Q_EMIT array_map_structChanged(); + Q_EMIT valueChanged(QStringLiteral("array_map_struct"), value); } } - bool canExit() const { - return p_canExit; + void resetArray_map_struct() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("array_map_struct")); + }); + } + } + Q_INVOKABLE bool array_map_structIsDefaultValue() const + { + return !m_data->testPropertySet(2); + } + bool canExit() const + { + return m_data->p_canExit; } void setCanExit(const bool &value) { - auto oldValue = p_canExit; - p_canExit = value; - markPropertySet(3); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("canExit"), value); + auto oldValue = m_data->p_canExit; + m_data->p_canExit = value; + m_data->markPropertySet(3); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("canExit"), value); }); } - if (p_canExit != oldValue) { + if (m_data->p_canExit != oldValue) { Q_EMIT canExitChanged(); + Q_EMIT valueChanged(QStringLiteral("canExit"), value); } } - QString key2() const { - return p_key2; + void resetCanExit() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("canExit")); + }); + } + } + Q_INVOKABLE bool canExitIsDefaultValue() const + { + return !m_data->testPropertySet(3); + } + QString key2() const + { + return m_data->p_key2; } void setKey2(const QString &value) { - auto oldValue = p_key2; - p_key2 = value; - markPropertySet(4); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("key2"), value); + auto oldValue = m_data->p_key2; + m_data->p_key2 = value; + m_data->markPropertySet(4); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("key2"), value); }); } - if (p_key2 != oldValue) { + if (m_data->p_key2 != oldValue) { Q_EMIT key2Changed(); + Q_EMIT valueChanged(QStringLiteral("key2"), value); } } - QString key3() const { - return p_key3; + void resetKey2() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("key2")); + }); + } + } + Q_INVOKABLE bool key2IsDefaultValue() const + { + return !m_data->testPropertySet(4); + } + QString key3() const + { + return m_data->p_key3; } void setKey3(const QString &value) { - auto oldValue = p_key3; - p_key3 = value; - markPropertySet(5); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("key3"), value); + auto oldValue = m_data->p_key3; + m_data->p_key3 = value; + m_data->markPropertySet(5); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("key3"), value); }); } - if (p_key3 != oldValue) { + if (m_data->p_key3 != oldValue) { Q_EMIT key3Changed(); + Q_EMIT valueChanged(QStringLiteral("key3"), value); + } + } + void resetKey3() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("key3")); + }); } } - QVariantMap map() const { - return p_map; + Q_INVOKABLE bool key3IsDefaultValue() const + { + return !m_data->testPropertySet(5); + } + QVariantMap map() const + { + return m_data->p_map; } void setMap(const QVariantMap &value) { - auto oldValue = p_map; - p_map = value; - markPropertySet(6); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("map"), value); + auto oldValue = m_data->p_map; + m_data->p_map = value; + m_data->markPropertySet(6); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("map"), value); }); } - if (p_map != oldValue) { + if (m_data->p_map != oldValue) { Q_EMIT mapChanged(); + Q_EMIT valueChanged(QStringLiteral("map"), value); + } + } + void resetMap() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("map")); + }); } } - QVariantMap map_array() const { - return p_map_array; + Q_INVOKABLE bool mapIsDefaultValue() const + { + return !m_data->testPropertySet(6); + } + QVariantMap map_array() const + { + return m_data->p_map_array; } void setMap_array(const QVariantMap &value) { - auto oldValue = p_map_array; - p_map_array = value; - markPropertySet(7); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("map_array"), value); + auto oldValue = m_data->p_map_array; + m_data->p_map_array = value; + m_data->markPropertySet(7); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("map_array"), value); }); } - if (p_map_array != oldValue) { + if (m_data->p_map_array != oldValue) { Q_EMIT map_arrayChanged(); + Q_EMIT valueChanged(QStringLiteral("map_array"), value); } } - double number() const { - return p_number; + void resetMap_array() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("map_array")); + }); + } } - void setNumber(const double &value) { - auto oldValue = p_number; - p_number = value; - markPropertySet(8); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("number"), value); + Q_INVOKABLE bool map_arrayIsDefaultValue() const + { + return !m_data->testPropertySet(7); + } + qlonglong number() const + { + return m_data->p_number; + } + void setNumber(const qlonglong &value) { + auto oldValue = m_data->p_number; + m_data->p_number = value; + m_data->markPropertySet(8); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("number"), value); }); } - if (p_number != oldValue) { + if (m_data->p_number != oldValue) { Q_EMIT numberChanged(); + Q_EMIT valueChanged(QStringLiteral("number"), value); + } + } + void resetNumber() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("number")); + }); } } - double numberDouble() const { - return p_numberDouble; + Q_INVOKABLE bool numberIsDefaultValue() const + { + return !m_data->testPropertySet(8); + } + double numberDouble() const + { + return m_data->p_numberDouble; } void setNumberDouble(const double &value) { - auto oldValue = p_numberDouble; - p_numberDouble = value; - markPropertySet(9); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("numberDouble"), value); + auto oldValue = m_data->p_numberDouble; + m_data->p_numberDouble = value; + m_data->markPropertySet(9); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("numberDouble"), value); }); } - if (p_numberDouble != oldValue) { + if (m_data->p_numberDouble != oldValue) { Q_EMIT numberDoubleChanged(); + Q_EMIT valueChanged(QStringLiteral("numberDouble"), value); } } - bool publicConfig() const { - return p_publicConfig; + void resetNumberDouble() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("numberDouble")); + }); + } + } + Q_INVOKABLE bool numberDoubleIsDefaultValue() const + { + return !m_data->testPropertySet(9); + } + bool publicConfig() const + { + return m_data->p_publicConfig; } void setPublicConfig(const bool &value) { - auto oldValue = p_publicConfig; - p_publicConfig = value; - markPropertySet(10); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("publicConfig"), value); + auto oldValue = m_data->p_publicConfig; + m_data->p_publicConfig = value; + m_data->markPropertySet(10); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("publicConfig"), value); }); } - if (p_publicConfig != oldValue) { + if (m_data->p_publicConfig != oldValue) { Q_EMIT publicConfigChanged(); + Q_EMIT valueChanged(QStringLiteral("publicConfig"), value); + } + } + void resetPublicConfig() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("publicConfig")); + }); } } - QVariantMap struct() const { - return p_struct; + Q_INVOKABLE bool publicConfigIsDefaultValue() const + { + return !m_data->testPropertySet(10); + } + bool readonly() const + { + return m_data->p_readonly; + } + void setReadonly(const bool &value) { + auto oldValue = m_data->p_readonly; + m_data->p_readonly = value; + m_data->markPropertySet(11); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("readonly"), value); + }); + } + if (m_data->p_readonly != oldValue) { + Q_EMIT readonlyChanged(); + Q_EMIT valueChanged(QStringLiteral("readonly"), value); + } + } + void resetReadonly() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("readonly")); + }); + } + } + Q_INVOKABLE bool readonlyIsDefaultValue() const + { + return !m_data->testPropertySet(11); + } + bool readwrite() const + { + return m_data->p_readwrite; + } + void setReadwrite(const bool &value) { + auto oldValue = m_data->p_readwrite; + m_data->p_readwrite = value; + m_data->markPropertySet(12); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("readwrite"), value); + }); + } + if (m_data->p_readwrite != oldValue) { + Q_EMIT readwriteChanged(); + Q_EMIT valueChanged(QStringLiteral("readwrite"), value); + } + } + void resetReadwrite() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("readwrite")); + }); + } + } + Q_INVOKABLE bool readwriteIsDefaultValue() const + { + return !m_data->testPropertySet(12); + } + QVariantMap struct() const + { + return m_data->p_struct; } void setStruct(const QVariantMap &value) { - auto oldValue = p_struct; - p_struct = value; - markPropertySet(11); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("struct"), value); + auto oldValue = m_data->p_struct; + m_data->p_struct = value; + m_data->markPropertySet(13); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("struct"), value); }); } - if (p_struct != oldValue) { + if (m_data->p_struct != oldValue) { Q_EMIT structChanged(); + Q_EMIT valueChanged(QStringLiteral("struct"), value); + } + } + void resetStruct() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("struct")); + }); } } + Q_INVOKABLE bool structIsDefaultValue() const + { + return !m_data->testPropertySet(13); + } +protected: + bool event(QEvent *e) override { + if (e->type() == QEvent::ThreadChange) { + Q_ASSERT_X(false, "dconfig_dconf-example_meta", "Moving dconfig_dconf-example_meta to another thread is forbidden!"); + } + return QObject::event(e); + } + Q_SIGNALS: + void configInitializeFailed(); + void configInitializeSucceed(DTK_CORE_NAMESPACE::DConfig *config); + void valueChanged(const QString &key, const QVariant &value); void arrayChanged(); void array_mapChanged(); void array_map_structChanged(); @@ -328,227 +664,466 @@ class dconf-example_meta : public QObject { void numberChanged(); void numberDoubleChanged(); void publicConfigChanged(); + void readonlyChanged(); + void readwriteChanged(); void structChanged(); + private: - void initialize(DTK_CORE_NAMESPACE::DConfig *config) { - Q_ASSERT(!m_config.loadRelaxed()); - m_config.storeRelaxed(config); - if (testPropertySet(0)) { - config->setValue(QStringLiteral("array"), QVariant::fromValue(p_array)); - } else { - updateValue(QStringLiteral("array"), QVariant::fromValue(p_array)); - } - if (testPropertySet(1)) { - config->setValue(QStringLiteral("array_map"), QVariant::fromValue(p_array_map)); - } else { - updateValue(QStringLiteral("array_map"), QVariant::fromValue(p_array_map)); - } - if (testPropertySet(2)) { - config->setValue(QStringLiteral("array_map_struct"), QVariant::fromValue(p_array_map_struct)); - } else { - updateValue(QStringLiteral("array_map_struct"), QVariant::fromValue(p_array_map_struct)); - } - if (testPropertySet(3)) { - config->setValue(QStringLiteral("canExit"), QVariant::fromValue(p_canExit)); - } else { - updateValue(QStringLiteral("canExit"), QVariant::fromValue(p_canExit)); - } - if (testPropertySet(4)) { - config->setValue(QStringLiteral("key2"), QVariant::fromValue(p_key2)); - } else { - updateValue(QStringLiteral("key2"), QVariant::fromValue(p_key2)); - } - if (testPropertySet(5)) { - config->setValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); - } else { - updateValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); - } - if (testPropertySet(6)) { - config->setValue(QStringLiteral("map"), QVariant::fromValue(p_map)); - } else { - updateValue(QStringLiteral("map"), QVariant::fromValue(p_map)); - } - if (testPropertySet(7)) { - config->setValue(QStringLiteral("map_array"), QVariant::fromValue(p_map_array)); - } else { - updateValue(QStringLiteral("map_array"), QVariant::fromValue(p_map_array)); - } - if (testPropertySet(8)) { - config->setValue(QStringLiteral("number"), QVariant::fromValue(p_number)); - } else { - updateValue(QStringLiteral("number"), QVariant::fromValue(p_number)); - } - if (testPropertySet(9)) { - config->setValue(QStringLiteral("numberDouble"), QVariant::fromValue(p_numberDouble)); - } else { - updateValue(QStringLiteral("numberDouble"), QVariant::fromValue(p_numberDouble)); - } - if (testPropertySet(10)) { - config->setValue(QStringLiteral("publicConfig"), QVariant::fromValue(p_publicConfig)); - } else { - updateValue(QStringLiteral("publicConfig"), QVariant::fromValue(p_publicConfig)); - } - if (testPropertySet(11)) { - config->setValue(QStringLiteral("struct"), QVariant::fromValue(p_struct)); - } else { - updateValue(QStringLiteral("struct"), QVariant::fromValue(p_struct)); - } - - connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) { - updateValue(key); - }, Qt::DirectConnection); - } - 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("array")) { - auto newValue = qvariant_cast>(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_array != newValue) { - p_array = newValue; - Q_EMIT arrayChanged(); - } + // Prevent external moveToThread calls + using QObject::moveToThread; + class Data : public QObject { + public: + enum class Status { + Invalid = 0, + Initializing = 1, + Succeeded = 2, + Failed = 3, + Destroyed = 4 + }; + + explicit Data() + : QObject(nullptr) {} + + QAtomicPointer m_config = nullptr; + QAtomicInteger m_status = static_cast(Status::Invalid); + QPointer m_userConfig = nullptr; + QAtomicInteger m_propertySetStatus0 = 0; + + // Property storage + QList p_array { QList{QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0031")), QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0032"))} }; + QList p_array_map { QList{QVariant(QVariantMap{{QStringLiteral(u"\u006b\u0065\u0079\u0031"), QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0031"))}, {QStringLiteral(u"\u006b\u0065\u0079\u0032"), QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0032"))}})} }; + QList p_array_map_struct { QList{QVariant(QVariantMap{{QStringLiteral(u"\u006b\u0065\u0079\u0031"), QVariant(QVariantMap{{QStringLiteral(u"\u0066\u0069\u0065\u006c\u0064\u0031"), QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0031"))}})}, {QStringLiteral(u"\u006b\u0065\u0079\u0032"), QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0032"))}})} }; + bool p_canExit { true }; + // Default value: "125" + QString p_key2 { QStringLiteral(u"\u0031\u0032\u0035") }; + // Default value: "application" + QString p_key3 { QStringLiteral(u"\u0061\u0070\u0070\u006c\u0069\u0063\u0061\u0074\u0069\u006f\u006e") }; + QVariantMap p_map { QVariantMap{{QStringLiteral(u"\u006b\u0065\u0079\u0031"), QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0031"))}, {QStringLiteral(u"\u006b\u0065\u0079\u0032"), QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0032"))}} }; + QVariantMap p_map_array { QVariantMap{{QStringLiteral(u"\u006b\u0065\u0079\u0031"), QVariant(QList{QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0031"))})}, {QStringLiteral(u"\u006b\u0065\u0079\u0032"), QVariant(QList{QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0032"))})}} }; + qlonglong p_number { 1 }; + double p_numberDouble { 1 }; + bool p_publicConfig { true }; + bool p_readonly { true }; + bool p_readwrite { true }; + QVariantMap p_struct { QVariantMap{{QStringLiteral(u"\u006b\u0065\u0079\u0031"), QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0031"))}, {QStringLiteral(u"\u006b\u0065\u0079\u0032"), QVariant(QStringLiteral(u"\u0076\u0061\u006c\u0075\u0065\u0032"))}} }; + + inline void initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config) { + Q_ASSERT(!m_config.loadRelaxed()); + m_config.storeRelaxed(config); + // Connect signals early - use QPointer to protect Data lifetime + QPointer selfData(this); + QObject::connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, config, [selfData](const QString &key) { + if (selfData) selfData->updateValue(key); }); - return; - } - if (key == QStringLiteral("array_map")) { - auto newValue = qvariant_cast>(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_array_map != newValue) { - p_array_map = newValue; - Q_EMIT array_mapChanged(); + if (testPropertySet(0)) { + config->setValue(QStringLiteral("array"), QVariant::fromValue(p_array)); + } else { + updateValue(QStringLiteral("array"), QVariant::fromValue(p_array)); + } + if (testPropertySet(1)) { + config->setValue(QStringLiteral("array_map"), QVariant::fromValue(p_array_map)); + } else { + updateValue(QStringLiteral("array_map"), QVariant::fromValue(p_array_map)); + } + if (testPropertySet(2)) { + config->setValue(QStringLiteral("array_map_struct"), QVariant::fromValue(p_array_map_struct)); + } else { + updateValue(QStringLiteral("array_map_struct"), QVariant::fromValue(p_array_map_struct)); + } + if (testPropertySet(3)) { + config->setValue(QStringLiteral("canExit"), QVariant::fromValue(p_canExit)); + } else { + updateValue(QStringLiteral("canExit"), QVariant::fromValue(p_canExit)); + } + if (testPropertySet(4)) { + config->setValue(QStringLiteral("key2"), QVariant::fromValue(p_key2)); + } else { + updateValue(QStringLiteral("key2"), QVariant::fromValue(p_key2)); + } + if (testPropertySet(5)) { + config->setValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); + } else { + updateValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); + } + if (testPropertySet(6)) { + config->setValue(QStringLiteral("map"), QVariant::fromValue(p_map)); + } else { + updateValue(QStringLiteral("map"), QVariant::fromValue(p_map)); + } + if (testPropertySet(7)) { + config->setValue(QStringLiteral("map_array"), QVariant::fromValue(p_map_array)); + } else { + updateValue(QStringLiteral("map_array"), QVariant::fromValue(p_map_array)); + } + if (testPropertySet(8)) { + config->setValue(QStringLiteral("number"), QVariant::fromValue(p_number)); + } else { + updateValue(QStringLiteral("number"), QVariant::fromValue(p_number)); + } + if (testPropertySet(9)) { + config->setValue(QStringLiteral("numberDouble"), QVariant::fromValue(p_numberDouble)); + } else { + updateValue(QStringLiteral("numberDouble"), QVariant::fromValue(p_numberDouble)); + } + if (testPropertySet(10)) { + config->setValue(QStringLiteral("publicConfig"), QVariant::fromValue(p_publicConfig)); + } else { + updateValue(QStringLiteral("publicConfig"), QVariant::fromValue(p_publicConfig)); + } + if (testPropertySet(11)) { + config->setValue(QStringLiteral("readonly"), QVariant::fromValue(p_readonly)); + } else { + updateValue(QStringLiteral("readonly"), QVariant::fromValue(p_readonly)); + } + if (testPropertySet(12)) { + config->setValue(QStringLiteral("readwrite"), QVariant::fromValue(p_readwrite)); + } else { + updateValue(QStringLiteral("readwrite"), QVariant::fromValue(p_readwrite)); + } + if (testPropertySet(13)) { + config->setValue(QStringLiteral("struct"), QVariant::fromValue(p_struct)); + } else { + updateValue(QStringLiteral("struct"), QVariant::fromValue(p_struct)); + } + } + + inline void updateValue(const QString &key, const QVariant &fallback = QVariant()) { + auto config = m_config.loadRelaxed(); + if (!config) return; + const QVariant &v = config->value(key, fallback); + if (key == QStringLiteral("array")) { + markPropertySet(0, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("array_map")) { + markPropertySet(1, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("array_map_struct")) { + markPropertySet(2, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("canExit")) { + markPropertySet(3, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("key2")) { + markPropertySet(4, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("key3")) { + markPropertySet(5, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("map")) { + markPropertySet(6, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("map_array")) { + markPropertySet(7, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("number")) { + markPropertySet(8, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("numberDouble")) { + markPropertySet(9, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("publicConfig")) { + markPropertySet(10, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("readonly")) { + markPropertySet(11, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("readwrite")) { + markPropertySet(12, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("struct")) { + markPropertySet(13, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + } + + inline void updateProperty(const QString &key, const QVariant &v) { + if (key == QStringLiteral("array")) { + QList nv = qvariant_cast>(v); + if (p_array != nv) { + p_array = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->arrayChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("array_map_struct")) { - auto newValue = qvariant_cast>(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_array_map_struct != newValue) { - p_array_map_struct = newValue; - Q_EMIT array_map_structChanged(); + return; + } + if (key == QStringLiteral("array_map")) { + QList nv = qvariant_cast>(v); + if (p_array_map != nv) { + p_array_map = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->array_mapChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("canExit")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_canExit != newValue) { - p_canExit = newValue; - Q_EMIT canExitChanged(); + return; + } + if (key == QStringLiteral("array_map_struct")) { + QList nv = qvariant_cast>(v); + if (p_array_map_struct != nv) { + p_array_map_struct = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->array_map_structChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("key2")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_key2 != newValue) { - p_key2 = newValue; - Q_EMIT key2Changed(); + return; + } + if (key == QStringLiteral("canExit")) { + bool nv = qvariant_cast(v); + if (p_canExit != nv) { + p_canExit = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->canExitChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("key3")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_key3 != newValue) { - p_key3 = newValue; - Q_EMIT key3Changed(); + return; + } + if (key == QStringLiteral("key2")) { + QString nv = qvariant_cast(v); + if (p_key2 != nv) { + p_key2 = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->key2Changed(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("map")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_map != newValue) { - p_map = newValue; - Q_EMIT mapChanged(); + return; + } + if (key == QStringLiteral("key3")) { + QString nv = qvariant_cast(v); + if (p_key3 != nv) { + p_key3 = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->key3Changed(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("map_array")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_map_array != newValue) { - p_map_array = newValue; - Q_EMIT map_arrayChanged(); + return; + } + if (key == QStringLiteral("map")) { + QVariantMap nv = qvariant_cast(v); + if (p_map != nv) { + p_map = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->mapChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("number")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_number != newValue) { - p_number = newValue; - Q_EMIT numberChanged(); + return; + } + if (key == QStringLiteral("map_array")) { + QVariantMap nv = qvariant_cast(v); + if (p_map_array != nv) { + p_map_array = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->map_arrayChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("numberDouble")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_numberDouble != newValue) { - p_numberDouble = newValue; - Q_EMIT numberDoubleChanged(); + return; + } + if (key == QStringLiteral("number")) { + qlonglong nv = qvariant_cast(v); + if (p_number != nv) { + p_number = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->numberChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("publicConfig")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_publicConfig != newValue) { - p_publicConfig = newValue; - Q_EMIT publicConfigChanged(); + return; + } + if (key == QStringLiteral("numberDouble")) { + double nv = qvariant_cast(v); + if (p_numberDouble != nv) { + p_numberDouble = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->numberDoubleChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("struct")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_struct != newValue) { - p_struct = newValue; - Q_EMIT structChanged(); + return; + } + if (key == QStringLiteral("publicConfig")) { + bool nv = qvariant_cast(v); + if (p_publicConfig != nv) { + p_publicConfig = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->publicConfigChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - } - inline void markPropertySet(const int index) { - if (index < 32) { - m_propertySetStatus0.fetchAndOrOrdered(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 m_config = nullptr; - QList p_array { QList{QVariant(QStringLiteral("value1")), QVariant(QStringLiteral("value2"))} }; - QList p_array_map { QList{QVariant(QVariantMap{{QStringLiteral("key1"), QVariant(QStringLiteral("value1"))}, {QStringLiteral("key2"), QVariant(QStringLiteral("value2"))}})} }; - QList p_array_map_struct { QList{QVariant(QVariantMap{{QStringLiteral("key1"), QVariant(QVariantMap{{QStringLiteral("field1"), QVariant(QStringLiteral("value1"))}})}, {QStringLiteral("key2"), QVariant(QStringLiteral("value2"))}})} }; - bool p_canExit { true }; - QString p_key2 { QStringLiteral("125") }; - QString p_key3 { QStringLiteral("application") }; - QVariantMap p_map { QVariantMap{{QStringLiteral("key1"), QVariant(QStringLiteral("value1"))}, {QStringLiteral("key2"), QVariant(QStringLiteral("value2"))}} }; - QVariantMap p_map_array { QVariantMap{{QStringLiteral("key1"), QVariant(QList{QVariant(QStringLiteral("value1"))})}, {QStringLiteral("key2"), QVariant(QList{QVariant(QStringLiteral("value2"))})}} }; - double p_number { 1 }; - double p_numberDouble { 1 }; - bool p_publicConfig { true }; - QVariantMap p_struct { QVariantMap{{QStringLiteral("key1"), QVariant(QStringLiteral("value1"))}, {QStringLiteral("key2"), QVariant(QStringLiteral("value2"))}} }; - QAtomicInteger m_propertySetStatus0 = 0; + return; + } + if (key == QStringLiteral("readonly")) { + bool nv = qvariant_cast(v); + if (p_readonly != nv) { + p_readonly = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->readonlyChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } + } + return; + } + if (key == QStringLiteral("readwrite")) { + bool nv = qvariant_cast(v); + if (p_readwrite != nv) { + p_readwrite = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->readwriteChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } + } + return; + } + if (key == QStringLiteral("struct")) { + QVariantMap nv = qvariant_cast(v); + if (p_struct != nv) { + p_struct = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->structChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } + } + 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(); + } + }; + + Data *m_data; }; -#endif // DCONF-EXAMPLE_META_H +#endif // DCONFIG_DCONF-EXAMPLE_META_H diff --git a/toolGenerate/dconfig2cpp/dconf-example_other_app_configure_meta.hpp b/toolGenerate/dconfig2cpp/dconf-example_other_app_configure_meta.hpp index 1f9a54eb..afe0ce52 100644 --- a/toolGenerate/dconfig2cpp/dconf-example_other_app_configure_meta.hpp +++ b/toolGenerate/dconfig2cpp/dconf-example_other_app_configure_meta.hpp @@ -1,214 +1,385 @@ /** * This file is generated by dconfig2cpp. - * Command line arguments: ./dconfig2cpp -p ./dtkcore/toolGenerate/dconfig2cpp ./dtkcore/tests/data/dconf-example_other_app_configure.meta.json - * Generation time: 2025-01-14T10:54:59 + * Command line arguments: ./build/tools/dconfig2cpp/dconfig2cpp ./tests/data/dconf-example_other_app_configure.meta.json -o ./toolGenerate/dconfig2cpp/dconf-example_other_app_configure_meta.hpp + * Generation time: 2026-01-16T21:21:45 * 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 DCONF-EXAMPLE_OTHER_APP_CONFIGURE_META_H -#define DCONF-EXAMPLE_OTHER_APP_CONFIGURE_META_H +#ifndef DCONFIG_DCONF-EXAMPLE_OTHER_APP_CONFIGURE_META_H +#define DCONFIG_DCONF-EXAMPLE_OTHER_APP_CONFIGURE_META_H #include #include +#include #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#include +#endif +#include +#include #include -class dconf-example_other_app_configure_meta : public QObject { +class dconfig_dconf-example_other_app_configure_meta : public QObject { Q_OBJECT - Q_PROPERTY(QString appPrivate READ appPrivate WRITE setAppPrivate NOTIFY appPrivateChanged) - Q_PROPERTY(QString appPublic READ appPublic WRITE setAppPublic NOTIFY appPublicChanged) + Q_PROPERTY(QString appPrivate READ appPrivate WRITE setAppPrivate NOTIFY appPrivateChanged RESET resetAppPrivate) + Q_PROPERTY(QString appPublic READ appPublic WRITE setAppPublic NOTIFY appPublicChanged RESET resetAppPublic) + Q_CLASSINFO("DConfigKeyList", "appPrivate;appPublic") + Q_CLASSINFO("DConfigFileName", "dconf-example_other_app_configure.meta") + Q_CLASSINFO("DConfigFileVersion", "1.0") + public: - explicit dconf-example_other_app_configure_meta(QThread *thread, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { + explicit dconfig_dconf-example_other_app_configure_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, + const QString &name, const QString &appId, const QString &subpath, + bool isGeneric, QObject *parent) + : QObject(parent), m_data(new Data) { + m_data->m_userConfig = this; + m_data->moveToThread(thread); if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); + qWarning() << QLatin1String("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); + + QPointer safeData(m_data); + + QMetaObject::invokeMethod(worker, [safeData, backend, name, appId, subpath, isGeneric, worker]() mutable { + delete worker; + worker = nullptr; + + if (!safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Invalid), + static_cast(Data::Status::Initializing))) { + // CAS failed, state already changed - userConfig destructor will handle cleanup + // Do not attempt to delete here as it would race with destructor return; } - config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); - }); - } - explicit dconf-example_other_app_configure_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { - if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); - } - Q_ASSERT(QThread::currentThread() != thread); - auto worker = new QObject(); - worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, appId, name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); - return; + DTK_CORE_NAMESPACE::DConfig *config = nullptr; + if (isGeneric) { + if (backend) { + config = DTK_CORE_NAMESPACE::DConfig::createGeneric(backend, name, subpath, nullptr); + } else { + config = DTK_CORE_NAMESPACE::DConfig::createGeneric(name, subpath, nullptr); + } + } else { + if (backend) { + if (appId.isNull()) { + config = DTK_CORE_NAMESPACE::DConfig::create(backend, DTK_CORE_NAMESPACE::DSGApplication::id(), + 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(DTK_CORE_NAMESPACE::DSGApplication::id(), + name, subpath, nullptr); + } else { + config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); + } + } } - config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); - }); - } - explicit dconf-example_other_app_configure_meta(QThread *thread, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { - if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); - } - Q_ASSERT(QThread::currentThread() != thread); - auto worker = new QObject(); - worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); + if (!config || !config->isValid()) { + qWarning() << QLatin1String("Failed to create DConfig instance."); + + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Failed))) { + if (safeData->m_userConfig) { + QPointer selfData = safeData; + QMetaObject::invokeMethod(selfData, [selfData]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->configInitializeFailed(); + } + }, Qt::QueuedConnection); + } + } + + if (config) + delete config; + return; } config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); - }); - } - explicit dconf-example_other_app_configure_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { + // Initialize through Data class + safeData->initializeInConfigThread(config); - if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); - } - Q_ASSERT(QThread::currentThread() != thread); - auto worker = new QObject(); - worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); - return; + // Try to transition from Initializing to Succeeded + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Succeeded))) { + // CAS succeeded, connect destroyed signal + QPointer selfData = safeData; + QObject::connect(config, &QObject::destroyed, config, [selfData]() { + if (selfData) { + selfData->deleteLater(); } + }); + } else { + // CAS failed - state changed (e.g., set to Destroyed) + // We must clean up the config we just created + config->deleteLater(); + safeData->deleteLater(); } - config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); }); } - ~dconf-example_other_app_configure_meta() { - if (m_config.loadRelaxed()) { - m_config.loadRelaxed()->deleteLater(); + static dconfig_dconf-example_other_app_configure_meta* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_other_app_configure_meta(thread, nullptr, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0065\u0078\u0061\u006d\u0070\u006c\u0065\u005f\u006f\u0074\u0068\u0065\u0072\u005f\u0061\u0070\u0070\u005f\u0063\u006f\u006e\u0066\u0069\u0067\u0075\u0072\u0065\u002e\u006d\u0065\u0074\u0061"), appId, subpath, false, parent); } + static dconfig_dconf-example_other_app_configure_meta* 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_dconf-example_other_app_configure_meta(thread, backend, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0065\u0078\u0061\u006d\u0070\u006c\u0065\u005f\u006f\u0074\u0068\u0065\u0072\u005f\u0061\u0070\u0070\u005f\u0063\u006f\u006e\u0066\u0069\u0067\u0075\u0072\u0065\u002e\u006d\u0065\u0074\u0061"), appId, subpath, false, parent); } + static dconfig_dconf-example_other_app_configure_meta* createByName(const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_other_app_configure_meta(thread, nullptr, name, appId, subpath, false, parent); } + static dconfig_dconf-example_other_app_configure_meta* 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_dconf-example_other_app_configure_meta(thread, backend, name, appId, subpath, false, parent); } + static dconfig_dconf-example_other_app_configure_meta* createGeneric(const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_other_app_configure_meta(thread, nullptr, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0065\u0078\u0061\u006d\u0070\u006c\u0065\u005f\u006f\u0074\u0068\u0065\u0072\u005f\u0061\u0070\u0070\u005f\u0063\u006f\u006e\u0066\u0069\u0067\u0075\u0072\u0065\u002e\u006d\u0065\u0074\u0061"), {}, subpath, true, parent); } + static dconfig_dconf-example_other_app_configure_meta* create(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_other_app_configure_meta(thread, backend, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0065\u0078\u0061\u006d\u0070\u006c\u0065\u005f\u006f\u0074\u0068\u0065\u0072\u005f\u0061\u0070\u0070\u005f\u0063\u006f\u006e\u0066\u0069\u0067\u0075\u0072\u0065\u002e\u006d\u0065\u0074\u0061"), {}, subpath, true, parent); } + static dconfig_dconf-example_other_app_configure_meta* createGenericByName(const QString &name, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_other_app_configure_meta(thread, nullptr, name, {}, subpath, true, parent); } + static dconfig_dconf-example_other_app_configure_meta* createGenericByName(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-example_other_app_configure_meta(thread, backend, name, {}, subpath, true, parent); } + ~dconfig_dconf-example_other_app_configure_meta() { + int oldStatus = m_data->m_status.fetchAndStoreOrdered(static_cast(Data::Status::Destroyed)); + + if (oldStatus == static_cast(Data::Status::Succeeded)) { + // When Succeeded, release config object only + auto config = m_data->m_config.loadRelaxed(); + Q_ASSERT(config); + config->deleteLater(); + // m_data will be deleted by config's destroyed signal + } else if (oldStatus == static_cast(Data::Status::Failed) || + oldStatus == static_cast(Data::Status::Invalid)) { + // When Failed or Invalid, directly clean up Data object + m_data->deleteLater(); } } - QString appPrivate() const { - return p_appPrivate; + Q_INVOKABLE DTK_CORE_NAMESPACE::DConfig *config() const { + return m_data->m_config.loadRelaxed(); + } + Q_INVOKABLE bool isInitializeSucceed() const { + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Succeeded); + } + Q_INVOKABLE bool isInitializeFailed() const { + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Failed); + } + Q_INVOKABLE bool isInitializing() const { + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Initializing); + } + + Q_INVOKABLE QStringList keyList() const { + return { + QStringLiteral("appPrivate"), + QStringLiteral("appPublic") + }; + } + + Q_INVOKABLE bool isDefaultValue(const QString &key) const { + if (key == QStringLiteral("appPrivate")) + return appPrivateIsDefaultValue(); + if (key == QStringLiteral("appPublic")) + return appPublicIsDefaultValue(); + return false; + } + + QString appPrivate() const + { + return m_data->p_appPrivate; } void setAppPrivate(const QString &value) { - auto oldValue = p_appPrivate; - p_appPrivate = value; - markPropertySet(0); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("appPrivate"), value); + auto oldValue = m_data->p_appPrivate; + m_data->p_appPrivate = value; + m_data->markPropertySet(0); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("appPrivate"), value); }); } - if (p_appPrivate != oldValue) { + if (m_data->p_appPrivate != oldValue) { Q_EMIT appPrivateChanged(); + Q_EMIT valueChanged(QStringLiteral("appPrivate"), value); + } + } + void resetAppPrivate() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("appPrivate")); + }); } } - QString appPublic() const { - return p_appPublic; + Q_INVOKABLE bool appPrivateIsDefaultValue() const + { + return !m_data->testPropertySet(0); + } + QString appPublic() const + { + return m_data->p_appPublic; } void setAppPublic(const QString &value) { - auto oldValue = p_appPublic; - p_appPublic = value; - markPropertySet(1); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("appPublic"), value); + auto oldValue = m_data->p_appPublic; + m_data->p_appPublic = value; + m_data->markPropertySet(1); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("appPublic"), value); }); } - if (p_appPublic != oldValue) { + if (m_data->p_appPublic != oldValue) { Q_EMIT appPublicChanged(); + Q_EMIT valueChanged(QStringLiteral("appPublic"), value); + } + } + void resetAppPublic() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("appPublic")); + }); + } + } + Q_INVOKABLE bool appPublicIsDefaultValue() const + { + return !m_data->testPropertySet(1); + } +protected: + bool event(QEvent *e) override { + if (e->type() == QEvent::ThreadChange) { + Q_ASSERT_X(false, "dconfig_dconf-example_other_app_configure_meta", "Moving dconfig_dconf-example_other_app_configure_meta to another thread is forbidden!"); } + return QObject::event(e); } + Q_SIGNALS: + void configInitializeFailed(); + void configInitializeSucceed(DTK_CORE_NAMESPACE::DConfig *config); + void valueChanged(const QString &key, const QVariant &value); void appPrivateChanged(); void appPublicChanged(); + private: - void initialize(DTK_CORE_NAMESPACE::DConfig *config) { - Q_ASSERT(!m_config.loadRelaxed()); - m_config.storeRelaxed(config); - if (testPropertySet(0)) { - config->setValue(QStringLiteral("appPrivate"), QVariant::fromValue(p_appPrivate)); - } else { - updateValue(QStringLiteral("appPrivate"), QVariant::fromValue(p_appPrivate)); + // Prevent external moveToThread calls + using QObject::moveToThread; + class Data : public QObject { + public: + enum class Status { + Invalid = 0, + Initializing = 1, + Succeeded = 2, + Failed = 3, + Destroyed = 4 + }; + + explicit Data() + : QObject(nullptr) {} + + QAtomicPointer m_config = nullptr; + QAtomicInteger m_status = static_cast(Status::Invalid); + QPointer m_userConfig = nullptr; + QAtomicInteger m_propertySetStatus0 = 0; + + // Property storage + // Default value: "appPrivate" + QString p_appPrivate { QStringLiteral(u"\u0061\u0070\u0070\u0050\u0072\u0069\u0076\u0061\u0074\u0065") }; + // Default value: "publicValue" + QString p_appPublic { QStringLiteral(u"\u0070\u0075\u0062\u006c\u0069\u0063\u0056\u0061\u006c\u0075\u0065") }; + + inline void initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config) { + Q_ASSERT(!m_config.loadRelaxed()); + m_config.storeRelaxed(config); + // Connect signals early - use QPointer to protect Data lifetime + QPointer selfData(this); + QObject::connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, config, [selfData](const QString &key) { + if (selfData) selfData->updateValue(key); + }); + if (testPropertySet(0)) { + config->setValue(QStringLiteral("appPrivate"), QVariant::fromValue(p_appPrivate)); + } else { + updateValue(QStringLiteral("appPrivate"), QVariant::fromValue(p_appPrivate)); + } + if (testPropertySet(1)) { + config->setValue(QStringLiteral("appPublic"), QVariant::fromValue(p_appPublic)); + } else { + updateValue(QStringLiteral("appPublic"), QVariant::fromValue(p_appPublic)); + } } - if (testPropertySet(1)) { - config->setValue(QStringLiteral("appPublic"), QVariant::fromValue(p_appPublic)); - } else { - updateValue(QStringLiteral("appPublic"), QVariant::fromValue(p_appPublic)); + + inline void updateValue(const QString &key, const QVariant &fallback = QVariant()) { + auto config = m_config.loadRelaxed(); + if (!config) return; + const QVariant &v = config->value(key, fallback); + if (key == QStringLiteral("appPrivate")) { + markPropertySet(0, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + if (key == QStringLiteral("appPublic")) { + markPropertySet(1, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } } - connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) { - updateValue(key); - }, Qt::DirectConnection); - } - 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("appPrivate")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_appPrivate != newValue) { - p_appPrivate = newValue; - Q_EMIT appPrivateChanged(); + inline void updateProperty(const QString &key, const QVariant &v) { + if (key == QStringLiteral("appPrivate")) { + QString nv = qvariant_cast(v); + if (p_appPrivate != nv) { + p_appPrivate = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->appPrivateChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; - } - if (key == QStringLiteral("appPublic")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_appPublic != newValue) { - p_appPublic = newValue; - Q_EMIT appPublicChanged(); + return; + } + if (key == QStringLiteral("appPublic")) { + QString nv = qvariant_cast(v); + if (p_appPublic != nv) { + p_appPublic = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->appPublicChanged(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; + return; + } } - } - inline void markPropertySet(const int index) { - if (index < 32) { - m_propertySetStatus0.fetchAndOrOrdered(1 << (index - 0)); - 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(); } - Q_UNREACHABLE(); - } - inline bool testPropertySet(const int index) const { - if (index < 32) { - return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0))); + + inline bool testPropertySet(const int index) const { + if (index < 32) { + return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0))); + } + Q_UNREACHABLE(); } - Q_UNREACHABLE(); - } - QAtomicPointer m_config = nullptr; - QString p_appPrivate { QStringLiteral("appPrivate") }; - QString p_appPublic { QStringLiteral("publicValue") }; - QAtomicInteger m_propertySetStatus0 = 0; + }; + + Data *m_data; }; -#endif // DCONF-EXAMPLE_OTHER_APP_CONFIGURE_META_H +#endif // DCONFIG_DCONF-EXAMPLE_OTHER_APP_CONFIGURE_META_H diff --git a/toolGenerate/dconfig2cpp/dconf-global_meta.hpp b/toolGenerate/dconfig2cpp/dconf-global_meta.hpp index 50071ad4..acf3d566 100644 --- a/toolGenerate/dconfig2cpp/dconf-global_meta.hpp +++ b/toolGenerate/dconfig2cpp/dconf-global_meta.hpp @@ -1,180 +1,322 @@ /** * This file is generated by dconfig2cpp. - * Command line arguments: ./dconfig2cpp -p ./dtkcore/toolGenerate/dconfig2cpp ./dtkcore/tests/data/dconf-global.meta.json - * Generation time: 2025-01-14T10:54:59 + * Command line arguments: ./build/tools/dconfig2cpp/dconfig2cpp ./tests/data/dconf-global.meta.json -o ./toolGenerate/dconfig2cpp/dconf-global_meta.hpp + * Generation time: 2026-01-16T21:21:45 * 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 DCONF-GLOBAL_META_H -#define DCONF-GLOBAL_META_H +#ifndef DCONFIG_DCONF-GLOBAL_META_H +#define DCONFIG_DCONF-GLOBAL_META_H #include #include +#include #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#include +#endif +#include +#include #include -class dconf-global_meta : public QObject { +class dconfig_dconf-global_meta : public QObject { Q_OBJECT - Q_PROPERTY(QString key3 READ key3 WRITE setKey3 NOTIFY key3Changed) + Q_PROPERTY(QString key3 READ key3 WRITE setKey3 NOTIFY key3Changed RESET resetKey3) + Q_CLASSINFO("DConfigKeyList", "key3") + Q_CLASSINFO("DConfigFileName", "dconf-global.meta") + Q_CLASSINFO("DConfigFileVersion", "1.0") + public: - explicit dconf-global_meta(QThread *thread, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { + explicit dconfig_dconf-global_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, + const QString &name, const QString &appId, const QString &subpath, + bool isGeneric, QObject *parent) + : QObject(parent), m_data(new Data) { + m_data->m_userConfig = this; + m_data->moveToThread(thread); if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); + qWarning() << QLatin1String("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); + + QPointer safeData(m_data); + + QMetaObject::invokeMethod(worker, [safeData, backend, name, appId, subpath, isGeneric, worker]() mutable { + delete worker; + worker = nullptr; + + if (!safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Invalid), + static_cast(Data::Status::Initializing))) { + // CAS failed, state already changed - userConfig destructor will handle cleanup + // Do not attempt to delete here as it would race with destructor return; } - config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); - }); - } - explicit dconf-global_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { - if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); - } - Q_ASSERT(QThread::currentThread() != thread); - auto worker = new QObject(); - worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, appId, name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); - return; + DTK_CORE_NAMESPACE::DConfig *config = nullptr; + if (isGeneric) { + if (backend) { + config = DTK_CORE_NAMESPACE::DConfig::createGeneric(backend, name, subpath, nullptr); + } else { + config = DTK_CORE_NAMESPACE::DConfig::createGeneric(name, subpath, nullptr); + } + } else { + if (backend) { + if (appId.isNull()) { + config = DTK_CORE_NAMESPACE::DConfig::create(backend, DTK_CORE_NAMESPACE::DSGApplication::id(), + 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(DTK_CORE_NAMESPACE::DSGApplication::id(), + name, subpath, nullptr); + } else { + config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); + } + } } - config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); - }); - } - explicit dconf-global_meta(QThread *thread, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { - if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); - } - Q_ASSERT(QThread::currentThread() != thread); - auto worker = new QObject(); - worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); + if (!config || !config->isValid()) { + qWarning() << QLatin1String("Failed to create DConfig instance."); + + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Failed))) { + if (safeData->m_userConfig) { + QPointer selfData = safeData; + QMetaObject::invokeMethod(selfData, [selfData]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->configInitializeFailed(); + } + }, Qt::QueuedConnection); + } + } + + if (config) + delete config; + return; } config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); - }); - } - explicit dconf-global_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent = nullptr) - : QObject(parent) { + // Initialize through Data class + safeData->initializeInConfigThread(config); - if (!thread->isRunning()) { - qWarning() << QStringLiteral("Warning: The provided thread is not running."); - } - Q_ASSERT(QThread::currentThread() != thread); - auto worker = new QObject(); - worker->moveToThread(thread); - QMetaObject::invokeMethod(worker, [=]() { - auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, name, subpath, nullptr); - if (!config) { - qWarning() << QStringLiteral("Failed to create DConfig instance."); - worker->deleteLater(); - return; + // Try to transition from Initializing to Succeeded + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Succeeded))) { + // CAS succeeded, connect destroyed signal + QPointer selfData = safeData; + QObject::connect(config, &QObject::destroyed, config, [selfData]() { + if (selfData) { + selfData->deleteLater(); } + }); + } else { + // CAS failed - state changed (e.g., set to Destroyed) + // We must clean up the config we just created + config->deleteLater(); + safeData->deleteLater(); } - config->moveToThread(QThread::currentThread()); - initialize(config); - worker->deleteLater(); }); } - ~dconf-global_meta() { - if (m_config.loadRelaxed()) { - m_config.loadRelaxed()->deleteLater(); + static dconfig_dconf-global_meta* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-global_meta(thread, nullptr, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0067\u006c\u006f\u0062\u0061\u006c\u002e\u006d\u0065\u0074\u0061"), appId, subpath, false, parent); } + static dconfig_dconf-global_meta* 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_dconf-global_meta(thread, backend, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0067\u006c\u006f\u0062\u0061\u006c\u002e\u006d\u0065\u0074\u0061"), appId, subpath, false, parent); } + static dconfig_dconf-global_meta* createByName(const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-global_meta(thread, nullptr, name, appId, subpath, false, parent); } + static dconfig_dconf-global_meta* 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_dconf-global_meta(thread, backend, name, appId, subpath, false, parent); } + static dconfig_dconf-global_meta* createGeneric(const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-global_meta(thread, nullptr, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0067\u006c\u006f\u0062\u0061\u006c\u002e\u006d\u0065\u0074\u0061"), {}, subpath, true, parent); } + static dconfig_dconf-global_meta* create(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-global_meta(thread, backend, QStringLiteral(u"\u0064\u0063\u006f\u006e\u0066\u002d\u0067\u006c\u006f\u0062\u0061\u006c\u002e\u006d\u0065\u0074\u0061"), {}, subpath, true, parent); } + static dconfig_dconf-global_meta* createGenericByName(const QString &name, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-global_meta(thread, nullptr, name, {}, subpath, true, parent); } + static dconfig_dconf-global_meta* createGenericByName(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) + { return new dconfig_dconf-global_meta(thread, backend, name, {}, subpath, true, parent); } + ~dconfig_dconf-global_meta() { + int oldStatus = m_data->m_status.fetchAndStoreOrdered(static_cast(Data::Status::Destroyed)); + + if (oldStatus == static_cast(Data::Status::Succeeded)) { + // When Succeeded, release config object only + auto config = m_data->m_config.loadRelaxed(); + Q_ASSERT(config); + config->deleteLater(); + // m_data will be deleted by config's destroyed signal + } else if (oldStatus == static_cast(Data::Status::Failed) || + oldStatus == static_cast(Data::Status::Invalid)) { + // When Failed or Invalid, directly clean up Data object + m_data->deleteLater(); } } - QString key3() const { - return p_key3; + Q_INVOKABLE DTK_CORE_NAMESPACE::DConfig *config() const { + return m_data->m_config.loadRelaxed(); + } + Q_INVOKABLE bool isInitializeSucceed() const { + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Succeeded); + } + Q_INVOKABLE bool isInitializeFailed() const { + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Failed); + } + Q_INVOKABLE bool isInitializing() const { + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Initializing); + } + + Q_INVOKABLE QStringList keyList() const { + return { + QStringLiteral("key3") + }; + } + + Q_INVOKABLE bool isDefaultValue(const QString &key) const { + if (key == QStringLiteral("key3")) + return key3IsDefaultValue(); + return false; + } + + QString key3() const + { + return m_data->p_key3; } void setKey3(const QString &value) { - auto oldValue = p_key3; - p_key3 = value; - markPropertySet(0); - if (auto config = m_config.loadRelaxed()) { - QMetaObject::invokeMethod(config, [this, value]() { - m_config.loadRelaxed()->setValue(QStringLiteral("key3"), value); + auto oldValue = m_data->p_key3; + m_data->p_key3 = value; + m_data->markPropertySet(0); + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config, value]() { + config->setValue(QStringLiteral("key3"), value); }); } - if (p_key3 != oldValue) { + if (m_data->p_key3 != oldValue) { Q_EMIT key3Changed(); + Q_EMIT valueChanged(QStringLiteral("key3"), value); + } + } + void resetKey3() { + if (auto config = m_data->m_config.loadRelaxed()) { + QMetaObject::invokeMethod(config, [config]() { + config->reset(QStringLiteral("key3")); + }); } } + Q_INVOKABLE bool key3IsDefaultValue() const + { + return !m_data->testPropertySet(0); + } +protected: + bool event(QEvent *e) override { + if (e->type() == QEvent::ThreadChange) { + Q_ASSERT_X(false, "dconfig_dconf-global_meta", "Moving dconfig_dconf-global_meta to another thread is forbidden!"); + } + return QObject::event(e); + } + Q_SIGNALS: + void configInitializeFailed(); + void configInitializeSucceed(DTK_CORE_NAMESPACE::DConfig *config); + void valueChanged(const QString &key, const QVariant &value); void key3Changed(); + private: - void initialize(DTK_CORE_NAMESPACE::DConfig *config) { - Q_ASSERT(!m_config.loadRelaxed()); - m_config.storeRelaxed(config); - if (testPropertySet(0)) { - config->setValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); - } else { - updateValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); + // Prevent external moveToThread calls + using QObject::moveToThread; + class Data : public QObject { + public: + enum class Status { + Invalid = 0, + Initializing = 1, + Succeeded = 2, + Failed = 3, + Destroyed = 4 + }; + + explicit Data() + : QObject(nullptr) {} + + QAtomicPointer m_config = nullptr; + QAtomicInteger m_status = static_cast(Status::Invalid); + QPointer m_userConfig = nullptr; + QAtomicInteger m_propertySetStatus0 = 0; + + // Property storage + // Default value: "global" + QString p_key3 { QStringLiteral(u"\u0067\u006c\u006f\u0062\u0061\u006c") }; + + inline void initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config) { + Q_ASSERT(!m_config.loadRelaxed()); + m_config.storeRelaxed(config); + // Connect signals early - use QPointer to protect Data lifetime + QPointer selfData(this); + QObject::connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, config, [selfData](const QString &key) { + if (selfData) selfData->updateValue(key); + }); + if (testPropertySet(0)) { + config->setValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); + } else { + updateValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); + } } - connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) { - updateValue(key); - }, Qt::DirectConnection); - } - 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("key3")) { - auto newValue = qvariant_cast(value); - QMetaObject::invokeMethod(this, [this, newValue]() { - if (p_key3 != newValue) { - p_key3 = newValue; - Q_EMIT key3Changed(); + inline void updateValue(const QString &key, const QVariant &fallback = QVariant()) { + auto config = m_config.loadRelaxed(); + if (!config) return; + const QVariant &v = config->value(key, fallback); + if (key == QStringLiteral("key3")) { + markPropertySet(0, !config->isDefaultValue(key)); + updateProperty(key, v); + return; + } + } + + inline void updateProperty(const QString &key, const QVariant &v) { + if (key == QStringLiteral("key3")) { + QString nv = qvariant_cast(v); + if (p_key3 != nv) { + p_key3 = nv; + if (m_userConfig) { + QPointer selfData(this); + // Emit signals on main thread (userConfig's thread) + QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->key3Changed(); + Q_EMIT selfData->m_userConfig->valueChanged(key, v); + } + }, Qt::QueuedConnection); + } } - }); - return; + return; + } } - } - inline void markPropertySet(const int index) { - if (index < 32) { - m_propertySetStatus0.fetchAndOrOrdered(1 << (index - 0)); - 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(); } - Q_UNREACHABLE(); - } - inline bool testPropertySet(const int index) const { - if (index < 32) { - return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0))); + + inline bool testPropertySet(const int index) const { + if (index < 32) { + return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0))); + } + Q_UNREACHABLE(); } - Q_UNREACHABLE(); - } - QAtomicPointer m_config = nullptr; - QString p_key3 { QStringLiteral("global") }; - QAtomicInteger m_propertySetStatus0 = 0; + }; + + Data *m_data; }; -#endif // DCONF-GLOBAL_META_H +#endif // DCONFIG_DCONF-GLOBAL_META_H diff --git a/tools/dconfig2cpp/main.cpp b/tools/dconfig2cpp/main.cpp index 85d92a60..a864fe44 100644 --- a/tools/dconfig2cpp/main.cpp +++ b/tools/dconfig2cpp/main.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -11,6 +11,7 @@ #include #include #include +#include static QString toUnicodeEscape(const QString& input) { QString result; @@ -168,7 +169,6 @@ int main(int argc, char *argv[]) { " * If you need to change the content, please modify the dconfig2cpp tool.\n" " */\n\n" ).arg(commandLineArgs, generationTime, version); - headerStream << headerComment; } @@ -186,11 +186,9 @@ int main(int argc, char *argv[]) { headerStream << "#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)\n" << "#include \n" << "#endif\n"; - + headerStream << "#include \n"; headerStream << "#include \n"; headerStream << "#include \n\n"; - headerStream << "class " << className << " : public QObject {\n"; - headerStream << " Q_OBJECT\n\n"; struct Property { QString typeName; @@ -215,6 +213,7 @@ int main(int argc, char *argv[]) { "isDefaultValue", "m_config", "m_status", + "m_data", }; for (int i = 0; i <= (contents.size()) / 32; ++i) { @@ -265,31 +264,53 @@ int main(int argc, char *argv[]) { 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 << "class " << className << " : public QObject {\n" + << " Q_OBJECT\n\n"; + + // Generate Q_PROPERTY declarations + for (const Property &property : properties) { + const QString readFunction = usedKeywords.contains(property.propertyName) ? + QLatin1String(" READ get") + property.capitalizedPropertyName : + QLatin1String(" READ ") + property.propertyName; + headerStream << " Q_PROPERTY(" << property.typeName << " " << property.propertyName << readFunction << " WRITE set" + << property.capitalizedPropertyName << " NOTIFY " << property.propertyName << "Changed" + << " RESET reset" << property.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" + 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, + << " explicit " << className << R"((QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId, const QString &subpath, bool isGeneric, QObject *parent) - : QObject(nullptr) { + : QObject(parent), m_data(new Data) { + m_data->m_userConfig = this; + m_data->moveToThread(thread); + if (!thread->isRunning()) { qWarning() << QLatin1String("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); - QPointer watcher(parent); - QMetaObject::invokeMethod(worker, [=, this]() { + + QPointer safeData(m_data); + + QMetaObject::invokeMethod(worker, [safeData, backend, name, appId, subpath, isGeneric, worker]() mutable { + delete worker; + worker = nullptr; + + if (!safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Invalid), + static_cast(Data::Status::Initializing))) { + // CAS failed, state already changed - userConfig destructor will handle cleanup + // Do not attempt to delete here as it would race with destructor + return; + } + DTK_CORE_NAMESPACE::DConfig *config = nullptr; if (isGeneric) { if (backend) { @@ -314,268 +335,341 @@ int main(int argc, char *argv[]) { } } } - if (!config) { + + if (!config || !config->isValid()) { qWarning() << QLatin1String("Failed to create DConfig instance."); - worker->deleteLater(); + + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Failed))) { + if (safeData->m_userConfig) { + QPointer selfData = safeData; + QMetaObject::invokeMethod(selfData, [selfData]() { + if (selfData && selfData->m_userConfig) { + Q_EMIT selfData->m_userConfig->configInitializeFailed(); + } + }, Qt::QueuedConnection); + } + } + + if (config) + delete config; + return; } config->moveToThread(QThread::currentThread()); - initializeInConfigThread(config); - if (watcher != parent) { - // delete this if watcher is changed to nullptr. - deleteLater(); - } else if (!this->parent() && parent) { - // !parent() means that parent is not changed. - this->setParent(watcher); + // Initialize through Data class + safeData->initializeInConfigThread(config); + + // Try to transition from Initializing to Succeeded + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Succeeded))) { + // CAS succeeded, connect destroyed signal + QPointer selfData = safeData; + QObject::connect(config, &QObject::destroyed, config, [selfData]() { + if (selfData) { + selfData->deleteLater(); } + }); + } else { + // CAS failed - state changed (e.g., set to Destroyed) + // We must clean up the config we just created + config->deleteLater(); + safeData->deleteLater(); } - 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, false, 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, false, 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, false, 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, false, parent); }\n"; - - if (parser.isSet(forceRequestThread)) - headerStream << " static " << className << "* createGeneric(QThread *thread, const QString &subpath = {}, QObject *parent = nullptr)\n"; - else - headerStream << " static " << className << "* createGeneric(const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; - headerStream << " { return new " << className << "(thread, nullptr, " << jsonFileString << ", {}, subpath, true, parent); }\n"; - if (parser.isSet(forceRequestThread)) - headerStream << " static " << className << "* create(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &subpath = {}, QObject *parent = nullptr)\n"; - else - headerStream << " static " << className << "* create(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; - headerStream << " { return new " << className << "(thread, backend, " << jsonFileString << ", {}, subpath, true, parent); }\n"; - if (parser.isSet(forceRequestThread)) - headerStream << " static " << className << "* createGenericByName(QThread *thread, const QString &name, const QString &subpath = {}, QObject *parent = nullptr)\n"; - else - headerStream << " static " << className << "* createGenericByName(const QString &name, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; - headerStream << " { return new " << className << "(thread, nullptr, name, {}, subpath, true, parent); }\n"; - if (parser.isSet(forceRequestThread)) - headerStream << " static " << className << "* createGenericByName(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath = {}, QObject *parent = nullptr)\n"; - else - headerStream << " static " << className << "* createGenericByName(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; - headerStream << " { return new " << className << "(thread, backend, name, {}, subpath, true, parent); }\n"; + + // Create factory methods + if (parser.isSet(forceRequestThread)) { + headerStream + << " static " << className + << "* create(QThread *thread, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr)\n"; + headerStream << " { return new " << className << "(thread, nullptr, " << jsonFileString + << ", appId, subpath, false, parent); }\n"; + headerStream << " static " << className + << "* create(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId = {}, const " + "QString &subpath = {}, QObject *parent = nullptr)\n"; + headerStream << " { return new " << className << "(thread, backend, " << jsonFileString + << ", appId, subpath, false, parent); }\n"; + headerStream << " static " << className + << "* createByName(QThread *thread, const QString &name, const QString &appId = {}, const QString &subpath " + "= {}, QObject *parent = nullptr)\n"; + headerStream << " { return new " << className << "(thread, nullptr, name, appId, subpath, false, parent); }\n"; + headerStream << " static " << className + << "* createByName(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const " + "QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr)\n"; + headerStream << " { return new " << className << "(thread, backend, name, appId, subpath, false, parent); }\n"; + headerStream << " static " << className + << "* createGeneric(QThread *thread, const QString &subpath = {}, QObject *parent = nullptr)\n"; + headerStream << " { return new " << className << "(thread, nullptr, " << jsonFileString + << ", {}, subpath, true, parent); }\n"; + headerStream << " static " << className + << "* create(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &subpath = {}, " + "QObject *parent = nullptr)\n"; + headerStream << " { return new " << className << "(thread, backend, " << jsonFileString + << ", {}, subpath, true, parent); }\n"; + headerStream << " static " << className + << "* createGenericByName(QThread *thread, const QString &name, const QString &subpath = {}, QObject " + "*parent = nullptr)\n"; + headerStream << " { return new " << className << "(thread, nullptr, name, {}, subpath, true, parent); }\n"; + headerStream << " static " << className + << "* createGenericByName(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString " + "&name, const QString &subpath = {}, QObject *parent = nullptr)\n"; + headerStream << " { return new " << className << "(thread, backend, name, {}, subpath, true, parent); }\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, false, parent); }\n"; + 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, false, parent); }\n"; + 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, false, parent); }\n"; + 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, false, parent); }\n"; + headerStream << " static " << className + << "* createGeneric(const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = " + "DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; + headerStream << " { return new " << className << "(thread, nullptr, " << jsonFileString + << ", {}, subpath, true, parent); }\n"; + headerStream << " static " << className + << "* create(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &subpath = {}, QObject *parent = " + "nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; + headerStream << " { return new " << className << "(thread, backend, " << jsonFileString + << ", {}, subpath, true, parent); }\n"; + headerStream << " static " << className + << "* createGenericByName(const QString &name, const QString &subpath = {}, QObject *parent = nullptr, " + "QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; + headerStream << " { return new " << className << "(thread, nullptr, name, {}, subpath, true, parent); }\n"; + headerStream + << " static " << className + << "* createGenericByName(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath = " + "{}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; + headerStream << " { return new " << className << "(thread, backend, name, {}, subpath, true, parent); }\n"; + } // Destructor headerStream << " ~" << className << R"(() { - if (m_config.loadRelaxed()) { - m_config.loadRelaxed()->deleteLater(); - m_config.storeRelaxed(nullptr); + int oldStatus = m_data->m_status.fetchAndStoreOrdered(static_cast(Data::Status::Destroyed)); + + if (oldStatus == static_cast(Data::Status::Succeeded)) { + // When Succeeded, release config object only + auto config = m_data->m_config.loadRelaxed(); + Q_ASSERT(config); + config->deleteLater(); + // m_data will be deleted by config's destroyed signal + } else if (oldStatus == static_cast(Data::Status::Failed) || + oldStatus == static_cast(Data::Status::Invalid)) { + // When Failed or Invalid, directly clean up Data object + m_data->deleteLater(); } } Q_INVOKABLE DTK_CORE_NAMESPACE::DConfig *config() const { - return m_config.loadRelaxed(); + return m_data->m_config.loadRelaxed(); } - Q_INVOKABLE bool isInitializeSucceed() const { - return m_status.loadRelaxed() == static_cast(Status::Succeed); + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Succeeded); } - Q_INVOKABLE bool isInitializeFailed() const { - return m_status.loadRelaxed() == static_cast(Status::Failed); + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Failed); } - Q_INVOKABLE bool isInitializing() const { - return m_status.loadRelaxed() == static_cast(Status::Invalid); + return m_data->m_status.loadRelaxed() == static_cast(Data::Status::Initializing); } -)"; - - headerStream << " Q_INVOKABLE QStringList keyList() const {\n" - << " return { " << propertyNameStrings.join(",\n ") << "};\n" - << " }\n\n"; + Q_INVOKABLE QStringList keyList() const { + return { +)" << " " + propertyNameStrings.join(",\n ") << R"( + }; + } - 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"; + Q_INVOKABLE bool isDefaultValue(const QString &key) const { +)"; + for (const auto &p : properties) { + headerStream << " if (key == " << p.propertyNameString << ")\n" + << " return " << p.propertyName << "IsDefaultValue();\n"; } - headerStream << " return false;\n" - << " }\n\n"; + headerStream << " return false;\n }\n\n"; - // Generate property getter and setter methods + // Property getters/setters/signals + // Setters need to be thread safe. 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" + const auto &p = properties[i]; + const QString read = usedKeywords.contains(p.propertyName) ? "get" + p.capitalizedPropertyName : p.propertyName; + + headerStream << " " << p.typeName << " " << read << "() const\n" + << " {\n" + << " return m_data->p_" << p.propertyName << ";\n" + << " }\n" + << " void set" << p.capitalizedPropertyName << "(const " << p.typeName << " &value) {\n" + << " auto oldValue = m_data->p_" << p.propertyName << ";\n" + << " m_data->p_" << p.propertyName << " = value;\n" + << " m_data->markPropertySet(" << i << ");\n" + << " if (auto config = m_data->m_config.loadRelaxed()) {\n" + << " QMetaObject::invokeMethod(config, [config, value]() {\n" + << " config->setValue(" << p.propertyNameString << ", value);\n" << " });\n" << " }\n" - << " if (p_" << property.propertyName << " != oldValue) {\n" - << " Q_EMIT " << property.propertyName << "Changed();\n" - << " Q_EMIT valueChanged(" << property.propertyNameString << ", value);\n" + << " if (m_data->p_" << p.propertyName << " != oldValue) {\n" + << " Q_EMIT " << p.propertyName << "Changed();\n" + << " Q_EMIT valueChanged(" << p.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" + << " void reset" << p.capitalizedPropertyName << "() {\n" + << " if (auto config = m_data->m_config.loadRelaxed()) {\n" + << " QMetaObject::invokeMethod(config, [config]() {\n" + << " config->reset(" << p.propertyNameString << ");\n" << " });\n" << " }\n" - << " }\n"; - headerStream << "#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)\n"; - headerStream << " QBindable<" << property.typeName << "> bindable" << property.capitalizedPropertyName << "() {\n" - << " return QBindable<" << property.typeName << ">(this, \"" << property.propertyName << "\");\n" - << " }\n"; - headerStream << "#endif\n"; - - headerStream << " Q_INVOKABLE bool " << property.propertyName << "IsDefaultValue() const {\n" - << " return !testPropertySet(" << i << ");\n" + << " }\n" + << " Q_INVOKABLE bool " << p.propertyName << "IsDefaultValue() const\n" + << " {\n" + << " return !m_data->testPropertySet(" << i << ");\n" << " }\n"; } - // Generate signals for property changes - headerStream << "Q_SIGNALS:\n" - << " void configInitializeFailed(DTK_CORE_NAMESPACE::DConfig *config);\n" + headerStream << "protected:\n" + << " bool event(QEvent *e) override {\n" + << " if (e->type() == QEvent::ThreadChange) {\n" + << " Q_ASSERT_X(false, \"" << className << "\", \"Moving " << className + << " to another thread is forbidden!\");\n" + << " }\n" + << " return QObject::event(e);\n" + << " }\n" + << "\nQ_SIGNALS:\n" + << " void configInitializeFailed();\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"; + << " void valueChanged(const QString &key, const QVariant &value);\n"; + for (const auto &p : properties) + headerStream << " void " << p.propertyName << "Changed();\n"; + + headerStream << "\nprivate:\n" + << " // Prevent external moveToThread calls\n" + << " using QObject::moveToThread;\n" + << " class Data : public QObject {\n" + << " public:\n" + << " enum class Status {\n" + << " Invalid = 0,\n" + << " Initializing = 1,\n" + << " Succeeded = 2,\n" + << " Failed = 3,\n" + << " Destroyed = 4\n" + << " };\n" + << "\n" + << " explicit Data()\n" + << " : QObject(nullptr) {}\n" + << "\n" + << " QAtomicPointer m_config = nullptr;\n" + << " QAtomicInteger m_status = static_cast(Status::Invalid);\n" + << " QPointer<" << className << "> m_userConfig = nullptr;\n"; + + for (int i = 0; i <= (properties.size()) / 32; ++i) { + headerStream << " QAtomicInteger m_propertySetStatus" << i << " = 0;\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(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 << "\n // Property storage\n"; + for (const Property &property : properties) { + if (property.typeName == QLatin1String("QString")) { + headerStream << " // Default value: \"" + << property.defaultValue.toString().replace("\n", "\\n").replace("\r", "\\r") << "\"\n"; + } + headerStream << " " << property.typeName << " p_" << property.propertyName << " { " + << jsonValueToCppCode(property.defaultValue) << " };\n"; } - headerStream << R"( - if (!m_config.loadRelaxed()) - return; - connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) { - updateValue(key); - }, Qt::DirectConnection); - - m_status.storeRelaxed(static_cast(Status::Succeed)); - Q_EMIT configInitializeSucceed(config); + + headerStream << "\n inline void initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config) {\n" + << " Q_ASSERT(!m_config.loadRelaxed());\n" + << " m_config.storeRelaxed(config);\n" + << " // Connect signals early - use QPointer to protect Data lifetime\n" + << " QPointer selfData(this);\n" + << " QObject::connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, config, [selfData](const QString &key) {\n" + << " if (selfData) selfData->updateValue(key);\n" + << " });\n"; + + for (int i = 0; i < properties.size(); ++i) { + const auto &p = properties[i]; + headerStream << " if (testPropertySet(" << i << ")) {\n" + << " config->setValue(" << p.propertyNameString << ", QVariant::fromValue(p_" << p.propertyName << "));\n" + << " } else {\n" + << " updateValue(" << p.propertyNameString << ", QVariant::fromValue(p_" << p.propertyName << "));\n" + << " }\n"; } - void updateValue(const QString &key, const QVariant &fallback = QVariant()) { - if (!m_config.loadRelaxed()) - return; - Q_ASSERT(QThread::currentThread() == m_config.loadRelaxed()->thread()); - const QVariant &value = m_config.loadRelaxed()->value(key, fallback); + + headerStream << R"( } + + inline void updateValue(const QString &key, const QVariant &fallback = QVariant()) { + auto config = m_config.loadRelaxed(); + if (!config) return; + const QVariant &v = config->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"; + const auto &p = properties[i]; + headerStream << " if (key == " << p.propertyNameString << ") {\n" + << " markPropertySet(" << i << ", !config->isDefaultValue(key));\n" + << " updateProperty(key, v);\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 << " }\n\n" + << " inline void updateProperty(const QString &key, const QVariant &v) {\n"; + for (const auto &p : properties) { + headerStream << " if (key == " << p.propertyNameString << ") {\n" + << " " << p.typeName << " nv = qvariant_cast<" << p.typeName << ">(v);\n" + << " if (p_" << p.propertyName << " != nv) {\n" + << " p_" << p.propertyName << " = nv;\n" + << " if (m_userConfig) {\n" + << " QPointer selfData(this);\n" + << " // Emit signals on main thread (userConfig's thread)\n" + << " QMetaObject::invokeMethod(m_userConfig, [selfData, key, v]() {\n" + << " if (selfData && selfData->m_userConfig) {\n" + << " Q_EMIT selfData->m_userConfig->" << p.propertyName << "Changed();\n" + << " Q_EMIT selfData->m_userConfig->valueChanged(key, v);\n" + << " }\n" + << " }, Qt::QueuedConnection);\n" + << " }\n" + << " }\n" + << " return;\n" + << " }\n"; } - headerStream << " Q_UNREACHABLE();\n }\n"; + headerStream << " }\n" + << "\n inline void markPropertySet(const int index, bool on = true) {\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 m_config = nullptr; - -public: - enum class Status { - Invalid = 0, - Succeed = 1, - Failed = 2 - }; -private: - QAtomicInteger m_status = static_cast(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, use XXX.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"; + headerStream << " if (index < " << (i + 1) * 32 << ") {\n" + << " if (on)\n" + << " m_propertySetStatus" << i << ".fetchAndOrOrdered(1 << (index - " << i * 32 << "));\n" + << " else\n" + << " m_propertySetStatus" << i << ".fetchAndAndOrdered(~(1 << (index - " << i * 32 << ")));\n" + << " return;\n" + << " }\n"; } + headerStream << " Q_UNREACHABLE();\n" + << " }\n" + << "\n inline bool testPropertySet(const int index) const {\n"; - // Property set status variables for (int i = 0; i <= (properties.size()) / 32; ++i) { - headerStream << " QAtomicInteger m_propertySetStatus" << QString::number(i) << " = 0;\n"; + headerStream << " if (index < " << (i + 1) * 32 << ") {\n" + << " return (m_propertySetStatus" << i << ".loadRelaxed() & (1 << (index - " << i * 32 << ")));\n" + << " }\n"; } - headerStream << "};\n\n"; - headerStream << "#endif // " << className.toUpper() << "_H\n"; + headerStream << " Q_UNREACHABLE();\n" + << " }\n" + << " };\n\n" + << " Data *m_data;\n" + << "};\n\n" + << "#endif // " << className.toUpper() << "_H\n"; return 0; }