mirror of
https://github.com/YACReader/yacreader
synced 2025-05-28 03:10:27 -04:00
278 lines
8.5 KiB
C++
278 lines
8.5 KiB
C++
// Copyright (c) 2015, Axel Gembe <axel@gembe.net>
|
|
// All rights reserved.
|
|
|
|
// Redistribution and use in source and binary forms, with or without modification,
|
|
// are permitted provided that the following conditions are met:
|
|
|
|
// * Redistributions of source code must retain the above copyright notice, this
|
|
// list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright notice, this
|
|
// list of conditions and the following disclaimer in the documentation and/or other
|
|
// materials provided with the distribution.
|
|
// * The name of the contributors may not be used to endorse or promote products
|
|
// derived from this software without specific prior written permission.
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#include "QsLogWindow.h"
|
|
#include "QsLogWindowModel.h"
|
|
#include "QsLog.h"
|
|
#include "QsLogMessage.h"
|
|
#include "ui_QsLogWindow.h"
|
|
|
|
#include <QIcon>
|
|
#include <QSortFilterProxyModel>
|
|
#include <QClipboard>
|
|
#include <QKeyEvent>
|
|
#include <QFileDialog>
|
|
#include <QtGlobal>
|
|
#include <cstddef>
|
|
|
|
static const QIcon& pauseIcon()
|
|
{
|
|
static QIcon icon(QString::fromLatin1(":/QsLogWindow/images/icon-pause-16.png"));
|
|
return icon;
|
|
}
|
|
|
|
static const QIcon& playIcon()
|
|
{
|
|
static QIcon icon(QString::fromLatin1(":/QsLogWindow/images/icon-resume-16.png"));
|
|
return icon;
|
|
}
|
|
|
|
|
|
class QsLogging::WindowLogFilterProxyModel : public QSortFilterProxyModel
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
WindowLogFilterProxyModel(Level level, QObject* parent = 0)
|
|
: QSortFilterProxyModel(parent)
|
|
, mLevel(level)
|
|
, mLastVisibleRow(0)
|
|
{
|
|
}
|
|
|
|
Level level() const
|
|
{
|
|
return mLevel;
|
|
}
|
|
|
|
void setLevel(const Level level)
|
|
{
|
|
mLevel = level;
|
|
invalidateFilter();
|
|
}
|
|
|
|
void setPaused(bool paused)
|
|
{
|
|
mLastVisibleRow = paused ? rowCount() : 0;
|
|
if (!paused) {
|
|
invalidateFilter();
|
|
}
|
|
}
|
|
|
|
protected:
|
|
virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
|
|
{
|
|
Q_UNUSED(source_parent);
|
|
if (!mLastVisibleRow) {
|
|
LogWindowModel* model = dynamic_cast<LogWindowModel*>(sourceModel());
|
|
const LogMessage& d = model->at(source_row);
|
|
return d.level >= mLevel;
|
|
}
|
|
|
|
return source_row <= mLastVisibleRow;
|
|
}
|
|
|
|
private:
|
|
Level mLevel;
|
|
int mLastVisibleRow;
|
|
};
|
|
|
|
QsLogging::Window::Window(QWidget* parent)
|
|
: QDialog(parent)
|
|
, mUi(nullptr)
|
|
, mProxyModel(nullptr)
|
|
, mIsPaused(false)
|
|
, mHasAutoScroll(true)
|
|
{
|
|
mUi.reset(new Ui::LogWindow());
|
|
mUi->setupUi(this);
|
|
|
|
connect(mUi->toolButtonPause, SIGNAL(clicked()), SLOT(OnPauseClicked()));
|
|
connect(mUi->toolButtonSave, SIGNAL(clicked()), SLOT(OnSaveClicked()));
|
|
connect(mUi->toolButtonClear, SIGNAL(clicked()), SLOT(OnClearClicked()));
|
|
connect(mUi->toolButtonCopy, SIGNAL(clicked()), SLOT(OnCopyClicked()));
|
|
connect(mUi->comboBoxLevel, SIGNAL(currentIndexChanged(int)), SLOT(OnLevelChanged(int)));
|
|
connect(mUi->checkBoxAutoScroll, SIGNAL(toggled(bool)), SLOT(OnAutoScrollChanged(bool)));
|
|
connect(&mModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
|
|
SLOT(ModelRowsInserted(const QModelIndex&, int, int)));
|
|
|
|
// Install the sort / filter model
|
|
mProxyModel.reset(new WindowLogFilterProxyModel(InfoLevel, this));
|
|
mProxyModel->setSourceModel(&mModel);
|
|
mUi->tableViewMessages->setModel(mProxyModel.get());
|
|
|
|
mUi->tableViewMessages->installEventFilter(this);
|
|
|
|
mUi->tableViewMessages->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
#if QT_VERSION >= 0x050000
|
|
mUi->tableViewMessages->horizontalHeader()->setSectionResizeMode(LogWindowModel::TimeColumn, QHeaderView::ResizeToContents);
|
|
mUi->tableViewMessages->horizontalHeader()->setSectionResizeMode(LogWindowModel::LevelNameColumn, QHeaderView::ResizeToContents);
|
|
mUi->tableViewMessages->horizontalHeader()->setSectionResizeMode(LogWindowModel::MessageColumn, QHeaderView::Stretch);
|
|
mUi->tableViewMessages->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
|
#else
|
|
mUi->tableViewMessages->horizontalHeader()->setResizeMode(LogWindowModel::TimeColumn, QHeaderView::ResizeToContents);
|
|
mUi->tableViewMessages->horizontalHeader()->setResizeMode(LogWindowModel::LevelNameColumn, QHeaderView::ResizeToContents);
|
|
mUi->tableViewMessages->horizontalHeader()->setResizeMode(LogWindowModel::MessageColumn, QHeaderView::Stretch);
|
|
mUi->tableViewMessages->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
|
|
#endif
|
|
|
|
// Initialize log level selection
|
|
for (int l = TraceLevel; l < OffLevel; l++) {
|
|
const QString ln = LocalizedLevelName(static_cast<Level>(l));
|
|
mUi->comboBoxLevel->addItem(ln, l);
|
|
}
|
|
mUi->comboBoxLevel->setCurrentIndex(InfoLevel);
|
|
}
|
|
|
|
QsLogging::Window::~Window() noexcept = default;
|
|
|
|
bool QsLogging::Window::eventFilter(QObject *obj, QEvent *event)
|
|
{
|
|
if (obj == mUi->tableViewMessages) {
|
|
if (event->type() == QEvent::KeyPress) {
|
|
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
|
if (keyEvent->key() == Qt::Key_C && (keyEvent->modifiers() & Qt::ControlModifier)) {
|
|
copySelection();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} else {
|
|
return QDialog::eventFilter(obj, event);
|
|
}
|
|
}
|
|
|
|
void QsLogging::Window::addLogMessage(const QsLogging::LogMessage &m)
|
|
{
|
|
mModel.addEntry(m);
|
|
}
|
|
|
|
void QsLogging::Window::OnPauseClicked()
|
|
{
|
|
mUi->toolButtonPause->setIcon(mIsPaused ? pauseIcon() : playIcon());
|
|
mUi->toolButtonPause->setText(mIsPaused ? tr("&Pause") : tr("&Resume"));
|
|
|
|
mIsPaused = !mIsPaused;
|
|
|
|
mProxyModel->setPaused(mIsPaused);
|
|
}
|
|
|
|
void QsLogging::Window::OnSaveClicked()
|
|
{
|
|
saveSelection();
|
|
}
|
|
|
|
void QsLogging::Window::OnClearClicked()
|
|
{
|
|
mModel.clear();
|
|
}
|
|
|
|
void QsLogging::Window::OnCopyClicked()
|
|
{
|
|
copySelection();
|
|
}
|
|
|
|
void QsLogging::Window::OnLevelChanged(int value)
|
|
{
|
|
mProxyModel->setLevel(static_cast<Level>(value));
|
|
}
|
|
|
|
void QsLogging::Window::OnAutoScrollChanged(bool checked)
|
|
{
|
|
mHasAutoScroll = checked;
|
|
}
|
|
|
|
void QsLogging::Window::ModelRowsInserted(const QModelIndex& parent, int start, int last)
|
|
{
|
|
Q_UNUSED(parent);
|
|
Q_UNUSED(start);
|
|
Q_UNUSED(last);
|
|
if (mHasAutoScroll && !mIsPaused) {
|
|
mUi->tableViewMessages->scrollToBottom();
|
|
}
|
|
}
|
|
|
|
void QsLogging::Window::copySelection() const
|
|
{
|
|
const QString text = getSelectionText();
|
|
if (text.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
QApplication::clipboard()->setText(text);
|
|
}
|
|
|
|
void QsLogging::Window::saveSelection()
|
|
{
|
|
const QString text = getSelectionText();
|
|
if (text.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
QFileDialog dialog(this);
|
|
dialog.setWindowTitle(tr("Save log"));
|
|
dialog.setNameFilter(tr("Log file (*.log)"));
|
|
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
|
dialog.setDefaultSuffix("log");
|
|
dialog.exec();
|
|
|
|
const QStringList sel = dialog.selectedFiles();
|
|
if (sel.size() < 1) {
|
|
return;
|
|
}
|
|
|
|
QFile file(sel.at(0));
|
|
if (file.open(QIODevice::WriteOnly)) {
|
|
QTextStream stream(&file);
|
|
stream << text;
|
|
file.close();
|
|
}
|
|
}
|
|
|
|
QString QsLogging::Window::getSelectionText() const
|
|
{
|
|
QModelIndexList rows = mUi->tableViewMessages->selectionModel()->selectedRows();
|
|
std::sort(rows.begin(), rows.end());
|
|
|
|
QString text;
|
|
|
|
if (rows.count() == 0) {
|
|
for (int i = 0; i < mProxyModel->rowCount(); i++) {
|
|
const int srow = mProxyModel->mapToSource(mProxyModel->index(i, 0)).row();
|
|
text += mModel.at(srow).formatted + "\n";
|
|
}
|
|
} else {
|
|
for (QModelIndexList::const_iterator i = rows.begin();i != rows.end();++i) {
|
|
const int srow = mProxyModel->mapToSource(*i).row();
|
|
text += mModel.at(srow).formatted + "\n";
|
|
}
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
#include "QsLogWindow.moc"
|