]>
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>
31 using namespace eVaf::LogView::Internal
;
34 //-------------------------------------------------------------------
36 int const Model::MaxLines
= 1000;
38 char const * const Model::SeverityText
[Common::iLogger::Count
] = {
39 QT_TR_NOOP("[NONE] "),
40 QT_TR_NOOP("[FATAL] "),
41 QT_TR_NOOP("[ERROR] "),
42 QT_TR_NOOP("[WARNING]"),
43 QT_TR_NOOP("[INFO] "),
44 QT_TR_NOOP("[DEBUG] ")
47 Model::Model(QObject
* parent
)
48 : QAbstractListModel(parent
)
52 QVariant
Model::data(QModelIndex
const & index
, int role
) const
54 if (!index
.isValid() || index
.row() < 0 || index
.row() >= mData
.size() || index
.column() != 0)
59 // Return the message for the display role
60 case Qt::DisplayRole
: {
61 return mData
.at(index
.row()).simplified
;
65 // Change color for different message types
66 case Qt::ForegroundRole
: {
67 Common::iLogger::Severity s
= mData
.at(index
.row()).severity
;
69 case Common::iLogger::Info
:
70 return QBrush(QColor(Qt::blue
));
72 case Common::iLogger::Warning
:
73 return QBrush(QColor(Qt::black
));
75 case Common::iLogger::Error
:
76 case Common::iLogger::Fatal
:
77 return QBrush(QColor(Qt::red
));
89 void Model::addMessage(Common::iLogger::Severity severity
, QString
const & text
, QString
const & where
)
91 // Add the message to the end of the queue
92 beginInsertRows(QModelIndex(), mData
.size(), mData
.size());
93 mData
.enqueue(Message(severity
, text
, where
));
96 // Remove oldest messages if the list is full
97 if (mData
.size() > MaxLines
) {
98 beginRemoveRows(QModelIndex(), 0, 0);
103 emit
messageAdded(index(mData
.size() - 1, 0));
106 QString
Model::details(QModelIndex
const & index
) const
108 Message
const & m
= mData
.at(index
.row());
109 return tr("%1 %2 %3 : %4\nOccurred in %5")
110 .arg(m
.dt
.date().toString(Qt::DefaultLocaleShortDate
))
111 .arg(m
.dt
.time().toString("HH:mm:ss.zzz"))
112 .arg(tr(severityText(m
.severity
)))
117 bool Model::copyToClipboard(QModelIndex
const & index
)
119 mErrorString
.clear();
121 QClipboard
* cb
= QApplication::clipboard();
123 cb
->setText(details(index
));
127 mErrorString
= tr("The global clipboard is not available");
132 bool Model::saveToFile(QString
const & fileName
)
134 mErrorString
.clear();
137 if (!f
.open(QFile::WriteOnly
)) {
138 mErrorString
= tr("Failed to open the file '%1' for writing : %2").arg(fileName
).arg(f
.errorString());
144 for (int i
= 0; i
< mData
.size(); ++i
) {
145 Message
const & m
= mData
.at(i
);
146 out
<< tr("%1 %2 %3 : %4 (occurred in %5)\n")
147 .arg(m
.dt
.date().toString(Qt::DefaultLocaleShortDate
))
148 .arg(m
.dt
.time().toString("HH:mm:ss.zzz"))
149 .arg(tr(severityText(m
.severity
)))
158 char const * const Model::severityText(Common::iLogger::Severity s
) const
160 if (s
>= Common::iLogger::None
&& s
< Common::iLogger::Count
)
161 return SeverityText
[s
];
163 return SeverityText
[Common::iLogger::None
];
167 //-------------------------------------------------------------------
169 Widget::Widget(QString
const & source
, QWidget
* parent
)
174 QVBoxLayout
* w
= new QVBoxLayout
;
177 mModel
= new Model(this);
178 connect(mModel
, SIGNAL(messageAdded(QModelIndex
)), this, SLOT(messageAdded(QModelIndex
)));
180 wList
= new QListView
;
181 wList
->setModel(mModel
);
182 wList
->setUniformItemSizes(true);
183 connect(wList
->selectionModel(), SIGNAL(currentChanged(QModelIndex
,QModelIndex
)), this, SLOT(currentChanged(QModelIndex
,QModelIndex
)));
186 wList
->setContextMenuPolicy(Qt::ActionsContextMenu
);
188 QAction
* a
= new QAction(tr("&Copy", VER_MODULE_NAME_STR
), this);
189 a
->setStatusTip(tr("Copies the selected message to the clipboard for pasting into other applications", VER_MODULE_NAME_STR
));
190 connect(a
, SIGNAL(triggered()), this, SLOT(copyToClipboard()));
193 a
= new QAction(tr("&Save to ...", VER_MODULE_NAME_STR
), this);
194 a
->setStatusTip(tr("Saves all the messages to a file", VER_MODULE_NAME_STR
));
195 connect(a
, SIGNAL(triggered()), this, SLOT(saveToFile()));
198 wDetails
= new QLabel
;
199 wDetails
->setWordWrap(true);
200 w
->addWidget(wDetails
);
203 void Widget::messageAdded(QModelIndex
const & index
)
206 wList
->selectionModel()->setCurrentIndex(index
, QItemSelectionModel::ClearAndSelect
);
209 void Widget::currentChanged(QModelIndex
const & current
, QModelIndex
const & previous
)
213 if (!current
.isValid() || current
.row() < 0 || current
.row() > mModel
->rowCount()) {
218 mAutoScroll
= current
.row() == (mModel
->rowCount() - 1);
220 wDetails
->setText(mModel
->details(current
));
223 void Widget::copyToClipboard()
225 QModelIndex idx
= wList
->selectionModel()->currentIndex();
227 mModel
->copyToClipboard(idx
);
230 void Widget::saveToFile()
232 QString fileName
= QFileDialog::getSaveFileName(this,
233 tr("Save to file", VER_MODULE_NAME_STR
),
234 Common::iApp::instance()->dataRootDir() + QString("%1_%2.txt").arg(mSource
).arg(QDate::currentDate().toString("yyyyMMdd")),
235 tr("Text files (*.txt);;All files (*)", VER_MODULE_NAME_STR
));
236 if (fileName
.isEmpty())
239 if (!mModel
->saveToFile(fileName
))
240 QMessageBox::critical(this, tr("Error", VER_MODULE_NAME_STR
), mModel
->errorString());
244 //-------------------------------------------------------------------
246 Window::Window(QWidget
* parent
, Qt::WindowFlags flags
)
247 : QWidget(parent
, flags
)
249 setObjectName(QString("%1-Window").arg(VER_MODULE_NAME_STR
));
251 setWindowTitle(tr("Messages"));
253 Common::iLogger
* logger
= Common::iLogger::instance();
254 EVAF_TEST_X(logger
, "No iLogger interface");
256 mDefSource
= logger
->defaultSource();
257 if (mDefSource
.isEmpty())
258 mDefSource
= "Common";
260 QVBoxLayout
* w
= new QVBoxLayout
;
264 wTabs
= new QTabWidget
;
267 // Add the default source
268 Widget
* s
= new Widget(mDefSource
);
269 mLogViews
.insert(s
->source(), s
);
270 wTabs
->addTab(s
, s
->source());
272 wStatusBar
= new QStatusBar
;
273 w
->addWidget(wStatusBar
);
275 QAction
* a
= new QAction(this);
276 a
->setShortcut(Qt::Key_Escape
);
277 connect(a
, SIGNAL(triggered()), this, SLOT(close()));
282 connect(logger
, SIGNAL(loggerEvent(Common::iLogger::Severity
,QString
,QString
,QString
)), this, SLOT(loggerEvent(Common::iLogger::Severity
,QString
,QString
,QString
)));
286 EVAF_INFO("%s created", qPrintable(objectName()));
295 EVAF_INFO("%s destroyed", qPrintable(objectName()));
298 bool Window::event(QEvent
* e
)
300 if (e
->type() == QEvent::StatusTip
) {
301 QStatusTipEvent
* event
= static_cast<QStatusTipEvent
*>(e
);
302 wStatusBar
->showMessage(event
->tip());
305 return QWidget::event(e
);
308 void Window::saveSettings()
310 static int ver
[4] = {VER_FILE_VERSION
};
311 QSettings
settings(VER_COMPANY_NAME_STR
, Common::iApp::instance()->name());
312 settings
.setValue(QString("%1/version/major").arg(objectName()), ver
[0]);
313 settings
.setValue(QString("%1/version/minor").arg(objectName()), ver
[1]);
314 settings
.setValue(QString("%1/geometry").arg(objectName()), saveGeometry());
317 void Window::restoreSettings()
319 static int ver
[4] = {VER_FILE_VERSION
};
320 QSettings
settings(VER_COMPANY_NAME_STR
, Common::iApp::instance()->name());
322 // Ignore saved settings if the version number is not the same
323 // More intelligent checks can be implemented to allow upgrading from previous versions
324 QVariant v
= settings
.value(QString("%1/version/major").arg(objectName()));
325 if (!v
.isValid() || v
.toInt() != ver
[0])
327 v
= settings
.value(QString("%1/version/minor").arg(objectName()));
328 if (!v
.isValid() || v
.toInt() != ver
[1])
331 // Restore the geometry
332 restoreGeometry(settings
.value(QString("%1/geometry").arg(objectName())).toByteArray());
335 void Window::loggerEvent(Common::iLogger::Severity severity
, QString
const & text
, QString
const & source
, QString
const & where
)
337 // Ignore messages with >=DEBUG severity level
338 if (severity
>= Common::iLogger::Debug
)
341 // Find or create the log view widget for this source
343 QString s
= source
.isEmpty() ? mDefSource
: source
;
344 QHash
<QString
, Widget
*>::const_iterator it
= mLogViews
.constFind(s
);
345 if (it
== mLogViews
.constEnd()) {
347 mLogViews
.insert(w
->source(), w
);
348 wTabs
->addTab(w
, w
->source());
353 w
->addMessage(severity
, text
, where
);
357 //-------------------------------------------------------------------
363 setObjectName(QString("%1-Module").arg(VER_MODULE_NAME_STR
));
364 EVAF_INFO("%s created", qPrintable(objectName()));
369 EVAF_INFO("%s destroyed", qPrintable(objectName()));
372 bool Module::init(QString
const & args
)
376 wWindow
= new Window();
378 EVAF_INFO("%s initialized", qPrintable(objectName()));
390 EVAF_INFO("%s finalized", qPrintable(objectName()));