Shallow search and lazy loading for Other Logs page (#3664)

This commit is contained in:
TheKodeToad 2025-04-28 10:57:37 +01:00 committed by GitHub
commit 51cd4c2174
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 89 additions and 59 deletions

@ -1 +1 @@
Subproject commit 1f8e591b263eef8a0dc04929f2da135af59fac3c Subproject commit f5d368a31d6ef046eb2955c74ec6f54f32ed5c4e

View File

@ -198,15 +198,10 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
virtual QProcessEnvironment createEnvironment() = 0; virtual QProcessEnvironment createEnvironment() = 0;
virtual QProcessEnvironment createLaunchEnvironment() = 0; virtual QProcessEnvironment createLaunchEnvironment() = 0;
/*!
* Returns a matcher that can maps relative paths within the instance to whether they are 'log files'
*/
virtual IPathMatcher::Ptr getLogFileMatcher() = 0;
/*! /*!
* Returns the root folder to use for looking up log files * Returns the root folder to use for looking up log files
*/ */
virtual QString getLogFileRoot() = 0; virtual QStringList getLogFileSearchPaths() = 0;
virtual QString getStatusbarDescription() = 0; virtual QString getStatusbarDescription() = 0;

View File

@ -44,10 +44,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));
auto logMatcher = inst->getLogFileMatcher(); values.append(new OtherLogsPage(inst));
if (logMatcher) {
values.append(new OtherLogsPage(inst, logMatcher));
}
return values; return values;
} }

View File

@ -57,8 +57,7 @@ class NullInstance : public BaseInstance {
QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); } QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); }
QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); } QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); }
QMap<QString, QString> getVariables() override { return QMap<QString, QString>(); } QMap<QString, QString> getVariables() override { return QMap<QString, QString>(); }
IPathMatcher::Ptr getLogFileMatcher() override { return nullptr; } QStringList getLogFileSearchPaths() override { return {}; }
QString getLogFileRoot() override { return instanceRoot(); }
QString typeName() const override { return "Null"; } QString typeName() const override { return "Null"; }
bool canExport() const override { return false; } bool canExport() const override { return false; }
bool canEdit() const override { return false; } bool canEdit() const override { return false; }

View File

@ -1047,19 +1047,9 @@ MessageLevel::Enum MinecraftInstance::guessLevel(const QString& line, MessageLev
return level; return level;
} }
IPathMatcher::Ptr MinecraftInstance::getLogFileMatcher() QStringList MinecraftInstance::getLogFileSearchPaths()
{ {
auto combined = std::make_shared<MultiMatcher>(); return { FS::PathCombine(gameRoot(), "crash-reports"), FS::PathCombine(gameRoot(), "logs"), gameRoot() };
combined->add(std::make_shared<RegexpMatcher>(".*\\.log(\\.[0-9]*)?(\\.gz)?$"));
combined->add(std::make_shared<RegexpMatcher>("crash-.*\\.txt"));
combined->add(std::make_shared<RegexpMatcher>("IDMap dump.*\\.txt$"));
combined->add(std::make_shared<RegexpMatcher>("ModLoader\\.txt(\\..*)?$"));
return combined;
}
QString MinecraftInstance::getLogFileRoot()
{
return gameRoot();
} }
QString MinecraftInstance::getStatusbarDescription() QString MinecraftInstance::getStatusbarDescription()

View File

@ -142,9 +142,7 @@ class MinecraftInstance : public BaseInstance {
/// guess log level from a line of minecraft log /// guess log level from a line of minecraft log
MessageLevel::Enum guessLevel(const QString& line, MessageLevel::Enum level) override; MessageLevel::Enum guessLevel(const QString& line, MessageLevel::Enum level) override;
IPathMatcher::Ptr getLogFileMatcher() override; QStringList getLogFileSearchPaths() override;
QString getLogFileRoot() override;
QString getStatusbarDescription() override; QString getStatusbarDescription() override;

View File

@ -43,16 +43,18 @@
#include <FileSystem.h> #include <FileSystem.h>
#include <GZip.h> #include <GZip.h>
#include <QDir>
#include <QDirIterator>
#include <QFileSystemWatcher>
#include <QShortcut> #include <QShortcut>
#include "RecursiveFileSystemWatcher.h" #include <QUrl>
OtherLogsPage::OtherLogsPage(InstancePtr instance, IPathMatcher::Ptr fileFilter, QWidget* parent) OtherLogsPage::OtherLogsPage(InstancePtr instance, QWidget* parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::OtherLogsPage) , ui(new Ui::OtherLogsPage)
, m_instance(instance) , m_instance(instance)
, m_path(instance->getLogFileRoot()) , m_basePath(instance->gameRoot())
, m_fileFilter(fileFilter) , m_logSearchPaths(instance->getLogFileSearchPaths())
, m_watcher(new RecursiveFileSystemWatcher(this))
, m_model(new LogModel(this)) , m_model(new LogModel(this))
{ {
ui->setupUi(this); ui->setupUi(this);
@ -78,11 +80,7 @@ OtherLogsPage::OtherLogsPage(InstancePtr instance, IPathMatcher::Ptr fileFilter,
m_model->setOverflowMessage(tr("Cannot display this log since the log length surpassed %1 lines.").arg(m_model->getMaxLines())); m_model->setOverflowMessage(tr("Cannot display this log since the log length surpassed %1 lines.").arg(m_model->getMaxLines()));
m_proxy->setSourceModel(m_model.get()); m_proxy->setSourceModel(m_model.get());
m_watcher->setMatcher(fileFilter); connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &OtherLogsPage::populateSelectLogBox);
m_watcher->setRootDir(QDir::current().absoluteFilePath(m_path));
connect(m_watcher, &RecursiveFileSystemWatcher::filesChanged, this, &OtherLogsPage::populateSelectLogBox);
populateSelectLogBox();
auto findShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this); auto findShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this);
connect(findShortcut, &QShortcut::activated, this, &OtherLogsPage::findActivated); connect(findShortcut, &QShortcut::activated, this, &OtherLogsPage::findActivated);
@ -108,29 +106,54 @@ void OtherLogsPage::retranslate()
void OtherLogsPage::openedImpl() void OtherLogsPage::openedImpl()
{ {
m_watcher->enable(); 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 OtherLogsPage::closedImpl() void OtherLogsPage::closedImpl()
{ {
m_watcher->disable(); 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 OtherLogsPage::populateSelectLogBox() void OtherLogsPage::populateSelectLogBox()
{ {
const QString prevCurrentFile = m_currentFile;
ui->selectLogBox->blockSignals(true);
ui->selectLogBox->clear(); ui->selectLogBox->clear();
ui->selectLogBox->addItems(m_watcher->files()); ui->selectLogBox->addItems(getPaths());
if (m_currentFile.isEmpty()) { ui->selectLogBox->blockSignals(false);
setControlsEnabled(false);
ui->selectLogBox->setCurrentIndex(-1); if (!prevCurrentFile.isEmpty()) {
} else { const int index = ui->selectLogBox->findText(prevCurrentFile);
const int index = ui->selectLogBox->findText(m_currentFile);
if (index != -1) { if (index != -1) {
ui->selectLogBox->blockSignals(true);
ui->selectLogBox->setCurrentIndex(index); ui->selectLogBox->setCurrentIndex(index);
ui->selectLogBox->blockSignals(false);
setControlsEnabled(true); setControlsEnabled(true);
// don't refresh file
return;
} else { } else {
setControlsEnabled(false); setControlsEnabled(false);
} }
} }
on_selectLogBox_currentIndexChanged(ui->selectLogBox->currentIndex());
} }
void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index) void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index)
@ -140,7 +163,7 @@ void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index)
file = ui->selectLogBox->itemText(index); file = ui->selectLogBox->itemText(index);
} }
if (file.isEmpty() || !QFile::exists(FS::PathCombine(m_path, file))) { if (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);
@ -157,8 +180,7 @@ void OtherLogsPage::on_btnReload_clicked()
setControlsEnabled(false); setControlsEnabled(false);
return; return;
} }
QFile file(FS::PathCombine(m_basePath, m_currentFile));
QFile file(FS::PathCombine(m_path, m_currentFile));
if (!file.open(QFile::ReadOnly)) { if (!file.open(QFile::ReadOnly)) {
setControlsEnabled(false); setControlsEnabled(false);
ui->btnReload->setEnabled(true); // allow reload ui->btnReload->setEnabled(true); // allow reload
@ -267,7 +289,7 @@ void OtherLogsPage::on_btnDelete_clicked()
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) { QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) {
return; return;
} }
QFile file(FS::PathCombine(m_path, m_currentFile)); QFile file(FS::PathCombine(m_basePath, m_currentFile));
if (FS::trash(file.fileName())) { if (FS::trash(file.fileName())) {
return; return;
@ -280,7 +302,7 @@ void OtherLogsPage::on_btnDelete_clicked()
void OtherLogsPage::on_btnClean_clicked() void OtherLogsPage::on_btnClean_clicked()
{ {
auto toDelete = m_watcher->files(); auto toDelete = getPaths();
if (toDelete.isEmpty()) { if (toDelete.isEmpty()) {
return; return;
} }
@ -303,7 +325,9 @@ void OtherLogsPage::on_btnClean_clicked()
} }
QStringList failed; QStringList failed;
for (auto item : toDelete) { for (auto item : toDelete) {
QFile file(FS::PathCombine(m_path, item)); QString absolutePath = FS::PathCombine(m_basePath, item);
QFile file(absolutePath);
qDebug() << "Deleting log" << absolutePath;
if (FS::trash(file.fileName())) { if (FS::trash(file.fileName())) {
continue; continue;
} }
@ -357,6 +381,29 @@ void OtherLogsPage::setControlsEnabled(const bool enabled)
ui->btnClean->setEnabled(enabled); ui->btnClean->setEnabled(enabled);
} }
QStringList OtherLogsPage::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 OtherLogsPage::on_findButton_clicked() void OtherLogsPage::on_findButton_clicked()
{ {
auto modifiers = QApplication::keyboardModifiers(); auto modifiers = QApplication::keyboardModifiers();

View File

@ -39,6 +39,7 @@
#include <Application.h> #include <Application.h>
#include <pathmatcher/IPathMatcher.h> #include <pathmatcher/IPathMatcher.h>
#include <QFileSystemWatcher>
#include "LogPage.h" #include "LogPage.h"
#include "ui/pages/BasePage.h" #include "ui/pages/BasePage.h"
@ -52,7 +53,7 @@ class OtherLogsPage : public QWidget, public BasePage {
Q_OBJECT Q_OBJECT
public: public:
explicit OtherLogsPage(InstancePtr instance, IPathMatcher::Ptr fileFilter, QWidget* parent = 0); explicit OtherLogsPage(InstancePtr instance, QWidget* parent = 0);
~OtherLogsPage(); ~OtherLogsPage();
QString id() const override { return "logs"; } QString id() const override { return "logs"; }
@ -85,13 +86,16 @@ class OtherLogsPage : public QWidget, public BasePage {
private: private:
void setControlsEnabled(bool enabled); void setControlsEnabled(bool enabled);
QStringList getPaths();
private: private:
Ui::OtherLogsPage* ui; Ui::OtherLogsPage* ui;
InstancePtr m_instance; InstancePtr m_instance;
QString m_path; /** Path to display log paths relative to. */
QString m_basePath;
QStringList m_logSearchPaths;
QString m_currentFile; QString m_currentFile;
IPathMatcher::Ptr m_fileFilter; QFileSystemWatcher m_watcher;
RecursiveFileSystemWatcher* m_watcher;
LogFormatProxyModel* m_proxy; LogFormatProxyModel* m_proxy;
shared_qobject_ptr<LogModel> m_model; shared_qobject_ptr<LogModel> m_model;

@ -1 +1 @@
Subproject commit 1f820dc98d0a520c175433bcbb0098327d82aac6 Subproject commit a3d9394aba4b35789293378e04fb7473d65edf97

@ -1 +1 @@
Subproject commit 531449ba1c930c98e0bcf5d332b237a8566f9d78 Subproject commit 23b955121b8217c1c348a9ed2483167a6f3ff4ad

@ -1 +1 @@
Subproject commit 3fd3b299b875fbd2beac4894b8a870d80022cad7 Subproject commit 8aeb3f7d8254f4bf1f7c6cf2a8f59c2ca141a552