]>
vaikene.ee Git - evaf/blob - src/plugins/LogView/logview.cpp
2 * @file LogView/logview.cpp
3 * @brief Implementation of the LogView module
6 * Copyright (c) 2011 Enar Vaikene
8 * This file is part of the eVaf C++ cross-platform application development framework.
10 * This file can be used under the terms of the GNU General Public License
11 * version 3.0 as published by the Free Software Foundation and appearing in
12 * the file LICENSE included in the packaging of this file. Please review the
13 * the following information to ensure the GNU General Public License version
14 * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
16 * Alternatively, this file may be used in accordance with the Commercial License
17 * Agreement provided with the Software.
23 #include <Common/Globals>
24 #include <Common/iLogger>
25 #include <Common/iApp>
26 #include <Common/iRegistry>
27 #include <SdiWindow/iSdiWindow>
30 #include <QXmlStreamReader>
34 using namespace eVaf::LogView::Internal
;
37 //-------------------------------------------------------------------
39 int const Model::MaxLines
= 1000;
41 char const * const Model::SeverityText
[Common::iLogger::Count
] = {
42 QT_TR_NOOP("[NONE] "),
43 QT_TR_NOOP("[FATAL] "),
44 QT_TR_NOOP("[ERROR] "),
45 QT_TR_NOOP("[WARNING]"),
46 QT_TR_NOOP("[INFO] "),
47 QT_TR_NOOP("[DEBUG] ")
50 Model::Model(QObject
* parent
)
51 : QAbstractListModel(parent
)
55 QVariant
Model::data(QModelIndex
const & index
, int role
) const
57 if (!index
.isValid() || index
.row() < 0 || index
.row() >= mData
.size() || index
.column() != 0)
62 // Return the message for the display role
63 case Qt::DisplayRole
: {
64 return mData
.at(index
.row()).simplified
;
68 // Change color for different message types
69 case Qt::ForegroundRole
: {
70 Common::iLogger::Severity s
= mData
.at(index
.row()).severity
;
72 case Common::iLogger::Info
:
73 return QBrush(QColor(Qt::blue
));
75 case Common::iLogger::Warning
:
76 return QBrush(QColor(Qt::black
));
78 case Common::iLogger::Error
:
79 case Common::iLogger::Fatal
:
80 return QBrush(QColor(Qt::red
));
92 void Model::addMessage(Common::iLogger::Severity severity
, QString
const & text
, QString
const & where
)
94 // Add the message to the end of the queue
95 beginInsertRows(QModelIndex(), mData
.size(), mData
.size());
96 mData
.enqueue(Message(severity
, text
, where
));
99 // Remove oldest messages if the list is full
100 if (mData
.size() > MaxLines
) {
101 beginRemoveRows(QModelIndex(), 0, 0);
106 emit
messageAdded(index(mData
.size() - 1, 0));
109 QString
Model::details(QModelIndex
const & index
) const
111 Message
const & m
= mData
.at(index
.row());
112 return tr("%1 %2 %3 : %4\nOccurred in %5")
113 .arg(m
.dt
.date().toString(Qt::DefaultLocaleShortDate
))
114 .arg(m
.dt
.time().toString("HH:mm:ss.zzz"))
115 .arg(tr(severityText(m
.severity
)))
120 bool Model::copyToClipboard(QModelIndex
const & index
)
122 mErrorString
.clear();
124 QClipboard
* cb
= QApplication::clipboard();
126 cb
->setText(details(index
));
130 mErrorString
= tr("The global clipboard is not available");
135 bool Model::saveToFile(QString
const & fileName
)
137 mErrorString
.clear();
140 if (!f
.open(QFile::WriteOnly
)) {
141 mErrorString
= tr("Failed to open the file '%1' for writing : %2").arg(fileName
).arg(f
.errorString());
147 for (int i
= 0; i
< mData
.size(); ++i
) {
148 Message
const & m
= mData
.at(i
);
149 out
<< tr("%1 %2 %3 : %4 (occurred in %5)\n")
150 .arg(m
.dt
.date().toString(Qt::DefaultLocaleShortDate
))
151 .arg(m
.dt
.time().toString("HH:mm:ss.zzz"))
152 .arg(tr(severityText(m
.severity
)))
161 char const * const Model::severityText(Common::iLogger::Severity s
) const
163 if (s
>= Common::iLogger::None
&& s
< Common::iLogger::Count
)
164 return SeverityText
[s
];
166 return SeverityText
[Common::iLogger::None
];
170 //-------------------------------------------------------------------
172 Widget::Widget(QString
const & source
, QWidget
* parent
)
177 QVBoxLayout
* w
= new QVBoxLayout
;
180 mModel
= new Model(this);
181 connect(mModel
, SIGNAL(messageAdded(QModelIndex
)), this, SLOT(messageAdded(QModelIndex
)));
183 wList
= new QListView
;
184 wList
->setModel(mModel
);
185 wList
->setUniformItemSizes(true);
186 connect(wList
->selectionModel(), SIGNAL(currentChanged(QModelIndex
,QModelIndex
)), this, SLOT(currentChanged(QModelIndex
,QModelIndex
)));
189 wList
->setContextMenuPolicy(Qt::ActionsContextMenu
);
191 QAction
* a
= new QAction(tr("&Copy", VER_MODULE_NAME_STR
), this);
192 a
->setStatusTip(tr("Copies the selected message to the clipboard for pasting into other applications", VER_MODULE_NAME_STR
));
193 connect(a
, SIGNAL(triggered()), this, SLOT(copyToClipboard()));
196 a
= new QAction(tr("&Save to ...", VER_MODULE_NAME_STR
), this);
197 a
->setStatusTip(tr("Saves all the messages to a file", VER_MODULE_NAME_STR
));
198 connect(a
, SIGNAL(triggered()), this, SLOT(saveToFile()));
201 wDetails
= new QLabel
;
202 wDetails
->setWordWrap(true);
203 w
->addWidget(wDetails
);
206 void Widget::messageAdded(QModelIndex
const & index
)
209 wList
->selectionModel()->setCurrentIndex(index
, QItemSelectionModel::ClearAndSelect
);
212 void Widget::currentChanged(QModelIndex
const & current
, QModelIndex
const & previous
)
216 if (!current
.isValid() || current
.row() < 0 || current
.row() > mModel
->rowCount()) {
221 mAutoScroll
= current
.row() == (mModel
->rowCount() - 1);
223 wDetails
->setText(mModel
->details(current
));
226 void Widget::copyToClipboard()
228 QModelIndex idx
= wList
->selectionModel()->currentIndex();
230 mModel
->copyToClipboard(idx
);
233 void Widget::saveToFile()
235 QString fileName
= QFileDialog::getSaveFileName(this,
236 tr("Save to file", VER_MODULE_NAME_STR
),
237 Common::iApp::instance()->dataRootDir() + QString("%1_%2.txt").arg(mSource
).arg(QDate::currentDate().toString("yyyyMMdd")),
238 tr("Text files (*.txt);;All files (*)", VER_MODULE_NAME_STR
));
239 if (fileName
.isEmpty())
242 if (!mModel
->saveToFile(fileName
))
243 QMessageBox::critical(this, tr("Error", VER_MODULE_NAME_STR
), mModel
->errorString());
247 //-------------------------------------------------------------------
249 Window::Window(QString
const & args
, QWidget
* parent
, Qt::WindowFlags flags
)
250 : Gui::Panel(parent
, flags
)
252 setObjectName(QString("%1-Window").arg(VER_MODULE_NAME_STR
));
254 SdiWindow::iSdiWindow
* win
= evafQueryInterface
<SdiWindow::iSdiWindow
>("iSdiWindow");
255 win
->addPanel(getPanelName(args
), this);
257 setWindowTitle(tr("Messages"));
259 Common::iLogger
* logger
= Common::iLogger::instance();
260 EVAF_TEST_X(logger
, "No iLogger interface");
262 mDefSource
= logger
->defaultSource();
263 if (mDefSource
.isEmpty())
264 mDefSource
= "Common";
266 QVBoxLayout
* w
= new QVBoxLayout
;
270 wTabs
= new QTabWidget
;
273 // Add the default source
274 Widget
* s
= new Widget(mDefSource
);
275 mLogViews
.insert(s
->source(), s
);
276 wTabs
->addTab(s
, s
->source());
278 wStatusBar
= new QStatusBar
;
279 w
->addWidget(wStatusBar
);
281 QAction
* a
= new QAction(this);
282 a
->setShortcut(Qt::Key_Escape
);
283 connect(a
, SIGNAL(triggered()), this, SLOT(close()));
288 connect(logger
, SIGNAL(loggerEvent(Common::iLogger::Severity
,QString
,QString
,QString
)), this, SLOT(loggerEvent(Common::iLogger::Severity
,QString
,QString
,QString
)));
292 EVAF_INFO("%s created", qPrintable(objectName()));
301 EVAF_INFO("%s destroyed", qPrintable(objectName()));
304 QString
Window::getPanelName(QString
const & args
) const
306 QString panelName
= "LogView";
308 QXmlStreamReader
xml(args
);
309 while (!xml
.atEnd()) {
311 if (xml
.isStartElement() && xml
.name() == "attributes") {
312 if (xml
.attributes().hasAttribute("panelName")) {
313 QString s
= xml
.attributes().value("panelName").toString();
323 bool Window::event(QEvent
* e
)
325 if (e
->type() == QEvent::StatusTip
) {
326 QStatusTipEvent
* event
= static_cast<QStatusTipEvent
*>(e
);
327 wStatusBar
->showMessage(event
->tip());
330 return QWidget::event(e
);
333 void Window::saveSettings()
335 static int ver
[4] = {VER_FILE_VERSION
};
336 QSettings
settings(VER_COMPANY_NAME_STR
, Common::iApp::instance()->name());
337 settings
.setValue(QString("%1/version/major").arg(objectName()), ver
[0]);
338 settings
.setValue(QString("%1/version/minor").arg(objectName()), ver
[1]);
339 settings
.setValue(QString("%1/geometry").arg(objectName()), saveGeometry());
342 void Window::restoreSettings()
344 static int ver
[4] = {VER_FILE_VERSION
};
345 QSettings
settings(VER_COMPANY_NAME_STR
, Common::iApp::instance()->name());
347 // Ignore saved settings if the version number is not the same
348 // More intelligent checks can be implemented to allow upgrading from previous versions
349 QVariant v
= settings
.value(QString("%1/version/major").arg(objectName()));
350 if (!v
.isValid() || v
.toInt() != ver
[0])
352 v
= settings
.value(QString("%1/version/minor").arg(objectName()));
353 if (!v
.isValid() || v
.toInt() != ver
[1])
356 // Restore the geometry
357 restoreGeometry(settings
.value(QString("%1/geometry").arg(objectName())).toByteArray());
360 void Window::loggerEvent(Common::iLogger::Severity severity
, QString
const & text
, QString
const & source
, QString
const & where
)
362 // Ignore messages with >=DEBUG severity level
363 if (severity
>= Common::iLogger::Debug
)
366 // Find or create the log view widget for this source
368 QString s
= source
.isEmpty() ? mDefSource
: source
;
369 QHash
<QString
, Widget
*>::const_iterator it
= mLogViews
.constFind(s
);
370 if (it
== mLogViews
.constEnd()) {
372 mLogViews
.insert(w
->source(), w
);
373 wTabs
->addTab(w
, w
->source());
378 w
->addMessage(severity
, text
, where
);
382 //-------------------------------------------------------------------
388 setObjectName(QString("%1-Module").arg(VER_MODULE_NAME_STR
));
389 EVAF_INFO("%s created", qPrintable(objectName()));
394 EVAF_INFO("%s destroyed", qPrintable(objectName()));
397 bool Module::init(QString
const & args
)
399 wWindow
= new Window(args
);
401 EVAF_INFO("%s initialized", qPrintable(objectName()));
413 EVAF_INFO("%s finalized", qPrintable(objectName()));