From: Enar Väikene Date: Fri, 22 Apr 2011 10:12:08 +0000 (+0300) Subject: More work on the common library and the main GUI application. X-Git-Url: https://vaikene.ee/gitweb/index.html?a=commitdiff_plain;h=4d81227da330c21c7aa0badc88bd5ad4467067fb;p=evaf More work on the common library and the main GUI application. Changed directory names from GUI and CLI applications to follow namespace names. --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dc43d15..acc14c7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,3 @@ add_subdirectory(libs) -#add_subdirectory(main) +add_subdirectory(main) #add_subdirectory(plugins) diff --git a/src/libs/Common/app.h b/src/libs/Common/app.h index 1cf1fde..5d8886e 100644 --- a/src/libs/Common/app.h +++ b/src/libs/Common/app.h @@ -59,7 +59,7 @@ public: virtual void restart(); - virtual void quit(bool err); + virtual void quit(bool err = false); virtual bool isReady() const { return mReady; } diff --git a/src/libs/Common/globals.h b/src/libs/Common/globals.h index e21aa86..93346d5 100644 --- a/src/libs/Common/globals.h +++ b/src/libs/Common/globals.h @@ -21,9 +21,34 @@ # define __COMMON_GLOBALS_H #include "libcommon.h" +#include "ilogger.h" /** - * Common namespace for eVaf. + * eVaf is a C++ cross-platform modular application development framework using Qt. + * + * The eVaf main executable is an empty container that needs to be filled with external modules to + * provide the required functionality. The eVaf main GUI executable, if run without external modules, + * shows just an empty window that can be closed to terminate the application. The eVaf main CLI + * executable runs until terminated with CTRL+C. + * + * eVaf modules are loadable libraries (.so or .dll files) that implement the features and + * functions of the application. By combining together different modules, an unique application can + * be made in very little time. Every module implements a specific function or feature and only when + * put together, the actual application is created. + * + * eVaf interfaces are the way how the functionality of eVaf modules is used. Every feature implemented + * by a module has an interface used to feed the module with data or request information from the module. + * + * eVaf events are used by modules to send out information that they have collected or processed. + * While interfaces are the way how to feed modules with data or requests, then events are mostly for + * spontaneous data. + * + * Events broadcast by modules can have data objects attached to them. To avoid unnecessary copying of + * data, these data objects are shared and reference-counted. When the data object is attached to the + * event, its internal reference counter is increased by one. When the eVaf event queue has delivered + * the event to all the subscribers, it destroys the event and decreases the reference-counter of the + * data object by one. If no other module kept the data object, then the data object's reference counter + * becomes zero and it is destroyed too. */ namespace eVaf { @@ -40,15 +65,39 @@ namespace Common { /** * eVaf common library initialized - * @param args List of arguments * @return True if ok; false if the initialization failed * * Call this function to initialize the common eVaf library after creating the Qt application * object and before loading any of the modules. */ -extern bool COMMON_EXPORT init(QStringList const & args); +extern bool COMMON_EXPORT init(); +/** + * Internal implementation of the common eVaf library. + */ +namespace Internal { +} // namespace eVaf::Common::Internal } // namespace eVaf::Common } // namespace eVaf +/** + * Tests that the condition is true. + * + * This macro tests for the condition and if not true, exits with a fatal error. + * Use this macro to test for conditions that must be met in order for the application + * to continue. + */ +#define EVAF_TEST(cond) \ + if (!cond) \ + EVAF_FATAL(#cond); + +/** + * Tests that the condition is true with a custom error message. + * + * This macro tests for the condition and if not true, exist with a custom fatal error message. + */ +#define EVAF_TEST_X(const, msg) \ + if (!cond) \ + EVAF_FATAL(msg); + #endif // globals.h diff --git a/src/libs/Common/iapp.h b/src/libs/Common/iapp.h index 5329e1b..4c7caed 100644 --- a/src/libs/Common/iapp.h +++ b/src/libs/Common/iapp.h @@ -134,7 +134,7 @@ public: * * This function requests the eVaf application to quit. */ - virtual void quit(bool err) = 0; + virtual void quit(bool err = false) = 0; /** * Returns true if the eVaf application is ready. diff --git a/src/libs/Common/ilogger.h b/src/libs/Common/ilogger.h index 4a75e3e..81d8016 100644 --- a/src/libs/Common/ilogger.h +++ b/src/libs/Common/ilogger.h @@ -110,7 +110,7 @@ public: * are output. With this function the severity level can be changed so that also less important * messages are output. */ - virtual void setSeverity(Severity severity, QString const & source) = 0; + virtual void setSeverity(Severity severity, QString const & source = 0) = 0; /** * Returns the current maximum size of log files in KiB. @@ -244,4 +244,89 @@ void COMMON_EXPORT qInfo(char const * const msg, ...) #endif ; +/** + * Macro for fatal error messages. + * + * This macro expands to a fatal error message output with the location in the source code where the error + * occurred. + */ +#define EVAF_FATAL_ERROR(...) \ + do { \ + eVaf::Common::iLogger::instance()->write( \ + eVaf::Common::iLogger::Fatal, \ + eVaf::Common::iLogger::instance()->printf(__VA_ARGS__), \ + 0, \ + eVaf::Common::iLogger::instance()->printf("%s:%s:%d", __FILE__, __FUNCTION__, __LINE__) \ + ); \ + } while (0) + +/** + * Macro for error messages. + * + * This macro expands to an error message output with the location in the source code where the error + * occurred. + */ +#define EVAF_ERROR(...) \ + do { \ + eVaf::Common::iLogger::instance()->write( \ + eVaf::Common::iLogger::Error, \ + eVaf::Common::iLogger::instance()->printf(__VA_ARGS__), \ + 0, \ + eVaf::Common::iLogger::instance()->printf("%s:%s:%d", __FILE__, __FUNCTION__, __LINE__) \ + ); \ + } while (0) + +/** + * Macro for warning messages. + * + * This macro expands to a warning message output with the location in the source code where the warning + * occurred. + */ +#define EVAF_WARNING(...) \ + do { \ + eVaf::Common::iLogger::instance()->write( \ + eVaf::Common::iLogger::Warning, \ + eVaf::Common::iLogger::instance()->printf(__VA_ARGS__), \ + 0, \ + eVaf::Common::iLogger::instance()->printf("%s:%s:%d", __FILE__, __FUNCTION__, __LINE__) \ + ); \ + } while (0) + +/** + * Macro for info messages. + * + * This macro expands to an info message output with the location in the source code where the message + * is output. + */ +#define EVAF_INFO(...) \ + do { \ + eVaf::Common::iLogger::instance()->write( \ + eVaf::Common::iLogger::Info, \ + eVaf::Common::iLogger::instance()->printf(__VA_ARGS__), \ + 0, \ + eVaf::Common::iLogger::instance()->printf("%s:%s:%d", __FILE__, __FUNCTION__, __LINE__) \ + ); \ + } while (0) + +/** + * Macro for debug messages. + * + * This macro expands to a debug message output with the location in the source code where the message + * is output. All the debug messages are supressed when the NDEBUG directive is defined. + */ +#ifndef NDEBUG +# define EVAF_DEBUG(...) \ + do { \ + eVaf::Common::iLogger::instance()->write( \ + eVaf::Common::iLogger::Debug, \ + eVaf::Common::iLogger::instance()->printf(__VA_ARGS__), \ + 0, \ + eVaf::Common::iLogger::instance()->printf("%s:%s:%d", __FILE__, __FUNCTION__, __LINE__) \ + ); \ + } while (0) +#else +# define EVAF_DEBUG(...) \ + do { } while (0) +#endif + #endif // ilogger.h diff --git a/src/libs/Common/logger.cpp b/src/libs/Common/logger.cpp new file mode 100644 index 0000000..0909fad --- /dev/null +++ b/src/libs/Common/logger.cpp @@ -0,0 +1,90 @@ +/** + * @file Common/logger.cpp + * @brief iLogger interface implementation + * @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 "logger.h" +#include "iregistry.h" +#include "ienv.h" + +#include + +#ifdef Q_OS_WIN32 +# include +#endif + +#ifdef Q_OS_LINUX +# include +# include +# include +#endif + + +//------------------------------------------------------------------- + +using namespace eVaf::Common; + +iLogger * iLogger::instance() +{ + static Internal::Logger singleton; + return &singleton; +} + + +//------------------------------------------------------------------- + +using namespace eVaf::Common::Internal; + +void defFatalMsgHandler(QString const & msg, QString const & source, QString const & where) +{ + Q_UNUSED(source); + + fprintf(stderr, "FATAL ERROR: %s (occurred in %s)\n", qPrintable(msg), qPrintable(where)); + +#ifdef Q_OS_LINUX + abort(); +#else + exit(1); +#endif +} + + +//------------------------------------------------------------------- + +LoggerSource::LoggerSource() + : QSharedData() + , severity(iLogger::Fatal) + , maxSize(100 * 1024) + , maxCount(3) +{} + +LoggerSource::LoggerSource(LoggerSource const & o) + : QSharedData() + , severity(o.severity) + , maxSize(o.maxSize) + , maxCount(o.maxCount) +{} + +void LoggerSource::init(QString const & source, QString const & logDir, QString const & etcDir) +{ + Q_UNUSED(etcDir); + + fileName = logDir + source + ".log"; +} + + +//------------------------------------------------------------------- diff --git a/src/libs/Common/logger.h b/src/libs/Common/logger.h new file mode 100644 index 0000000..c47be4f --- /dev/null +++ b/src/libs/Common/logger.h @@ -0,0 +1,182 @@ +/** + * @file Common/logger.h + * @brief iLogger interface implementation + * @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. + */ + +#ifndef __COMMON_LOGGER_H +#define __COMMON_LOGGER_H + +#include "ilogger.h" + +#include + + +namespace eVaf { +namespace Common { +namespace Internal { + +/// Default fatal error message handler +void defFatalMsgHandler(QString const & msg, QString const & source, QString const & where); + +/** + * Logger source. + * + * This class stores information about known sources. + */ +class LoggerSource : public QSharedData +{ +public: + + LoggerSource(); + + LoggerSource(LoggerSource const & o); + + /** + * Initializes the source + * @param source Name of the source + * @param logDir Full path to the log directory + * @param etcDir Full path to the configuration files directory + * + * This function initializes the newly created logger source and sets initial + * parameters for the source. + * + * Default parameters: + * @li severity is set to Fatal + * @li maximum size of the log file is set to 100 KiB + * @li maximum number of log files is set to 3 + * + * Default parameters can be overwritten with values read from the logger.ini file. + * This file should have the [.default] section with new default values for all the + * sources. Individual sources can have their parameters changed in sections with the + * name of the source. + * + * Example logger.ini file: + * @code + * [.default] + * severity = Fatal + * maxSize = 100 + * maxCount = 3 + * + * [my-source] + * severity = Warning + * maxSize = 1000 + * maxCount = 10 + * @endcode + */ + void init(QString const & source, QString const & logDir, QString const & etcDir); + + +public: // Members (we don't bother adding getter/setter functions) + + /// Current severity level + iLogger::Severity severity; + + /// Current log file name + QString fileName; + + /// Current maximum size of log files + uint maxSize; + + /// Current maximum number of log files + uint maxCount; + +}; + +/** + * iLogger interface implementation. + * + * This class implements the iLogger interface. + */ +class Logger : public iLogger +{ + Q_OBJECT + +public: + + Logger(); + + virtual ~Logger(); + + /** + * Initializes the interface implementation + * @return True if ok; false if initialization failed + */ + bool init(); + + /* + iLogger interface + */ + + virtual QString defaultSource() const { return mDefaultSource; } + + virtual void setDefaultSource(QString const & source); + + virtual Severity severity(QString const & source = 0) const; + + virtual void setSeverity(Severity severity, QString const & source = 0); + + virtual uint maxSize(QString const & source = 0) const; + + virtual void setMaxSize(uint maxSize, QString const & source = 0); + + virtual uint maxCount(QString const & source = 0) const; + + virtual void setMaxCount(uint maxCount, QString const & source = 0); + + virtual Severity consoleSeverity() const { return mConsoleSeverity; } + + virtual void setConsoleSeverity(Severity severity); + + virtual void write(Severity severity, QString const & msg, QString const & source = 0, QString const & where = 0); + + virtual QString printf(char const * const fmt, ...) const; + + virtual FatalMsgHandler installFatalMsgHandler(FatalMsgHandler newHandler); + + +private: // Members + + /// Current fatal error message handler + FatalMsgHandler mFatalMsgHandler; + + /// Current default source (defaults to "evaf") + QString mDefaultSource; + + /// Logger sources + QHash > mSources; + + +private: // Methods + + /// Returns the source by the name + LoggerSource * getSource(QString const & name) const; + + /// Creates a new source + LoggerSource * addSource(QString const & name); + +#ifdef Q_OS_WIN32 + /// Changes text colors on the Windows console + void setColor(short int c); +#endif + +}; + +} // namespace eVaf::Common::Internal +} // namespace eVaf::Common +} // namespace eVaf + +#endif // logger.h diff --git a/src/libs/Common/version.rc b/src/libs/Common/version.rc index 7ca43fa..4ada862 100644 --- a/src/libs/Common/version.rc +++ b/src/libs/Common/version.rc @@ -46,6 +46,7 @@ VS_VERSION_INFO VERSIONINFO VALUE "OriginalFilename", VER_ORIGINAL_FILENAME_STR VALUE "ProductName", VER_PRODUC_TNAME_STR VALUE "ProductVersion", VER_PRODUCT_VERSION_STR + VALUE "Build Date", VER_PRODUCT_DATE_STR VALUE "Module Name", VER_MODULE_NAME_STR VALUE "Module Type", VER_MODULE_TYPE_STR END diff --git a/src/main/cli/CMakeLists.txt b/src/main/CLI/CMakeLists.txt similarity index 100% rename from src/main/cli/CMakeLists.txt rename to src/main/CLI/CMakeLists.txt diff --git a/src/main/cli/main.cpp b/src/main/CLI/main.cpp similarity index 100% rename from src/main/cli/main.cpp rename to src/main/CLI/main.cpp diff --git a/src/main/cli/main.h b/src/main/CLI/main.h similarity index 100% rename from src/main/cli/main.h rename to src/main/CLI/main.h diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt index b686c31..a5b8305 100644 --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -1,2 +1,2 @@ -add_subdirectory(gui) -add_subdirectory(cli) +add_subdirectory(GUI) +#add_subdirectory(CLI) diff --git a/src/main/gui/CMakeLists.txt b/src/main/GUI/CMakeLists.txt similarity index 91% rename from src/main/gui/CMakeLists.txt rename to src/main/GUI/CMakeLists.txt index 5339fea..c9ba20e 100644 --- a/src/main/gui/CMakeLists.txt +++ b/src/main/GUI/CMakeLists.txt @@ -9,27 +9,27 @@ include(${QT_USE_FILE}) include_directories(${eVaf_INCLUDE}) # Required eVaf libraries -set(eVaf_LIBRARIES) +set(eVaf_LIBRARIES CommonLib) # Source files set(SRCS main.cpp exithandler.cpp fatalerr.cpp - version.cpp + #version.cpp ) if(WIN32) set(SRCS ${SRCS} winconsole.cpp ) -) +endif(WIN32) # Header files for the meta-object compiler set(MOC_HDRS main.h fatalerr.h - version_p.h + #version_p.h ) # Resources diff --git a/src/main/GUI/exithandler.cpp b/src/main/GUI/exithandler.cpp new file mode 100644 index 0000000..99d376f --- /dev/null +++ b/src/main/GUI/exithandler.cpp @@ -0,0 +1,137 @@ +/** + * @file main/GUI/exithandler.cpp + * @brief Exit handlers for the eVaf main executable + * @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 "exithandler.h" + +#include +#include + +#include + +#ifdef Q_OS_LINUX +# include +#endif + +#ifdef Q_OS_WIN32 +# include +#endif + +namespace eVaf { +namespace GUI { +namespace Internal { + +#ifdef Q_OS_LINUX + +/** + * Signal handler on Linux + * + * Handles TERM and HUP signals and either quits or restarts the application. + * + * @TODO According to the signal(7) documentation, only "safe" functions can be called from the + * signal handler. We don't know how safe it is to call iApp::quit() and iApp::restart() and + * probably have to implement "safe" versions of these functions. + */ +static void signalHandler(int sig) +{ + eVaf::Common::iApp * app = eVaf::Common::iApp::instance(); + + switch (sig) { + case SIGTERM: + if (app) + app->quit(); + else + exit(0); + break; + case SIGHUP: + if (app) + app->restart(); + break; + } +} + +#endif + +#ifdef Q_OS_WIN32 + +/** + * Signal handler on Windows + * + * Either quits or restarts the application. + * + * @TODO Is there a similar concept of "safe" functions for Windows signal handlers? + */ +static BOOL WINAPI signalHandler(DWORD sig) +{ + eVaf::Common::iApp * app = eVaf::Common::iApp::instance(); + + switch (sig) { + case CTRL_C_EVENT: + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + if (app) + app->quit(); + else + exit(0); + return true; + break; + case CTRL_BREAK_EVENT: + if (app) + app->restart(); + return true; + break; + } + + return false; +} + +#endif + +} // namespace eVaf::GUI::Internal +} // namespace eVaf::GUI +} // namespace eVaf + +using namespace eVaf::GUI::Internal; + +bool installExitHandler() +{ + +#ifdef Q_OS_LINUX + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signalHandler; + if (sigaction(SIGTERM, &sa, NULL) != 0) { + EVAF_FATAL_ERROR("sigaction() failed: %m"); + return false; + } + if (sigaction(SIGHUP, &sa, NULL) != 0) { + EVAF_FATAL_ERROR("sigaction() failed: %m"); + return false; + } +#endif + +#ifdef Q_OS_WIN32 + if (SetConsoleCtrlHandler(signalHandler, true) == 0) { + EVAF_FATAL_ERROR("SetConsoleCtrlHandler() failed"); + return false; + } +#endif + + return true; +} diff --git a/src/main/gui/main.h b/src/main/GUI/exithandler.h similarity index 54% rename from src/main/gui/main.h rename to src/main/GUI/exithandler.h index 46daca7..e1ccd41 100644 --- a/src/main/gui/main.h +++ b/src/main/GUI/exithandler.h @@ -1,6 +1,7 @@ /** - * @file main/gui/main.h - * @brief The main eVaf GUI application class + * @file main/GUI/exithandler.h + * @brief Exit handlers for the eVaf main executable + * @author Enar Vaikene * * Copyright (c) 2011 Enar Vaikene * @@ -16,35 +17,23 @@ * Agreement provided with the Software. */ -#ifndef __GUI_MAIN_H -#define __GUI_MAIN_H - -#include +#ifndef __GUI_EXITHANDLER_H +# define __GUI_EXITHANDLER_H +namespace eVaf { +namespace GUI { +namespace Internal { /** - * The main eVaf GUI application. + * Installs an exit handler for the selected platform. * - * eVafGUI is the main GUI executable. It provides an empty GUI application - * that is used to load other eVaf modules. - */ -namespace eVafGUI { - -/** - * The main eVaf GUI application class. + * Exit handler quits or restarts the application when a corresponding signal + * is received. */ -class Application : public QApplication -{ - Q_OBJECT - -public: - - Application(int & argc, char ** argv); - - virtual ~Application(); - -}; +bool installExitHandler(); -} // namespace eVafGUI +} // namespace eVaf::GUI::Internal +} // namespace eVaf::GUI +} // namespace eVaf -#endif // main.h +#endif // exithandler.h diff --git a/src/main/GUI/fatalerr.cpp b/src/main/GUI/fatalerr.cpp new file mode 100644 index 0000000..3c37b0f --- /dev/null +++ b/src/main/GUI/fatalerr.cpp @@ -0,0 +1,109 @@ +/** + * @file main/GUI/fatalerr.cpp + * @brief Fatal error message dialog box + * @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 "fatalerr.h" + +#include + +using namespace eVaf::GUI::Internal; + + +//------------------------------------------------------------------- + +FatalErr::FatalErr(QString const & title, QString const & text, QWidget * parent) + : QDialog(parent, Qt::WindowTitleHint) + , mTimer(Timer) +{ + setWindowTitle(title); + + QVBoxLayout * layout = new QVBoxLayout; + layout->setSpacing(10); + setLayout(layout); + + QHBoxLayout * messageBox = new QHBoxLayout; + messageBox->setSpacing(20); + layout->addLayout(messageBox); + + // Icon + QLabel * l = new QLabel; + l->setPixmap(QMessageBox::standardIcon(QMessageBox::Critical)); + l->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + messageBox->addWidget(l); + + // Error message text + l = new QLabel(text); + l->setWordWrap(true); + l->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + messageBox->addWidget(l); + + // Warning about the Ignore button + l = new QLabel; + l->setTextFormat(Qt::RichText); + l->setText(tr( + "

