/** * @file main/GUI/main.cpp * @brief The main eVaf GUI application class * @author Enar Vaikene * * Copyright (c) 2011 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 "main.h" #include "exithandler.h" #include "fatalerr.h" //#include "version_p.h" #include "version.h" #ifdef Q_OS_WIN32 #include "winconsole.h" #endif #include #include #include #include #include #ifdef Q_OS_LINUX # include # include #endif //------------------------------------------------------------------- namespace eVaf { namespace GUI { namespace Internal { /** * Flag indicating that the application should be more verbose when dealing with fatal errors. * * If this flag is set, then shows fatal errors on the screen as dialog boxes and * the user has to close them before terminating the application. * * If this flag is not set, then no messages are shown and the application terminates * silently. Error messages are written only into the log file. */ static bool BeVerbose = true; #ifdef Q_OS_WIN32 /** * Flag indicating that the application needs a console window. * * If this flag is set, opens an extra console window for message output. */ static bool NeedsConsole = false; #endif /** * Console severity level. * * This variable is used to set the console severity level. The severity level is changed * with command-line arguments. */ static eVaf::Common::iLogger::Severity ConsoleSeverityLevel = eVaf::Common::iLogger::Fatal; /** * Qt message handler replacement. * @param type Type of the message * @param msg The message * * This function outputs messages to the console and to the log file. */ static void messageOutput(QtMsgType type, QMessageLogContext const &, QString const & msg) { static bool inHandler = false; // Avoid recursions in case outputting a message causes another message to be output if (inHandler) return; inHandler = true; // Qt message type conversion to eVaf logger severity levels eVaf::Common::iLogger::Severity v; switch (type) { case QtWarningMsg: v = eVaf::Common::iLogger::Warning; break; case QtCriticalMsg: v = eVaf::Common::iLogger::Error; break; case QtFatalMsg: v = eVaf::Common::iLogger::Fatal; break; default: v = eVaf::Common::iLogger::Debug; } // Output to the log file and console eVaf::Common::iLogger::instance()->write(v, msg); inHandler = false; } /** * Fatal error message handler * @param msg The error message * @param source Source of the message * @param where Where the error occurred * * This function shows a critical error message box on the screen if needed and then terminates * the application. * * If the critical error message is shown, then the user has an option to ignore the error. In this * case the application is not terminated. */ static void fatalMsgHandler(QString const & msg, QString const & source, QString const & where) { // Show the message on the screen if (BeVerbose) { if (FatalErr::message(QObject::tr("Fatal Error"), QObject::tr("%1\n\nOccurred in '%2'") .arg(msg) .arg(where), 0) == FatalErr::Ignore) return; } #ifdef Q_OS_LINUX abort(); #else exit(1); #endif } } // namespace eVaf::GUI::Internal } // namespace eVaf::GUI } // namespace eVaf //------------------------------------------------------------------- using namespace eVaf; using namespace eVaf::GUI; Application::Application(int & argc, char ** argv) : QApplication(argc, argv) { setObjectName(QString("%1-%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__)); EVAF_INFO("%s version %s created", qPrintable(objectName()), VER_FILE_VERSION_STR); } Application::~Application() { EVAF_INFO("%s destroyed", qPrintable(objectName())); } bool Application::processCommandLine(int argc, char ** argv) { QStringList args; for (int i = 1; i < argc; ++i) args += argv[i]; for (int i = 0; i < args.size(); ++i) { // Get the argument and optional value QStringList arg = args.at(i).simplified().split(QChar('=')); if (QRegExp("(-[-]?version)|([-//]V)").exactMatch(arg.at(0))) { printVersion(); return false; } else if (QRegExp("(-[-]?help)|([-//][h/?])").exactMatch(arg.at(0))) { printHelp(); return false; } else if (QRegExp("-[-]?help-qt").exactMatch(arg.at(0))) { printQtHelp(); return false; } else if (QRegExp("-[-]?verbose").exactMatch(arg.at(0)) && arg.size() > 1) { #ifdef Q_OS_WIN32 Internal::NeedsConsole = true; #endif QString v = arg.at(1).toLower(); if (v == "debug") Internal::ConsoleSeverityLevel = Common::iLogger::Debug; else if (v == "info") Internal::ConsoleSeverityLevel = Common::iLogger::Info; else if (v == "warning") Internal::ConsoleSeverityLevel = Common::iLogger::Warning; else if (v == "error") Internal::ConsoleSeverityLevel = Common::iLogger::Error; else if (v == "fatal") Internal::ConsoleSeverityLevel = Common::iLogger::Fatal; else if (v == "none") { Internal::ConsoleSeverityLevel = Common::iLogger::None; Internal::BeVerbose = false; #ifdef Q_OS_WIN32 Internal::NeedsConsole = false; #endif } else { printHelp(); return false; } } else if (QRegExp("-[v]+").exactMatch(arg.at(0)) && arg.size() == 1) { // The number of 'v's increases the verbosity for (int j = 1; j < arg.at(0).size(); ++j) { switch (Internal::ConsoleSeverityLevel) { case Common::iLogger::None: Internal::ConsoleSeverityLevel = Common::iLogger::Fatal; break; case Common::iLogger::Fatal: Internal::ConsoleSeverityLevel = Common::iLogger::Error; break; case Common::iLogger::Error: Internal::ConsoleSeverityLevel = Common::iLogger::Warning; break; case Common::iLogger::Warning: Internal::ConsoleSeverityLevel = Common::iLogger::Info; break; case Common::iLogger::Info: Internal::ConsoleSeverityLevel = Common::iLogger::Debug; break; default: break; } } } } return true; } void Application::printHelp() { char const * const txt = QT_TR_NOOP( "Usage: eVafGUI [options]\n" "\n" // General options " -help Shows this help and quits.\n" " -help-qt Shows Qt command line options and quits.\n" " -version Shows version information and quits.\n" " -verbose=LEVEL Specifies the verbose level. LEVEL can be one of the\n" " following: NONE, FATAL, ERROR, WARNING, INFO, DEBUG.\n" " -v Makes the application more verbose. Can be repeated for\n" " more verbosity.\n" // Handled by the iApp interface implementation " -appl[ication]=NAME Specifies the name of the application.\n" " -lang[uage]=xx[_CC] Specifies the language, where xx is the ISO 639\n" " language code followed by an optional ISO 3166 country\n" " code.\n" " -root[dir]=DIR Specifies the application's root directory.\n" " -dataroot[dir]=DIR Specifies the data root directory.\n" " -etc[dir]=DIR Specifies the configuration files directory.\n" " -log[dir]=DIR Specifies the log files directory.\n" " -doc[dir]=DIR Specifies the documentation directory.\n" " -qtplugins[dir]=DIR Specifies the Qt plugins directory.\n" ); ::fputs(tr(txt).toLocal8Bit().constData(), stdout); } void Application::printQtHelp() { // Cannot translate this text as QT_TR_NOOP() is not able to process #ifdef parts. char const * const txt = #ifdef QT_DEBUG "Qt debugging options:\n" " -nograb tells Qt that it must never grab the mouse or the keyboard.\n" #ifdef Q_OS_UNIX " -dograb running under a debugger can cause an implicit -nograb,\n" " use -dograb to override.\n" " -sync switches to synchronous mode for debugging.\n\n" #endif #endif "Qt common options:\n" " -style=STYLE sets the application GUI style. Possible values are motif,\n" " windows, and platinum.\n" " -style STYLE is the same as listed above.\n" " -stylesheet=STYLESHEET sets the application style sheet.\n" " -stylesheet STYLESHEET is the same as listed above.\n" " -session=SESSION restores the application from an earlier session.\n" " -session SESSION is the same as listed above.\n" " -widgetcount prints debug message at the end about number of widgets\n" " left undestroyed and maximum number of widgets existed at\n" " the same time.\n" " -reverse sets the application's layout direction to Qt::RightToLeft\n\n" #ifdef Q_OS_WIN32 "Qt options on Windows:\n" " -direct3d will make the Direct3D paint engine the default widget\n" " paint engine in Qt.\n\n" #endif #ifdef Q_WS_X11 "Qt options on X11:\n" " -display DISPLAY sets the X display.\n" " -geometry GEOMETRY sets the client geometry of the first window that is\n" " shown.\n" " -fn or -font FONT defines the application font.\n" " -bg or -background COLOR sets the default background color and an\n" " application palette.\n" " -fg or -foreground COLOR sets the default foreground color.\n" " -btn or -button COLOR sets the default button color.\n" " -name NAME sets the application name.\n" " -title TITLE sets the application title.\n" " -visual TrueColor forces the application to use a TrueColor visual on an\n" " 8-bit display.\n" " -ncols COUNT limits the number of colors allocated in the color cube on\n" " an 8-bit display, if the application is using the\n" " QApplication::ManyColor color specification. If COUNT is\n" " 216 then a 6x6x6 color cube is used (i.e. 6 levels of red,\n" " 6 of green, and 6 of blue); for other values, a cube\n" " approximately proportional to a 2x3x1 cube is used.\n" " -cmap causes the application to install a private color map on an\n" " 8-bit display.\n" " -im sets the input method server (equivalent to setting the\n" " XMODIFIERS environment variable).\n" " -noxim disables the input method framework (\"no X input method\").\n" " -inputstyle defines how the input is inserted into the given widget.\n" " E.g., onTheSpot makes the input appear directly in the\n" " widget, while overTheSpot makes the input appear in a box\n" " floating over the widget and is not inserted until the\n" " editing is done.\n" #endif ; ::fputs(txt, stdout); } void Application::printVersion() { ::printf("%s version %s release date %s, %s version %s\n", VER_PRODUCT_NAME_STR, VER_PRODUCT_VERSION_STR, VER_PRODUCT_DATE_STR, VER_MODULE_NAME_STR, VER_FILE_VERSION_STR ); } //------------------------------------------------------------------- int main(int argc, char ** argv) { Common::iLogger::instance()->setSeverity(Common::iLogger::Warning); // Install our own message handlers Common::iLogger::instance()->installFatalMsgHandler(Internal::fatalMsgHandler); qInstallMessageHandler(Internal::messageOutput); // Process command-line arguments if (!Application::processCommandLine(argc, argv)) return 1; // Set the console severity Common::iLogger::instance()->setConsoleSeverity(Internal::ConsoleSeverityLevel); #ifdef Q_OS_WIN32 // Enable the extra message console on Windows if (Internal::NeedsConsole) Internal::enableWinConsole(); #endif EVAF_INFO("%s version %s release date %s, %s version %s", VER_PRODUCT_NAME_STR, VER_PRODUCT_VERSION_STR, VER_PRODUCT_DATE_STR, VER_MODULE_NAME_STR, VER_FILE_VERSION_STR); #ifdef Q_OS_LINUX EVAF_INFO("%s application pid = %d", VER_MODULE_NAME_STR, getpid()); #endif Application app(argc, argv); // Install the exit handler if (!Internal::installExitHandler()) return 1; // Plugin manager Plugins::PluginManager pluginManager; // The main run loop bool quit = false; int rval; while (!quit) { EVAF_INFO("%s is starting up", VER_MODULE_NAME_STR); // Initialize the common library if (!Common::init()) return 1; // Initialize the plugin manager and load plugins if (!pluginManager.init()) return 1; // Run the application EVAF_INFO("Running %s", VER_MODULE_NAME_STR); rval = Common::iApp::instance()->exec(); quit = rval != Common::iApp::RC_Restart; EVAF_INFO("%s is %s", VER_MODULE_NAME_STR, quit ? "exiting" : "restarting"); // Unload plugins and finalize the plugin manager pluginManager.done(); } EVAF_INFO("%s exit with code %d", VER_MODULE_NAME_STR, rval); return rval; }