]> vaikene.ee Git - evaf/blob - src/libs/Common/config.cpp
7ddc61ea9829b4270203fabfba61d143b0505abb
[evaf] / src / libs / Common / config.cpp
1 /**
2 * @file Common/config.cpp
3 * @brief eVaf configuration interface implementation
4 * @author Enar Vaikene
5 *
6 * Copyright (c) 2011-2019 Enar Vaikene
7 *
8 * This file is part of the eVaf C++ cross-platform application development framework.
9 *
10 * This file can be used under the terms of the GNU General Public License
11 * version 3.0 as published by the Free Software Foundation and appearing in
12 * the file LICENSE included in the packaging of this file. Please review the
13 * the following information to ensure the GNU General Public License version
14 * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
15 *
16 * Alternatively, this file may be used in accordance with the Commercial License
17 * Agreement provided with the Software.
18 */
19
20 #include "config.h"
21 #include "inifile.h"
22 #include "iregistry.h"
23 #include "ilogger.h"
24 #include "iapp.h"
25 #include "version.h"
26
27 #include <QtCore>
28
29 //-------------------------------------------------------------------
30
31 using namespace eVaf::Common;
32
33 namespace
34 {
35 static Internal::Config * singleton = nullptr;
36 }
37
38 iConfig * iConfig::instance()
39 {
40 if (nullptr == singleton)
41 {
42 singleton = new Internal::Config;
43 }
44 return singleton->_interface();
45 }
46
47
48 //-------------------------------------------------------------------
49
50 using namespace eVaf::Common::Internal;
51
52 void Config::destroyInstance()
53 {
54 if (nullptr != singleton)
55 {
56 delete singleton;
57 singleton = nullptr;
58 }
59 }
60
61 Config::Config()
62 : iConfig()
63 {
64 setObjectName(QString("%1.iConfig").arg(VER_MODULE_NAME_STR));
65
66 // Register the iConfig interface
67 iRegistry::instance()->registerInterface("iConfig", this);
68
69 EVAF_INFO("%s-Config created", VER_MODULE_NAME_STR);
70 }
71
72 Config::~Config()
73 {
74 done();
75 EVAF_INFO("%s-Config destroyed", VER_MODULE_NAME_STR);
76 }
77
78 iConfig * Config::_interface() const
79 {
80 return evafQueryInterface<iConfig>("iConfig");
81 }
82
83 bool Config::init()
84 {
85 // Finalize first in case this is not the first time init() is called
86 done();
87
88 return true;
89 }
90
91 void Config::done()
92 {
93 // Commit any queued parameters
94 commitValues();
95
96 // Clear the list of opened INI files
97 QHash<QString, IniFile *>::iterator it = mIniFiles.begin();
98 while (it != mIniFiles.end()) {
99 delete it.value();
100 it = mIniFiles.erase(it);
101 }
102 }
103
104 QVariant Config::getValue(QString const & paramName, QVariant const & defaultValue) const
105 {
106 // Get the optional file part
107 int idx = paramName.indexOf('/');
108 if (idx < 0) {
109 EVAF_ERROR("Invalid parameter name '%s'", qPrintable(paramName));
110 return defaultValue;
111 }
112 QString file = paramName.left(idx);
113 QString name = paramName.mid(idx + 1);
114
115 // Ignore the optional backend identifier in the file name
116 idx = file.indexOf(':');
117 if (idx >= 0)
118 file.remove(0, idx + 1);
119
120 // If the file name is empty or '*', use the application's name
121 if (file.isEmpty() || file == "*")
122 file = iApp::instance()->name();
123
124 IniFile * ini = nullptr;
125
126 // Is this INI file already opened?
127 QHash<QString, IniFile *>::const_iterator it = mIniFiles.constFind(file);
128
129 // The file is opened and we can reuse it
130 if (it != mIniFiles.constEnd()) {
131 ini = *it;
132 }
133
134 // The file is not opened
135 else {
136 ini = new IniFile(QString("%1/%2.ini").arg(iApp::instance()->etcDir()).arg(file));
137 if (!ini->isValid()) {
138 EVAF_ERROR("Failed to open '%s' : %s", qPrintable(name), qPrintable(ini->errorString()));
139 delete ini;
140 return defaultValue;
141 }
142 mIniFiles.insert(file, ini);
143 }
144
145 // Read the value
146 return ini->getValue(name.toLocal8Bit(), defaultValue);
147 }
148
149 bool Config::setValue(QString const & paramName, QVariant const & value, bool commit)
150 {
151 if (!commit) {
152 // Queue the write operation
153 mCommitQueue.enqueue(NameValuePair(paramName, value));
154 }
155 else {
156 // Commit any queued parameters
157 if (!commitValues())
158 return false;
159
160 // Write the parameter
161 if (!writeValue(paramName, value))
162 return false;
163 }
164
165 return true;
166 }
167
168 bool Config::commitValues()
169 {
170 while (!mCommitQueue.isEmpty()) {
171 if (!writeValue(mCommitQueue.dequeue())) {
172 mCommitQueue.clear();
173 return false;
174 }
175 }
176 return true;
177 }
178
179 bool Config::writeValue(QString const & paramName, QVariant const & value)
180 {
181 // Get the optional file part
182 int idx = paramName.indexOf('/');
183 if (idx < 0) {
184 EVAF_ERROR("Invalid parameter name '%s'", qPrintable(paramName));
185 return false;
186 }
187 QString file = paramName.left(idx);
188 QString name = paramName.mid(idx + 1);
189
190 // Ignore the optional backend identifier in the file name
191 idx = file.indexOf(':');
192 if (idx >= 0)
193 file.remove(0, idx + 1);
194
195 // If the file name is empty or '*', use the application's name
196 if (file.isEmpty() || file == "*")
197 file = iApp::instance()->name();
198
199 IniFile * ini = nullptr;
200
201 // Is this INI file already opened?
202 QHash<QString, IniFile *>::const_iterator it = mIniFiles.constFind(file);
203
204 // The file is opened and we can reuse it
205 if (it != mIniFiles.constEnd()) {
206 ini = *it;
207 }
208
209 // The file is not opened
210 else {
211 ini = new IniFile(QString("%1/%2.ini").arg(iApp::instance()->etcDir()).arg(file));
212 if (!ini->isValid()) {
213 EVAF_ERROR("Failed to open '%s' : %s", qPrintable(name), qPrintable(ini->errorString()));
214 delete ini;
215 return false;
216 }
217 mIniFiles.insert(file, ini);
218 }
219
220 // Write the value
221 if (!ini->setValue(name.toLocal8Bit(), value))
222 return false;
223
224 return true;
225 }