Add support for view older launcher logs
Signed-off-by: Yihe Li <winmikedows@hotmail.com>
This commit is contained in:
parent
c58cc3396a
commit
289645266a
8 changed files with 560 additions and 183 deletions
|
@ -697,16 +697,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||
m_settings->registerSetting("ConsoleMaxLines", 100000);
|
||||
m_settings->registerSetting("ConsoleOverflowStop", true);
|
||||
|
||||
auto lineSetting = settings()->getSetting("ConsoleMaxLines");
|
||||
bool conversionOk = false;
|
||||
int maxLines = lineSetting->get().toInt(&conversionOk);
|
||||
if (!conversionOk) {
|
||||
maxLines = lineSetting->defValue().toInt();
|
||||
qWarning() << "ConsoleMaxLines has nonsensical value, defaulting to" << maxLines;
|
||||
}
|
||||
logModel->setMaxLines(maxLines);
|
||||
logModel->setStopOnOverflow(settings()->get("ConsoleOverflowStop").toBool());
|
||||
logModel->setOverflowMessage(tr("Cannot display this log since the log length surpassed %1 lines.").arg(maxLines));
|
||||
logModel->setMaxLines(getConsoleMaxLines());
|
||||
logModel->setStopOnOverflow(shouldStopOnConsoleOverflow());
|
||||
logModel->setOverflowMessage(tr("Cannot display this log since the log length surpassed %1 lines.").arg(logModel->getMaxLines()));
|
||||
|
||||
// Folders
|
||||
m_settings->registerSetting("InstanceDir", "instances");
|
||||
|
@ -1614,6 +1607,23 @@ void Application::updateIsRunning(bool running)
|
|||
m_updateRunning = running;
|
||||
}
|
||||
|
||||
int Application::getConsoleMaxLines() const
|
||||
{
|
||||
auto lineSetting = settings()->getSetting("ConsoleMaxLines");
|
||||
bool conversionOk = false;
|
||||
int maxLines = lineSetting->get().toInt(&conversionOk);
|
||||
if (!conversionOk) {
|
||||
maxLines = lineSetting->defValue().toInt();
|
||||
qWarning() << "ConsoleMaxLines has nonsensical value, defaulting to" << maxLines;
|
||||
}
|
||||
return maxLines;
|
||||
}
|
||||
|
||||
bool Application::shouldStopOnConsoleOverflow() const
|
||||
{
|
||||
return settings()->get("ConsoleOverflowStop").toBool();
|
||||
}
|
||||
|
||||
void Application::controllerSucceeded()
|
||||
{
|
||||
auto controller = qobject_cast<LaunchController*>(QObject::sender());
|
||||
|
|
|
@ -162,6 +162,9 @@ class Application : public QApplication {
|
|||
QString getModrinthAPIToken();
|
||||
QString getUserAgent();
|
||||
|
||||
int getConsoleMaxLines() const;
|
||||
bool shouldStopOnConsoleOverflow() const;
|
||||
|
||||
/// this is the root of the 'installation'. Used for automatic updates
|
||||
const QString& root() { return m_rootPath; }
|
||||
|
||||
|
|
|
@ -54,3 +54,18 @@ MessageLevel::Enum MessageLevel::fromLine(QString& line)
|
|||
}
|
||||
return MessageLevel::Unknown;
|
||||
}
|
||||
|
||||
MessageLevel::Enum MessageLevel::fromLauncherLine(QString& line)
|
||||
{
|
||||
// Level prefix
|
||||
int startMark = 0;
|
||||
while (startMark < line.size() && (line[startMark].isDigit() || line[startMark].isSpace() || line[startMark] == '.'))
|
||||
++startMark;
|
||||
int endmark = line.indexOf(":");
|
||||
if (startMark < line.size() && endmark != -1) {
|
||||
auto level = MessageLevel::getLevel(line.left(endmark).mid(startMark));
|
||||
line = line.mid(endmark + 2);
|
||||
return level;
|
||||
}
|
||||
return MessageLevel::Unknown;
|
||||
}
|
||||
|
|
|
@ -26,4 +26,7 @@ MessageLevel::Enum getLevel(QtMsgType type);
|
|||
|
||||
/* Get message level from a line. Line is modified if it was successful. */
|
||||
MessageLevel::Enum fromLine(QString& line);
|
||||
|
||||
/* Get message level from a line from the launcher log. Line is modified if it was successful. */
|
||||
MessageLevel::Enum fromLauncherLine(QString& line);
|
||||
} // namespace MessageLevel
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2024 TheKodeToad <TheKodeToad@proton.me>
|
||||
* Copyright (c) 2025 Yihe Li <winmikedows@hotmail.com>
|
||||
*
|
||||
|
@ -39,19 +38,18 @@
|
|||
#include "LauncherLogPage.h"
|
||||
#include "ui_LauncherLogPage.h"
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include <QIdentityProxyModel>
|
||||
#include <QScrollBar>
|
||||
#include <QShortcut>
|
||||
|
||||
#include "launch/LaunchTask.h"
|
||||
#include "settings/Setting.h"
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "ui/GuiUtil.h"
|
||||
#include "ui/themes/ThemeManager.h"
|
||||
|
||||
#include <BuildConfig.h>
|
||||
#include <FileSystem.h>
|
||||
#include <GZip.h>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QShortcut>
|
||||
#include <QUrl>
|
||||
|
||||
QVariant LogFormatProxyModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
|
@ -129,7 +127,12 @@ QModelIndex LogFormatProxyModel::find(const QModelIndex& start, const QString& v
|
|||
return QModelIndex();
|
||||
}
|
||||
|
||||
LauncherLogPage::LauncherLogPage(QWidget* parent) : QWidget(parent), ui(new Ui::LauncherLogPage)
|
||||
LauncherLogPage::LauncherLogPage(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::LauncherLogPage)
|
||||
, m_model(APPLICATION->logModel)
|
||||
, m_basePath(APPLICATION->dataRoot())
|
||||
, m_logSearchPaths({ "logs" })
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->tabWidget->tabBar()->hide();
|
||||
|
@ -148,16 +151,21 @@ LauncherLogPage::LauncherLogPage(QWidget* parent) : QWidget(parent), ui(new Ui::
|
|||
}
|
||||
|
||||
ui->text->setModel(m_proxy);
|
||||
m_proxy->setSourceModel(APPLICATION->logModel.get());
|
||||
m_proxy->setSourceModel(m_model.get());
|
||||
modelStateToUI();
|
||||
|
||||
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &LauncherLogPage::populateSelectLogBox);
|
||||
|
||||
auto findShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this);
|
||||
connect(findShortcut, SIGNAL(activated()), SLOT(findActivated()));
|
||||
connect(findShortcut, &QShortcut::activated, this, &LauncherLogPage::findActivated);
|
||||
|
||||
auto findNextShortcut = new QShortcut(QKeySequence(QKeySequence::FindNext), this);
|
||||
connect(findNextShortcut, SIGNAL(activated()), SLOT(findNextActivated()));
|
||||
connect(ui->searchBar, SIGNAL(returnPressed()), SLOT(on_findButton_clicked()));
|
||||
connect(findNextShortcut, &QShortcut::activated, this, &LauncherLogPage::findNextActivated);
|
||||
|
||||
auto findPreviousShortcut = new QShortcut(QKeySequence(QKeySequence::FindPrevious), this);
|
||||
connect(findPreviousShortcut, SIGNAL(activated()), SLOT(findPreviousActivated()));
|
||||
connect(findPreviousShortcut, &QShortcut::activated, this, &LauncherLogPage::findPreviousActivated);
|
||||
|
||||
connect(ui->searchBar, &QLineEdit::returnPressed, this, &LauncherLogPage::on_findButton_clicked);
|
||||
}
|
||||
|
||||
LauncherLogPage::~LauncherLogPage()
|
||||
|
@ -167,21 +175,21 @@ LauncherLogPage::~LauncherLogPage()
|
|||
|
||||
void LauncherLogPage::modelStateToUI()
|
||||
{
|
||||
if (APPLICATION->logModel->wrapLines()) {
|
||||
if (m_model->wrapLines()) {
|
||||
ui->text->setWordWrap(true);
|
||||
ui->wrapCheckbox->setCheckState(Qt::Checked);
|
||||
} else {
|
||||
ui->text->setWordWrap(false);
|
||||
ui->wrapCheckbox->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
if (APPLICATION->logModel->colorLines()) {
|
||||
if (m_model->colorLines()) {
|
||||
ui->text->setColorLines(true);
|
||||
ui->colorCheckbox->setCheckState(Qt::Checked);
|
||||
} else {
|
||||
ui->text->setColorLines(false);
|
||||
ui->colorCheckbox->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
if (APPLICATION->logModel->suspended()) {
|
||||
if (m_model->suspended()) {
|
||||
ui->trackLogCheckbox->setCheckState(Qt::Unchecked);
|
||||
} else {
|
||||
ui->trackLogCheckbox->setCheckState(Qt::Checked);
|
||||
|
@ -190,47 +198,205 @@ void LauncherLogPage::modelStateToUI()
|
|||
|
||||
void LauncherLogPage::UIToModelState()
|
||||
{
|
||||
if (!APPLICATION->logModel) {
|
||||
if (!m_model) {
|
||||
return;
|
||||
}
|
||||
APPLICATION->logModel->setLineWrap(ui->wrapCheckbox->checkState() == Qt::Checked);
|
||||
APPLICATION->logModel->setColorLines(ui->colorCheckbox->checkState() == Qt::Checked);
|
||||
APPLICATION->logModel->suspend(ui->trackLogCheckbox->checkState() != Qt::Checked);
|
||||
m_model->setLineWrap(ui->wrapCheckbox->checkState() == Qt::Checked);
|
||||
m_model->setColorLines(ui->colorCheckbox->checkState() == Qt::Checked);
|
||||
m_model->suspend(ui->trackLogCheckbox->checkState() != Qt::Checked);
|
||||
}
|
||||
|
||||
void LauncherLogPage::retranslate()
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
||||
void LauncherLogPage::openedImpl()
|
||||
{
|
||||
const QStringList failedPaths = m_watcher.addPaths(m_logSearchPaths);
|
||||
|
||||
for (const QString& path : m_logSearchPaths) {
|
||||
if (failedPaths.contains(path))
|
||||
qDebug() << "Failed to start watching" << path;
|
||||
else
|
||||
qDebug() << "Started watching" << path;
|
||||
}
|
||||
|
||||
populateSelectLogBox();
|
||||
}
|
||||
|
||||
void LauncherLogPage::closedImpl()
|
||||
{
|
||||
const QStringList failedPaths = m_watcher.removePaths(m_logSearchPaths);
|
||||
|
||||
for (const QString& path : m_logSearchPaths) {
|
||||
if (failedPaths.contains(path))
|
||||
qDebug() << "Failed to stop watching" << path;
|
||||
else
|
||||
qDebug() << "Stopped watching" << path;
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherLogPage::populateSelectLogBox()
|
||||
{
|
||||
const QString prevCurrentFile = m_currentFile;
|
||||
|
||||
ui->selectLogBox->blockSignals(true);
|
||||
ui->selectLogBox->clear();
|
||||
ui->selectLogBox->addItem("Current logs");
|
||||
ui->selectLogBox->addItems(getPaths());
|
||||
ui->selectLogBox->blockSignals(false);
|
||||
|
||||
if (!prevCurrentFile.isEmpty()) {
|
||||
const int index = ui->selectLogBox->findText(prevCurrentFile);
|
||||
if (index != -1) {
|
||||
ui->selectLogBox->blockSignals(true);
|
||||
ui->selectLogBox->setCurrentIndex(index);
|
||||
ui->selectLogBox->blockSignals(false);
|
||||
setControlsEnabled(true);
|
||||
// don't refresh file
|
||||
return;
|
||||
} else {
|
||||
setControlsEnabled(false);
|
||||
}
|
||||
} else {
|
||||
ui->selectLogBox->setCurrentIndex(0);
|
||||
setControlsEnabled(true);
|
||||
}
|
||||
|
||||
on_selectLogBox_currentIndexChanged(ui->selectLogBox->currentIndex());
|
||||
}
|
||||
|
||||
void LauncherLogPage::on_selectLogBox_currentIndexChanged(const int index)
|
||||
{
|
||||
QString file;
|
||||
if (index > 0) {
|
||||
file = ui->selectLogBox->itemText(index);
|
||||
}
|
||||
|
||||
if (index != 0 && (file.isEmpty() || !QFile::exists(FS::PathCombine(m_basePath, file)))) {
|
||||
m_currentFile = QString();
|
||||
ui->text->clear();
|
||||
setControlsEnabled(false);
|
||||
} else {
|
||||
m_currentFile = file;
|
||||
reload();
|
||||
setControlsEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherLogPage::on_btnReload_clicked()
|
||||
{
|
||||
if (m_currentFile.isEmpty()) {
|
||||
if (!m_model)
|
||||
return;
|
||||
m_model->clear();
|
||||
m_container->refreshContainer();
|
||||
} else {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherLogPage::reload()
|
||||
{
|
||||
if (m_currentFile.isEmpty()) {
|
||||
m_model = APPLICATION->logModel;
|
||||
m_proxy->setSourceModel(m_model.get());
|
||||
ui->text->setModel(m_proxy);
|
||||
ui->text->scrollToBottom();
|
||||
UIToModelState();
|
||||
setControlsEnabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(FS::PathCombine(m_basePath, m_currentFile));
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
setControlsEnabled(false);
|
||||
ui->btnReload->setEnabled(true); // allow reload
|
||||
m_currentFile = QString();
|
||||
QMessageBox::critical(this, tr("Error"), tr("Unable to open %1 for reading: %2").arg(m_currentFile, file.errorString()));
|
||||
} else {
|
||||
auto setPlainText = [this](const QString& text) {
|
||||
QTextDocument* doc = ui->text->document();
|
||||
doc->setDefaultFont(m_proxy->getFont());
|
||||
ui->text->setPlainText(text);
|
||||
};
|
||||
auto showTooBig = [setPlainText, &file]() {
|
||||
setPlainText(tr("The file (%1) is too big. You may want to open it in a viewer optimized "
|
||||
"for large files.")
|
||||
.arg(file.fileName()));
|
||||
};
|
||||
if (file.size() > (1024ll * 1024ll * 12ll)) {
|
||||
showTooBig();
|
||||
return;
|
||||
}
|
||||
MessageLevel::Enum last = MessageLevel::Unknown;
|
||||
|
||||
auto handleLine = [this, &last](QString line) {
|
||||
if (line.isEmpty())
|
||||
return false;
|
||||
if (line.back() == '\n')
|
||||
line = line.remove(line.size() - 1, 1);
|
||||
QString lineTemp = line; // don't edit out the time and level for clarity
|
||||
MessageLevel::Enum level = MessageLevel::fromLauncherLine(lineTemp);
|
||||
|
||||
last = level;
|
||||
m_model->append(level, line);
|
||||
return m_model->isOverFlow();
|
||||
};
|
||||
|
||||
// Try to determine a level for each line
|
||||
ui->text->clear();
|
||||
ui->text->setModel(nullptr);
|
||||
m_model.reset(new LogModel(this));
|
||||
m_model->setMaxLines(APPLICATION->getConsoleMaxLines());
|
||||
m_model->setStopOnOverflow(APPLICATION->shouldStopOnConsoleOverflow());
|
||||
m_model->setOverflowMessage(tr("Cannot display this log since the log length surpassed %1 lines.").arg(m_model->getMaxLines()));
|
||||
m_model->clear();
|
||||
if (file.fileName().endsWith(".gz")) {
|
||||
QString line;
|
||||
auto error = GZip::readGzFileByBlocks(&file, [&line, handleLine](const QByteArray& d) {
|
||||
auto block = d;
|
||||
int newlineIndex = block.indexOf('\n');
|
||||
while (newlineIndex != -1) {
|
||||
line += QString::fromUtf8(block).left(newlineIndex);
|
||||
block.remove(0, newlineIndex + 1);
|
||||
if (handleLine(line)) {
|
||||
line.clear();
|
||||
return false;
|
||||
}
|
||||
line.clear();
|
||||
newlineIndex = block.indexOf('\n');
|
||||
}
|
||||
line += QString::fromUtf8(block);
|
||||
return true;
|
||||
});
|
||||
if (!error.isEmpty()) {
|
||||
setPlainText(tr("The file (%1) encountered an error when reading: %2.").arg(file.fileName(), error));
|
||||
return;
|
||||
} else if (!line.isEmpty()) {
|
||||
handleLine(line);
|
||||
}
|
||||
} else {
|
||||
while (!file.atEnd() && !handleLine(QString::fromUtf8(file.readLine()))) {
|
||||
}
|
||||
}
|
||||
m_proxy->setSourceModel(m_model.get());
|
||||
ui->text->setModel(m_proxy);
|
||||
ui->text->scrollToBottom();
|
||||
UIToModelState();
|
||||
setControlsEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherLogPage::on_btnPaste_clicked()
|
||||
{
|
||||
if (!APPLICATION->logModel)
|
||||
return;
|
||||
|
||||
// FIXME: turn this into a proper task and move the upload logic out of GuiUtil!
|
||||
APPLICATION->logModel->append(MessageLevel::Launcher,
|
||||
QString("Log upload triggered at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)));
|
||||
auto url = GuiUtil::uploadPaste(tr("Launcher Log"), APPLICATION->logModel->toPlainText(), this);
|
||||
if (!url.has_value()) {
|
||||
APPLICATION->logModel->append(MessageLevel::Error, QString("Log upload canceled"));
|
||||
} else if (url->isNull()) {
|
||||
APPLICATION->logModel->append(MessageLevel::Error, QString("Log upload failed!"));
|
||||
} else {
|
||||
APPLICATION->logModel->append(MessageLevel::Launcher, QString("Log uploaded to: %1").arg(url.value()));
|
||||
}
|
||||
GuiUtil::uploadPaste(m_currentFile, ui->text->toPlainText(), this);
|
||||
}
|
||||
|
||||
void LauncherLogPage::on_btnCopy_clicked()
|
||||
{
|
||||
if (!APPLICATION->logModel)
|
||||
return;
|
||||
APPLICATION->logModel->append(MessageLevel::Launcher,
|
||||
QString("Clipboard copy at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)));
|
||||
GuiUtil::setClipboardText(APPLICATION->logModel->toPlainText());
|
||||
}
|
||||
|
||||
void LauncherLogPage::on_btnClear_clicked()
|
||||
{
|
||||
if (!APPLICATION->logModel)
|
||||
return;
|
||||
APPLICATION->logModel->clear();
|
||||
m_container->refreshContainer();
|
||||
GuiUtil::setClipboardText(ui->text->toPlainText());
|
||||
}
|
||||
|
||||
void LauncherLogPage::on_btnBottom_clicked()
|
||||
|
@ -240,25 +406,149 @@ void LauncherLogPage::on_btnBottom_clicked()
|
|||
|
||||
void LauncherLogPage::on_trackLogCheckbox_clicked(bool checked)
|
||||
{
|
||||
if (!APPLICATION->logModel)
|
||||
if (!m_model)
|
||||
return;
|
||||
APPLICATION->logModel->suspend(!checked);
|
||||
m_model->suspend(!checked);
|
||||
}
|
||||
|
||||
void LauncherLogPage::on_btnDelete_clicked()
|
||||
{
|
||||
if (m_currentFile.isEmpty()) {
|
||||
setControlsEnabled(false);
|
||||
return;
|
||||
}
|
||||
if (QMessageBox::question(this, tr("Confirm Deletion"),
|
||||
tr("You are about to delete \"%1\".\n"
|
||||
"This may be permanent and it will be gone from the logs folder.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(m_currentFile),
|
||||
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) {
|
||||
return;
|
||||
}
|
||||
QFile file(FS::PathCombine(m_basePath, m_currentFile));
|
||||
|
||||
if (FS::trash(file.fileName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.remove()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Unable to delete %1: %2").arg(m_currentFile, file.errorString()));
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherLogPage::on_btnClean_clicked()
|
||||
{
|
||||
auto toDelete = getPaths();
|
||||
if (toDelete.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QMessageBox* messageBox = new QMessageBox(this);
|
||||
messageBox->setWindowTitle(tr("Confirm Cleanup"));
|
||||
if (toDelete.size() > 5) {
|
||||
messageBox->setText(tr("Are you sure you want to delete all log files?"));
|
||||
messageBox->setDetailedText(toDelete.join('\n'));
|
||||
} else {
|
||||
messageBox->setText(tr("Are you sure you want to delete all these files?\n%1").arg(toDelete.join('\n')));
|
||||
}
|
||||
messageBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
||||
messageBox->setDefaultButton(QMessageBox::Ok);
|
||||
messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
messageBox->setIcon(QMessageBox::Question);
|
||||
messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
|
||||
if (messageBox->exec() != QMessageBox::Ok) {
|
||||
return;
|
||||
}
|
||||
QStringList failed;
|
||||
for (auto item : toDelete) {
|
||||
QString absolutePath = FS::PathCombine(m_basePath, item);
|
||||
QFile file(absolutePath);
|
||||
qDebug() << "Deleting log" << absolutePath;
|
||||
if (FS::trash(file.fileName())) {
|
||||
continue;
|
||||
}
|
||||
if (!file.remove()) {
|
||||
failed.push_back(item);
|
||||
}
|
||||
}
|
||||
if (!failed.empty()) {
|
||||
QMessageBox* messageBoxFailure = new QMessageBox(this);
|
||||
messageBoxFailure->setWindowTitle(tr("Error"));
|
||||
if (failed.size() > 5) {
|
||||
messageBoxFailure->setText(tr("Couldn't delete some files!"));
|
||||
messageBoxFailure->setDetailedText(failed.join('\n'));
|
||||
} else {
|
||||
messageBoxFailure->setText(tr("Couldn't delete some files:\n%1").arg(failed.join('\n')));
|
||||
}
|
||||
messageBoxFailure->setStandardButtons(QMessageBox::Ok);
|
||||
messageBoxFailure->setDefaultButton(QMessageBox::Ok);
|
||||
messageBoxFailure->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
messageBoxFailure->setIcon(QMessageBox::Critical);
|
||||
messageBoxFailure->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
messageBoxFailure->exec();
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherLogPage::on_wrapCheckbox_clicked(bool checked)
|
||||
{
|
||||
ui->text->setWordWrap(checked);
|
||||
if (!APPLICATION->logModel)
|
||||
if (!m_model)
|
||||
return;
|
||||
APPLICATION->logModel->setLineWrap(checked);
|
||||
m_model->setLineWrap(checked);
|
||||
ui->text->scrollToBottom();
|
||||
}
|
||||
|
||||
void LauncherLogPage::on_colorCheckbox_clicked(bool checked)
|
||||
{
|
||||
ui->text->setColorLines(checked);
|
||||
if (!APPLICATION->logModel)
|
||||
if (!m_model)
|
||||
return;
|
||||
APPLICATION->logModel->setColorLines(checked);
|
||||
m_model->setColorLines(checked);
|
||||
ui->text->scrollToBottom();
|
||||
}
|
||||
|
||||
void LauncherLogPage::setControlsEnabled(const bool enabled)
|
||||
{
|
||||
if (!m_currentFile.isEmpty()) {
|
||||
ui->btnReload->setText("&Reload");
|
||||
ui->btnReload->setToolTip("Reload the contents of the log from the disk");
|
||||
ui->btnDelete->setEnabled(enabled);
|
||||
ui->btnClean->setEnabled(enabled);
|
||||
ui->trackLogCheckbox->setEnabled(false);
|
||||
} else {
|
||||
ui->btnReload->setText("Clear");
|
||||
ui->btnReload->setToolTip("Clear the log");
|
||||
ui->btnDelete->setEnabled(false);
|
||||
ui->btnClean->setEnabled(false);
|
||||
ui->trackLogCheckbox->setEnabled(enabled);
|
||||
}
|
||||
ui->btnReload->setEnabled(enabled);
|
||||
ui->btnCopy->setEnabled(enabled);
|
||||
ui->btnPaste->setEnabled(enabled);
|
||||
ui->text->setEnabled(enabled);
|
||||
}
|
||||
|
||||
QStringList LauncherLogPage::getPaths()
|
||||
{
|
||||
QDir baseDir(m_basePath);
|
||||
|
||||
QStringList result;
|
||||
|
||||
for (QString searchPath : m_logSearchPaths) {
|
||||
QDir searchDir(searchPath);
|
||||
|
||||
QStringList filters{ "*.log", "*.log.gz" };
|
||||
|
||||
if (searchPath != m_basePath)
|
||||
filters.append("*.txt");
|
||||
|
||||
QStringList entries = searchDir.entryList(filters, QDir::Files | QDir::Readable, QDir::SortFlag::Time);
|
||||
|
||||
for (const QString& name : entries)
|
||||
result.append(baseDir.relativeFilePath(searchDir.filePath(name)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void LauncherLogPage::on_findButton_clicked()
|
||||
|
@ -286,8 +576,3 @@ void LauncherLogPage::findActivated()
|
|||
ui->searchBar->selectAll();
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherLogPage::retranslate()
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QIdentityProxyModel>
|
||||
#include <QWidget>
|
||||
|
||||
|
@ -48,6 +49,7 @@ namespace Ui {
|
|||
class LauncherLogPage;
|
||||
}
|
||||
class QTextCharFormat;
|
||||
class RecursiveFileSystemWatcher;
|
||||
|
||||
class LogFormatProxyModel : public QIdentityProxyModel {
|
||||
public:
|
||||
|
@ -74,10 +76,17 @@ class LauncherLogPage : public QWidget, public BasePage {
|
|||
QString helpPage() const override { return "Launcher-Logs"; }
|
||||
void retranslate() override;
|
||||
|
||||
void openedImpl() override;
|
||||
void closedImpl() override;
|
||||
|
||||
private slots:
|
||||
void populateSelectLogBox();
|
||||
void on_selectLogBox_currentIndexChanged(int index);
|
||||
void on_btnReload_clicked();
|
||||
void on_btnPaste_clicked();
|
||||
void on_btnCopy_clicked();
|
||||
void on_btnClear_clicked();
|
||||
void on_btnDelete_clicked();
|
||||
void on_btnClean_clicked();
|
||||
void on_btnBottom_clicked();
|
||||
|
||||
void on_trackLogCheckbox_clicked(bool checked);
|
||||
|
@ -90,10 +99,21 @@ class LauncherLogPage : public QWidget, public BasePage {
|
|||
void findPreviousActivated();
|
||||
|
||||
private:
|
||||
void reload();
|
||||
void modelStateToUI();
|
||||
void UIToModelState();
|
||||
void setControlsEnabled(bool enabled);
|
||||
|
||||
QStringList getPaths();
|
||||
|
||||
private:
|
||||
Ui::LauncherLogPage* ui;
|
||||
LogFormatProxyModel* m_proxy;
|
||||
shared_qobject_ptr<LogModel> m_model;
|
||||
|
||||
/** Path to display log paths relative to. */
|
||||
QString m_basePath;
|
||||
QStringList m_logSearchPaths;
|
||||
QString m_currentFile;
|
||||
QFileSystemWatcher m_watcher;
|
||||
};
|
||||
|
|
|
@ -33,6 +33,40 @@
|
|||
<string notr="true">Tab 1</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Search:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="searchBar"/>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="findButton">
|
||||
<property name="text">
|
||||
<string>&Find</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QPushButton" name="btnBottom">
|
||||
<property name="toolTip">
|
||||
<string>Scroll all the way to bottom</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Bottom</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="5">
|
||||
<widget class="LogView" name="text">
|
||||
<property name="undoRedoEnabled">
|
||||
|
@ -52,8 +86,44 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="5">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0" colspan="5">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="selectLogBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnDelete">
|
||||
<property name="toolTip">
|
||||
<string>Delete the selected log</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Delete Selected</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnClean">
|
||||
<property name="toolTip">
|
||||
<string>Delete all the logs</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete &All</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="5">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout1">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="trackLogCheckbox">
|
||||
<property name="text">
|
||||
|
@ -113,55 +183,23 @@
|
|||
<string>Upload the log to the paste service configured in preferences</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Upload</string>
|
||||
<string>&Upload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnClear">
|
||||
<widget class="QPushButton" name="btnReload">
|
||||
<property name="toolTip">
|
||||
<string>Clear the log</string>
|
||||
<string>Reload the contents of the log from the disk</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
<string>&Reload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Search:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="findButton">
|
||||
<property name="text">
|
||||
<string>Find</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="searchBar"/>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QPushButton" name="btnBottom">
|
||||
<property name="toolTip">
|
||||
<string>Scroll all the way to bottom</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Bottom</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@ -178,12 +216,14 @@
|
|||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>tabWidget</tabstop>
|
||||
<tabstop>trackLogCheckbox</tabstop>
|
||||
<tabstop>wrapCheckbox</tabstop>
|
||||
<tabstop>colorCheckbox</tabstop>
|
||||
<tabstop>selectLogBox</tabstop>
|
||||
<tabstop>btnReload</tabstop>
|
||||
<tabstop>btnCopy</tabstop>
|
||||
<tabstop>btnPaste</tabstop>
|
||||
<tabstop>btnClear</tabstop>
|
||||
<tabstop>btnDelete</tabstop>
|
||||
<tabstop>btnClean</tabstop>
|
||||
<tabstop>wrapCheckbox</tabstop>
|
||||
<tabstop>colorCheckbox</tabstop>
|
||||
<tabstop>text</tabstop>
|
||||
<tabstop>searchBar</tabstop>
|
||||
<tabstop>findButton</tabstop>
|
||||
|
|
|
@ -211,7 +211,8 @@ void OtherLogsPage::on_btnReload_clicked()
|
|||
MessageLevel::Enum level = MessageLevel::Unknown;
|
||||
|
||||
// if the launcher part set a log level, use it
|
||||
auto innerLevel = MessageLevel::fromLine(line);
|
||||
QString lineTemp = line; // don't edit out the time and level for clarity
|
||||
auto innerLevel = MessageLevel::fromLine(lineTemp);
|
||||
if (innerLevel != MessageLevel::Unknown) {
|
||||
level = innerLevel;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue