Add a page to view launcher logs (#3831)
This commit is contained in:
commit
9f9aabcf97
17 changed files with 320 additions and 66 deletions
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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">
|
||||||
|
|
25
launcher/ui/ViewLogWindow.cpp
Normal file
25
launcher/ui/ViewLogWindow.cpp
Normal 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();
|
||||||
|
}
|
23
launcher/ui/ViewLogWindow.h
Normal file
23
launcher/ui/ViewLogWindow.h
Normal 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;
|
||||||
|
};
|
|
@ -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()
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue