From 31e526453fe2983e8855342c980a1814bd39db7b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Enar=20V=C3=A4ikene?= Date: Wed, 19 Oct 2011 15:57:24 +0300 Subject: [PATCH] Implemented the LogView module that shows messages output using the Common::iLogger interface. --- src/plugins/LogView/logview.cpp | 206 +++++++++++++++++++++++++++++--- src/plugins/LogView/logview.h | 75 +++++++++++- src/plugins/LogView/version.h | 4 +- 3 files changed, 264 insertions(+), 21 deletions(-) diff --git a/src/plugins/LogView/logview.cpp b/src/plugins/LogView/logview.cpp index e1c1400..2eaae97 100644 --- a/src/plugins/LogView/logview.cpp +++ b/src/plugins/LogView/logview.cpp @@ -22,6 +22,7 @@ #include #include +#include #include @@ -57,7 +58,7 @@ QVariant Model::data(QModelIndex const & index, int role) const // Return the message for the display role case Qt::DisplayRole: { - return mData.at(index.row()).text; + return mData.at(index.row()).simplified; break; } @@ -98,15 +99,16 @@ void Model::addMessage(Common::iLogger::Severity severity, QString const & text, 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 : %5\nOccurred in %6") + return tr("%1 %2 %3 : %4\nOccurred in %5") .arg(m.dt.date().toString(Qt::DefaultLocaleShortDate)) - .arg(m.dt.time().toString(Qt::DefaultLocaleLongDate)) - .arg(m.dt.time().msec(), 3, 10, QChar('0')) + .arg(m.dt.time().toString("HH:mm:ss.zzz")) .arg(tr(severityText(m.severity))) .arg(m.text) .arg(m.where); @@ -141,10 +143,9 @@ bool Model::saveToFile(QString const & fileName) for (int i = 0; i < mData.size(); ++i) { Message const & m = mData.at(i); - out << tr("%1 %2.%3 %4 : %5 (occurred in %6)\n") + out << tr("%1 %2 %3 : %4 (occurred in %5)\n") .arg(m.dt.date().toString(Qt::DefaultLocaleShortDate)) - .arg(m.dt.time().toString(Qt::DefaultLocaleLongDate)) - .arg(m.dt.time().msec(), 3, 10, QChar('0')) + .arg(m.dt.time().toString("HH:mm:ss.zzz")) .arg(tr(severityText(m.severity))) .arg(m.text) .arg(m.where) @@ -165,24 +166,199 @@ char const * const Model::severityText(Common::iLogger::Severity s) const //------------------------------------------------------------------- -Widget::Widget(QWidget * parent, Qt::WindowFlags flags) +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-Widget").arg(VER_MODULE_NAME_STR)); + 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())); } -Widget::~Widget() +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(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::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() - , wWidget(0) + , wWindow(0) { setObjectName(QString("%1-Module").arg(VER_MODULE_NAME_STR)); EVAF_INFO("%s created", qPrintable(objectName())); @@ -197,7 +373,7 @@ bool Module::init(QString const & args) { Q_UNUSED(args); - wWidget = new Widget(); + wWindow = new Window(); EVAF_INFO("%s initialized", qPrintable(objectName())); @@ -206,9 +382,9 @@ bool Module::init(QString const & args) void Module::done() { - if (wWidget) { - delete wWidget; - wWidget = 0; + if (wWindow) { + delete wWindow; + wWindow = 0; } EVAF_INFO("%s finalized", qPrintable(objectName())); diff --git a/src/plugins/LogView/logview.h b/src/plugins/LogView/logview.h index 383588d..1bfe6a8 100644 --- a/src/plugins/LogView/logview.h +++ b/src/plugins/LogView/logview.h @@ -30,6 +30,11 @@ #include #include +class QListView; +class QLabel; +class QTabWidget; +class QStatusBar; +class QEvent; namespace eVaf { @@ -62,12 +67,14 @@ public: : dt(QDateTime::currentDateTime()) , severity(s) , text(t) + , simplified(t.simplified()) , where(w) {} QDateTime dt; Common::iLogger::Severity severity; QString text; + QString simplified; QString where; }; @@ -118,6 +125,8 @@ private: // Methods /** * The log view widget + * + * The Widget class implements a widget that shows messages from one logger source. */ class Widget : public QWidget { @@ -125,9 +134,59 @@ class Widget : public QWidget public: - Widget(QWidget * parent = 0, Qt::WindowFlags flags = 0); + 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 &); - virtual ~Widget(); + 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 @@ -136,6 +195,14 @@ private: // Methods void restoreSettings(); + +private: // Members + + QString mDefSource; + QTabWidget * wTabs; + QHash mLogViews; + QStatusBar * wStatusBar; + }; /** @@ -156,11 +223,11 @@ public: virtual void done(); - virtual bool isReady() const { return wWidget != 0; } + virtual bool isReady() const { return wWindow != 0; } private: // Members - Widget * wWidget; + Window * wWindow; }; diff --git a/src/plugins/LogView/version.h b/src/plugins/LogView/version.h index d60fea9..d8d3133 100644 --- a/src/plugins/LogView/version.h +++ b/src/plugins/LogView/version.h @@ -25,12 +25,12 @@ /** * 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) -- 2.45.0