From 2f60895fb7262ad8ec3fe72bad6f9df6f06e2ae5 Mon Sep 17 00:00:00 2001 From: Mentalflow <312902918@qq.com> Date: Wed, 28 May 2025 23:27:33 +0800 Subject: [PATCH] RibbonConfig, RibbonSingleton: Added. --- 3rdparty/Qt5QMLPlugin | 2 +- CMakeLists.txt | 2 +- {example => RibbonUIAPP}/CMakeLists.txt | 26 ++++- .../i18n/RibbonUIAPP_en_US.ts | 0 .../i18n/RibbonUIAPP_zh_CN.ts | 0 RibbonUIAPP/include/localization.h | 27 +++++ .../qml/Qt5/SplashScreen.qml | 6 ++ {example => RibbonUIAPP}/qml/Qt5/about.qml | 0 .../RibbonMessageListViewExample.qml | 0 .../qml/Qt5/components/TabBar.qml | 0 {example => RibbonUIAPP}/qml/Qt5/example.qml | 2 + .../qml/Qt5/pages/SettingsMenuPage.qml | 12 ++- .../qml/Qt6/SplashScreen.qml | 6 ++ {example => RibbonUIAPP}/qml/Qt6/about.qml | 0 .../RibbonMessageListViewExample.qml | 0 .../qml/Qt6/components/TabBar.qml | 0 {example => RibbonUIAPP}/qml/Qt6/example.qml | 2 + .../qml/Qt6/pages/SettingsMenuPage.qml | 12 ++- .../resources/imgs/AppIcon.icns | Bin .../resources/imgs/heart.png | Bin .../resources/imgs/icon.ico | Bin .../resources/imgs/icon.png | Bin .../resources/imgs/search.png | Bin {example => RibbonUIAPP/source}/example.cpp | 0 RibbonUIAPP/source/localization.cpp | 11 +++ lib_source/CMakeLists.txt | 9 +- lib_source/include/platformsupport.h | 21 ++-- lib_source/include/ribbonconfig.h | 36 +++++++ lib_source/include/ribbonlocalization.h | 23 ++--- lib_source/include/ribbonsingleton.h | 92 ++++++++++++++++++ lib_source/include/ribbontheme.h | 12 +-- lib_source/include/ribbonui.h | 17 ++-- lib_source/qml/Qt5/RibbonWindow.qml | 2 - lib_source/qml/Qt6/RibbonWindow.qml | 2 - lib_source/source/ribbonconfig.cpp | 71 ++++++++++++++ lib_source/source/ribbonlocalization.cpp | 69 ++++++++----- lib_source/source/ribbontheme.cpp | 12 +-- lib_source/source/ribbonui.cpp | 23 ++--- 38 files changed, 386 insertions(+), 111 deletions(-) rename {example => RibbonUIAPP}/CMakeLists.txt (89%) rename {example => RibbonUIAPP}/i18n/RibbonUIAPP_en_US.ts (100%) rename {example => RibbonUIAPP}/i18n/RibbonUIAPP_zh_CN.ts (100%) create mode 100644 RibbonUIAPP/include/localization.h rename {example => RibbonUIAPP}/qml/Qt5/SplashScreen.qml (82%) rename {example => RibbonUIAPP}/qml/Qt5/about.qml (100%) rename {example => RibbonUIAPP}/qml/Qt5/components/RibbonMessageListViewExample.qml (100%) rename {example => RibbonUIAPP}/qml/Qt5/components/TabBar.qml (100%) rename {example => RibbonUIAPP}/qml/Qt5/example.qml (99%) rename {example => RibbonUIAPP}/qml/Qt5/pages/SettingsMenuPage.qml (92%) rename {example => RibbonUIAPP}/qml/Qt6/SplashScreen.qml (82%) rename {example => RibbonUIAPP}/qml/Qt6/about.qml (100%) rename {example => RibbonUIAPP}/qml/Qt6/components/RibbonMessageListViewExample.qml (100%) rename {example => RibbonUIAPP}/qml/Qt6/components/TabBar.qml (100%) rename {example => RibbonUIAPP}/qml/Qt6/example.qml (99%) rename {example => RibbonUIAPP}/qml/Qt6/pages/SettingsMenuPage.qml (92%) rename {example => RibbonUIAPP}/resources/imgs/AppIcon.icns (100%) rename {example => RibbonUIAPP}/resources/imgs/heart.png (100%) rename {example => RibbonUIAPP}/resources/imgs/icon.ico (100%) rename {example => RibbonUIAPP}/resources/imgs/icon.png (100%) rename {example => RibbonUIAPP}/resources/imgs/search.png (100%) rename {example => RibbonUIAPP/source}/example.cpp (100%) create mode 100644 RibbonUIAPP/source/localization.cpp create mode 100644 lib_source/include/ribbonconfig.h create mode 100644 lib_source/include/ribbonsingleton.h create mode 100644 lib_source/source/ribbonconfig.cpp diff --git a/3rdparty/Qt5QMLPlugin b/3rdparty/Qt5QMLPlugin index fd7734e..489650d 160000 --- a/3rdparty/Qt5QMLPlugin +++ b/3rdparty/Qt5QMLPlugin @@ -1 +1 @@ -Subproject commit fd7734e79071d0acc1286004dc53db8c9b8c5a1a +Subproject commit 489650df0eea78db580c9338406abd4dd9718780 diff --git a/CMakeLists.txt b/CMakeLists.txt index c233190..18c11d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,7 @@ endif() add_subdirectory(lib_source) if (RIBBONUI_BUILD_EXAMPLES) - add_subdirectory(example) + add_subdirectory(RibbonUIAPP) endif() message("---------------------------- RibbonUI ----------------------------") diff --git a/example/CMakeLists.txt b/RibbonUIAPP/CMakeLists.txt similarity index 89% rename from example/CMakeLists.txt rename to RibbonUIAPP/CMakeLists.txt index 6399891..cb7f877 100644 --- a/example/CMakeLists.txt +++ b/RibbonUIAPP/CMakeLists.txt @@ -37,7 +37,12 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick LinguistTools REQUIRED) set(ts_files i18n/${PROJECT_NAME}_zh_CN.ts i18n/${PROJECT_NAME}_en_US.ts) # Source and QML files -set(sources_files example.cpp) +set(sources_files + source/example.cpp +) +set(module_sources_files + include/localization.h source/localization.cpp +) set(qml_files example.qml about.qml SplashScreen.qml components/RibbonMessageListViewExample.qml pages/SettingsMenuPage.qml components/TabBar.qml) @@ -127,6 +132,15 @@ endif() # Include Qt5 QML plugin for Qt versions less than 6 if (${QT_VERSION_MAJOR} LESS 6) include(Qt5QMLPlugin) +else() + # Update QML_IMPORT_PATH (cached variable) + if(NOT QML_IMPORT_PATH MATCHES "(^|;)${CMAKE_CURRENT_BINARY_DIR}($|;)") + if(QML_IMPORT_PATH) + set(QML_IMPORT_PATH "${QML_IMPORT_PATH};${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "Set for Qt Creator" FORCE) + else() + set(QML_IMPORT_PATH "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "Set for Qt Creator" FORCE) + endif() + endif() endif() # Define the QML module @@ -135,6 +149,7 @@ qt_add_qml_module(${PROJECT_NAME} VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} RESOURCE_PREFIX "/qt/qml/" QML_FILES ${qml_files} + SOURCES ${module_sources_files} RESOURCES resources/imgs/heart.png resources/imgs/search.png ) @@ -183,4 +198,11 @@ target_link_libraries(${PROJECT_NAME} PRIVATE ) target_compile_definitions(${PROJECT_NAME} PRIVATE $<$,$>:QT_QML_DEBUG>) -target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}) +target_include_directories(${PROJECT_NAME} PUBLIC + ${PROJECT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR}/include +) + +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + target_compile_definitions(${PROJECT_NAME} PRIVATE QT_QML_DEBUG) +endif() diff --git a/example/i18n/RibbonUIAPP_en_US.ts b/RibbonUIAPP/i18n/RibbonUIAPP_en_US.ts similarity index 100% rename from example/i18n/RibbonUIAPP_en_US.ts rename to RibbonUIAPP/i18n/RibbonUIAPP_en_US.ts diff --git a/example/i18n/RibbonUIAPP_zh_CN.ts b/RibbonUIAPP/i18n/RibbonUIAPP_zh_CN.ts similarity index 100% rename from example/i18n/RibbonUIAPP_zh_CN.ts rename to RibbonUIAPP/i18n/RibbonUIAPP_zh_CN.ts diff --git a/RibbonUIAPP/include/localization.h b/RibbonUIAPP/include/localization.h new file mode 100644 index 0000000..0b606fd --- /dev/null +++ b/RibbonUIAPP/include/localization.h @@ -0,0 +1,27 @@ +#ifndef LOCALIZATION_H +#define LOCALIZATION_H + +#include +#include +#include "ribbonlocalization.h" + +class Localization : public RibbonLocalization +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + + RIBBON_SINGLETON(Localization) +public: + virtual void loadCurrentLanguage() override; + virtual void saveCurrentLanguage(const QString &language)override; +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +public: +#else +private: +#endif + Localization() = default; + ~Localization() = default; +}; + +#endif // LOCALIZATION_H diff --git a/example/qml/Qt5/SplashScreen.qml b/RibbonUIAPP/qml/Qt5/SplashScreen.qml similarity index 82% rename from example/qml/Qt5/SplashScreen.qml rename to RibbonUIAPP/qml/Qt5/SplashScreen.qml index bc437fb..33e5242 100644 --- a/example/qml/Qt5/SplashScreen.qml +++ b/RibbonUIAPP/qml/Qt5/SplashScreen.qml @@ -1,5 +1,6 @@ import QtQuick 2.15 import RibbonUI 1.1 +import RibbonUIAPP 1.1 RibbonSplashScreen { id: root @@ -23,4 +24,9 @@ RibbonSplashScreen { root.showLoadingLog(qsTr("Loading...Remain %1s...").arg(remainSeconds), {}) } } + + Component.onCompleted: { + RibbonUI.autoLoadLanguage = true + RibbonUI.setTranslator(Localization) + } } diff --git a/example/qml/Qt5/about.qml b/RibbonUIAPP/qml/Qt5/about.qml similarity index 100% rename from example/qml/Qt5/about.qml rename to RibbonUIAPP/qml/Qt5/about.qml diff --git a/example/qml/Qt5/components/RibbonMessageListViewExample.qml b/RibbonUIAPP/qml/Qt5/components/RibbonMessageListViewExample.qml similarity index 100% rename from example/qml/Qt5/components/RibbonMessageListViewExample.qml rename to RibbonUIAPP/qml/Qt5/components/RibbonMessageListViewExample.qml diff --git a/example/qml/Qt5/components/TabBar.qml b/RibbonUIAPP/qml/Qt5/components/TabBar.qml similarity index 100% rename from example/qml/Qt5/components/TabBar.qml rename to RibbonUIAPP/qml/Qt5/components/TabBar.qml diff --git a/example/qml/Qt5/example.qml b/RibbonUIAPP/qml/Qt5/example.qml similarity index 99% rename from example/qml/Qt5/example.qml rename to RibbonUIAPP/qml/Qt5/example.qml index 204d358..2323aee 100644 --- a/example/qml/Qt5/example.qml +++ b/RibbonUIAPP/qml/Qt5/example.qml @@ -3,6 +3,7 @@ import QtQuick.Controls 2.15 import QtQuick.Layouts 1.11 import QtQuick.Window 2.15 import RibbonUI 1.1 +import RibbonUIAPP 1.1 import "components" RibbonWindow { @@ -145,6 +146,7 @@ RibbonWindow { } Component.onCompleted: { RibbonUI.autoLoadLanguage = true + RibbonUI.setTranslator(Localization) tour.open() } diff --git a/example/qml/Qt5/pages/SettingsMenuPage.qml b/RibbonUIAPP/qml/Qt5/pages/SettingsMenuPage.qml similarity index 92% rename from example/qml/Qt5/pages/SettingsMenuPage.qml rename to RibbonUIAPP/qml/Qt5/pages/SettingsMenuPage.qml index 54b685a..602701f 100644 --- a/example/qml/Qt5/pages/SettingsMenuPage.qml +++ b/RibbonUIAPP/qml/Qt5/pages/SettingsMenuPage.qml @@ -3,6 +3,7 @@ import QtQuick.Layouts 1.11 import QtQuick.Controls 2.15 import QtQuick.Window 2.15 import RibbonUI 1.1 +import RibbonUIAPP 1.1 RibbonBackStagePage{ id: page @@ -118,23 +119,24 @@ RibbonBackStagePage{ textRole: "text" iconSource: RibbonIcons.LocalLanguage Component.onCompleted: update_state() - onActivated: RibbonLocalization.currentLanguage = model.get(currentIndex).value + onActivated: Localization.currentLanguage = model.get(currentIndex).value Connections{ - target: RibbonLocalization + target: Localization function onCurrentLanguageChanged(){ lang_combo.update_state() } } function update_state(){ model.clear() - let langs = RibbonLocalization.languageList() + let langs = Localization.languageList() for(let i = 0; i < langs.length; i++){ model.append({ - text:RibbonLocalization.languageTranslate(langs[i]), + text:Localization.languageTranslate(langs[i]), value:langs[i] }) } - currentIndex = find(RibbonLocalization.languageTranslate(RibbonLocalization.currentLanguage)) + + currentIndex = find(Localization.languageTranslate(Localization.currentLanguage)) } } } diff --git a/example/qml/Qt6/SplashScreen.qml b/RibbonUIAPP/qml/Qt6/SplashScreen.qml similarity index 82% rename from example/qml/Qt6/SplashScreen.qml rename to RibbonUIAPP/qml/Qt6/SplashScreen.qml index 8bbe02a..abb2247 100644 --- a/example/qml/Qt6/SplashScreen.qml +++ b/RibbonUIAPP/qml/Qt6/SplashScreen.qml @@ -1,5 +1,6 @@ import QtQuick import RibbonUI +import RibbonUIAPP RibbonSplashScreen { id: root @@ -23,4 +24,9 @@ RibbonSplashScreen { root.showLoadingLog(qsTr("Loading...Remain %1s...").arg(remainSeconds), {}) } } + + Component.onCompleted: { + RibbonUI.autoLoadLanguage = true + RibbonUI.setTranslator(Localization) + } } diff --git a/example/qml/Qt6/about.qml b/RibbonUIAPP/qml/Qt6/about.qml similarity index 100% rename from example/qml/Qt6/about.qml rename to RibbonUIAPP/qml/Qt6/about.qml diff --git a/example/qml/Qt6/components/RibbonMessageListViewExample.qml b/RibbonUIAPP/qml/Qt6/components/RibbonMessageListViewExample.qml similarity index 100% rename from example/qml/Qt6/components/RibbonMessageListViewExample.qml rename to RibbonUIAPP/qml/Qt6/components/RibbonMessageListViewExample.qml diff --git a/example/qml/Qt6/components/TabBar.qml b/RibbonUIAPP/qml/Qt6/components/TabBar.qml similarity index 100% rename from example/qml/Qt6/components/TabBar.qml rename to RibbonUIAPP/qml/Qt6/components/TabBar.qml diff --git a/example/qml/Qt6/example.qml b/RibbonUIAPP/qml/Qt6/example.qml similarity index 99% rename from example/qml/Qt6/example.qml rename to RibbonUIAPP/qml/Qt6/example.qml index 92afeca..bb20849 100644 --- a/example/qml/Qt6/example.qml +++ b/RibbonUIAPP/qml/Qt6/example.qml @@ -3,6 +3,7 @@ import QtQuick.Controls import QtQuick.Layouts import QtQuick.Window import RibbonUI +import RibbonUIAPP import "components" RibbonWindow { @@ -145,6 +146,7 @@ RibbonWindow { } Component.onCompleted: { RibbonUI.autoLoadLanguage = true + RibbonUI.setTranslator(Localization) tour.open() } diff --git a/example/qml/Qt6/pages/SettingsMenuPage.qml b/RibbonUIAPP/qml/Qt6/pages/SettingsMenuPage.qml similarity index 92% rename from example/qml/Qt6/pages/SettingsMenuPage.qml rename to RibbonUIAPP/qml/Qt6/pages/SettingsMenuPage.qml index 18e0b8a..ef96201 100644 --- a/example/qml/Qt6/pages/SettingsMenuPage.qml +++ b/RibbonUIAPP/qml/Qt6/pages/SettingsMenuPage.qml @@ -3,6 +3,7 @@ import QtQuick.Layouts import QtQuick.Controls import QtQuick.Window import RibbonUI +import RibbonUIAPP RibbonBackStagePage{ id: page @@ -118,23 +119,24 @@ RibbonBackStagePage{ textRole: "text" iconSource: RibbonIcons.LocalLanguage Component.onCompleted: update_state() - onActivated: RibbonLocalization.currentLanguage = model.get(currentIndex).value + onActivated: Localization.currentLanguage = model.get(currentIndex).value Connections{ - target: RibbonLocalization + target: Localization function onCurrentLanguageChanged(){ lang_combo.update_state() } } function update_state(){ model.clear() - let langs = RibbonLocalization.languageList() + let langs = Localization.languageList() for(let i = 0; i < langs.length; i++){ model.append({ - text:RibbonLocalization.languageTranslate(langs[i]), + text:Localization.languageTranslate(langs[i]), value:langs[i] }) } - currentIndex = find(RibbonLocalization.languageTranslate(RibbonLocalization.currentLanguage)) + + currentIndex = find(Localization.languageTranslate(Localization.currentLanguage)) } } } diff --git a/example/resources/imgs/AppIcon.icns b/RibbonUIAPP/resources/imgs/AppIcon.icns similarity index 100% rename from example/resources/imgs/AppIcon.icns rename to RibbonUIAPP/resources/imgs/AppIcon.icns diff --git a/example/resources/imgs/heart.png b/RibbonUIAPP/resources/imgs/heart.png similarity index 100% rename from example/resources/imgs/heart.png rename to RibbonUIAPP/resources/imgs/heart.png diff --git a/example/resources/imgs/icon.ico b/RibbonUIAPP/resources/imgs/icon.ico similarity index 100% rename from example/resources/imgs/icon.ico rename to RibbonUIAPP/resources/imgs/icon.ico diff --git a/example/resources/imgs/icon.png b/RibbonUIAPP/resources/imgs/icon.png similarity index 100% rename from example/resources/imgs/icon.png rename to RibbonUIAPP/resources/imgs/icon.png diff --git a/example/resources/imgs/search.png b/RibbonUIAPP/resources/imgs/search.png similarity index 100% rename from example/resources/imgs/search.png rename to RibbonUIAPP/resources/imgs/search.png diff --git a/example/example.cpp b/RibbonUIAPP/source/example.cpp similarity index 100% rename from example/example.cpp rename to RibbonUIAPP/source/example.cpp diff --git a/RibbonUIAPP/source/localization.cpp b/RibbonUIAPP/source/localization.cpp new file mode 100644 index 0000000..6bda5e9 --- /dev/null +++ b/RibbonUIAPP/source/localization.cpp @@ -0,0 +1,11 @@ +#include "localization.h" +#include "ribbonconfig.h" + +void Localization::loadCurrentLanguage(){ + QString language = RibbonConfig::getInstance()->get("Settings", "Current Language").toString(); + setCurrentLanguage(language); +} + +void Localization::saveCurrentLanguage(const QString &language){ + RibbonConfig::getInstance()->set("Settings", "Current Language", language); +} diff --git a/lib_source/CMakeLists.txt b/lib_source/CMakeLists.txt index f3a0375..be0c39e 100644 --- a/lib_source/CMakeLists.txt +++ b/lib_source/CMakeLists.txt @@ -67,7 +67,10 @@ set (source_files include/definitions.h include/ribbontheme.h source/ribbontheme.cpp include/platformsupport.h - include/ribbonlocalization.h source/ribbonlocalization.cpp) + include/ribbonlocalization.h source/ribbonlocalization.cpp + include/ribbonsingleton.h + include/ribbonconfig.h source/ribbonconfig.cpp +) # Configure version header set(__ribbonui_project_version "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") @@ -171,5 +174,9 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR} ) +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + target_compile_definitions(${PROJECT_NAME} PRIVATE QT_QML_DEBUG) +endif() + # Install QML plugin directory install(DIRECTORY ${RIBBONUI_QML_PLUGIN_DIRECTORY} DESTINATION ${CMAKE_INSTALL_PREFIX}/imports) diff --git a/lib_source/include/platformsupport.h b/lib_source/include/platformsupport.h index cf8c22e..8d746c5 100644 --- a/lib_source/include/platformsupport.h +++ b/lib_source/include/platformsupport.h @@ -1,26 +1,17 @@ #ifndef PLATFORMSUPPORT_H #define PLATFORMSUPPORT_H -#include + #include -#include +#include "ribbonsingleton.h" class PlatformSupport : public QObject { Q_OBJECT QML_ELEMENT QML_SINGLETON -public: - static PlatformSupport* create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return instance();} - static PlatformSupport* instance(){ - static QMutex mutex; - QMutexLocker locker(&mutex); - static PlatformSupport *singleton = nullptr; - if (!singleton) { - singleton = new PlatformSupport(); - } - return singleton; - } + RIBBON_SINGLETON(PlatformSupport) +public: #ifdef Q_OS_MACOS Q_INVOKABLE void showSystemTitleBtns(QWindow *window, bool enable); #endif @@ -28,9 +19,9 @@ public: public: #else private: - Q_DISABLE_COPY_MOVE(PlatformSupport) #endif PlatformSupport(QObject *parent = nullptr) : QObject(parent){} +private: + bool bindEngine(){return bindEngineBegin();}; }; - #endif // PLATFORMSUPPORT_H diff --git a/lib_source/include/ribbonconfig.h b/lib_source/include/ribbonconfig.h new file mode 100644 index 0000000..9a46dee --- /dev/null +++ b/lib_source/include/ribbonconfig.h @@ -0,0 +1,36 @@ +#ifndef RIBBONCONFIG_H +#define RIBBONCONFIG_H + +#include +#include +#include "ribbonsingleton.h" + +class RibbonConfig : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + + RIBBON_SINGLETON(RibbonConfig) +public: + Q_INVOKABLE void set(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue); + Q_INVOKABLE void setArray(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue); + Q_INVOKABLE QVariant get(QString qstrnodename,QString qstrkeyname); + Q_INVOKABLE QVariant getArray(QString qstrnodename,QString qstrkeyname); + void clear(); + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +public: +#else +private: +#endif + explicit RibbonConfig(QString qstrfilename = ""); + ~RibbonConfig() override; +protected: + virtual bool bindEngine(){return bindEngineBegin();}; + QString qstrFileName; + QSettings *setting=nullptr; + QMutex mutex; +}; +#endif // RIBBONCONFIG_H + diff --git a/lib_source/include/ribbonlocalization.h b/lib_source/include/ribbonlocalization.h index 8f75374..d850890 100644 --- a/lib_source/include/ribbonlocalization.h +++ b/lib_source/include/ribbonlocalization.h @@ -1,41 +1,42 @@ #ifndef RIBBONLOCALIZATION_H #define RIBBONLOCALIZATION_H -#include #include #include +#include "ribbonsingleton.h" +#include "definitions.h" -class RibbonLocalization : public QQuickItem +class RibbonLocalization : public QObject { Q_OBJECT QML_ELEMENT QML_SINGLETON Q_PROPERTY(QString currentLanguage READ currentLanguage WRITE setCurrentLanguage NOTIFY currentLanguageChanged FINAL) + Q_PROPERTY_RW(bool, enabled); + RIBBON_SINGLETON(RibbonLocalization) public: typedef QPair LangItem; // example: <"zh_CN", "qrc://i18n/xxx_zh_CN.qm"> typedef QMap> Translator; // example: <"main", mainTranslator> typedef QMap ModuleTranslator; // example: - static RibbonLocalization* create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return instance();} - static RibbonLocalization* instance(); Q_INVOKABLE bool registerLanguage(QString langName, QString path, QString moduleName); Q_INVOKABLE bool removeLanguage(QString langName, QString path); - Q_INVOKABLE void bindEngine(); Q_INVOKABLE QList languageList(); Q_INVOKABLE QString languageTranslate(QString langStr); QString currentLanguage(); bool setCurrentLanguage(QString langName); // Use if you need to directly save/load language from config files - Q_INVOKABLE virtual void loadCurrentLanguage(){}; - virtual bool saveCurrentLanguage(const QString &language){return false;}; + virtual void loadCurrentLanguage(){}; + virtual void saveCurrentLanguage(const QString &language){}; #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) public: #else -private: - Q_DISABLE_COPY_MOVE(RibbonLocalization) +protected: #endif RibbonLocalization(); - ~RibbonLocalization(); + virtual ~RibbonLocalization() override; protected: + virtual bool bindEngine(); + virtual void switchState(); ModuleTranslator moduleLangList; Translator transList; QString _currentLang; @@ -47,6 +48,6 @@ protected: }; signals: void currentLanguageChanged(); + void registerLanguageFinished(); }; - #endif // RIBBONLOCALIZATION_H diff --git a/lib_source/include/ribbonsingleton.h b/lib_source/include/ribbonsingleton.h new file mode 100644 index 0000000..efcbfb6 --- /dev/null +++ b/lib_source/include/ribbonsingleton.h @@ -0,0 +1,92 @@ +#ifndef RIBBONSINGLETON_H +#define RIBBONSINGLETON_H + +#include +#include +#include +#include +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#include "ribbonui_version.h" +#endif + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#define RIBBON_SINGLETON(X) \ +public: \ + static X* create (QQmlEngine *qmlEngine, QJSEngine *jsEngine){return getInstance();} \ + static X* getInstance(){ \ + static QMutex mutex; \ + QMutexLocker locker(&mutex); \ + static X *singleton = nullptr; \ + if (!singleton || needRefresh) { \ + needRefresh() = false; \ + if(getTypeId() == -1 || !getEngine()) \ + singleton = new X(); \ + else \ + singleton = getEngine()->singletonInstance(getTypeId()); \ + } \ + return singleton; \ + }; \ + static void destroy(){ \ + needRefresh() = true; \ + X::getInstance()->~X(); \ + }; \ +protected: \ + static int getTypeId(){ \ + static int typeId = -1; \ + if(typeId == -1){ \ + QString version(RIBBONUI_VERSION); \ + QStringList versionList = version.split('.'); \ + typeId = qmlTypeId("RibbonUI", versionList[0].toInt(), \ + versionList[1].toInt(), staticMetaObject.className()); \ + } \ + return typeId; \ + }; \ + static QQmlApplicationEngine*& getEngine(){ \ + static QQmlApplicationEngine* engine = nullptr; \ + return engine; \ + } \ + static bool& needRefresh(){ \ + static bool need = false; \ + return need; \ + } \ + bool bindEngineBegin(){ \ + QQmlApplicationEngine* &engine = getEngine(); \ + engine = dynamic_cast(qmlEngine(this)); \ + if (!engine){ \ + dynamic_cast(this)->~X(); \ + return false; \ + } \ + return true; \ + }; \ + void initialBind(){ \ + QTimer::singleShot(1, this, &X::bindEngine); \ + }; +#else +#define RIBBON_SINGLETON(X) \ +public: \ + static X* create (QQmlEngine *qmlEngine, QJSEngine *jsEngine){return getInstance();} \ + static X* getInstance(){ \ + static QMutex mutex; \ + QMutexLocker locker(&mutex); \ + static X *singleton = nullptr; \ + if (!singleton) { \ + singleton = new X(); \ + } \ + return singleton; \ + }; \ + static void destroy(){ \ + X::getInstance()->~X(); \ + }; \ +protected: \ + bool bindEngineBegin(){ \ + QQmlApplicationEngine *engine = dynamic_cast(qmlEngine(this)); \ + if (!engine){ \ + return false; \ + } \ + return true; \ + }; \ + void initialBind(){QTimer::singleShot(1000, this, &X::bindEngine);}; \ +private: \ + Q_DISABLE_COPY_MOVE(X) +#endif +#endif // RIBBONSINGLETON_H diff --git a/lib_source/include/ribbontheme.h b/lib_source/include/ribbontheme.h index 98328f4..79fe79e 100644 --- a/lib_source/include/ribbontheme.h +++ b/lib_source/include/ribbontheme.h @@ -1,10 +1,10 @@ #ifndef RIBBONTHEME_H #define RIBBONTHEME_H -#include +#include "ribbonsingleton.h" #include "definitions.h" -class RibbonTheme : public QQuickItem +class RibbonTheme : public QObject { Q_OBJECT QML_ELEMENT @@ -14,21 +14,21 @@ class RibbonTheme : public QQuickItem Q_PROPERTY_RW(RibbonThemeType::ThemeMode,themeMode) Q_PROPERTY_RW(bool,modernStyle) Q_PROPERTY_RW(bool,nativeText) + + RIBBON_SINGLETON(RibbonTheme) public: - static RibbonTheme* create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return instance();} - static RibbonTheme* instance(); Q_SIGNAL void isDarkModeChanged(); bool isDarkMode(); #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) public: #else private: - Q_DISABLE_COPY_MOVE(RibbonTheme) #endif RibbonTheme(); +private: bool eventFilter(QObject *obj, QEvent *event); + bool bindEngine(){return bindEngineBegin();}; RibbonThemeType::ThemeMode currentTheme(); RibbonThemeType::ThemeMode _system_themeMode; }; - #endif // RIBBONTHEME_H diff --git a/lib_source/include/ribbonui.h b/lib_source/include/ribbonui.h index 026dfaf..b65192b 100644 --- a/lib_source/include/ribbonui.h +++ b/lib_source/include/ribbonui.h @@ -1,11 +1,11 @@ #ifndef RIBBONUI_H #define RIBBONUI_H -#include +#include "ribbonsingleton.h" #include "definitions.h" #include "ribbonlocalization.h" -class RibbonUI : public QQuickItem +class RibbonUI : public QObject { Q_OBJECT QML_ELEMENT @@ -16,12 +16,12 @@ class RibbonUI : public QQuickItem Q_PROPERTY_R(int, isWin11) Q_PROPERTY_RW(QVariantMap, windowsSet) Q_PROPERTY(bool autoLoadLanguage READ autoLoadLanguage WRITE setAutoLoadLanguage NOTIFY autoLoadLanguageChanged FINAL) + + RIBBON_SINGLETON(RibbonUI) public: - static RibbonUI* instance(); - static RibbonUI* create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return instance();} RIBBONUI_API static void init(); RIBBONUI_API static void registerTypes(const char *uri); - RIBBONUI_API Q_INVOKABLE void setTranslator(RibbonLocalization *translator = RibbonLocalization::instance()); + RIBBONUI_API Q_INVOKABLE void setTranslator(RibbonLocalization *translator = RibbonLocalization::getInstance()); Q_INVOKABLE void initTranslator(); bool autoLoadLanguage(){return _autoLoadLanguage;}; void setAutoLoadLanguage(bool value); @@ -31,15 +31,16 @@ public: public: #else private: - Q_DISABLE_COPY_MOVE(RibbonUI) #endif - explicit RibbonUI(QQuickItem *parent = nullptr); + explicit RibbonUI(QObject *parent = nullptr); private: - RibbonLocalization* _translator; + bool bindEngine(){return bindEngineBegin();}; + RibbonLocalization* _translator = nullptr; bool _autoLoadLanguage = false; signals: void autoLoadLanguageChanged(); + void initTranslatorFinished(); }; #endif // RIBBONUI_H diff --git a/lib_source/qml/Qt5/RibbonWindow.qml b/lib_source/qml/Qt5/RibbonWindow.qml index 58d6ed0..74425f5 100644 --- a/lib_source/qml/Qt5/RibbonWindow.qml +++ b/lib_source/qml/Qt5/RibbonWindow.qml @@ -70,9 +70,7 @@ Window { { windowAgent.setWindowAttribute("blur-effect", blurBehindWindow ? RibbonTheme.isDarkMode ? "dark" : "light" : "none") } - RibbonLocalization.bindEngine(); RibbonUI.setTranslator(RibbonLocalization) - window.visible = true windowAgent.centralize() raise() diff --git a/lib_source/qml/Qt6/RibbonWindow.qml b/lib_source/qml/Qt6/RibbonWindow.qml index f0caec4..b40ce4b 100644 --- a/lib_source/qml/Qt6/RibbonWindow.qml +++ b/lib_source/qml/Qt6/RibbonWindow.qml @@ -70,9 +70,7 @@ Window { { windowAgent.setWindowAttribute("blur-effect", blurBehindWindow ? RibbonTheme.isDarkMode ? "dark" : "light" : "none") } - RibbonLocalization.bindEngine(); RibbonUI.setTranslator(RibbonLocalization) - window.visible = true windowAgent.centralize() raise() diff --git a/lib_source/source/ribbonconfig.cpp b/lib_source/source/ribbonconfig.cpp new file mode 100644 index 0000000..5f75a64 --- /dev/null +++ b/lib_source/source/ribbonconfig.cpp @@ -0,0 +1,71 @@ +#include "ribbonconfig.h" +#include +#include + +RibbonConfig::RibbonConfig(QString qstrfilename): + QObject(nullptr) +{ + if (qstrfilename.isEmpty()) + { + qstrFileName = QCoreApplication::applicationDirPath() + "/config.ini"; + } + else + { + qstrFileName = qstrfilename; + } + + setting = new QSettings(qstrFileName, QSettings::IniFormat); + initialBind(); +} + +RibbonConfig::~RibbonConfig() +{ + delete setting; + setting = nullptr; +} + +void RibbonConfig::set(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue) +{ + QMutexLocker locker(&mutex); + setting->setValue(QString("/%1/%2").arg(qstrnodename, qstrkeyname), qvarvalue); +} + +void RibbonConfig::setArray(QString qstrnodename,QString qstrkeyname,QVariant qvarvalue) +{ + QMutexLocker locker(&mutex); + setting->beginWriteArray(QString("/%1/%2").arg(qstrnodename, qstrkeyname)); + QList list = qvarvalue.toList(); + for (int i = 0; i< list.length(); i++) + { + setting->setArrayIndex(i); + setting->setValue(qstrkeyname, list.at(i)); + } + setting->endArray(); +} + +QVariant RibbonConfig::get(QString qstrnodename,QString qstrkeyname) +{ + QMutexLocker locker(&mutex); + QVariant qvar = setting->value(QString("/%1/%2").arg(qstrnodename, qstrkeyname)); + return qvar; +} + +QVariant RibbonConfig::getArray(QString qstrnodename,QString qstrkeyname) +{ + QMutexLocker locker(&mutex); + QList list; + int size = setting->beginReadArray(QString("/%1/%2").arg(qstrnodename, qstrkeyname)); + for (int i = 0; i< size; i++) + { + setting->setArrayIndex(i); + list.append(setting->value(qstrkeyname)); + } + setting->endArray(); + return list; +} + +void RibbonConfig::clear() +{ + QMutexLocker locker(&mutex); + setting->clear(); +} diff --git a/lib_source/source/ribbonlocalization.cpp b/lib_source/source/ribbonlocalization.cpp index fa9e2bd..ad82afc 100644 --- a/lib_source/source/ribbonlocalization.cpp +++ b/lib_source/source/ribbonlocalization.cpp @@ -1,28 +1,20 @@ #include "ribbonlocalization.h" #include #include -#include +#include -RibbonLocalization::RibbonLocalization() { +RibbonLocalization::RibbonLocalization(){ _currentLang = "en_US"; + _enabled = true; + initialBind(); + connect(this, &RibbonLocalization::enabledChanged, this, &RibbonLocalization::switchState); } RibbonLocalization::~RibbonLocalization() { - for (auto item : transList) + for (auto item : std::as_const(transList)) item.clear(); } -RibbonLocalization* RibbonLocalization::instance(){ - static QMutex mutex; - QMutexLocker locker(&mutex); - - static RibbonLocalization *singleton = nullptr; - if (!singleton) { - singleton = new RibbonLocalization(); - } - return singleton; -} - bool RibbonLocalization::registerLanguage(QString langName, QString path, QString moduleName){ LangItem temp(langName, path); if(!moduleLangList.contains(temp)){ @@ -34,8 +26,10 @@ bool RibbonLocalization::registerLanguage(QString langName, QString path, QStrin } } moduleLangList.insert(temp, moduleName); + emit registerLanguageFinished(); return true; } + emit registerLanguageFinished(); return false; } @@ -62,12 +56,13 @@ QString RibbonLocalization::currentLanguage(){ bool RibbonLocalization::setCurrentLanguage(QString langName){ bool hasChanged = false; QMap isNeeded; - for(auto langItem : moduleLangList.keys()){ + auto keys = moduleLangList.keys(); + for(auto &langItem : keys){ if(langItem.first == langName){ isNeeded[moduleLangList[langItem]] = true; Q_UNUSED(transList[moduleLangList[langItem]].get()->load(langItem.second)); _currentLang = langName; - qApp->installTranslator(transList[moduleLangList[langItem]].get());; + qApp->installTranslator(transList[moduleLangList[langItem]].get()); hasChanged = true; } else{ @@ -83,23 +78,31 @@ bool RibbonLocalization::setCurrentLanguage(QString langName){ return hasChanged; } -void RibbonLocalization::bindEngine(){ - QQmlApplicationEngine * engine = dynamic_cast(qmlEngine(this)); - Q_ASSERT(engine); - if (!engine) - return; - QObject::connect(this, &RibbonLocalization::currentLanguageChanged, engine, [engine]() -> void { - engine->retranslate(); - }); +bool RibbonLocalization::bindEngine(){ +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + QQmlApplicationEngine* &engine = getEngine(); + engine = dynamic_cast(qmlEngine(this)); +#else + QQmlApplicationEngine *engine = dynamic_cast(qmlEngine(this)); +#endif + if(bindEngineBegin()){ + QObject::connect(this, &RibbonLocalization::currentLanguageChanged, engine, [engine]() -> void { + engine->retranslate(); + }); + loadCurrentLanguage(); + return true; + } + return false; } QList RibbonLocalization::languageList(){ QList list; QSet set; - for(auto langItem : moduleLangList.keys()){ + auto keys = moduleLangList.keys(); + for(auto &langItem : keys){ set.insert(langItem.first); } - for(auto setItem : set){ + for(auto &setItem : set){ list.append(setItem); } return list; @@ -112,3 +115,17 @@ QString RibbonLocalization::languageTranslate(QString langStr){ else return tr("Not Found"); } + +void RibbonLocalization::switchState(){ + if(_enabled){ + setCurrentLanguage(_currentLang); + } + else{ + auto keys = moduleLangList.keys(); + for(auto &langItem : keys){ + if(langItem.first == _currentLang){ + qApp->removeTranslator(transList[moduleLangList[langItem]].get()); + } + } + } +} diff --git a/lib_source/source/ribbontheme.cpp b/lib_source/source/ribbontheme.cpp index b6d5c4b..a02380a 100644 --- a/lib_source/source/ribbontheme.cpp +++ b/lib_source/source/ribbontheme.cpp @@ -21,17 +21,7 @@ RibbonTheme::RibbonTheme() modernStyle(false); nativeText(true); qApp->installEventFilter(this); -} - -RibbonTheme* RibbonTheme::instance(){ - static QMutex mutex; - QMutexLocker locker(&mutex); - - static RibbonTheme *singleton = nullptr; - if (!singleton) { - singleton = new RibbonTheme(); - } - return singleton; + initialBind(); } bool RibbonTheme::eventFilter(QObject *obj, QEvent *event) diff --git a/lib_source/source/ribbonui.cpp b/lib_source/source/ribbonui.cpp index 7ede2dd..0d2ec21 100644 --- a/lib_source/source/ribbonui.cpp +++ b/lib_source/source/ribbonui.cpp @@ -7,24 +7,14 @@ #include #include "ribbonui_version.h" -RibbonUI::RibbonUI(QQuickItem *parent) - : QQuickItem(parent) +RibbonUI::RibbonUI(QObject *parent) + : QObject(parent) { _version = RIBBONUI_VERSION; _qtVersion = QString(qVersion()).replace('.',"").toInt(); _isWin11 = QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 22000); - _translator = RibbonLocalization::instance(); -} - -RibbonUI* RibbonUI::instance(){ - static QMutex mutex; - QMutexLocker locker(&mutex); - - static RibbonUI *singleton = nullptr; - if (!singleton) { - singleton = new RibbonUI(); - } - return singleton; + _translator = RibbonLocalization::getInstance(); + initialBind(); } void RibbonUI::init() @@ -49,7 +39,9 @@ void RibbonUI::registerTypes(const char *uri) } void RibbonUI::setTranslator(RibbonLocalization *translator){ + _translator->enabled(false); _translator = translator; + _translator->enabled(true); initTranslator(); } @@ -59,7 +51,7 @@ void RibbonUI::initTranslator(){ filters<<"*.qm"; dir.setNameFilters(filters); QStringList matchedFiles = dir.entryList(); - for(auto file : matchedFiles){ + for(auto &file : std::as_const(matchedFiles)){ QString project, lang; int start = 0; int end = file.indexOf('_'); @@ -79,6 +71,7 @@ void RibbonUI::initTranslator(){ } } } + emit initTranslatorFinished(); } void RibbonUI::setAutoLoadLanguage(bool value){