set(CMAKE_MODULE_PATH ${eVaf_SOURCE_DIR}/mk/cmake)
# Find Qt4
-find_package(Qt4 REQUIRED)
+find_package(Qt4 4.6 REQUIRED)
# Default to the Debug build type if none is specified
IF(NOT CMAKE_BUILD_TYPE)
include_directories(${eVaf_INCLUDE})
# Required eVaf libraries
-set(eVaf_LIBRARIES CommonLib PluginsLib SdiWindow)
+set(eVaf_LIBRARIES CommonLib PluginsLib)
# Source files
set(SRCS
class Module : public Plugins::iPlugin
{
Q_OBJECT
+ Q_INTERFACES(eVaf::Plugins::iPlugin)
public:
class Module : public Plugins::iPlugin
{
Q_OBJECT
+ Q_INTERFACES(eVaf::Plugins::iPlugin)
public:
class Module : public Plugins::iPlugin
{
Q_OBJECT
+ Q_INTERFACES(eVaf::Plugins::iPlugin)
public:
}
// Send the event to all the subscribers
- QHash<uint, QList<QPointer<QObject> > >::const_iterator subscribersIt = mSubscribers.constFind(id);
+ QHash<uint, QVector<QWeakPointer<QObject> > >::const_iterator subscribersIt = mSubscribers.constFind(id);
if (subscribersIt != mSubscribers.constEnd()) {
- QList<QPointer<QObject> > subscribers = *subscribersIt;
+ QVector<QWeakPointer<QObject> > subscribers = *subscribersIt;
int sz = subscribers.size();
for (int i = 0; i < sz; ++i) {
// Get the subscriber object and make sure that it is still alive
- QPointer<QObject> obj = subscribers.at(i);
+ QWeakPointer<QObject> obj = subscribers.at(i);
if (obj.isNull()) {
continue;
}
// Notify the subscriber
- bool rval = QCoreApplication::sendEvent(obj, e);
+ bool rval = QCoreApplication::sendEvent(obj.data(), e);
if (rval) {
// The event was consumed and should be sent to any other subscribers
if (mEvents.constFind(id) == mEvents.constEnd())
return;
- mSubscribers[id].removeAll(obj);
+ // Remove from the list of subscribers
+ QVector<QWeakPointer<QObject> >::iterator it = mSubscribers[id].begin();
+ QVector<QWeakPointer<QObject> >::iterator e = mSubscribers[id].end();
+ while (it != e) {
+ if (!it->isNull() && it->data() == obj)
+ it = mSubscribers[id].erase(it);
+ else
+ ++it;
+ }
}
void EventQueue::broadcastEvent(Event * event)
#include <QObject>
#include <QString>
#include <QHash>
-#include <QList>
-#include <QPointer>
+#include <QVector>
+#include <QWeakPointer>
namespace eVaf {
QHash<uint, QString> mEvents;
/// List of subscribers
- QHash<uint, QList<QPointer<QObject> > > mSubscribers;
+ QHash<uint, QVector<QWeakPointer<QObject> > > mSubscribers;
};
Error, ///< Unexpected issues in the software that could be solved automatically.
Warning, ///< Expected issues in the software that will be solved automatically.
Info, ///< General information output by the application or modules.
- Debug ///< Information for debugging purposes.
+ Debug, ///< Information for debugging purposes.
+ Count ///< Number of severity levels
};
/// Interface constructor
* your receiver to this signal if you want to add your own message handling. For example,
* use this signal to show messages in a log window etc.
*/
- void loggerEvent(eVaf::Common::iLogger::Severity severity, QString const & text, QString const & source, QString const & where);
+ void loggerEvent(Common::iLogger::Severity severity, QString const & text, QString const & source, QString const & where);
};
Logger::~Logger()
{
// Disconnect any potential receivers from this object
- disconnect(this, SIGNAL(loggerEvent(eVaf::Common::iLogger::Severity,QString,QString,QString)), 0, 0);
+ disconnect(this, SIGNAL(loggerEvent(Common::iLogger::Severity,QString,QString,QString)), 0, 0);
// Destroy the worker thread
if (mWorker) {
bool Registry::registerInterface(QString const & name, QObject * obj)
{
- mInterfaces.insert(name, QPointer<QObject>(obj));
+ mInterfaces.insert(name, QWeakPointer<QObject>(obj));
return true;
}
QObject * Registry::queryInterface(QString const & name) const
{
- QHash<QString, QPointer<QObject> >::const_iterator it = mInterfaces.constFind(name);
- return it != mInterfaces.constEnd() ? *it : 0;
+ QHash<QString, QWeakPointer<QObject> >::const_iterator it = mInterfaces.constFind(name);
+ return it != mInterfaces.constEnd() ? (*it).data() : 0;
}
#include <QObject>
#include <QString>
-#include <QPointer>
+#include <QWeakPointer>
#include <QHash>
namespace eVaf {
* iRegistry interface implementation.
*
* This class implements the global registry for interfaces. Interfaces are stored in a QHash container
- * and quarded with QPointer.
+ * and quarded with QWeakPointer.
*/
class Registry : public iRegistry
{
private:
/// All the registered interfaces
- QHash<QString, QPointer<QObject> > mInterfaces;
+ QHash<QString, QWeakPointer<QObject> > mInterfaces;
};
/**
* Module/library version number in the form major,minor,release,build
*/
-#define VER_FILE_VERSION 0,1,1,3
+#define VER_FILE_VERSION 0,1,2,5
/**
* Module/library version number in the string format (shall end with \0)
*/
-#define VER_FILE_VERSION_STR "0.1.1.3\0"
+#define VER_FILE_VERSION_STR "0.1.2.5\0"
/**
* Module/library name (shall end with \0)
} // namespace eVaf::Plugins
} // namespace eVaf
+Q_DECLARE_INTERFACE(eVaf::Plugins::iPlugin, "eVaf.Plugins.iPlugin/1.0")
+
#endif // iplugin.h
} // namespace eVaf::Plugins
} // namespace eVaf
+Q_DECLARE_INTERFACE(eVaf::Plugins::iPluginFactory, "eVaf.Plugins.iPluginFactory/1.0")
+
#endif // ipluginfactory.h
/**
* Module/library version number in the form major,minor,release,build
*/
-#define VER_FILE_VERSION 0,1,2,4
+#define VER_FILE_VERSION 0,1,3,5
/**
* Module/library version number in the string format (shall end with \0)
*/
-#define VER_FILE_VERSION_STR "0.1.2.4\0"
+#define VER_FILE_VERSION_STR "0.1.3.5\0"
/**
* Module/library name (shall end with \0)
case Common::iLogger::Info:
consoleSeverityLevel = Common::iLogger::Debug;
break;
- case Common::iLogger::Debug:
+ default:
break;
}
}
/**
* Module/library version number in the form major,minor,release,build
*/
-#define VER_FILE_VERSION 0,1,1,1
+#define VER_FILE_VERSION 0,1,1,2
/**
* Module/library version number in the string format (shall end with \0)
*/
-#define VER_FILE_VERSION_STR "0.1.1.1\0"
+#define VER_FILE_VERSION_STR "0.1.1.2\0"
/**
* Module/library name (shall end with \0)
case Common::iLogger::Info:
Internal::ConsoleSeverityLevel = Common::iLogger::Debug;
break;
- case Common::iLogger::Debug:
+ default:
break;
}
}
/**
* Module/library version number in the form major,minor,release,build
*/
-#define VER_FILE_VERSION 0,1,1,3
+#define VER_FILE_VERSION 0,1,1,4
/**
* Module/library version number in the string format (shall end with \0)
*/
-#define VER_FILE_VERSION_STR "0.1.1.3\0"
+#define VER_FILE_VERSION_STR "0.1.1.4\0"
/**
* Module/library name (shall end with \0)
add_subdirectory(SdiWindow)
+add_subdirectory(LogView)
add_subdirectory(Test)
--- /dev/null
+# Name of the target
+set(TARGET LogView)
+
+# Qt modules
+include(${QT_USE_FILE})
+
+# Needed for exporting/importing symbols
+add_definitions(-DLOGVIEW_LIBRARY)
+
+# Include files
+include_directories(${eVaf_INCLUDE})
+
+# Required eVaf libraries
+set(eVaf_LIBRARIES CommonLib PluginsLib)
+
+# Source files
+set(SRCS
+ factory.cpp
+ logview.cpp
+)
+
+# Header files for the meta-object compiler
+set(MOC_HDRS
+ factory.h
+ logview.h
+)
+
+# Version info resource file for Windows builds
+if(WIN32)
+ set(SRCS ${SRCS} version.rc)
+endif(WIN32)
+
+qt4_wrap_cpp(MOC_SRCS ${MOC_HDRS})
+
+add_library(${TARGET} SHARED ${SRCS} ${MOC_SRCS})
+
+target_link_libraries(${TARGET} ${QT_LIBRARIES} ${eVaf_LIBRARIES})
+
+install(TARGETS ${TARGET} DESTINATION bin)
--- /dev/null
+/**
+ * @file LogView/factory.cpp
+ * @brief LogView module's factory 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 "factory.h"
+#include "logview.h"
+#include "version.h"
+
+#include <Common/iLogger>
+
+#include <QtCore>
+
+using namespace eVaf::LogView;
+
+VER_EXPORT_VERSION_INFO()
+Q_EXPORT_PLUGIN2(VER_MODULE_NAME_STR, Factory)
+
+
+//-------------------------------------------------------------------
+
+Factory::Factory()
+ : Plugins::iPluginFactory()
+ , mPlugin(0)
+{
+ setObjectName(QString("%1-Factory").arg(VER_MODULE_NAME_STR));
+
+ EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+Factory::~Factory()
+{
+ if (mPlugin)
+ delete mPlugin;
+
+ EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+QObject * Factory::create(QString const & name)
+{
+ Q_UNUSED(name);
+
+ if (mPlugin == 0)
+ mPlugin = new Internal::Module;
+ return mPlugin;
+}
--- /dev/null
+/**
+ * @file LogView/factory.h
+ * @brief LogView module's factory 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 __LOGVIEW_FACTORY_H
+# define __LOGVIEW_FACTORY_H
+
+#include <Plugins/iPluginFactory>
+
+namespace eVaf {
+namespace LogView {
+namespace Internal {
+ class Module;
+} // namespace eVaf::LogView::Internal
+
+
+/**
+ * Plugin factory class for the module
+ */
+class Factory : public Plugins::iPluginFactory
+{
+ Q_OBJECT
+ Q_INTERFACES(eVaf::Plugins::iPluginFactory)
+
+public:
+
+ Factory();
+
+ virtual ~Factory();
+
+ virtual QObject * create(QString const & name);
+
+
+private: // Members
+
+ Internal::Module * mPlugin;
+
+};
+
+} // namespace eVaf::LogView
+} // namespace eVaf
+
+#endif // factory.h
--- /dev/null
+/**
+ * @file LogView/liblogview.h
+ * @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 __LOGVIEW_LIBLOGVIEW_H
+# define __LOGVIEW_LIBLOGVIEW_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(LOGVIEW_LIBRARY)
+# define LOGVIEW_EXPORT Q_DECL_EXPORT
+#else
+# define LOGVIEW_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // liblogview.h
--- /dev/null
+/**
+ * @file LogView/logview.cpp
+ * @brief Implementation of the LogView module
+ * @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 "logview.h"
+#include "version.h"
+
+#include <Common/Globals>
+#include <Common/iLogger>
+#include <Common/iApp>
+
+#include <QtGui>
+
+
+using namespace eVaf;
+using namespace eVaf::LogView::Internal;
+
+
+//-------------------------------------------------------------------
+
+int const Model::MaxLines = 1000;
+
+char const * const Model::SeverityText[Common::iLogger::Count] = {
+ QT_TR_NOOP("[NONE] "),
+ QT_TR_NOOP("[FATAL] "),
+ QT_TR_NOOP("[ERROR] "),
+ QT_TR_NOOP("[WARNING]"),
+ QT_TR_NOOP("[INFO] "),
+ QT_TR_NOOP("[DEBUG] ")
+};
+
+Model::Model(QObject * parent)
+ : QAbstractListModel(parent)
+{
+}
+
+QVariant Model::data(QModelIndex const & index, int role) const
+{
+ if (!index.isValid() || index.row() < 0 || index.row() >= mData.size() || index.column() != 0)
+ return QVariant();
+
+ switch (role) {
+
+ // Return the message for the display role
+ case Qt::DisplayRole: {
+ return mData.at(index.row()).simplified;
+ break;
+ }
+
+ // Change color for different message types
+ case Qt::ForegroundRole: {
+ Common::iLogger::Severity s = mData.at(index.row()).severity;
+ switch (s) {
+ case Common::iLogger::Info:
+ return QBrush(QColor(Qt::blue));
+ break;
+ case Common::iLogger::Warning:
+ return QBrush(QColor(Qt::black));
+ break;
+ case Common::iLogger::Error:
+ case Common::iLogger::Fatal:
+ return QBrush(QColor(Qt::red));
+ break;
+ default:
+ return QVariant();
+ }
+ break;
+ }
+ } // switch (role)
+
+ return QVariant();
+}
+
+void Model::addMessage(Common::iLogger::Severity severity, QString const & text, QString const & where)
+{
+ // Add the message to the end of the queue
+ beginInsertRows(QModelIndex(), mData.size(), mData.size());
+ mData.enqueue(Message(severity, text, where));
+ endInsertRows();
+
+ // Remove oldest messages if the list is full
+ if (mData.size() > MaxLines) {
+ beginRemoveRows(QModelIndex(), 0, 0);
+ mData.dequeue();
+ endRemoveRows();
+ }
+
+ emit messageAdded(index(mData.size() - 1, 0));
+}
+
+QString Model::details(QModelIndex const & index) const
+{
+ Message const & m = mData.at(index.row());
+ return tr("%1 %2 %3 : %4\nOccurred in %5")
+ .arg(m.dt.date().toString(Qt::DefaultLocaleShortDate))
+ .arg(m.dt.time().toString("HH:mm:ss.zzz"))
+ .arg(tr(severityText(m.severity)))
+ .arg(m.text)
+ .arg(m.where);
+}
+
+bool Model::copyToClipboard(QModelIndex const & index)
+{
+ mErrorString.clear();
+
+ QClipboard * cb = QApplication::clipboard();
+ if (cb) {
+ cb->setText(details(index));
+ return true;
+ }
+ else {
+ mErrorString = tr("The global clipboard is not available");
+ return false;
+ }
+}
+
+bool Model::saveToFile(QString const & fileName)
+{
+ mErrorString.clear();
+
+ QFile f(fileName);
+ if (!f.open(QFile::WriteOnly)) {
+ mErrorString = tr("Failed to open the file '%1' for writing : %2").arg(fileName).arg(f.errorString());
+ return false;
+ }
+
+ QTextStream out(&f);
+
+ for (int i = 0; i < mData.size(); ++i) {
+ Message const & m = mData.at(i);
+ out << tr("%1 %2 %3 : %4 (occurred in %5)\n")
+ .arg(m.dt.date().toString(Qt::DefaultLocaleShortDate))
+ .arg(m.dt.time().toString("HH:mm:ss.zzz"))
+ .arg(tr(severityText(m.severity)))
+ .arg(m.text)
+ .arg(m.where)
+ << endl;
+ }
+
+ return true;
+}
+
+char const * const Model::severityText(Common::iLogger::Severity s) const
+{
+ if (s >= Common::iLogger::None && s < Common::iLogger::Count)
+ return SeverityText[s];
+ else
+ return SeverityText[Common::iLogger::None];
+}
+
+
+//-------------------------------------------------------------------
+
+Widget::Widget(QString const & source, QWidget * parent)
+ : QWidget(parent)
+ , mSource(source)
+ , mAutoScroll(true)
+{
+ QVBoxLayout * w = new QVBoxLayout;
+ setLayout(w);
+
+ mModel = new Model(this);
+ connect(mModel, SIGNAL(messageAdded(QModelIndex)), this, SLOT(messageAdded(QModelIndex)));
+
+ wList = new QListView;
+ wList->setModel(mModel);
+ wList->setUniformItemSizes(true);
+ connect(wList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(currentChanged(QModelIndex,QModelIndex)));
+ w->addWidget(wList);
+
+ wList->setContextMenuPolicy(Qt::ActionsContextMenu);
+
+ QAction * a = new QAction(tr("&Copy", VER_MODULE_NAME_STR), this);
+ a->setStatusTip(tr("Copies the selected message to the clipboard for pasting into other applications", VER_MODULE_NAME_STR));
+ connect(a, SIGNAL(triggered()), this, SLOT(copyToClipboard()));
+ wList->addAction(a);
+
+ a = new QAction(tr("&Save to ...", VER_MODULE_NAME_STR), this);
+ a->setStatusTip(tr("Saves all the messages to a file", VER_MODULE_NAME_STR));
+ connect(a, SIGNAL(triggered()), this, SLOT(saveToFile()));
+ wList->addAction(a);
+
+ wDetails = new QLabel;
+ wDetails->setWordWrap(true);
+ w->addWidget(wDetails);
+}
+
+void Widget::messageAdded(QModelIndex const & index)
+{
+ if (mAutoScroll)
+ wList->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
+}
+
+void Widget::currentChanged(QModelIndex const & current, QModelIndex const & previous)
+{
+ Q_UNUSED(previous);
+
+ if (!current.isValid() || current.row() < 0 || current.row() > mModel->rowCount()) {
+ wDetails->clear();
+ return;
+ }
+
+ mAutoScroll = current.row() == (mModel->rowCount() - 1);
+
+ wDetails->setText(mModel->details(current));
+}
+
+void Widget::copyToClipboard()
+{
+ QModelIndex idx = wList->selectionModel()->currentIndex();
+ if (idx.isValid())
+ mModel->copyToClipboard(idx);
+}
+
+void Widget::saveToFile()
+{
+ QString fileName = QFileDialog::getSaveFileName(this,
+ tr("Save to file", VER_MODULE_NAME_STR),
+ Common::iApp::instance()->dataRootDir() + QString("%1_%2.txt").arg(mSource).arg(QDate::currentDate().toString("yyyyMMdd")),
+ tr("Text files (*.txt);;All files (*)", VER_MODULE_NAME_STR));
+ if (fileName.isEmpty())
+ return;
+
+ if (!mModel->saveToFile(fileName))
+ QMessageBox::critical(this, tr("Error", VER_MODULE_NAME_STR), mModel->errorString());
+}
+
+
+//-------------------------------------------------------------------
+
+Window::Window(QWidget * parent, Qt::WindowFlags flags)
+ : QWidget(parent, flags)
+{
+ setObjectName(QString("%1-Window").arg(VER_MODULE_NAME_STR));
+
+ setWindowTitle(tr("Messages"));
+
+ Common::iLogger * logger = Common::iLogger::instance();
+ EVAF_TEST_X(logger, "No iLogger interface");
+
+ mDefSource = logger->defaultSource();
+ if (mDefSource.isEmpty())
+ mDefSource = "Common";
+
+ QVBoxLayout * w = new QVBoxLayout;
+ w->setMargin(0);
+ setLayout(w);
+
+ wTabs = new QTabWidget;
+ w->addWidget(wTabs);
+
+ // Add the default source
+ Widget * s = new Widget(mDefSource);
+ mLogViews.insert(s->source(), s);
+ wTabs->addTab(s, s->source());
+
+ wStatusBar = new QStatusBar;
+ w->addWidget(wStatusBar);
+
+ QAction * a = new QAction(this);
+ a->setShortcut(Qt::Key_Escape);
+ connect(a, SIGNAL(triggered()), this, SLOT(close()));
+ addAction(a);
+
+ restoreSettings();
+
+ connect(logger, SIGNAL(loggerEvent(Common::iLogger::Severity,QString,QString,QString)), this, SLOT(loggerEvent(Common::iLogger::Severity,QString,QString,QString)));
+
+ show();
+
+ EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+Window::~Window()
+{
+ mLogViews.clear();
+
+ saveSettings();
+
+ EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+bool Window::event(QEvent * e)
+{
+ if (e->type() == QEvent::StatusTip) {
+ QStatusTipEvent * event = static_cast<QStatusTipEvent *>(e);
+ wStatusBar->showMessage(event->tip());
+ return true;
+ }
+ return QWidget::event(e);
+}
+
+void Window::saveSettings()
+{
+ static int ver[4] = {VER_FILE_VERSION};
+ QSettings settings(VER_COMPANY_NAME_STR, Common::iApp::instance()->name());
+ settings.setValue(QString("%1/version/major").arg(objectName()), ver[0]);
+ settings.setValue(QString("%1/version/minor").arg(objectName()), ver[1]);
+ settings.setValue(QString("%1/geometry").arg(objectName()), saveGeometry());
+}
+
+void Window::restoreSettings()
+{
+ static int ver[4] = {VER_FILE_VERSION};
+ QSettings settings(VER_COMPANY_NAME_STR, Common::iApp::instance()->name());
+
+ // Ignore saved settings if the version number is not the same
+ // More intelligent checks can be implemented to allow upgrading from previous versions
+ QVariant v = settings.value(QString("%1/version/major").arg(objectName()));
+ if (!v.isValid() || v.toInt() != ver[0])
+ return;
+ v = settings.value(QString("%1/version/minor").arg(objectName()));
+ if (!v.isValid() || v.toInt() != ver[1])
+ return;
+
+ // Restore the geometry
+ restoreGeometry(settings.value(QString("%1/geometry").arg(objectName())).toByteArray());
+}
+
+void Window::loggerEvent(Common::iLogger::Severity severity, QString const & text, QString const & source, QString const & where)
+{
+ // Ignore messages with >=DEBUG severity level
+ if (severity >= Common::iLogger::Debug)
+ return;
+
+ // Find or create the log view widget for this source
+ Widget * w = 0;
+ QString s = source.isEmpty() ? mDefSource : source;
+ QHash<QString, Widget *>::const_iterator it = mLogViews.constFind(s);
+ if (it == mLogViews.constEnd()) {
+ w = new Widget(s);
+ mLogViews.insert(w->source(), w);
+ wTabs->addTab(w, w->source());
+ }
+ else
+ w = *it;
+
+ w->addMessage(severity, text, where);
+}
+
+
+//-------------------------------------------------------------------
+
+Module::Module()
+ : Plugins::iPlugin()
+ , wWindow(0)
+{
+ setObjectName(QString("%1-Module").arg(VER_MODULE_NAME_STR));
+ EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+Module::~Module()
+{
+ EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+bool Module::init(QString const & args)
+{
+ Q_UNUSED(args);
+
+ wWindow = new Window();
+
+ EVAF_INFO("%s initialized", qPrintable(objectName()));
+
+ return true;
+}
+
+void Module::done()
+{
+ if (wWindow) {
+ delete wWindow;
+ wWindow = 0;
+ }
+
+ EVAF_INFO("%s finalized", qPrintable(objectName()));
+}
--- /dev/null
+/**
+ * @file LogView/logview.h
+ * @brief Implementation of the LogView module
+ * @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 __LOGVIEW_LOGVIEW_H
+# define __LOGVIEW_LOGVIEW_H
+
+#include <Plugins/iPlugin>
+#include <Common/iLogger>
+
+#include <QObject>
+#include <QString>
+#include <QWidget>
+#include <QAbstractListModel>
+#include <QQueue>
+#include <QDateTime>
+
+class QListView;
+class QLabel;
+class QTabWidget;
+class QStatusBar;
+class QEvent;
+
+namespace eVaf {
+
+/**
+ * Module for showing messages output with the eVaf::Common::iLogger interface.
+ *
+ * The LogView module implements a widget that shows all the messages output with the
+ * eVaf::Common::iLogger interface.
+ */
+namespace LogView {
+
+/**
+ * Internal implementation of the LogView module.
+ */
+namespace Internal {
+
+/**
+ * Data model for the log view widget
+ */
+class Model : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+
+ /// One logger message
+ struct Message
+ {
+ Message(Common::iLogger::Severity s, QString const & t, QString const & w)
+ : dt(QDateTime::currentDateTime())
+ , severity(s)
+ , text(t)
+ , simplified(t.simplified())
+ , where(w)
+ {}
+
+ QDateTime dt;
+ Common::iLogger::Severity severity;
+ QString text;
+ QString simplified;
+ QString where;
+ };
+
+ Model(QObject * parent = 0);
+
+ Message const & messageAt(int idx) const { return mData.at(idx); }
+
+ virtual int rowCount(QModelIndex const & parent = QModelIndex()) const { return mData.size(); }
+
+ virtual QVariant data(QModelIndex const & index, int role = Qt::DisplayRole) const;
+
+ void addMessage(Common::iLogger::Severity severity, QString const & text, QString const & where);
+
+ QString details(QModelIndex const & index) const;
+
+ bool saveToFile(QString const & fileName);
+
+ bool copyToClipboard(QModelIndex const & index);
+
+ QString errorString() const { return mErrorString; }
+
+
+signals:
+
+ void messageAdded(QModelIndex const & index);
+
+
+private: // Members
+
+ /// Maximum number of lines in the queue
+ static int const MaxLines;
+
+ /// Human-readable texts for message severity levels
+ static char const * const SeverityText[Common::iLogger::Count];
+
+ /// Currently shown messages
+ QQueue<Message> mData;
+
+ /// Human-readable error string if the last operation failed
+ QString mErrorString;
+
+
+private: // Methods
+
+ inline char const * const severityText(Common::iLogger::Severity s) const;
+
+};
+
+/**
+ * The log view widget
+ *
+ * The Widget class implements a widget that shows messages from one logger source.
+ */
+class Widget : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ Widget(QString const & source, QWidget * parent = 0);
+
+ QString const & source() const { return mSource; }
+
+ inline void addMessage(Common::iLogger::Severity severity, QString const & text, QString const & where)
+ {
+ mModel->addMessage(severity, text, where);
+ }
+
+
+private slots:
+
+ void messageAdded(QModelIndex const & index);
+
+ void currentChanged(QModelIndex const &, QModelIndex const &);
+
+ void copyToClipboard();
+
+ void saveToFile();
+
+
+private:
+
+ QString mSource;
+
+ Model * mModel;
+
+ bool mAutoScroll;
+
+ QListView * wList;
+ QLabel * wDetails;
+
+};
+
+/**
+ * The log view window
+ */
+class Window : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ Window(QWidget * parent = 0, Qt::WindowFlags flags = 0);
+
+ virtual ~Window();
+
+ virtual bool event(QEvent * e);
+
+
+public slots:
+
+ void loggerEvent(Common::iLogger::Severity severity, QString const & text, QString const & source, QString const & where);
+
+
+private: // Methods
+
+ void saveSettings();
+
+ void restoreSettings();
+
+
+private: // Members
+
+ QString mDefSource;
+ QTabWidget * wTabs;
+ QHash<QString, Widget *> mLogViews;
+ QStatusBar * wStatusBar;
+
+};
+
+/**
+ * LogView module's implementation
+ */
+class Module : public Plugins::iPlugin
+{
+ Q_OBJECT
+ Q_INTERFACES(eVaf::Plugins::iPlugin)
+
+public:
+
+ Module();
+
+ virtual ~Module();
+
+ virtual bool init(QString const & args);
+
+ virtual void done();
+
+ virtual bool isReady() const { return wWindow != 0; }
+
+private: // Members
+
+ Window * wWindow;
+
+};
+
+} // namespace eVaf::LogView::Internal
+} // namespace eVaf::LogView
+} // namespace eVaf
+
+#endif // logview.h
--- /dev/null
+/**
+ * @file LogView/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 __LOGVIEW_VERSION_H
+#define __LOGVIEW_VERSION_H
+
+#include <version_rc.h>
+
+/**
+ * Module/library version number in the form major,minor,release,build
+ */
+#define VER_FILE_VERSION 0,1,1,2
+
+/**
+ * Module/library version number in the string format (shall end with \0)
+ */
+#define VER_FILE_VERSION_STR "0.1.1.2\0"
+
+/**
+ * Module/library name (shall end with \0)
+ */
+#define VER_MODULE_NAME_STR "LogView\0"
+
+/**
+ * Module type (see version_rc.h for all the types)
+ */
+#define VER_MODULE_TYPE MT_GENERIC
+
+/**
+ * Module type in the string format (see version_rc for all the types)
+ */
+#define VER_MODULE_TYPE_STR MT_GENERIC
+
+/**
+ * Original file name for windows (shall end with \0)
+ */
+#define VER_ORIGINAL_FILE_NAME_STR "LogView.dll\0"
+
+/**
+ * Description of the module/library (shall end with \0)
+ */
+#define VER_FILE_DESCRIPTION_STR "Module for viewing messages output using the iLogger interface.\0"
+
+#endif // version.h
--- /dev/null
+/**
+ * @file LogView/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 <version_rc.h>
+#include <winver.h>
+
+
+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_FILE_NAME_STR
+ VALUE "ProductName", VER_PRODUCT_NAME_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
+ END
+ END
# Header files for the meta-object compiler
set(MOC_HDRS
factory.h
- isdiwindow.h
sdiwindow.h
)
class Factory : public Plugins::iPluginFactory
{
Q_OBJECT
+ Q_INTERFACES(eVaf::Plugins::iPluginFactory)
public:
#include "libsdiwindow.h"
-#include <QObject>
#include <QString>
+#include <QtPlugin>
class QWidget;
class QLayout;
* The iSdiWindow interface provides access to the SDI main window. The SDI main window is
* an empty window that the application can fill with widgets.
*/
-class SDIWINDOW_EXPORT iSdiWindow : public QObject
+struct SDIWINDOW_EXPORT iSdiWindow
{
- Q_OBJECT
-
-public:
-
- /// Interface constructor
- iSdiWindow() : QObject() {}
-
- /// Empty virtual destructor
- virtual ~iSdiWindow() {}
-
/**
* Returns the iSdiWindow interface instance
* @return The iSdiWindow interface or zero if not available
} // namespace eVaf::SdiWindow
} // namespace eVaf
+Q_DECLARE_INTERFACE(eVaf::SdiWindow::iSdiWindow, "eVaf.SdiWindow.iSdiWindow/1.0")
+
#endif // isdiwindow.h
MainWindow::MainWindow(QWidget * parent, Qt::WindowFlags flags)
: QWidget(parent, flags)
+ , mReady(false)
{
setObjectName(QString("%1-%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
mLayout = new QVBoxLayout;
setLayout(mLayout);
+ mSdiWindow = this;
+
EVAF_INFO("%s created", qPrintable(objectName()));
}
MainWindow::~MainWindow()
{
+ mSdiWindow = 0;
+
// Save geometry
saveSettings();
EVAF_INFO("%s destroyed", qPrintable(objectName()));
}
-bool MainWindow::init()
+bool MainWindow::init(QString const & args)
{
+ Q_UNUSED(args);
+
+ Common::iRegistry::instance()->registerInterface("iSdiWindow", this);
+
setWindowTitle(Common::iApp::instance()->name());
show();
+ mReady = true;
+
EVAF_INFO("%s initialized", qPrintable(objectName()));
return true;
void MainWindow::done()
{
+ mReady = false;
+
close();
// Delete all the items added to the main window
while (mItemsAdded.count() > 0) {
- QPointer<QObject> item = mItemsAdded.takeAt(0);
- if (item)
+ QWeakPointer<QObject> item = mItemsAdded.takeAt(0);
+ if (!item.isNull())
delete item.data();
}
}
-//-------------------------------------------------------------------
-
-SdiWindowImpl::SdiWindowImpl()
- : iSdiWindow()
- , mReady(false)
-{
- setObjectName(QString("%1.iSdiWindow").arg(VER_MODULE_NAME_STR));
-
- mSdiWindow = this;
-
- wWindow = new MainWindow;
-
- Common::iRegistry::instance()->registerInterface("iSdiWindow", this);
-
- EVAF_INFO("%s created", qPrintable(objectName()));
-}
-
-SdiWindowImpl::~SdiWindowImpl()
-{
- delete wWindow;
-
- mSdiWindow = 0;
-
- EVAF_INFO("%s destroyed", qPrintable(objectName()));
-}
-
-bool SdiWindowImpl::init(const QString & args)
-{
- Q_UNUSED(args);
-
- if (!wWindow->init())
- return false;
-
- mReady = true;
-
- EVAF_INFO("%s initialized", qPrintable(objectName()));
-
- return true;
-}
-
-void SdiWindowImpl::done()
-{
- mReady = false;
-
- wWindow->done();
-
- EVAF_INFO("%s finalized", qPrintable(objectName()));
-}
-
-
//-------------------------------------------------------------------
SdiWindowPlugin::SdiWindowPlugin()
{
setObjectName(VER_MODULE_NAME_STR);
- mWindow = new SdiWindowImpl;
+ mWindow = new MainWindow;
EVAF_INFO("%s created", qPrintable(objectName()));
}
#include <QString>
#include <QWidget>
#include <QList>
-#include <QPointer>
+#include <QWeakPointer>
class QVBoxLayout;
namespace Internal {
/**
- * Main window widget
+ * Main window widget implementing the iSdiWindow interface
*/
-class MainWindow : public QWidget
+class MainWindow : public QWidget, public iSdiWindow
{
Q_OBJECT
+ Q_INTERFACES(eVaf::SdiWindow::iSdiWindow)
public:
virtual ~MainWindow();
- bool init();
+ virtual bool init(QString const & args);
- void done();
+ virtual void done();
+
+ virtual bool isReady() { return mReady; }
- void addWidget(QWidget * widget);
+ virtual void addWidget(QWidget * widget);
- void addLayout(QLayout * layout);
+ virtual void addLayout(QLayout * layout);
private: // Methods
private: // Members
+ /// Ready flag
+ bool mReady;
+
/// The layout of the window
QVBoxLayout * mLayout;
/// Widgets and layouts added to the main window
- QList<QPointer<QObject> > mItemsAdded;
-
-};
-
-/**
- * iSdiWindow interface implementation
- */
-class SdiWindowImpl : public iSdiWindow
-{
- Q_OBJECT
-
-public:
-
- SdiWindowImpl();
-
- virtual ~SdiWindowImpl();
-
- bool init(const QString & args);
-
- void done();
-
- bool isReady() const { return mReady; }
-
- virtual void addWidget(QWidget * widget) { wWindow->addWidget(widget); }
-
- virtual void addLayout(QLayout * layout) { wWindow->addLayout(layout); }
-
-
-private: // Members
-
- /// Ready flag
- bool mReady;
+ QList<QWeakPointer<QObject> > mItemsAdded;
- /// The main window widget
- MainWindow * wWindow;
};
/**
class SdiWindowPlugin : public Plugins::iPlugin
{
Q_OBJECT
+ Q_INTERFACES(eVaf::Plugins::iPlugin)
public:
private:
/// iSdiWindow interface implementation
- SdiWindowImpl * mWindow;
+ MainWindow * mWindow;
};
} // namespace eVaf::SdiWindow::Internal
/**
* Module/library version number in the form major,minor,release,build
*/
-#define VER_FILE_VERSION 0,2,2,3
+#define VER_FILE_VERSION 0,2,4,5
/**
* Module/library version number in the string format (shall end with \0)
*/
-#define VER_FILE_VERSION_STR "0.2.2.3\0"
+#define VER_FILE_VERSION_STR "0.2.4.5\0"
/**
* Module/library name (shall end with \0)
class Factory : public Plugins::iPluginFactory
{
Q_OBJECT
+ Q_INTERFACES(eVaf::Plugins::iPluginFactory)
public:
class TestPlugin : public Plugins::iPlugin
{
Q_OBJECT
+ Q_INTERFACES(eVaf::Plugins::iPlugin)
public: