]> vaikene.ee Git - evaf/blob - src/libs/Common/app.cpp
Mac OS changes and switched to c++11.
[evaf] / src / libs / Common / app.cpp
1 /**
2 * @file Common/app.cpp
3 * @brief Application 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 "app.h"
21 #include "globals.h"
22 #include "iregistry.h"
23 #include "ieventqueue.h"
24 #include "event.h"
25 #include "version.h"
26
27 #include <QtCore>
28
29
30 //-------------------------------------------------------------------
31
32 using namespace eVaf::Common;
33
34 namespace
35 {
36 static Internal::App * singleton = nullptr;
37 }
38
39 iApp * iApp::instance()
40 {
41 if (nullptr == singleton)
42 {
43 singleton = new Internal::App;
44 }
45 return singleton;
46 }
47
48 char const * const iApp::EV_QUIT = "iApp::quit";
49 char const * const iApp::EV_RESTART = "iApp::restart";
50 char const * const iApp::EV_READY = "iApp::ready";
51 char const * const iApp::EV_TERMINATING = "iApp::terminating";
52
53
54 //-------------------------------------------------------------------
55
56 using namespace eVaf::Common::Internal;
57
58 void App::destroyInstance()
59 {
60 if (nullptr != singleton)
61 {
62 delete singleton;
63 singleton = nullptr;
64 }
65 }
66
67 App::App()
68 : iApp()
69 , mReady(false)
70 , mName(VER_PRODUCT_NAME_STR)
71 , mEvQuit(0)
72 , mEvRestart(0)
73 , mEvReady(0)
74 , mEvTerminating(0)
75 {
76 setObjectName(QString("%1.iApp").arg(VER_MODULE_NAME_STR));
77 EVAF_INFO("%s-App created", VER_MODULE_NAME_STR);
78 }
79
80 App::~App()
81 {
82 EVAF_INFO("%s-App destroyed", VER_MODULE_NAME_STR);
83 }
84
85 bool App::init()
86 {
87 // Register our interface
88 iRegistry::instance()->registerInterface("iApp", this);
89
90 // Register events
91 mEvQuit = iEventQueue::instance()->subscribeEvent(iEventQueue::instance()->registerEvent(EV_QUIT), this);
92 mEvRestart = iEventQueue::instance()->subscribeEvent(iEventQueue::instance()->registerEvent(EV_RESTART), this);
93 mEvReady = iEventQueue::instance()->registerEvent(EV_READY);
94 mEvTerminating = iEventQueue::instance()->registerEvent(EV_TERMINATING);
95
96 // Set the default application name and language
97 mName = VER_PRODUCT_NAME_STR;
98 mLanguage = QLocale::system().name();
99
100 // Clear the XML file name
101 mXmlFile.clear();
102
103 // Set initial bin and root directories
104 mRootDir = mBinDir = qApp->applicationDirPath();
105 int t = mBinDir.lastIndexOf(QChar('/'), -1);
106 if (t >= 0)
107 mRootDir = mBinDir.left(t);
108
109 if (!mBinDir.endsWith('/'))
110 mBinDir.append('/');
111 if (!mRootDir.endsWith('/'))
112 mRootDir.append('/');
113
114 // Clear other directories
115 mDataRootDir.clear();
116 mQtPluginsDir.clear();
117 mEtcDir.clear();
118 mLogDir.clear();
119 mDocDir.clear();
120
121 // Process environment variables
122 QStringList env = QProcess::systemEnvironment();
123 for (int i = 0; i < env.size(); ++i) {
124 // Get the name/value pair
125 QString name = env.at(i).section('=', 0, 0).trimmed();
126 QString value = env.at(i).section('=', 1).trimmed();
127
128 if (name == "EVAF_APP_NAME")
129 mName = value;
130 else if (name == "EVAF_LANGUAGE")
131 mLanguage = value;
132 else if (name == "EVAF_ROOT_DIR") {
133 mRootDir = value;
134 if (!mRootDir.endsWith('/'))
135 mRootDir.append('/');
136 }
137 else if (name == "EVAF_DATA_ROOT_DIR") {
138 mDataRootDir = value;
139 if (!mDataRootDir.endsWith('/'))
140 mDataRootDir.append('/');
141 }
142 else if (name == "EVAF_ETC_DIR") {
143 mEtcDir = value;
144 if (!mEtcDir.endsWith('/'))
145 mEtcDir.append('/');
146 }
147 else if (name == "EVAF_LOG_DIR") {
148 mLogDir = value;
149 if (!mLogDir.endsWith('/'))
150 mLogDir.append('/');
151 }
152 else if (name == "EVAF_DOC_DIR") {
153 mDocDir = value;
154 if (!mDocDir.endsWith('/'))
155 mDocDir.append('/');
156 }
157 else if (name == "EVAF_QT_PLUGINS_DIR") {
158 mQtPluginsDir = value;
159 if (!mQtPluginsDir.endsWith('/'))
160 mQtPluginsDir.append('/');
161 }
162 }
163
164 // Then process command-line arguments
165 env = QCoreApplication::arguments();
166 for (int i = 0; i < env.size(); ++i) {
167 // Get the name and optional value
168 QStringList arg = env.at(i).simplified().split('=');
169
170 if (QRegExp("-[-]?app(lication)?").exactMatch(arg.at(0)) && arg.size() > 1)
171 mName = arg.at(1);
172 else if (QRegExp("-[-]?lang(uage)?").exactMatch(arg.at(0)) && arg.size() > 1)
173 mLanguage = arg.at(1);
174 else if (QRegExp("-[-]?root(dir)?").exactMatch(arg.at(0)) && arg.size() > 1) {
175 mRootDir = arg.at(1);
176 if (!mRootDir.endsWith('/'))
177 mRootDir.append('/');
178 }
179 else if (QRegExp("-[-]?dataroot(dir)?").exactMatch(arg.at(0)) && arg.size() > 1) {
180 mDataRootDir = arg.at(1);
181 if (!mDataRootDir.endsWith('/'))
182 mDataRootDir.append('/');
183 }
184 else if (QRegExp("-[-]?etc(dir)?").exactMatch(arg.at(0)) && arg.size() > 1) {
185 mEtcDir = arg.at(1);
186 if (!mEtcDir.endsWith('/'))
187 mEtcDir.append('/');
188 }
189 else if (QRegExp("-[-]?log(dir)?").exactMatch(arg.at(0)) && arg.size() > 1) {
190 mLogDir = arg.at(1);
191 if (!mLogDir.endsWith('/'))
192 mLogDir.append('/');
193 }
194 else if (QRegExp("-[-]?doc(dir)?").exactMatch(arg.at(0)) && arg.size() > 1) {
195 mDocDir = arg.at(1);
196 if (!mDocDir.endsWith('/'))
197 mDocDir.append('/');
198 }
199 else if (QRegExp("-[-]?qtplugins(dir)?").exactMatch(arg.at(0)) && arg.size() > 1) {
200 mQtPluginsDir = arg.at(1);
201 if (!mQtPluginsDir.endsWith('/'))
202 mQtPluginsDir.append('/');
203 }
204 }
205
206 return true;
207 }
208
209 bool App::event(QEvent * e)
210 {
211 if (e->type() == Event::eVafEvent) {
212 Event * event = static_cast<Event *>(e);
213 if (event->id() == mEvQuit)
214 quit();
215 else if (event->id() == mEvRestart)
216 restart();
217
218 return false;
219 }
220 else
221 return iApp::event(e);
222 }
223
224 QString const App::dataRootDir() const
225 {
226 if (mDataRootDir.isEmpty()) {
227 #if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
228 QString dataLoc = QDir::homePath();
229 if (!dataLoc.endsWith('/'))
230 dataLoc.append('/');
231 dataLoc.append(".local/share/data/");
232 mDataRootDir = dataLoc + name();
233 if (!mDataRootDir.endsWith('/'))
234 mDataRootDir.append('/');
235 #endif
236 /// @TODO: Needs local data directory on Windows
237 mDataRootDir = rootDir();
238 }
239
240 return mDataRootDir;
241 }
242
243 QString const App::etcDir() const
244 {
245 if (mEtcDir.isEmpty())
246 mEtcDir = dataRootDir() + "etc/";
247 return mEtcDir;
248 }
249
250 QString const App::logDir() const
251 {
252 if (mLogDir.isEmpty())
253 mLogDir = dataRootDir() + "log/";
254 return mLogDir;
255 }
256
257 QString const App::docDir() const
258 {
259 if (mDocDir.isEmpty())
260 mDocDir = rootDir() + "doc/";
261 return mDocDir;
262 }
263
264 QString const App::qtPluginsDir() const
265 {
266 if (mQtPluginsDir.isEmpty())
267 mQtPluginsDir = binDir();
268 return mQtPluginsDir;
269 }
270
271 QString const App::xmlFileName() const
272 {
273 if (mXmlFile.isEmpty()) {
274 QFileInfo fi;
275
276 // Try the full application name + country + language combination
277 QString name = mName + "_" + mLanguage + ".xml";
278 fi.setFile(etcDir() + name);
279 if (fi.isReadable())
280 mXmlFile = name;
281 else {
282 // Try application name + country
283 name = mName + "_" + mLanguage.left(2) + ".xml";
284 fi.setFile(etcDir() + name);
285 if (fi.isReadable())
286 mXmlFile = name;
287 else
288 // Fall-back to the generic name
289 mXmlFile = mName + ".xml";
290 }
291 }
292 return mXmlFile;
293 }
294
295 int App::exec()
296 {
297 setReady(true);
298 int rval = QCoreApplication::exec();
299 setReady(false);
300 return rval;
301 }
302
303 void App::restart()
304 {
305 QCoreApplication::exit(RC_Restart);
306 }
307
308 void App::quit(bool err)
309 {
310 QCoreApplication::exit(err ? RC_Error : RC_Quit);
311 }
312
313 void App::setReady(bool value)
314 {
315 if (mReady != value) {
316 mReady = value;
317 iEventQueue::instance()->broadcastEvent(new Event(mReady ? mEvReady : mEvTerminating));
318 if (mReady)
319 emit ready();
320 else
321 emit terminating();
322 }
323 }