]> vaikene.ee Git - evaf/blob - src/main/GUI/main.cpp
Added Plugin manager initialiation and loading/unloading plugins.
[evaf] / src / main / GUI / main.cpp
1 /**
2 * @file main/GUI/main.cpp
3 * @brief The main eVaf GUI application class
4 * @author Enar Vaikene
5 *
6 * Copyright (c) 2011 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 "main.h"
21 #include "exithandler.h"
22 #include "fatalerr.h"
23 //#include "version_p.h"
24 #include "version.h"
25
26 #ifdef Q_OS_WIN32
27 #include "winconsole.h"
28 #endif
29
30 #include <Common/Globals>
31 #include <Common/iLogger>
32 #include <Common/iEnv>
33 #include <Common/iApp>
34
35 #include <Plugins/PluginManager>
36
37 #include <QtGui>
38
39 #ifdef Q_OS_LINUX
40 # include <sys/types.h>
41 # include <unistd.h>
42 #endif
43
44
45 //-------------------------------------------------------------------
46
47 namespace eVaf {
48 namespace GUI {
49 namespace Internal {
50
51 /**
52 * Flag indicating that the application should be more verbose when dealing with fatal errors.
53 *
54 * If this flag is set, then shows fatal errors on the screen as dialog boxes and
55 * the user has to close them before terminating the application.
56 *
57 * If this flag is not set, then no messages are shown and the application terminates
58 * silently. Error messages are written only into the log file.
59 */
60 static bool BeVerbose = true;
61
62 #ifdef Q_OS_WIN32
63 /**
64 * Flag indicating that the application needs a console window.
65 *
66 * If this flag is set, opens an extra console window for message output.
67 */
68 static bool NeedsConsole = false;
69 #endif
70
71 /**
72 * Console severity level.
73 *
74 * This variable is used to set the console severity level. The severity level is changed
75 * with command-line arguments.
76 */
77 static eVaf::Common::iLogger::Severity ConsoleSeverityLevel = eVaf::Common::iLogger::Fatal;
78
79 /**
80 * Qt message handler replacement.
81 * @param type Type of the message
82 * @param msg The message
83 *
84 * This function outputs messages to the console and to the log file.
85 */
86 static void messageOutput(QtMsgType type, char const * const msg)
87 {
88 static bool inHandler = false;
89
90 // Avoid recursions in case outputting a message causes another message to be output
91 if (inHandler)
92 return;
93 inHandler = true;
94
95 // Qt message type conversion to eVaf logger severity levels
96 eVaf::Common::iLogger::Severity v;
97 switch (type) {
98 case QtWarningMsg:
99 v = eVaf::Common::iLogger::Warning;
100 break;
101 case QtCriticalMsg:
102 v = eVaf::Common::iLogger::Error;
103 break;
104 case QtFatalMsg:
105 v = eVaf::Common::iLogger::Fatal;
106 break;
107 default:
108 v = eVaf::Common::iLogger::Debug;
109 }
110
111 // Output to the log file and console
112 eVaf::Common::iLogger::instance()->write(v, msg);
113
114 inHandler = false;
115 }
116
117 /**
118 * Fatal error message handler
119 * @param msg The error message
120 * @param source Source of the message
121 * @param where Where the error occurred
122 *
123 * This function shows a critical error message box on the screen if needed and then terminates
124 * the application.
125 *
126 * If the critical error message is shown, then the user has an option to ignore the error. In this
127 * case the application is not terminated.
128 */
129 static void fatalMsgHandler(QString const & msg, QString const & source, QString const & where)
130 {
131 // Show the message on the screen
132 if (BeVerbose) {
133 if (FatalErr::message(QObject::tr("Fatal Error"),
134 QObject::tr("%1\n\nOccurred in '%2'")
135 .arg(msg)
136 .arg(where),
137 0) == FatalErr::Ignore)
138 return;
139 }
140 #ifdef Q_OS_LINUX
141 abort();
142 #else
143 exit(1);
144 #endif
145 }
146
147 } // namespace eVaf::GUI::Internal
148 } // namespace eVaf::GUI
149 } // namespace eVaf
150
151
152 //-------------------------------------------------------------------
153
154 using namespace eVaf;
155 using namespace eVaf::GUI;
156
157 Application::Application(int & argc, char ** argv)
158 : QApplication(argc, argv)
159 {
160 setObjectName(QString("%1-%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
161
162 EVAF_INFO("%s version %s created", qPrintable(objectName()), VER_FILE_VERSION_STR);
163 }
164
165 Application::~Application()
166 {
167 EVAF_INFO("%s destroyed", qPrintable(objectName()));
168 }
169
170 bool Application::processCommandLine(int argc, char ** argv)
171 {
172 QStringList args;
173 for (int i = 1; i < argc; ++i)
174 args += argv[i];
175
176 for (int i = 0; i < args.size(); ++i) {
177 // Get the argument and optional value
178 QStringList arg = args.at(i).simplified().split(QChar('='));
179
180 if (QRegExp("(-[-]?version)|([-//]V)").exactMatch(arg.at(0))) {
181 printVersion();
182 return false;
183 }
184 else if (QRegExp("(-[-]?help)|([-//][h/?])").exactMatch(arg.at(0))) {
185 printHelp();
186 return false;
187 }
188 else if (QRegExp("-[-]?help-qt").exactMatch(arg.at(0))) {
189 printQtHelp();
190 return false;
191 }
192 else if (QRegExp("-[-]?verbose").exactMatch(arg.at(0)) && arg.size() > 1) {
193 #ifdef Q_OS_WIN32
194 Internal::NeedsConsole = true;
195 #endif
196 QString v = arg.at(1).toLower();
197 if (v == "debug")
198 Internal::ConsoleSeverityLevel = Common::iLogger::Debug;
199 else if (v == "info")
200 Internal::ConsoleSeverityLevel = Common::iLogger::Info;
201 else if (v == "warning")
202 Internal::ConsoleSeverityLevel = Common::iLogger::Warning;
203 else if (v == "error")
204 Internal::ConsoleSeverityLevel = Common::iLogger::Error;
205 else if (v == "fatal")
206 Internal::ConsoleSeverityLevel = Common::iLogger::Fatal;
207 else if (v == "none") {
208 Internal::ConsoleSeverityLevel = Common::iLogger::None;
209 Internal::BeVerbose = false;
210 #ifdef Q_OS_WIN32
211 Internal::NeedsConsole = false;
212 #endif
213 }
214 else {
215 printHelp();
216 return false;
217 }
218 }
219 else if (QRegExp("-[v]+").exactMatch(arg.at(0)) && arg.size() == 1) {
220 // The number of 'v's increases the verbosity
221 for (int j = 1; j < arg.at(0).size(); ++j) {
222 switch (Internal::ConsoleSeverityLevel) {
223 case Common::iLogger::None:
224 Internal::ConsoleSeverityLevel = Common::iLogger::Fatal;
225 break;
226 case Common::iLogger::Fatal:
227 Internal::ConsoleSeverityLevel = Common::iLogger::Error;
228 break;
229 case Common::iLogger::Error:
230 Internal::ConsoleSeverityLevel = Common::iLogger::Warning;
231 break;
232 case Common::iLogger::Warning:
233 Internal::ConsoleSeverityLevel = Common::iLogger::Info;
234 break;
235 case Common::iLogger::Info:
236 Internal::ConsoleSeverityLevel = Common::iLogger::Debug;
237 break;
238 case Common::iLogger::Debug:
239 break;
240 }
241 }
242 }
243 }
244
245 return true;
246 }
247
248 void Application::printHelp()
249 {
250 char const * const txt = QT_TR_NOOP(
251 "Usage: eVafGUI [options]\n"
252 "\n"
253 // General options
254 " -help Shows this help and quits.\n"
255 " -help-qt Shows Qt command line options and quits.\n"
256 " -version Shows version information and quits.\n"
257 " -verbose=LEVEL Specifies the verbose level. LEVEL can be one of the\n"
258 " following: NONE, FATAL, ERROR, WARNING, INFO, DEBUG.\n"
259 " -v Makes the application more verbose. Can be repeated for\n"
260 " more verbosity.\n"
261 // Handled by the iApp interface implementation
262 " -appl[ication]=NAME Specifies the name of the application.\n"
263 " -lang[uage]=xx[_CC] Specifies the language, where xx is the ISO 639\n"
264 " language code followed by an optional ISO 3166 country\n"
265 " code.\n"
266 // Handled by the iEnv interface implementation
267 " -root[dir]=DIR Specifies the application's root directory.\n"
268 " -dataroot[dir]=DIR Specifies the data root directory.\n"
269 " -etc[dir]=DIR Specifies the configuration files directory.\n"
270 " -log[dir]=DIR Specifies the log files directory.\n"
271 " -doc[dir]=DIR Specifies the documentation directory.\n"
272 " -qtplugins[dir]=DIR Specifies the Qt plugins directory.\n"
273 );
274 ::fputs(tr(txt).toLocal8Bit().constData(), stdout);
275 }
276
277 void Application::printQtHelp()
278 {
279 // Cannot translate this text as QT_TR_NOOP() is not able to process #ifdef parts.
280 char const * const txt =
281 #ifdef QT_DEBUG
282 "Qt debugging options:\n"
283 " -nograb tells Qt that it must never grab the mouse or the keyboard.\n"
284 #ifdef Q_OS_UNIX
285 " -dograb running under a debugger can cause an implicit -nograb,\n"
286 " use -dograb to override.\n"
287 " -sync switches to synchronous mode for debugging.\n\n"
288 #endif
289 #endif
290 "Qt common options:\n"
291 " -style=STYLE sets the application GUI style. Possible values are motif,\n"
292 " windows, and platinum.\n"
293 " -style STYLE is the same as listed above.\n"
294 " -stylesheet=STYLESHEET sets the application style sheet.\n"
295 " -stylesheet STYLESHEET is the same as listed above.\n"
296 " -session=SESSION restores the application from an earlier session.\n"
297 " -session SESSION is the same as listed above.\n"
298 " -widgetcount prints debug message at the end about number of widgets\n"
299 " left undestroyed and maximum number of widgets existed at\n"
300 " the same time.\n"
301 " -reverse sets the application's layout direction to Qt::RightToLeft\n\n"
302 #ifdef Q_OS_WIN32
303 "Qt options on Windows:\n"
304 " -direct3d will make the Direct3D paint engine the default widget\n"
305 " paint engine in Qt.\n\n"
306 #endif
307 #ifdef Q_WS_X11
308 "Qt options on X11:\n"
309 " -display DISPLAY sets the X display.\n"
310 " -geometry GEOMETRY sets the client geometry of the first window that is\n"
311 " shown.\n"
312 " -fn or -font FONT defines the application font.\n"
313 " -bg or -background COLOR sets the default background color and an\n"
314 " application palette.\n"
315 " -fg or -foreground COLOR sets the default foreground color.\n"
316 " -btn or -button COLOR sets the default button color.\n"
317 " -name NAME sets the application name.\n"
318 " -title TITLE sets the application title.\n"
319 " -visual TrueColor forces the application to use a TrueColor visual on an\n"
320 " 8-bit display.\n"
321 " -ncols COUNT limits the number of colors allocated in the color cube on\n"
322 " an 8-bit display, if the application is using the\n"
323 " QApplication::ManyColor color specification. If COUNT is\n"
324 " 216 then a 6x6x6 color cube is used (i.e. 6 levels of red,\n"
325 " 6 of green, and 6 of blue); for other values, a cube\n"
326 " approximately proportional to a 2x3x1 cube is used.\n"
327 " -cmap causes the application to install a private color map on an\n"
328 " 8-bit display.\n"
329 " -im sets the input method server (equivalent to setting the\n"
330 " XMODIFIERS environment variable).\n"
331 " -noxim disables the input method framework (\"no X input method\").\n"
332 " -inputstyle defines how the input is inserted into the given widget.\n"
333 " E.g., onTheSpot makes the input appear directly in the\n"
334 " widget, while overTheSpot makes the input appear in a box\n"
335 " floating over the widget and is not inserted until the\n"
336 " editing is done.\n"
337 #endif
338 ;
339 ::fputs(txt, stdout);
340 }
341
342 void Application::printVersion()
343 {
344 ::printf("%s version %s release date %s, %s version %s\n",
345 VER_PRODUCT_NAME_STR,
346 VER_PRODUCT_VERSION_STR,
347 VER_PRODUCT_DATE_STR,
348 VER_MODULE_NAME_STR,
349 VER_FILE_VERSION_STR
350 );
351 }
352
353
354 //-------------------------------------------------------------------
355
356 int main(int argc, char ** argv)
357 {
358 Common::iLogger::instance()->setSeverity(Common::iLogger::Warning);
359
360 // Install our own message handlers
361 Common::iLogger::instance()->installFatalMsgHandler(Internal::fatalMsgHandler);
362 qInstallMsgHandler(Internal::messageOutput);
363
364 // Process command-line arguments
365 if (!Application::processCommandLine(argc, argv))
366 return 1;
367
368 // Set the console severity
369 Common::iLogger::instance()->setConsoleSeverity(Internal::ConsoleSeverityLevel);
370
371 #ifdef Q_OS_WIN32
372 // Enable the extra message console on Windows
373 if (Internal::NeedsConsole)
374 Internal::enableWinConsole();
375 #endif
376
377 EVAF_INFO("%s version %s release date %s, %s version %s",
378 VER_PRODUCT_NAME_STR,
379 VER_PRODUCT_VERSION_STR,
380 VER_PRODUCT_DATE_STR,
381 VER_MODULE_NAME_STR,
382 VER_FILE_VERSION_STR);
383
384 #ifdef Q_OS_LINUX
385 EVAF_INFO("%s application pid = %d", VER_MODULE_NAME_STR, getpid());
386 #endif
387
388 Application app(argc, argv);
389
390 // Install the exit handler
391 if (!Internal::installExitHandler())
392 return 1;
393
394 // Plugin manager
395 Plugins::PluginManager pluginManager;
396
397 // The main run loop
398 bool quit = false;
399 int rval;
400 while (!quit) {
401
402 EVAF_INFO("%s is starting up", VER_MODULE_NAME_STR);
403
404 // Initialize the common library
405 if (!Common::init())
406 return 1;
407
408 // Initialize the plugin manager and load plugins
409 if (!pluginManager.init())
410 return 1;
411
412 // Run the application
413 EVAF_INFO("Running %s", VER_MODULE_NAME_STR);
414 rval = app.exec();
415
416 quit = rval != Common::iApp::RC_Restart;
417
418 EVAF_INFO("%s is %s", VER_MODULE_NAME_STR, quit ? "exiting" : "restarting");
419
420 // Unload plugins and finalize the plugin manager
421 pluginManager.done();
422 }
423
424 EVAF_INFO("%s exit with code %d", VER_MODULE_NAME_STR, rval);
425
426 return rval;
427 }