Clicking on the 'Abort' button aborts the application.
" + "Clicking on the 'Ignore' button keeps the application running for diagnostics.

" + "

The application might be unstable if fatal errors are ignored!

" + )); + layout->addWidget(l); + + // Buttons + QHBoxLayout * buttonBox = new QHBoxLayout; + layout->addLayout(buttonBox); + + buttonBox->addStretch(); + + wAbort = new QPushButton(tr("%Abort (%1 sec)").arg(mTimer)); + connect(wAbort, SIGNAL(clicked()), this, SLOT(abortClicked())); + buttonBox->addWidget(wAbort); + setFocusProxy(wAbort); + + QPushButton * b = new QPushButton(tr("&Ignore")); + connect(b, SIGNAL(clicked()), this, SLOT(ignoreClicked())); + buttonBox->addWidget(b); + + setResult(Abort); + + // Start the count-down timer + startTimer(1000); +} + +void FatalErr::timerEvent(QTimerEvent *) +{ + --mTimer; + wAbort->setText(tr("&Abort (%1 sec)").arg(mTimer)); + + if (mTimer <= 0) + done(Abort); +} + +void FatalErr::abortClicked() +{ + done(Abort); +} + +void FatalErr::ignoreClicked() +{ + done(Ignore); +} + +int FatalErr::message(QString const & title, QString const & text, QWidget * parent) +{ + FatalErr msg(title, text, parent); + return msg.exec(); +} diff --git a/src/main/GUI/fatalerr.h b/src/main/GUI/fatalerr.h new file mode 100644 index 0000000..d10b1d7 --- /dev/null +++ b/src/main/GUI/fatalerr.h @@ -0,0 +1,100 @@ +/** + * @file main/GUI/fatalerr.h + * @brief Fatal error message dialog box + * @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. + */ + +#ifndef __GUI_FATALERR_H +# define __GUI_FATALERR_H + +#include + +class QTimerEvent; + +namespace eVaf { +namespace GUI { +namespace Internal { + +/** + * Fatal error message dialog box + * + * The fatal error message dialog box shows a fatal error message and starts a count-down + * to close the dialog box and abort the application. Users can click on the Ignore button + * to keep the application running for diagnostics. + */ +class FatalErr : public QDialog +{ + Q_OBJECT + +public: + + /// Returns values + enum Result { + Abort = 0, ///< User clicked on the Abort button or the dialog box timed out + Ignore = 1 ///< User clicked on the Ignore button + }; + + /** + * Creates the fatal error message dialog box + * @param title Title of the dialog box + * @param text Text shown on the dialog box + * @param parent Optional parent widget + */ + FatalErr(QString const & title, QString const & text, QWidget * parent = 0); + + /** + * Shows a fatal error message dialog box + * @param title Title of the dialog box + * @param text Text shown on the dialog box + * @param parent Optional parent widget + * @return The result code + */ + static int message(QString const & title, QString const & text, QWidget * parent = 0); + + +protected: + + /// Timer event handler + virtual void timerEvent(QTimerEvent *); + + +private slots: + + /// Ignore button clicked + void ignoreClicked(); + + /// Abort button clicked + void abortClicked(); + + +private: + + /// Count-down time in secons + static int const Timer = 60; + + /// Count-down timer + int mTimer; + + /// The Abort button + QPushButton * wAbort; + +}; + +} // namespace eVaf::GUI::Internal +} // namespace eVaf::GUI +} // namespace eVaf + +#endif // fatalerr.h diff --git a/src/main/GUI/gui.qrc b/src/main/GUI/gui.qrc new file mode 100644 index 0000000..bcf4729 --- /dev/null +++ b/src/main/GUI/gui.qrc @@ -0,0 +1,4 @@ + + + + diff --git a/src/main/GUI/gui.rc b/src/main/GUI/gui.rc new file mode 100644 index 0000000..e69de29 diff --git a/src/main/GUI/main.cpp b/src/main/GUI/main.cpp new file mode 100644 index 0000000..45c5043 --- /dev/null +++ b/src/main/GUI/main.cpp @@ -0,0 +1,424 @@ +/** + * @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, char const * 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; + case Common::iLogger::Debug: + 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" + // Handled by the iEnv interface implementation + " -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); + qInstallMsgHandler(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 + rval = app.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; +} diff --git a/src/main/GUI/main.h b/src/main/GUI/main.h new file mode 100644 index 0000000..2c51846 --- /dev/null +++ b/src/main/GUI/main.h @@ -0,0 +1,89 @@ +/** + * @file main/GUI/main.h + * @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. + */ + +#ifndef __GUI_MAIN_H +# define __GUI_MAIN_H + +#include + + +namespace eVaf { + +/** + * The main eVaf GUI application. + * + * eVafGUI is the main GUI executable. It provides an empty GUI application + * that is used to load other eVaf modules. + */ +namespace GUI { + +/** + * Internal implementation of the main eVaf GUI application. + */ +namespace Internal { +} // namespace eVaf::GUI::Internal + +/** + * The main eVaf GUI application class. + */ +class Application : public QApplication +{ + Q_OBJECT + +public: + + Application(int & argc, char ** argv); + + virtual ~Application(); + + +public: // Static methods + + /** + * Processes command-line arguments + * @param argc Number of command-line arguments + * @param argv List of command-line arguments + * @return True if ok; false if the application should terminate + * + * This function processes command-line arguments and should be called before running + * the application. + */ + static bool processCommandLine(int argc, char ** argv); + + /** + * Prints out help for command-line arguments. + */ + static void printHelp(); + + /** + * Prints out help for Qt command-line arguments. + */ + static void printQtHelp(); + + /** + * Prints out version information. + */ + static void printVersion(); + +}; + +} // namespace eVaf::GUI +} // namespace eVaf + +#endif // main.h diff --git a/src/main/GUI/version.h b/src/main/GUI/version.h new file mode 100644 index 0000000..ff98d7a --- /dev/null +++ b/src/main/GUI/version.h @@ -0,0 +1,50 @@ +/** + * @file main/GUI/version.h + * @brief Version information for eVaf modules + * @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. + */ + +#ifndef __GUI_VERSION_H +# define __GUI_VERSION_H + +#include + +/** + * Module/library version number in the form major,minor,release,build + */ +#define VER_FILE_VERSION 0,1,1,1 + +/** + * Module/library version number in the string format (shall end with \0) + */ +#define VER_FILE_VERSION_STR "0.1.1.1\0" + +/** + * Module/library name (shall end with \0) + */ +#define VER_MODULE_NAME_STR "eVafGUI\0" + +/** + * Original file name for windows (shall end with \0) + */ +#define VER_ORIGINAL_FILE_NAME_STR "eVafGUI.exe\0" + +/** + * Description of the module/library (shall end with \0) + */ +#define VER_FILE_DESCRIPTION_STR "Main eVaf GUI executable.\0" + +#endif // version.h diff --git a/src/main/GUI/version.rc b/src/main/GUI/version.rc new file mode 100644 index 0000000..bf94cb0 --- /dev/null +++ b/src/main/GUI/version.rc @@ -0,0 +1,53 @@ +/** + * @file main/GUI/version.rc + * @brief Windows resource file with module/library version information. + * @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 "version.h" +#include +#include + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VER_FILE_VERSION + PRODUCTVERSION VER_PRODUCT_VERSION + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0x0L + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", VER_COMPANY_NAME_STR + VALUE "FileDescription", VER_FILE_DESCRIPTION_STR + VALUE "FileVersion", VER_FILE_VERSION_STR + VALUE "LegalCopyright", VER_LEGAL_COPYRIGHT_STR + VALUE "OriginalFilename", VER_ORIGINAL_FILENAME_STR + VALUE "ProductName", VER_PRODUC_TNAME_STR + VALUE "ProductVersion", VER_PRODUCT_VERSION_STR + VALUE "Build Date", VER_PRODUCT_DATE_STR + VALUE "Module Name", VER_MODULE_NAME_STR + END + END + END diff --git a/src/main/GUI/winconsole.cpp b/src/main/GUI/winconsole.cpp new file mode 100644 index 0000000..6a59c69 --- /dev/null +++ b/src/main/GUI/winconsole.cpp @@ -0,0 +1,41 @@ +/** + * @file main/GUI/winconsole.cpp + * @brief Functions to redirect stdin, stdout and stderr to a separate console on Windows + * @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. + */ + +#ifdef Q_OS_WIN32 + +#include "winconsole.h" + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include + +using namespace eVaf::GUI::Internal; + +void enableWinConsole() +{ + AllocConsole(); + freopen("conin$", "r", stdin); + freopen("conout$", "w", stdout); + freopen("conout$", "w", stderr); +} + +#undef _CRT_SECURE_NO_WARNINGS + +#endif diff --git a/src/main/GUI/winconsole.h b/src/main/GUI/winconsole.h new file mode 100644 index 0000000..dc075b1 --- /dev/null +++ b/src/main/GUI/winconsole.h @@ -0,0 +1,40 @@ +/** + * @file main/GUI/winconsole.h + * @brief Functions to redirect stdin, stdout and stderr to a separate console on Windows + * @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. + */ + +#ifndef __GUI_WINCONSOLE_H +# define __GUI_WINCONSOLE_H + +namespace eVaf { +namespace GUI { +namespace Internal { + +#ifdef Q_OS_WIN32 + +/** + * Enables the console window on Windows + */ +void enableWinConsole(); + +#endif + +} // namespace eVaf::GUI::Internal +} // namespace eVaf::GUI +} // namespace eVaf + +#endif