/*! * * Copyright (c) 2021-2024 Diality Inc. - All Rights Reserved. * \copyright * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * \file Settings.h * \author (last) Behrouz NematiPour * \date (last) 13-Sep-2023 * \author (original) Behrouz NematiPour * \date (original) 29-Mar-2021 * */ #pragma once // Qt #include #include #include #include // Project #include "main.h" // Doxygen : do not remove #include "StorageGlobals.h" #include "Threads.h" // forward declarations class tst_initializations; namespace Storage { // TODO - IMPORTANT: this MVC needs to change to configurations in oppose to Settings. // It named settings because it suppose to be like QSettings, // but since we have settings it is mixing up with that and is very confusing. // FIXME- IMPORTANT: This set of Settings (MVC) design is not correct: // - the data structure should change in Model from column based (keys, values) to tree/map based // - the singleton should be the controller not the Model, to protect the model usage, and avoid the shared memory issues. // - the model class should be private class, or an object defined in this class, not a global class. class Settings { private: // Settings static constexpr const char *_config_attribute_tag = "#--"; static constexpr const char *_duplicate_key_on = "duplicate_key_on"; static constexpr const char *_duplicate_key_off = "duplicate_key_off"; static constexpr const char*_settingsExt = "conf"; static constexpr const char *_settingsFormat = "%1/%2.%3"; static constexpr const char*_settingsLocalSeparator = "_"; static constexpr const char*_translationExt = "qm"; struct Detail { QString category; QString location; QString content; }; // TODO make this the SettingsError class // { Class SettingsError public: enum Settings_Error { eError_None = 0 , // always has to be 0 eError_POST , eError_PathEmpty , eError_MkDir , eError_Write , eError_Read , eError_Empty , eError_Parse , eError_Copy , eError_Remove , eError_No_SettingsFolder , eError_No_SettingsFile , eError_SettingNotExists , eError_No_SettingsLocale , eError_Not_Writable , eError_TranslationNotExists , }; private: static inline QHash settingsError_Message { // no translation for the error. My experience shows the error messages if translated is not useful for serviceability and debugging. { eError_None , "The configuration file '%1' successfully loaded," }, { eError_POST , "The configuration source check failed." }, { eError_PathEmpty , "The settings path is empty." }, { eError_MkDir , "The configuration folder '%1' cannot be created." }, { eError_Write , "The settings file %1 can't be written." }, { eError_Read , "The settings file %1 can't be read." }, { eError_Empty , "The settings file %1 is empty." }, { eError_Parse , "The settings file %1 parse error." }, { eError_Copy , "The configuration folder '%1' cannot be copied." }, { eError_Remove , "The configuration folder '%1' cannot be removed." }, { eError_No_SettingsFolder , "No settings folder in the %1 path found." }, { eError_No_SettingsFile , "No settings file in the %1 folder found." }, { eError_SettingNotExists , "The setting file %1 doesn't exists." }, { eError_No_SettingsLocale , "The system locale not defined. The default en_US used." }, { eError_Not_Writable , "The setting file %1 is not writable." }, { eError_TranslationNotExists , "The translation file %1 doesn't exists." }, }; static const QString errorMessage(int vErr, QString vArg1 = "", QString vArg2 = "") { if ( settingsError_Message.contains(vErr) ) { if ( ! vArg1.isEmpty() ) return QString(settingsError_Message[vErr]).arg(vArg1); if ( ! vArg2.isEmpty() ) return QString(settingsError_Message[vErr]).arg(vArg1).arg(vArg2); /* default */ return QString(settingsError_Message[vErr]); } return "[unknown]"; } // } Class SettingsError Settings() {} public: enum Category_Enum { eSettingsSystem = 0, // has to be the first one to read the other configs according to the locale set in the Systems.conf eInstructions , eParametersDataList , // TODO: the category for this conf is not used. may need to be merged into the Settings, but since it is list, It needs a little more thought. eAlarms , eEvents , eRejects , eMessagesUnhandled , eGenericConfirm , eTranslation , eConfigurationsLocale , }; // IMPORTANT: not having a eCount in the enum is intentional. to make sure in switch no enum is missed when not using the default. static constexpr int _configurationsCount = eGenericConfirm; enum Key_Enum { eKeyTitle , eKeyMessage , eKeyListTitle , eKeyConfirm , eKeyCancel , }; enum Location_Enum { eInit , eSecured , }; static int readConfigurations (); static int save (const QString &vGroup, const QString &vKey, const QString &vValue, Category_Enum vCategory = eSettingsSystem); static int configurationsMove (QString *vMessage = nullptr, bool vIsUpdate = false); static int readLocale (); static int loadTranslation (QTranslator &vTranslator); static QString locale(Category_Enum vCategory, bool vSeparator = false) { auto mLocale = [=](){ QString s = _Settings.systemLocale(); QString l = s.isEmpty() ? "" : QString( vSeparator ? _settingsLocalSeparator : "") + s ; return l; }; switch (vCategory) { // NOTE: don't use default case case eSettingsSystem : return "" ; case eInstructions : return mLocale() ; case eParametersDataList : return mLocale() ; case eAlarms : return mLocale() ; case eEvents : return mLocale() ; case eRejects : return mLocale() ; case eMessagesUnhandled : return "" ; case eGenericConfirm : return mLocale() ; case eTranslation : return mLocale() ; case eConfigurationsLocale : return "" ; } return ""; } static QString extention(Category_Enum vCategory) { switch (vCategory) { // NOTE: don't use default case case eSettingsSystem : return _settingsExt ; case eInstructions : return _settingsExt ; case eParametersDataList : return _settingsExt ; case eAlarms : return _settingsExt ; case eEvents : return _settingsExt ; case eRejects : return _settingsExt ; case eMessagesUnhandled : return _settingsExt ; case eGenericConfirm : return _settingsExt ; case eTranslation : return _translationExt ; case eConfigurationsLocale : return _settingsExt ; } return ""; } static QString path(Category_Enum vCategory) { switch (vCategory) { // NOTE: don't use default case case eSettingsSystem : return Storage::Settings_Path() ; case eInstructions : return Storage::Settings_Path() ; case eParametersDataList : return Storage::Settings_Path() ; case eAlarms : return Storage::Settings_Path() ; case eEvents : return Storage::Settings_Path() ; case eRejects : return Storage::Settings_Path() ; case eMessagesUnhandled : return Storage::Settings_Path() ; case eGenericConfirm : return Storage::Settings_Path() ; case eTranslation : return Storage::Translations_Path() ; case eConfigurationsLocale : return Storage::Configurations_Path() ; } return ""; } static QString category(Category_Enum vCategory) { switch (vCategory) { // NOTE: don't use default case case eSettingsSystem : return Storage::Settings_Category_SettingsSystem ; case eInstructions : return Storage::Settings_Category_Instructions ; case eParametersDataList : return Storage::Settings_Category_DataList ; case eAlarms : return Storage::Settings_Category_Alarms ; case eEvents : return Storage::Settings_Category_Events ; case eRejects : return Storage::Settings_Category_Rejects ; case eMessagesUnhandled : return Storage::Settings_Category_MessagesUnhandled ; case eGenericConfirm : return Storage::Settings_Category_GenericConfirm ; case eTranslation : return Storage::Settings_Category_Translation ; case eConfigurationsLocale : return Storage::Settings_Category_Locale ; } return ""; } static QString key(Key_Enum vKey) { switch (vKey) { // NOTE: don't use default case case eKeyTitle : return Storage::Settings_Key_Title ; case eKeyMessage : return Storage::Settings_Key_Message ; case eKeyListTitle : return Storage::Settings_Key_ListTitle ; case eKeyConfirm : return Storage::Settings_Key_Confirm ; case eKeyCancel : return Storage::Settings_Key_Cancel ; } return ""; } //Note: this funtion is specific to the settings and should not use the StorageGlobals function. static QString location(Location_Enum vLoc) { switch (vLoc) { // NOTE: don't use default case case eInit : return Storage::Settings_Path_Init; case eSecured : return Storage::Settings_Path_Name; } return Storage::Settings_Path_Name; } static bool isCategorySettingsSystem (const QString &vCategory) { return vCategory == category( eSettingsSystem ); } static bool isCategoryInstructions (const QString &vCategory) { return vCategory == category( eInstructions ); } static bool isCategoryParametersDataList (const QString &vCategory) { return vCategory == category( eParametersDataList ); } static bool isCategoryAlarms (const QString &vCategory) { return vCategory == category( eAlarms ); } static bool isCategoryEvents (const QString &vCategory) { return vCategory == category( eEvents ); } static bool isCategoryRejects (const QString &vCategory) { return vCategory == category( eRejects ); } static bool isCategoryMessagesUnhandled (const QString &vCategory) { return vCategory == category( eMessagesUnhandled ); } static bool isCategoryConfirm (const QString &vCategory) { return vCategory == category( eGenericConfirm ); } static bool isKeyTitle (const QString &vKey ) { return vKey == key ( eKeyTitle ); } static bool isKeyMessage (const QString &vKey ) { return vKey == key ( eKeyMessage ); } static bool isKeyListTitle (const QString &vKey ) { return vKey == key ( eKeyListTitle ); } static bool isKeyConfirm (const QString &vKey ) { return vKey == key ( eKeyConfirm ); } static bool isKeyCancel (const QString &vKey ) { return vKey == key ( eKeyCancel ); } private: // using the Category_Enum so have to be defined after. /*! * \brief Settings::fileName * \details returns the conf file by the settings information provided. * \param vCategory - the settings file category * \param vLocale - the settings file locale * \return QString configuration/settings file name */ static QString fileName ( Category_Enum vCategory ) { return QString("%1%2%4.%3").arg(path(vCategory)).arg(category(vCategory)).arg(extention(vCategory)).arg(locale(vCategory,true)); } static bool isCategoryWritable ( Category_Enum vCategory ) { const QVector mCategory_Writable { eSettingsSystem , eConfigurationsLocale , }; return mCategory_Writable.contains(vCategory); } static bool parse (const Detail &vDetail ); static int readCategory (Category_Enum vCategory ); static int configurationsPOST (Location_Enum vLoc = Location_Enum::eSecured) { Q_UNUSED(vLoc); return true; } }; }