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 "tools/GenericProfiler.h"
#include "ui/InstanceWindow.h" #include "ui/InstanceWindow.h"
#include "ui/MainWindow.h" #include "ui/MainWindow.h"
#include "ui/ViewLogWindow.h"
#include "ui/dialogs/ProgressDialog.h" #include "ui/dialogs/ProgressDialog.h"
#include "ui/instanceview/AccessibleInstanceView.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); 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->write(out.toUtf8());
APPLICATION->logFile->flush(); APPLICATION->logFile->flush();
@ -538,6 +542,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
qInstallMessageHandler(appDebugOutput); qInstallMessageHandler(appDebugOutput);
qSetMessagePattern(defaultLogFormat); qSetMessagePattern(defaultLogFormat);
logModel.reset(new LogModel(this));
bool foundLoggingRules = false; bool foundLoggingRules = false;
auto logRulesFile = QStringLiteral("qtlogging.ini"); 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("ConsoleMaxLines", 100000);
m_settings->registerSetting("ConsoleOverflowStop", true); 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 // Folders
m_settings->registerSetting("InstanceDir", "instances"); m_settings->registerSetting("InstanceDir", "instances");
m_settings->registerSetting({ "CentralModsDir", "ModsDir" }, "mods"); m_settings->registerSetting({ "CentralModsDir", "ModsDir" }, "mods");
@ -1683,6 +1693,20 @@ MainWindow* Application::showMainWindow(bool minimized)
return m_mainWindow; 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) InstanceWindow* Application::showInstanceWindow(InstancePtr instance, QString page)
{ {
if (!instance) if (!instance)
@ -1737,6 +1761,10 @@ void Application::on_windowClose()
if (mainWindow) { if (mainWindow) {
m_mainWindow = nullptr; m_mainWindow = nullptr;
} }
auto logWindow = qobject_cast<ViewLogWindow*>(sender());
if (logWindow) {
m_viewLogWindow = nullptr;
}
// quit when there are no more windows. // quit when there are no more windows.
if (shouldExitNow()) { if (shouldExitNow()) {
exit(0); exit(0);

View file

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

View file

@ -53,6 +53,23 @@
#include "Commandline.h" #include "Commandline.h"
#include "FileSystem.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() BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir) : QObject()
{ {
m_settings = settings; 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 QStringList BaseInstance::getLinkedInstances() const
{ {
auto setting = m_settings->get("linkedInstances").toString(); auto setting = m_settings->get("linkedInstances").toString();

View file

@ -78,6 +78,10 @@ struct ShortcutData {
ShortcutTarget target = ShortcutTarget::Other; ShortcutTarget target = ShortcutTarget::Other;
}; };
/// Console settings
int getConsoleMaxLines(SettingsObjectPtr settings);
bool shouldStopOnConsoleOverflow(SettingsObjectPtr settings);
/*! /*!
* \brief Base class for instances. * \brief Base class for instances.
* This class implements many functions that are common between instances and * 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; Status currentStatus() const;
int getConsoleMaxLines() const;
bool shouldStopOnConsoleOverflow() const;
QStringList getLinkedInstances() const; QStringList getLinkedInstances() const;
void setLinkedInstances(const QStringList& list); void setLinkedInstances(const QStringList& list);
void addLinkedInstanceId(const QString& id); void addLinkedInstanceId(const QString& id);

View file

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

View file

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

View file

@ -15,7 +15,7 @@ MessageLevel::Enum MessageLevel::getLevel(const QString& levelName)
return MessageLevel::Message; return MessageLevel::Message;
else if (name == "WARNING" || name == "WARN") else if (name == "WARNING" || name == "WARN")
return MessageLevel::Warning; return MessageLevel::Warning;
else if (name == "ERROR") else if (name == "ERROR" || name == "CRITICAL")
return MessageLevel::Error; return MessageLevel::Error;
else if (name == "FATAL") else if (name == "FATAL")
return MessageLevel::Fatal; return MessageLevel::Fatal;
@ -25,6 +25,24 @@ MessageLevel::Enum MessageLevel::getLevel(const QString& levelName)
return MessageLevel::Unknown; 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) MessageLevel::Enum MessageLevel::fromLine(QString& line)
{ {
// Level prefix // Level prefix
@ -36,3 +54,18 @@ MessageLevel::Enum MessageLevel::fromLine(QString& line)
} }
return MessageLevel::Unknown; 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 #pragma once
#include <QString> #include <QString>
#include <QtLogging>
/** /**
* @brief the MessageLevel Enum * @brief the MessageLevel Enum
@ -21,7 +22,11 @@ enum Enum {
Fatal, /**< Fatal Errors */ Fatal, /**< Fatal Errors */
}; };
MessageLevel::Enum getLevel(const QString& levelName); MessageLevel::Enum getLevel(const QString& levelName);
MessageLevel::Enum getLevel(QtMsgType type);
/* Get message level from a line. Line is modified if it was successful. */ /* Get message level from a line. Line is modified if it was successful. */
MessageLevel::Enum fromLine(QString& line); 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 } // namespace MessageLevel

View file

@ -203,8 +203,8 @@ shared_qobject_ptr<LogModel> LaunchTask::getLogModel()
{ {
if (!m_logModel) { if (!m_logModel) {
m_logModel.reset(new LogModel()); m_logModel.reset(new LogModel());
m_logModel->setMaxLines(m_instance->getConsoleMaxLines()); m_logModel->setMaxLines(getConsoleMaxLines(m_instance->settings()));
m_logModel->setStopOnOverflow(m_instance->shouldStopOnConsoleOverflow()); m_logModel->setStopOnOverflow(shouldStopOnConsoleOverflow(m_instance->settings()));
// FIXME: should this really be here? // FIXME: should this really be here?
m_logModel->setOverflowMessage(tr("Stopped watching the game log because the log length surpassed %1 lines.\n" 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" "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. */ /** Gets, respectively, the lower and upper versions supported by the set pack format. */
[[nodiscard]] std::pair<Version, Version> compatibleVersions() const override; [[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 "InstanceWindow.h"
#include "ui/GuiUtil.h" #include "ui/GuiUtil.h"
#include "ui/ViewLogWindow.h"
#include "ui/dialogs/AboutDialog.h" #include "ui/dialogs/AboutDialog.h"
#include "ui/dialogs/CopyInstanceDialog.h" #include "ui/dialogs/CopyInstanceDialog.h"
#include "ui/dialogs/CreateShortcutDialog.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); ui->actionViewJavaFolder->setEnabled(BuildConfig.JAVA_DOWNLOADER_ENABLED);
} }
{ // logs upload { // logs viewing
connect(ui->actionViewLog, &QAction::triggered, this, [] { APPLICATION->showLogWindow(); });
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);
} }
// add the toolbar toggles to the view menu // add the toolbar toggles to the view menu

View file

@ -215,7 +215,7 @@
</property> </property>
<addaction name="actionClearMetadata"/> <addaction name="actionClearMetadata"/>
<addaction name="actionReportBug"/> <addaction name="actionReportBug"/>
<addaction name="actionUploadLog"/> <addaction name="actionViewLog"/>
<addaction name="actionAddToPATH"/> <addaction name="actionAddToPATH"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionMATRIX"/> <addaction name="actionMATRIX"/>
@ -663,16 +663,16 @@
<string>Clear cached metadata</string> <string>Clear cached metadata</string>
</property> </property>
</action> </action>
<action name="actionUploadLog"> <action name="actionViewLog">
<property name="icon"> <property name="icon">
<iconset theme="log"> <iconset theme="log">
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>Upload logs</string> <string>View logs</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Upload launcher logs to the selected log provider</string> <string>View current and previous launcher logs</string>
</property> </property>
</action> </action>
<action name="actionAddToPATH"> <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 <QMessageBox>
#include "ui/GuiUtil.h" #include "ui/GuiUtil.h"
#include "ui/themes/ThemeManager.h"
#include <FileSystem.h> #include <FileSystem.h>
#include <GZip.h> #include <GZip.h>
@ -49,18 +50,26 @@
#include <QShortcut> #include <QShortcut>
#include <QUrl> #include <QUrl>
OtherLogsPage::OtherLogsPage(InstancePtr instance, QWidget* parent) OtherLogsPage::OtherLogsPage(QString id, QString displayName, QString helpPage, InstancePtr instance, QWidget* parent)
: QWidget(parent) : QWidget(parent)
, m_id(id)
, m_displayName(displayName)
, m_helpPage(helpPage)
, ui(new Ui::OtherLogsPage) , ui(new Ui::OtherLogsPage)
, m_instance(instance) , m_instance(instance)
, m_basePath(instance->gameRoot()) , m_basePath(instance ? instance->gameRoot() : APPLICATION->dataRoot())
, m_logSearchPaths(instance->getLogFileSearchPaths()) , m_logSearchPaths(instance ? instance->getLogFileSearchPaths() : QStringList{ "logs" })
, m_model(new LogModel(this))
{ {
ui->setupUi(this); ui->setupUi(this);
ui->tabWidget->tabBar()->hide(); ui->tabWidget->tabBar()->hide();
m_proxy = new LogFormatProxyModel(this); 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 // set up fonts in the log proxy
{ {
@ -75,9 +84,13 @@ OtherLogsPage::OtherLogsPage(InstancePtr instance, QWidget* parent)
ui->text->setModel(m_proxy); ui->text->setModel(m_proxy);
m_model->setMaxLines(m_instance->getConsoleMaxLines()); if (m_instance) {
m_model->setStopOnOverflow(m_instance->shouldStopOnConsoleOverflow()); m_model->setMaxLines(getConsoleMaxLines(m_instance->settings()));
m_model->setOverflowMessage(tr("Cannot display this log since the log length surpassed %1 lines.").arg(m_model->getMaxLines())); 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()); m_proxy->setSourceModel(m_model.get());
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &OtherLogsPage::populateSelectLogBox); connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &OtherLogsPage::populateSelectLogBox);
@ -99,6 +112,39 @@ OtherLogsPage::~OtherLogsPage()
delete ui; 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() void OtherLogsPage::retranslate()
{ {
ui->retranslateUi(this); ui->retranslateUi(this);
@ -136,6 +182,8 @@ void OtherLogsPage::populateSelectLogBox()
ui->selectLogBox->blockSignals(true); ui->selectLogBox->blockSignals(true);
ui->selectLogBox->clear(); ui->selectLogBox->clear();
if (!m_instance)
ui->selectLogBox->addItem("Current logs");
ui->selectLogBox->addItems(getPaths()); ui->selectLogBox->addItems(getPaths());
ui->selectLogBox->blockSignals(false); ui->selectLogBox->blockSignals(false);
@ -151,6 +199,9 @@ void OtherLogsPage::populateSelectLogBox()
} else { } else {
setControlsEnabled(false); setControlsEnabled(false);
} }
} else if (!m_instance) {
ui->selectLogBox->setCurrentIndex(0);
setControlsEnabled(true);
} }
on_selectLogBox_currentIndexChanged(ui->selectLogBox->currentIndex()); on_selectLogBox_currentIndexChanged(ui->selectLogBox->currentIndex());
@ -159,27 +210,50 @@ void OtherLogsPage::populateSelectLogBox()
void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index) void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index)
{ {
QString file; QString file;
if (index != -1) { if (index > 0 || (index == 0 && m_instance)) {
file = ui->selectLogBox->itemText(index); 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(); m_currentFile = QString();
ui->text->clear(); ui->text->clear();
setControlsEnabled(false); setControlsEnabled(false);
} else { } else {
m_currentFile = file; m_currentFile = file;
on_btnReload_clicked(); reload();
setControlsEnabled(true); setControlsEnabled(true);
} }
} }
void OtherLogsPage::on_btnReload_clicked() 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()) { 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; return;
} }
QFile file(FS::PathCombine(m_basePath, m_currentFile)); QFile file(FS::PathCombine(m_basePath, m_currentFile));
if (!file.open(QFile::ReadOnly)) { if (!file.open(QFile::ReadOnly)) {
setControlsEnabled(false); setControlsEnabled(false);
@ -210,15 +284,20 @@ void OtherLogsPage::on_btnReload_clicked()
line = line.remove(line.size() - 1, 1); line = line.remove(line.size() - 1, 1);
MessageLevel::Enum level = MessageLevel::Unknown; MessageLevel::Enum level = MessageLevel::Unknown;
// if the launcher part set a log level, use it QString lineTemp = line; // don't edit out the time and level for clarity
auto innerLevel = MessageLevel::fromLine(line); if (!m_instance) {
if (innerLevel != MessageLevel::Unknown) { level = MessageLevel::fromLauncherLine(lineTemp);
level = innerLevel; } 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 the level is still undetermined, guess level
if (level == MessageLevel::StdErr || level == MessageLevel::StdOut || level == MessageLevel::Unknown) { if (level == MessageLevel::StdErr || level == MessageLevel::StdOut || level == MessageLevel::Unknown) {
level = LogParser::guessLevel(line, last); level = LogParser::guessLevel(line, last);
}
} }
last = level; last = level;
@ -229,6 +308,12 @@ void OtherLogsPage::on_btnReload_clicked()
// Try to determine a level for each line // Try to determine a level for each line
ui->text->clear(); ui->text->clear();
ui->text->setModel(nullptr); 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(); m_model->clear();
if (file.fileName().endsWith(".gz")) { if (file.fileName().endsWith(".gz")) {
QString line; QString line;
@ -258,14 +343,24 @@ void OtherLogsPage::on_btnReload_clicked()
while (!file.atEnd() && !handleLine(QString::fromUtf8(file.readLine()))) { 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() 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() void OtherLogsPage::on_btnCopy_clicked()
@ -278,6 +373,13 @@ void OtherLogsPage::on_btnBottom_clicked()
ui->text->scrollToBottom(); ui->text->scrollToBottom();
} }
void OtherLogsPage::on_trackLogCheckbox_clicked(bool checked)
{
if (!m_model)
return;
m_model->suspend(!checked);
}
void OtherLogsPage::on_btnDelete_clicked() void OtherLogsPage::on_btnDelete_clicked()
{ {
if (m_currentFile.isEmpty()) { if (m_currentFile.isEmpty()) {
@ -376,12 +478,27 @@ void OtherLogsPage::on_colorCheckbox_clicked(bool checked)
void OtherLogsPage::setControlsEnabled(const bool enabled) 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->btnReload->setEnabled(enabled);
ui->btnDelete->setEnabled(enabled);
ui->btnCopy->setEnabled(enabled); ui->btnCopy->setEnabled(enabled);
ui->btnPaste->setEnabled(enabled); ui->btnPaste->setEnabled(enabled);
ui->text->setEnabled(enabled); ui->text->setEnabled(enabled);
ui->btnClean->setEnabled(enabled);
} }
QStringList OtherLogsPage::getPaths() QStringList OtherLogsPage::getPaths()

View file

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

View file

@ -127,6 +127,16 @@
</item> </item>
<item row="1" column="0" colspan="5"> <item row="1" column="0" colspan="5">
<layout class="QHBoxLayout" name="horizontalLayout1"> <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> <item>
<widget class="QCheckBox" name="wrapCheckbox"> <widget class="QCheckBox" name="wrapCheckbox">
<property name="text"> <property name="text">