]> vaikene.ee Git - evaf/commitdiff
Implemented the LogView module that shows messages output using the Common::iLogger...
authorEnar Väikene <enar@vaikene.net>
Wed, 19 Oct 2011 12:57:24 +0000 (15:57 +0300)
committerEnar Väikene <enar@vaikene.net>
Wed, 19 Oct 2011 12:57:24 +0000 (15:57 +0300)
src/plugins/LogView/logview.cpp
src/plugins/LogView/logview.h
src/plugins/LogView/version.h

index e1c140004a8e21632361f86aef609c59c8013770..2eaae975d2ea4eae1338eeeb417d000d5d1f893a 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <Common/Globals>
 #include <Common/iLogger>
+#include <Common/iApp>
 
 #include <QtGui>
 
@@ -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<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()
-    , 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()));
index 383588de454272efb192c1c019531688143004c6..1bfe6a8228b62c30943efa09787ee95fd3ecfa25 100644 (file)
 #include <QQueue>
 #include <QDateTime>
 
+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<QString, Widget *> 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;
 
 };
 
index d60fea9b3393339ea7889561d6f9b550238817fa..d8d31338dee47ed37b0b11254aca75de61c169d6 100644 (file)
 /**
  * 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)