/** * @file Common/config.cpp * @brief eVaf configuration interface implementation * @author Enar Vaikene * * Copyright (c) 2011-2019 Enar Vaikene * * This file is part of the eVaf C++ cross-platform application development framework. * * This file can be used under the terms of the GNU General Public License * version 3.0 as published by the Free Software Foundation and appearing in * the file LICENSE included in the packaging of this file. Please review the * the following information to ensure the GNU General Public License version * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. * * Alternatively, this file may be used in accordance with the Commercial License * Agreement provided with the Software. */ #include "config.h" #include "inifile.h" #include "iregistry.h" #include "ilogger.h" #include "iapp.h" #include "version.h" #include //------------------------------------------------------------------- using namespace eVaf::Common; namespace { static Internal::Config * singleton = nullptr; } iConfig * iConfig::instance() { if (nullptr == singleton) { singleton = new Internal::Config; } return singleton->_interface(); } //------------------------------------------------------------------- using namespace eVaf::Common::Internal; void Config::destroyInstance() { if (nullptr != singleton) { delete singleton; singleton = nullptr; } } Config::Config() : iConfig() { setObjectName(QString("%1.iConfig").arg(VER_MODULE_NAME_STR)); // Register the iConfig interface iRegistry::instance()->registerInterface("iConfig", this); EVAF_INFO("%s-Config created", VER_MODULE_NAME_STR); } Config::~Config() { done(); EVAF_INFO("%s-Config destroyed", VER_MODULE_NAME_STR); } iConfig * Config::_interface() const { return evafQueryInterface("iConfig"); } bool Config::init() { // Finalize first in case this is not the first time init() is called done(); return true; } void Config::done() { // Commit any queued parameters commitValues(); // Clear the list of opened INI files QHash::iterator it = mIniFiles.begin(); while (it != mIniFiles.end()) { delete it.value(); it = mIniFiles.erase(it); } } QVariant Config::getValue(QString const & paramName, QVariant const & defaultValue) const { // Get the optional file part int idx = paramName.indexOf('/'); if (idx < 0) { EVAF_ERROR("Invalid parameter name '%s'", qPrintable(paramName)); return defaultValue; } QString file = paramName.left(idx); QString name = paramName.mid(idx + 1); // Ignore the optional backend identifier in the file name idx = file.indexOf(':'); if (idx >= 0) file.remove(0, idx + 1); // If the file name is empty or '*', use the application's name if (file.isEmpty() || file == "*") file = iApp::instance()->name(); IniFile * ini = nullptr; // Is this INI file already opened? QHash::const_iterator it = mIniFiles.constFind(file); // The file is opened and we can reuse it if (it != mIniFiles.constEnd()) { ini = *it; } // The file is not opened else { ini = new IniFile(QString("%1/%2.ini").arg(iApp::instance()->etcDir()).arg(file)); if (!ini->isValid()) { EVAF_ERROR("Failed to open '%s' : %s", qPrintable(name), qPrintable(ini->errorString())); delete ini; return defaultValue; } mIniFiles.insert(file, ini); } // Read the value return ini->getValue(name.toLocal8Bit(), defaultValue); } bool Config::setValue(QString const & paramName, QVariant const & value, bool commit) { if (!commit) { // Queue the write operation mCommitQueue.enqueue(NameValuePair(paramName, value)); } else { // Commit any queued parameters if (!commitValues()) return false; // Write the parameter if (!writeValue(paramName, value)) return false; } return true; } bool Config::commitValues() { while (!mCommitQueue.isEmpty()) { if (!writeValue(mCommitQueue.dequeue())) { mCommitQueue.clear(); return false; } } return true; } bool Config::writeValue(QString const & paramName, QVariant const & value) { // Get the optional file part int idx = paramName.indexOf('/'); if (idx < 0) { EVAF_ERROR("Invalid parameter name '%s'", qPrintable(paramName)); return false; } QString file = paramName.left(idx); QString name = paramName.mid(idx + 1); // Ignore the optional backend identifier in the file name idx = file.indexOf(':'); if (idx >= 0) file.remove(0, idx + 1); // If the file name is empty or '*', use the application's name if (file.isEmpty() || file == "*") file = iApp::instance()->name(); IniFile * ini = nullptr; // Is this INI file already opened? QHash::const_iterator it = mIniFiles.constFind(file); // The file is opened and we can reuse it if (it != mIniFiles.constEnd()) { ini = *it; } // The file is not opened else { ini = new IniFile(QString("%1/%2.ini").arg(iApp::instance()->etcDir()).arg(file)); if (!ini->isValid()) { EVAF_ERROR("Failed to open '%s' : %s", qPrintable(name), qPrintable(ini->errorString())); delete ini; return false; } mIniFiles.insert(file, ini); } // Write the value if (!ini->setValue(name.toLocal8Bit(), value)) return false; return true; }