2017-08-27 22:10:06 +00:00
|
|
|
// Copyright 2017 Dolphin Emulator Project
|
|
|
|
// Licensed under GPLv2+
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2018-07-06 22:40:15 +00:00
|
|
|
#include "DolphinQt/Config/LogWidget.h"
|
2017-08-27 22:10:06 +00:00
|
|
|
|
|
|
|
#include <QCheckBox>
|
|
|
|
#include <QComboBox>
|
|
|
|
#include <QFont>
|
|
|
|
#include <QFontDatabase>
|
2019-08-30 21:55:40 +00:00
|
|
|
#include <QGridLayout>
|
|
|
|
#include <QPlainTextEdit>
|
2017-08-27 22:10:06 +00:00
|
|
|
#include <QPushButton>
|
|
|
|
#include <QTimer>
|
2019-08-30 21:55:40 +00:00
|
|
|
|
|
|
|
#include "Core/ConfigManager.h"
|
2017-08-27 22:10:06 +00:00
|
|
|
|
|
|
|
#include "Common/FileUtil.h"
|
2018-12-02 11:09:27 +00:00
|
|
|
#include "Common/StringUtil.h"
|
2018-05-28 01:48:04 +00:00
|
|
|
|
2017-08-27 22:10:06 +00:00
|
|
|
#include "Core/ConfigManager.h"
|
2018-05-28 01:48:04 +00:00
|
|
|
|
2019-02-08 12:21:21 +00:00
|
|
|
#include "DolphinQt/QtUtils/QueueOnObject.h"
|
2018-07-06 22:40:15 +00:00
|
|
|
#include "DolphinQt/Settings.h"
|
2017-08-27 22:10:06 +00:00
|
|
|
|
|
|
|
// Delay in ms between calls of UpdateLog()
|
|
|
|
constexpr int UPDATE_LOG_DELAY = 100;
|
2019-08-30 21:55:40 +00:00
|
|
|
// Maximum number of lines to show in log viewer
|
|
|
|
constexpr int MAX_LOG_LINES = 5000;
|
2017-08-27 22:10:06 +00:00
|
|
|
// Maximum lines to process at a time
|
2019-08-30 21:55:40 +00:00
|
|
|
constexpr size_t MAX_LOG_LINES_TO_UPDATE = 200;
|
2017-08-27 22:10:06 +00:00
|
|
|
// Timestamp length
|
|
|
|
constexpr int TIMESTAMP_LENGTH = 10;
|
|
|
|
|
|
|
|
LogWidget::LogWidget(QWidget* parent) : QDockWidget(parent), m_timer(new QTimer(this))
|
|
|
|
{
|
|
|
|
setWindowTitle(tr("Log"));
|
2018-04-19 09:32:00 +00:00
|
|
|
setObjectName(QStringLiteral("log"));
|
|
|
|
|
2017-08-27 22:10:06 +00:00
|
|
|
setHidden(!Settings::Instance().IsLogVisible());
|
|
|
|
setAllowedAreas(Qt::AllDockWidgetAreas);
|
|
|
|
|
|
|
|
CreateWidgets();
|
|
|
|
LoadSettings();
|
|
|
|
|
|
|
|
ConnectWidgets();
|
|
|
|
|
|
|
|
connect(m_timer, &QTimer::timeout, this, &LogWidget::UpdateLog);
|
2019-08-30 22:09:47 +00:00
|
|
|
connect(this, &QDockWidget::visibilityChanged, [this](bool visible) {
|
|
|
|
if (visible)
|
|
|
|
m_timer->start(UPDATE_LOG_DELAY);
|
|
|
|
else
|
|
|
|
m_timer->stop();
|
|
|
|
});
|
2017-08-27 22:10:06 +00:00
|
|
|
|
2018-03-29 01:01:25 +00:00
|
|
|
connect(&Settings::Instance(), &Settings::DebugFontChanged, this, &LogWidget::UpdateFont);
|
|
|
|
|
2017-08-27 22:10:06 +00:00
|
|
|
LogManager::GetInstance()->RegisterListener(LogListener::LOG_WINDOW_LISTENER, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
LogWidget::~LogWidget()
|
|
|
|
{
|
|
|
|
SaveSettings();
|
|
|
|
|
|
|
|
LogManager::GetInstance()->RegisterListener(LogListener::LOG_WINDOW_LISTENER, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LogWidget::UpdateLog()
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(m_log_mutex);
|
|
|
|
|
|
|
|
if (m_log_queue.empty())
|
|
|
|
return;
|
|
|
|
|
2019-08-30 21:55:40 +00:00
|
|
|
for (size_t i = 0; !m_log_queue.empty() && i < MAX_LOG_LINES_TO_UPDATE; i++)
|
2017-08-27 22:10:06 +00:00
|
|
|
{
|
2019-08-30 21:55:40 +00:00
|
|
|
m_log_text->appendHtml(m_log_queue.front());
|
2017-08-27 22:10:06 +00:00
|
|
|
m_log_queue.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LogWidget::UpdateFont()
|
|
|
|
{
|
|
|
|
QFont f;
|
|
|
|
|
|
|
|
switch (m_log_font->currentIndex())
|
|
|
|
{
|
|
|
|
case 0: // Default font
|
|
|
|
break;
|
|
|
|
case 1: // Monospace font
|
|
|
|
f = QFont(QStringLiteral("Monospace"));
|
|
|
|
f.setStyleHint(QFont::TypeWriter);
|
|
|
|
break;
|
2018-03-29 01:01:25 +00:00
|
|
|
case 2: // Debugger font
|
|
|
|
f = Settings::Instance().GetDebugFont();
|
|
|
|
break;
|
2017-08-27 22:10:06 +00:00
|
|
|
}
|
|
|
|
m_log_text->setFont(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LogWidget::CreateWidgets()
|
|
|
|
{
|
|
|
|
// Log
|
2019-08-30 21:55:40 +00:00
|
|
|
m_log_text = new QPlainTextEdit;
|
2017-08-27 22:10:06 +00:00
|
|
|
m_log_wrap = new QCheckBox(tr("Word Wrap"));
|
|
|
|
m_log_font = new QComboBox;
|
|
|
|
m_log_clear = new QPushButton(tr("Clear"));
|
|
|
|
|
2018-03-29 01:01:25 +00:00
|
|
|
m_log_font->addItems({tr("Default Font"), tr("Monospaced Font"), tr("Selected Font")});
|
2017-08-27 22:10:06 +00:00
|
|
|
|
|
|
|
auto* log_layout = new QGridLayout;
|
|
|
|
log_layout->addWidget(m_log_wrap, 0, 0);
|
|
|
|
log_layout->addWidget(m_log_font, 0, 1);
|
|
|
|
log_layout->addWidget(m_log_clear, 0, 2);
|
|
|
|
log_layout->addWidget(m_log_text, 1, 0, 1, -1);
|
|
|
|
|
|
|
|
QWidget* widget = new QWidget;
|
|
|
|
widget->setLayout(log_layout);
|
|
|
|
|
|
|
|
setWidget(widget);
|
|
|
|
|
|
|
|
m_log_text->setReadOnly(true);
|
2019-08-30 21:55:40 +00:00
|
|
|
m_log_text->setUndoRedoEnabled(false);
|
|
|
|
m_log_text->setMaximumBlockCount(MAX_LOG_LINES);
|
2017-08-27 22:10:06 +00:00
|
|
|
|
|
|
|
QPalette palette = m_log_text->palette();
|
|
|
|
palette.setColor(QPalette::Base, Qt::black);
|
|
|
|
palette.setColor(QPalette::Text, Qt::white);
|
|
|
|
m_log_text->setPalette(palette);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LogWidget::ConnectWidgets()
|
|
|
|
{
|
2019-08-30 22:05:01 +00:00
|
|
|
connect(m_log_clear, &QPushButton::clicked, [this] {
|
|
|
|
m_log_text->clear();
|
|
|
|
m_log_queue = {};
|
|
|
|
});
|
2017-08-27 22:10:06 +00:00
|
|
|
connect(m_log_wrap, &QCheckBox::toggled, this, &LogWidget::SaveSettings);
|
|
|
|
connect(m_log_font, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
|
|
|
&LogWidget::SaveSettings);
|
|
|
|
connect(this, &QDockWidget::topLevelChanged, this, &LogWidget::SaveSettings);
|
2019-08-30 22:05:01 +00:00
|
|
|
connect(&Settings::Instance(), &Settings::LogVisibilityChanged, this, &LogWidget::setVisible);
|
2017-08-27 22:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LogWidget::LoadSettings()
|
|
|
|
{
|
2018-03-23 11:10:53 +00:00
|
|
|
auto& settings = Settings::GetQSettings();
|
2017-08-27 22:10:06 +00:00
|
|
|
|
|
|
|
restoreGeometry(settings.value(QStringLiteral("logwidget/geometry")).toByteArray());
|
|
|
|
setFloating(settings.value(QStringLiteral("logwidget/floating")).toBool());
|
|
|
|
|
|
|
|
// Log - Wrap Lines
|
|
|
|
m_log_wrap->setChecked(settings.value(QStringLiteral("logging/wraplines")).toBool());
|
2019-08-30 21:55:40 +00:00
|
|
|
m_log_text->setLineWrapMode(m_log_wrap->isChecked() ? QPlainTextEdit::WidgetWidth :
|
|
|
|
QPlainTextEdit::NoWrap);
|
2017-08-27 22:10:06 +00:00
|
|
|
|
|
|
|
// Log - Font Selection
|
|
|
|
// Currently "Debugger Font" is not supported as there is no Qt Debugger, defaulting to Monospace
|
|
|
|
m_log_font->setCurrentIndex(std::min(settings.value(QStringLiteral("logging/font")).toInt(), 1));
|
|
|
|
UpdateFont();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LogWidget::SaveSettings()
|
|
|
|
{
|
2018-03-23 11:10:53 +00:00
|
|
|
auto& settings = Settings::GetQSettings();
|
2017-08-27 22:10:06 +00:00
|
|
|
|
|
|
|
settings.setValue(QStringLiteral("logwidget/geometry"), saveGeometry());
|
|
|
|
settings.setValue(QStringLiteral("logwidget/floating"), isFloating());
|
|
|
|
|
|
|
|
// Log - Wrap Lines
|
|
|
|
settings.setValue(QStringLiteral("logging/wraplines"), m_log_wrap->isChecked());
|
2019-08-30 21:55:40 +00:00
|
|
|
m_log_text->setLineWrapMode(m_log_wrap->isChecked() ? QPlainTextEdit::WidgetWidth :
|
|
|
|
QPlainTextEdit::NoWrap);
|
2017-08-27 22:10:06 +00:00
|
|
|
|
|
|
|
// Log - Font Selection
|
|
|
|
settings.setValue(QStringLiteral("logging/font"), m_log_font->currentIndex());
|
|
|
|
UpdateFont();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LogWidget::Log(LogTypes::LOG_LEVELS level, const char* text)
|
|
|
|
{
|
2019-02-08 12:21:21 +00:00
|
|
|
// The text has to be copied here as it will be deallocated after this method has returned
|
2018-12-02 11:09:27 +00:00
|
|
|
std::string str(text);
|
2019-02-08 12:21:21 +00:00
|
|
|
|
|
|
|
QueueOnObject(this, [this, level, str]() mutable {
|
|
|
|
std::lock_guard<std::mutex> lock(m_log_mutex);
|
|
|
|
|
|
|
|
const char* color = "white";
|
|
|
|
|
|
|
|
switch (level)
|
|
|
|
{
|
|
|
|
case LogTypes::LOG_LEVELS::LERROR:
|
|
|
|
color = "red";
|
|
|
|
break;
|
|
|
|
case LogTypes::LOG_LEVELS::LWARNING:
|
|
|
|
color = "yellow";
|
|
|
|
break;
|
|
|
|
case LogTypes::LOG_LEVELS::LNOTICE:
|
|
|
|
color = "lime";
|
|
|
|
break;
|
|
|
|
case LogTypes::LOG_LEVELS::LINFO:
|
|
|
|
color = "cyan";
|
|
|
|
break;
|
|
|
|
case LogTypes::LOG_LEVELS::LDEBUG:
|
|
|
|
color = "lightgrey";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringPopBackIf(&str, '\n');
|
|
|
|
m_log_queue.push(
|
|
|
|
QStringLiteral("%1 <span style=\"color: %2; white-space: pre\">%3</span>")
|
|
|
|
.arg(QString::fromStdString(str.substr(0, TIMESTAMP_LENGTH)),
|
|
|
|
QString::fromStdString(color),
|
|
|
|
QString::fromStdString(str.substr(TIMESTAMP_LENGTH)).toHtmlEscaped()));
|
|
|
|
});
|
2017-08-27 22:10:06 +00:00
|
|
|
}
|
2017-09-20 11:18:36 +00:00
|
|
|
|
|
|
|
void LogWidget::closeEvent(QCloseEvent*)
|
|
|
|
{
|
|
|
|
Settings::Instance().SetLogVisible(false);
|
|
|
|
}
|