Add a page to view launcher logs (#3831)

This commit is contained in:
TheKodeToad 2025-06-06 14:59:57 +00:00 committed by GitHub
commit 9f9aabcf97
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 320 additions and 66 deletions

View file

@ -52,6 +52,7 @@
#include "tools/GenericProfiler.h"
#include "ui/InstanceWindow.h"
#include "ui/MainWindow.h"
#include "ui/ViewLogWindow.h"
#include "ui/dialogs/ProgressDialog.h"
#include "ui/instanceview/AccessibleInstanceView.h"
@ -244,8 +245,11 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext& context, const QSt
}
QString out = qFormatLogMessage(type, context, msg);
out += QChar::LineFeed;
if (APPLICATION->logModel) {
APPLICATION->logModel->append(MessageLevel::getLevel(type), out);
}
out += QChar::LineFeed;
APPLICATION->logFile->write(out.toUtf8());
APPLICATION->logFile->flush();
@ -538,6 +542,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
qInstallMessageHandler(appDebugOutput);
qSetMessagePattern(defaultLogFormat);
logModel.reset(new LogModel(this));
bool foundLoggingRules = false;
auto logRulesFile = QStringLiteral("qtlogging.ini");
@ -691,6 +697,10 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
m_settings->registerSetting("ConsoleMaxLines", 100000);
m_settings->registerSetting("ConsoleOverflowStop", true);
logModel->setMaxLines(getConsoleMaxLines(settings()));
logModel->setStopOnOverflow(shouldStopOnConsoleOverflow(settings()));
logModel->setOverflowMessage(tr("Cannot display this log since the log length surpassed %1 lines.").arg(logModel->getMaxLines()));
// Folders
m_settings->registerSetting("InstanceDir", "instances");
m_settings->registerSetting({ "CentralModsDir", "ModsDir" }, "mods");
@ -1683,6 +1693,20 @@ MainWindow* Application::showMainWindow(bool minimized)
return m_mainWindow;
}
ViewLogWindow* Application::showLogWindow()
{
if (m_viewLogWindow) {
m_viewLogWindow->setWindowState(m_viewLogWindow->windowState() & ~Qt::WindowMinimized);
m_viewLogWindow->raise();
m_viewLogWindow->activateWindow();
} else {
m_viewLogWindow = new ViewLogWindow();
connect(m_viewLogWindow, &ViewLogWindow::isClosing, this, &Application::on_windowClose);
m_openWindows++;
}
return m_viewLogWindow;
}
InstanceWindow* Application::showInstanceWindow(InstancePtr instance, QString page)
{
if (!instance)
@ -1737,6 +1761,10 @@ void Application::on_windowClose()
if (mainWindow) {
m_mainWindow = nullptr;
}
auto logWindow = qobject_cast<ViewLogWindow*>(sender());
if (logWindow) {
m_viewLogWindow = nullptr;
}
// quit when there are no more windows.
if (shouldExitNow()) {
exit(0);

View file

@ -48,12 +48,14 @@
#include <BaseInstance.h>
#include "launch/LogModel.h"
#include "minecraft/launch/MinecraftTarget.h"
class LaunchController;
class LocalPeer;
class InstanceWindow;
class MainWindow;
class ViewLogWindow;
class SetupWizard;
class GenericPageProvider;
class QFile;
@ -182,6 +184,7 @@ class Application : public QApplication {
InstanceWindow* showInstanceWindow(InstancePtr instance, QString page = QString());
MainWindow* showMainWindow(bool minimized = false);
ViewLogWindow* showLogWindow();
void updateIsRunning(bool running);
bool updatesAreAllowed();
@ -289,6 +292,9 @@ class Application : public QApplication {
// main window, if any
MainWindow* m_mainWindow = nullptr;
// log window, if any
ViewLogWindow* m_viewLogWindow = nullptr;
// peer launcher instance connector - used to implement single instance launcher and signalling
LocalPeer* m_peerInstance = nullptr;
@ -307,6 +313,7 @@ class Application : public QApplication {
QList<QUrl> m_urlsToImport;
QString m_instanceIdToShowWindowOf;
std::unique_ptr<QFile> logFile;
shared_qobject_ptr<LogModel> logModel;
public:
void addQSavePath(QString);

View file

@ -53,6 +53,23 @@
#include "Commandline.h"
#include "FileSystem.h"
int getConsoleMaxLines(SettingsObjectPtr settings)
{
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 shouldStopOnConsoleOverflow(SettingsObjectPtr settings)
{
return settings->get("ConsoleOverflowStop").toBool();
}
BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir) : QObject()
{
m_settings = settings;
@ -184,23 +201,6 @@ void BaseInstance::copyManagedPack(BaseInstance& other)
}
}
int BaseInstance::getConsoleMaxLines() const
{
auto lineSetting = m_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 BaseInstance::shouldStopOnConsoleOverflow() const
{
return m_settings->get("ConsoleOverflowStop").toBool();
}
QStringList BaseInstance::getLinkedInstances() const
{
auto setting = m_settings->get("linkedInstances").toString();

View file

@ -78,6 +78,10 @@ struct ShortcutData {
ShortcutTarget target = ShortcutTarget::Other;
};
/// Console settings
int getConsoleMaxLines(SettingsObjectPtr settings);
bool shouldStopOnConsoleOverflow(SettingsObjectPtr settings);
/*!
* \brief Base class for instances.
* This class implements many functions that are common between instances and
@ -272,9 +276,6 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
Status currentStatus() const;
int getConsoleMaxLines() const;
bool shouldStopOnConsoleOverflow() const;
QStringList getLinkedInstances() const;
void setLinkedInstances(const QStringList& list);
void addLinkedInstanceId(const QString& id);

View file

@ -847,6 +847,8 @@ SET(LAUNCHER_SOURCES
ui/MainWindow.cpp
ui/InstanceWindow.h
ui/InstanceWindow.cpp
ui/ViewLogWindow.h
ui/ViewLogWindow.cpp
# FIXME: maybe find a better home for this.
FileIgnoreProxy.cpp

View file

@ -46,7 +46,7 @@ class InstancePageProvider : protected QObject, public BasePageProvider {
// values.append(new GameOptionsPage(onesix.get()));
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
values.append(new InstanceSettingsPage(onesix));
values.append(new OtherLogsPage(inst));
values.append(new OtherLogsPage("logs", tr("Other logs"), "Other-Logs", inst));
return values;
}

View file

@ -15,7 +15,7 @@ MessageLevel::Enum MessageLevel::getLevel(const QString& levelName)
return MessageLevel::Message;
else if (name == "WARNING" || name == "WARN")
return MessageLevel::Warning;
else if (name == "ERROR")
else if (name == "ERROR" || name == "CRITICAL")
return MessageLevel::Error;
else if (name == "FATAL")
return MessageLevel::Fatal;
@ -25,6 +25,24 @@ MessageLevel::Enum MessageLevel::getLevel(const QString& levelName)
return MessageLevel::Unknown;
}
MessageLevel::Enum MessageLevel::getLevel(QtMsgType type)
{
switch (type) {
case QtDebugMsg:
return MessageLevel::Debug;
case QtInfoMsg:
return MessageLevel::Info;
case QtWarningMsg:
return MessageLevel::Warning;
case QtCriticalMsg:
return MessageLevel::Error;
case QtFatalMsg:
return MessageLevel::Fatal;
default:
return MessageLevel::Unknown;
}
}
MessageLevel::Enum MessageLevel::fromLine(QString& line)
{
// Level prefix
@ -36,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;
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <QString>
#include <QtLogging>
/**
* @brief the MessageLevel Enum
@ -21,7 +22,11 @@ enum Enum {
Fatal, /**< Fatal Errors */
};
MessageLevel::Enum getLevel(const QString& levelName);
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

View file

@ -203,8 +203,8 @@ shared_qobject_ptr<LogModel> LaunchTask::getLogModel()
{
if (!m_logModel) {
m_logModel.reset(new LogModel());
m_logModel->setMaxLines(m_instance->getConsoleMaxLines());
m_logModel->setStopOnOverflow(m_instance->shouldStopOnConsoleOverflow());
m_logModel->setMaxLines(getConsoleMaxLines(m_instance->settings()));
m_logModel->setStopOnOverflow(shouldStopOnConsoleOverflow(m_instance->settings()));
// FIXME: should this really be here?
m_logModel->setOverflowMessage(tr("Stopped watching the game log because the log length surpassed %1 lines.\n"
"You may have to fix your mods because the game is still logging to files and"

View file

@ -24,5 +24,5 @@ class ResourcePack : public DataPack {
/** Gets, respectively, the lower and upper versions supported by the set pack format. */
[[nodiscard]] std::pair<Version, Version> compatibleVersions() const override;
virtual QString directory() override { return "/assets"; }
QString directory() override { return "/assets"; }
};

View file

@ -92,6 +92,7 @@
#include "InstanceWindow.h"
#include "ui/GuiUtil.h"
#include "ui/ViewLogWindow.h"
#include "ui/dialogs/AboutDialog.h"
#include "ui/dialogs/CopyInstanceDialog.h"
#include "ui/dialogs/CreateShortcutDialog.h"
@ -238,14 +239,8 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
ui->actionViewJavaFolder->setEnabled(BuildConfig.JAVA_DOWNLOADER_ENABLED);
}
{ // logs upload
auto menu = new QMenu(this);
for (auto file : QDir("logs").entryInfoList(QDir::Files)) {
auto action = menu->addAction(file.fileName());
connect(action, &QAction::triggered, this, [this, file] { GuiUtil::uploadPaste(file.fileName(), file, this); });
}
ui->actionUploadLog->setMenu(menu);
{ // logs viewing
connect(ui->actionViewLog, &QAction::triggered, this, [] { APPLICATION->showLogWindow(); });
}
// add the toolbar toggles to the view menu

View file

@ -215,7 +215,7 @@
</property>
<addaction name="actionClearMetadata"/>
<addaction name="actionReportBug"/>
<addaction name="actionUploadLog"/>
<addaction name="actionViewLog"/>
<addaction name="actionAddToPATH"/>
<addaction name="separator"/>
<addaction name="actionMATRIX"/>
@ -663,16 +663,16 @@
<string>Clear cached metadata</string>
</property>
</action>
<action name="actionUploadLog">
<action name="actionViewLog">
<property name="icon">
<iconset theme="log">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Upload logs</string>
<string>View logs</string>
</property>
<property name="toolTip">
<string>Upload launcher logs to the selected log provider</string>
<string>View current and previous launcher logs</string>
</property>
</action>
<action name="actionAddToPATH">

View file

@ -0,0 +1,25 @@
#include <QCloseEvent>
#include "ViewLogWindow.h"
#include "ui/pages/instance/OtherLogsPage.h"
ViewLogWindow::ViewLogWindow(QWidget* parent)
: QMainWindow(parent), m_page(new OtherLogsPage("launcher-logs", tr("Launcher Logs"), "Launcher-Logs", nullptr, parent))
{
setAttribute(Qt::WA_DeleteOnClose);
setWindowIcon(APPLICATION->getThemedIcon("log"));
setWindowTitle(tr("View Launcher Logs"));
setCentralWidget(m_page);
setMinimumSize(m_page->size());
setContentsMargins(0, 0, 0, 0);
m_page->opened();
show();
}
void ViewLogWindow::closeEvent(QCloseEvent* event)
{
m_page->closed();
emit isClosing();
event->accept();
}

View file

@ -0,0 +1,23 @@
#pragma once
#include <QMainWindow>
#include "Application.h"
class OtherLogsPage;
class ViewLogWindow : public QMainWindow {
Q_OBJECT
public:
explicit ViewLogWindow(QWidget* parent = nullptr);
signals:
void isClosing();
protected:
void closeEvent(QCloseEvent*) override;
private:
OtherLogsPage* m_page;
};

View file

@ -40,6 +40,7 @@
#include <QMessageBox>
#include "ui/GuiUtil.h"
#include "ui/themes/ThemeManager.h"
#include <FileSystem.h>
#include <GZip.h>
@ -49,18 +50,26 @@
#include <QShortcut>
#include <QUrl>
OtherLogsPage::OtherLogsPage(InstancePtr instance, QWidget* parent)
OtherLogsPage::OtherLogsPage(QString id, QString displayName, QString helpPage, InstancePtr instance, QWidget* parent)
: QWidget(parent)
, m_id(id)
, m_displayName(displayName)
, m_helpPage(helpPage)
, ui(new Ui::OtherLogsPage)
, m_instance(instance)
, m_basePath(instance->gameRoot())
, m_logSearchPaths(instance->getLogFileSearchPaths())
, m_model(new LogModel(this))
, m_basePath(instance ? instance->gameRoot() : APPLICATION->dataRoot())
, m_logSearchPaths(instance ? instance->getLogFileSearchPaths() : QStringList{ "logs" })
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
m_proxy = new LogFormatProxyModel(this);
if (m_instance) {
m_model.reset(new LogModel(this));
ui->trackLogCheckbox->hide();
} else {
m_model = APPLICATION->logModel;
}
// set up fonts in the log proxy
{
@ -75,9 +84,13 @@ OtherLogsPage::OtherLogsPage(InstancePtr instance, QWidget* parent)
ui->text->setModel(m_proxy);
m_model->setMaxLines(m_instance->getConsoleMaxLines());
m_model->setStopOnOverflow(m_instance->shouldStopOnConsoleOverflow());
m_model->setOverflowMessage(tr("Cannot display this log since the log length surpassed %1 lines.").arg(m_model->getMaxLines()));
if (m_instance) {
m_model->setMaxLines(getConsoleMaxLines(m_instance->settings()));
m_model->setStopOnOverflow(shouldStopOnConsoleOverflow(m_instance->settings()));
m_model->setOverflowMessage(tr("Cannot display this log since the log length surpassed %1 lines.").arg(m_model->getMaxLines()));
} else {
modelStateToUI();
}
m_proxy->setSourceModel(m_model.get());
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &OtherLogsPage::populateSelectLogBox);
@ -99,6 +112,39 @@ OtherLogsPage::~OtherLogsPage()
delete ui;
}
void OtherLogsPage::modelStateToUI()
{
if (m_model->wrapLines()) {
ui->text->setWordWrap(true);
ui->wrapCheckbox->setCheckState(Qt::Checked);
} else {
ui->text->setWordWrap(false);
ui->wrapCheckbox->setCheckState(Qt::Unchecked);
}
if (m_model->colorLines()) {
ui->text->setColorLines(true);
ui->colorCheckbox->setCheckState(Qt::Checked);
} else {
ui->text->setColorLines(false);
ui->colorCheckbox->setCheckState(Qt::Unchecked);
}
if (m_model->suspended()) {
ui->trackLogCheckbox->setCheckState(Qt::Unchecked);
} else {
ui->trackLogCheckbox->setCheckState(Qt::Checked);
}
}
void OtherLogsPage::UIToModelState()
{
if (!m_model) {
return;
}
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 OtherLogsPage::retranslate()
{
ui->retranslateUi(this);
@ -136,6 +182,8 @@ void OtherLogsPage::populateSelectLogBox()
ui->selectLogBox->blockSignals(true);
ui->selectLogBox->clear();
if (!m_instance)
ui->selectLogBox->addItem("Current logs");
ui->selectLogBox->addItems(getPaths());
ui->selectLogBox->blockSignals(false);
@ -151,6 +199,9 @@ void OtherLogsPage::populateSelectLogBox()
} else {
setControlsEnabled(false);
}
} else if (!m_instance) {
ui->selectLogBox->setCurrentIndex(0);
setControlsEnabled(true);
}
on_selectLogBox_currentIndexChanged(ui->selectLogBox->currentIndex());
@ -159,27 +210,50 @@ void OtherLogsPage::populateSelectLogBox()
void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index)
{
QString file;
if (index != -1) {
if (index > 0 || (index == 0 && m_instance)) {
file = ui->selectLogBox->itemText(index);
}
if (file.isEmpty() || !QFile::exists(FS::PathCombine(m_basePath, file))) {
if ((index != 0 || m_instance) && (file.isEmpty() || !QFile::exists(FS::PathCombine(m_basePath, file)))) {
m_currentFile = QString();
ui->text->clear();
setControlsEnabled(false);
} else {
m_currentFile = file;
on_btnReload_clicked();
reload();
setControlsEnabled(true);
}
}
void OtherLogsPage::on_btnReload_clicked()
{
if (!m_instance && m_currentFile.isEmpty()) {
if (!m_model)
return;
m_model->clear();
if (m_container)
m_container->refreshContainer();
} else {
reload();
}
}
void OtherLogsPage::reload()
{
if (m_currentFile.isEmpty()) {
setControlsEnabled(false);
if (m_instance) {
setControlsEnabled(false);
} else {
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);
@ -210,15 +284,20 @@ void OtherLogsPage::on_btnReload_clicked()
line = line.remove(line.size() - 1, 1);
MessageLevel::Enum level = MessageLevel::Unknown;
// if the launcher part set a log level, use it
auto innerLevel = MessageLevel::fromLine(line);
if (innerLevel != MessageLevel::Unknown) {
level = innerLevel;
}
QString lineTemp = line; // don't edit out the time and level for clarity
if (!m_instance) {
level = MessageLevel::fromLauncherLine(lineTemp);
} else {
// if the launcher part set a log level, use it
auto innerLevel = MessageLevel::fromLine(lineTemp);
if (innerLevel != MessageLevel::Unknown) {
level = innerLevel;
}
// If the level is still undetermined, guess level
if (level == MessageLevel::StdErr || level == MessageLevel::StdOut || level == MessageLevel::Unknown) {
level = LogParser::guessLevel(line, last);
// If the level is still undetermined, guess level
if (level == MessageLevel::StdErr || level == MessageLevel::StdOut || level == MessageLevel::Unknown) {
level = LogParser::guessLevel(line, last);
}
}
last = level;
@ -229,6 +308,12 @@ void OtherLogsPage::on_btnReload_clicked()
// Try to determine a level for each line
ui->text->clear();
ui->text->setModel(nullptr);
if (!m_instance) {
m_model.reset(new LogModel(this));
m_model->setMaxLines(getConsoleMaxLines(APPLICATION->settings()));
m_model->setStopOnOverflow(shouldStopOnConsoleOverflow(APPLICATION->settings()));
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;
@ -258,14 +343,24 @@ void OtherLogsPage::on_btnReload_clicked()
while (!file.atEnd() && !handleLine(QString::fromUtf8(file.readLine()))) {
}
}
ui->text->setModel(m_proxy);
ui->text->scrollToBottom();
if (m_instance) {
ui->text->setModel(m_proxy);
ui->text->scrollToBottom();
} else {
m_proxy->setSourceModel(m_model.get());
ui->text->setModel(m_proxy);
ui->text->scrollToBottom();
UIToModelState();
setControlsEnabled(true);
}
}
}
void OtherLogsPage::on_btnPaste_clicked()
{
GuiUtil::uploadPaste(m_currentFile, ui->text->toPlainText(), this);
QString name = m_currentFile.isEmpty() ? displayName() : m_currentFile;
GuiUtil::uploadPaste(name, ui->text->toPlainText(), this);
}
void OtherLogsPage::on_btnCopy_clicked()
@ -278,6 +373,13 @@ void OtherLogsPage::on_btnBottom_clicked()
ui->text->scrollToBottom();
}
void OtherLogsPage::on_trackLogCheckbox_clicked(bool checked)
{
if (!m_model)
return;
m_model->suspend(!checked);
}
void OtherLogsPage::on_btnDelete_clicked()
{
if (m_currentFile.isEmpty()) {
@ -376,12 +478,27 @@ void OtherLogsPage::on_colorCheckbox_clicked(bool checked)
void OtherLogsPage::setControlsEnabled(const bool enabled)
{
if (m_instance) {
ui->btnDelete->setEnabled(enabled);
ui->btnClean->setEnabled(enabled);
} else 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->btnDelete->setEnabled(enabled);
ui->btnCopy->setEnabled(enabled);
ui->btnPaste->setEnabled(enabled);
ui->text->setEnabled(enabled);
ui->btnClean->setEnabled(enabled);
}
QStringList OtherLogsPage::getPaths()

View file

@ -53,13 +53,13 @@ class OtherLogsPage : public QWidget, public BasePage {
Q_OBJECT
public:
explicit OtherLogsPage(InstancePtr instance, QWidget* parent = 0);
explicit OtherLogsPage(QString id, QString displayName, QString helpPage, InstancePtr instance = nullptr, QWidget* parent = 0);
~OtherLogsPage();
QString id() const override { return "logs"; }
QString displayName() const override { return tr("Other logs"); }
QString id() const override { return m_id; }
QString displayName() const override { return m_displayName; }
QIcon icon() const override { return APPLICATION->getThemedIcon("log"); }
QString helpPage() const override { return "other-Logs"; }
QString helpPage() const override { return m_helpPage; }
void retranslate() override;
void openedImpl() override;
@ -75,6 +75,7 @@ class OtherLogsPage : public QWidget, public BasePage {
void on_btnClean_clicked();
void on_btnBottom_clicked();
void on_trackLogCheckbox_clicked(bool checked);
void on_wrapCheckbox_clicked(bool checked);
void on_colorCheckbox_clicked(bool checked);
@ -84,11 +85,18 @@ class OtherLogsPage : public QWidget, public BasePage {
void findPreviousActivated();
private:
void reload();
void modelStateToUI();
void UIToModelState();
void setControlsEnabled(bool enabled);
QStringList getPaths();
private:
QString m_id;
QString m_displayName;
QString m_helpPage;
Ui::OtherLogsPage* ui;
InstancePtr m_instance;
/** Path to display log paths relative to. */

View file

@ -127,6 +127,16 @@
</item>
<item row="1" column="0" colspan="5">
<layout class="QHBoxLayout" name="horizontalLayout1">
<item>
<widget class="QCheckBox" name="trackLogCheckbox">
<property name="text">
<string>Keep updating</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="wrapCheckbox">
<property name="text">