X-Git-Url: https://vaikene.ee/gitweb/highlight.css?a=blobdiff_plain;f=src%2Fplugins%2FLogView%2Flogview.cpp;h=1bd41a170a5573cfa799ae89c59417b8000ba709;hb=HEAD;hp=e1c140004a8e21632361f86aef609c59c8013770;hpb=6490924aa3d05fe32a3437fbd6cdde289a6a9a6b;p=evaf diff --git a/src/plugins/LogView/logview.cpp b/src/plugins/LogView/logview.cpp index e1c1400..1bd41a1 100644 --- a/src/plugins/LogView/logview.cpp +++ b/src/plugins/LogView/logview.cpp @@ -3,7 +3,7 @@ * @brief Implementation of the LogView module * @author Enar Vaikene * - * Copyright (c) 2011 Enar Vaikene + * Copyright (c) 2011-2019 Enar Vaikene * * This file is part of the eVaf C++ cross-platform application development framework. * @@ -22,8 +22,12 @@ #include #include +#include +#include +#include -#include +#include +#include using namespace eVaf; @@ -57,8 +61,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; - break; + return mData.at(index.row()).simplified; } // Change color for different message types @@ -67,18 +70,14 @@ QVariant Model::data(QModelIndex const & index, int role) const 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) @@ -98,15 +97,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 +141,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) @@ -154,7 +153,7 @@ bool Model::saveToFile(QString const & fileName) return true; } -char const * const Model::severityText(Common::iLogger::Severity s) const +char const * Model::severityText(Common::iLogger::Severity s) const { if (s >= Common::iLogger::None && s < Common::iLogger::Count) return SeverityText[s]; @@ -165,24 +164,221 @@ char const * const Model::severityText(Common::iLogger::Severity s) const //------------------------------------------------------------------- -Widget::Widget(QWidget * parent, Qt::WindowFlags flags) - : QWidget(parent, 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) { - setObjectName(QString("%1-Widget").arg(VER_MODULE_NAME_STR)); + 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(QString const & args, QWidget * parent, Qt::WindowFlags flags) + : Gui::Panel(parent, flags) +{ + setObjectName(QString("%1-Window").arg(VER_MODULE_NAME_STR)); + + SdiWindow::iSdiWindow * win = evafQueryInterface("iSdiWindow"); + win->addPanel(getPanelName(args), this); + + 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())); } +QString Window::getPanelName(QString const & args) const +{ + QString panelName = "LogView"; + + QXmlStreamReader xml(args); + while (!xml.atEnd()) { + xml.readNext(); + if (xml.isStartElement() && xml.name() == "attributes") { + if (xml.attributes().hasAttribute("panelName")) { + QString s = xml.attributes().value("panelName").toString(); + if (!s.isEmpty()) + panelName = s; + } + } + } + + return panelName; +} + +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())); @@ -195,9 +391,7 @@ Module::~Module() bool Module::init(QString const & args) { - Q_UNUSED(args); - - wWidget = new Widget(); + wWindow = new Window(args); EVAF_INFO("%s initialized", qPrintable(objectName())); @@ -206,9 +400,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()));