/*! * * 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.cpp * \author (last) Behrouz NematiPour * \date (last) 08-Aug-2023 * \author (original) Behrouz NematiPour * \date (original) 29-Mar-2021 * */ // Qt #include #include #include // Project #include "StorageGlobals.h" #include "FileHandler.h" #include "MSettings.h" #include "Logger.h" // namespace using namespace Storage; #include "Settings.h" bool Settings::exists(const QString &vSettingFile) { int err = Settings::Settings_Error::eError_None; if (! QFileInfo::exists(vSettingFile)) { err = Settings::Settings_Error::eError_SettingNotExists; LOG_DEBUG(errorMessage(err).arg(vSettingFile)); return false; } return true; } /*! * \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 */ QString Settings::fileName(const QString &vCategory, const QString &vLocale) { return QString("%1%2%4.%3").arg(Storage::Settings_Path()).arg(vCategory).arg(_settingsExt).arg(vLocale.trimmed().isEmpty() ? "" : _settingsLocalSeparator + vLocale); } /*! * \brief Settings::doRead * \details Reads all the configuration files * \return non-zero, error value on error, and zero on success. */ int Settings::read() { int err = Settings::Settings_Error::eError_None; QFileInfo mSettingFile; QString mCategory; for ( quint8 i = 0; i <= _categoryCount; i++ ) { mCategory = category(static_cast(i)); switch (i) { // NOTE: don't use default case case eSettingsSystem : case eMessagesUnhandled : mSettingFile.setFile(fileName(mCategory, "")); // FALLTHROUGH break; case eInstructions : case eConfigurationsDataList : case eAlarms : case eEvents : case eRejects : case eGenericConfirm : mSettingFile.setFile(fileName(mCategory, _Settings.systemLocale())); // FALLTHROUGH break; } if (! exists(mSettingFile.absoluteFilePath())) continue; // error handling is done in exists(), so just continue. QFile file(mSettingFile.absoluteFilePath()); if (! file.open(QIODevice::ReadOnly | QIODevice::Text)) { err = Settings::Settings_Error::eError_Read; LOG_APPED_PO(errorMessage(err).arg(Storage::Settings_Path())); return err; } Detail detail; detail.content = file.readAll().trimmed(); if (detail.content.isEmpty()) { //TODO Do not error out for now, the list of the config files which can be empty or not needs to be defined. // err = Settings::Settings_Error::eError_Empty; LOG_APPED_PO(errorMessage(Settings::Settings_Error::eError_Empty).arg(mSettingFile.fileName())); continue; } detail.location = mSettingFile.absolutePath() + "/"; detail.category = mCategory; if ( ! parse(detail) ) { LOG_DEBUG( (QString("Configuration file '%1' failed to load").arg(mSettingFile.fileName())) ); } else { LOG_DEBUG( (QString("Configuration file '%1' successfully loaded").arg(mSettingFile.fileName())) ); } } return err; } /*! * \brief Settings::parse * \details The function to parse the content of the conf file and fill in the Settings model. * \param vDetail - the conf file detail has been read. * \return bool - true on success. */ bool Settings::parse(const Detail &vDetail) { bool enableDuplicateKey = false; QString attribute = QString("%1%2").arg(_config_attribute_tag); QString group = ""; QStringList lines = vDetail.content.split('\n'); for (QString line : lines) { // ----- trim the line line = line.trimmed(); // ----- ignore empty lines if ( line.isEmpty() ) continue; // ----- find comments int commentPosition = line.indexOf('#'); // ----- ignore comment line or find attributes if ( commentPosition == 0 ) { // ----- find the configuration file attribute int attributeTagPosition = line.indexOf(_config_attribute_tag); if ( attributeTagPosition == 0 ) { // ----- find the attribute : duplicate_key_... if ( line == attribute.arg( _duplicate_key_on ) ) { enableDuplicateKey = true ;} else if ( line == attribute.arg(_duplicate_key_off ) ) { enableDuplicateKey = false ;} else { LOG_APPED_PO(( "Unknown '" + line + "' attribute in %1").arg(vDetail.category)); return false; } } // next line continue; } // ----- remove inline comment if ( commentPosition > 0 ) line.truncate(commentPosition); line = line.trimmed(); // ----- find group if (line.startsWith("[") && line.endsWith("]")) { line.replace("[","").replace("]", ""); group = line; } else { if ( group.isEmpty() ) { continue; } else { if ( ! line.isEmpty() ) { QString key = ""; QString value = ""; if ( line.contains('=') ) { QStringList keyValue = line.split('='); key = keyValue[0].trimmed().replace("\\n","\n"); value = keyValue[1].trimmed().replace("\\n","\n"); } else { key = line; } _Settings.add(vDetail.category, group, key, QVariant(value), enableDuplicateKey); // DEBUG: qDebug() << group << key << value << location << category; } } } // DEBUG: qDebug() << group << line; } return true; } /*! * \brief Settings::save * \details Writes the setting in the configuration files * \return */ int Settings::saveSystem(const QString &vGroup, const QString &vKey, const QString &vValue) { // qDebug() << vCategory // << vGroup // << vKey // << vValue; QString mCategory = Storage::Settings_Category_SettingsSystem; QString mFileName = fileName(mCategory, ""); QString mContent; int err = Settings_Error::eError_None; // -------------------------------------------------------------------------------------------------------------- //Note: the configuration files which can be saved, are like settings and should not have duplicate values. // as an example the Alarm volume can't have two separate duplicate entry in the settings. // -------------------------------------------------------------------------------------------------------------- _Settings.add(mCategory, vGroup, vKey, vValue, false); QString mPath = QFileInfo(mFileName).absolutePath(); if ( mPath.trimmed().isEmpty() ) { err = Settings_Error::eError_PathEmpty; LOG_DEBUG(errorMessage(err)); return err; } if ( ! FileHandler::makeFolder(mPath) ) { err = Settings_Error::eError_MkDir; LOG_DEBUG(errorMessage(err).arg(mPath)); return err; } for ( const auto &group : _Settings.groups(mCategory) ) { mContent += QString("\n[%1]\n").arg(group); for ( const auto &key : _Settings.keys(mCategory, group) ) { mContent += QString("%1 = %2\n").arg(key).arg(_Settings.value(mCategory, group, key).toString()); } } if ( ! FileHandler::write(mFileName,mContent, false) ) { err = Settings_Error::eError_Write; LOG_DEBUG(errorMessage(err).arg(mFileName)); return err; } return err; } /*! * \brief Settings::configurationsMove * \details After the encrypted partition is ready the configuration files are moved from the root home to denali home. * \param vMessage * \return */ int Settings::configurationsMove(QString *vMessage, bool vIsUpdate) { int err = Settings_Error::eError_None ; Location_Enum loc = Location_Enum ::eInit ; QString src = Settings::location(Location_Enum ::eInit ); QString dst = Settings::location(Location_Enum ::eSecured ); QString msg = ""; QStringList lstExclude; if ( vIsUpdate ) { lstExclude << QFileInfo( src + Storage::Settings_Category_SettingsSystem ).absolutePath(); } if ( ! Settings ::configurationsPOST(loc )) { err = Settings_Error::eError_Remove; msg = errorMessage(err ); LOG_DEBUG(msg); goto lOut; } if ( ! FileHandler ::makeFolder ( dst )) { err = Settings_Error::eError_Copy ; msg = errorMessage(err ); LOG_DEBUG(msg); goto lOut; } for( QString dir : FileHandler::subFolders(src)) { QString sub = src + dir; if ( ! lstExclude.contains( sub ) ) { if ( FileHandler ::copyFolder (sub, dst )) { err = Settings_Error::eError_MkDir ; msg = errorMessage(err, dir); LOG_DEBUG(msg); goto lOut; } } if ( FileHandler ::removeFolder (sub )) { err = Settings_Error::eError_POST ; msg = errorMessage(err, dir); LOG_DEBUG(msg); goto lOut; } } Storage::Settings_Secured(); lOut: if ( vMessage ) { *vMessage = msg; } return err; } /*! * \brief Settings::loadTranslation * \return */ int Settings::loadTranslation() { int err = Settings_Error::eError_None; QString qmFile; bool ok = true; // QString mCategory = Storage::Settings_Category_SettingsSystem; // QString mLanguage = ""; // mLanguage = _Settings.value(mCategory, "Localization", "Language").toString(); // if ( mLanguage.isEmpty() ) { // qDebug() << __FUNCTION__ << ":" << __LINE__ << "-------------Could Not Find the Language"; // } // else { // qDebug() << __FUNCTION__ << ":" << __LINE__ << "-------------mLanguage:" << mLanguage; // } // QLocale::setDefault(QLocale::German); QString locale = _Settings.systemLocale(); if( locale.isEmpty()) { err = Settings_Error::eError_No_SettingsLocale; qDebug() << __FUNCTION__ << ":" << __LINE__ << "-------------Could Not Find the Language"; LOG_DEBUG(errorMessage(err)); // goto lOut; } qmFile = QString("%1%2%4.%3") .arg(Storage::Settings_Path()) .arg(Storage::Settings_Category_Translation) .arg("qm") .arg(_settingsLocalSeparator + QString("es")); // locale); qDebug() << __FUNCTION__ << ":" << __LINE__ << "-------------qmFile:" << qmFile; ok = _translator.load(qmFile); if ( ! ok) { qDebug() << __FUNCTION__ << ":" << __LINE__ << "-------------FAILED"; err = Settings_Error::eError_SettingNotExists; goto lOut; } QApplication::installTranslator(&_translator); lOut: return err; }