diff options
29 files changed, 621 insertions, 145 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 077c2650..f6ace39f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/jars) ######## Set compiler flags ######## include(UseCXX11) include(Coverage) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +set(CMAKE_CXX_FLAGS " -Wall ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror=return-type") ################################ 3rd Party Libs ################################ @@ -280,6 +280,10 @@ SET(MULTIMC_SOURCES logger/QsLogDest.cpp logger/QsLogDest.h + # GUI - general utilities + gui/GuiUtil.h + gui/GuiUtil.cpp + # GUI - windows gui/MainWindow.h gui/MainWindow.cpp @@ -287,6 +291,7 @@ SET(MULTIMC_SOURCES gui/ConsoleWindow.cpp # GUI - page dialog pages + gui/pages/BasePage.h gui/pages/VersionPage.cpp gui/pages/VersionPage.h gui/pages/TexturePackPage.h @@ -305,6 +310,8 @@ SET(MULTIMC_SOURCES gui/pages/InstanceSettingsPage.h gui/pages/ScreenshotsPage.cpp gui/pages/ScreenshotsPage.h + gui/pages/OtherLogsPage.cpp + gui/pages/OtherLogsPage.h # GUI - dialogs gui/dialogs/AboutDialog.cpp @@ -512,6 +519,10 @@ SET(MULTIMC_SOURCES logic/minecraft/VersionPatch.h logic/minecraft/VersionSource.h + # A Recursive file system watcher + logic/RecursiveFileSystemWatcher.h + logic/RecursiveFileSystemWatcher.cpp + # Various base classes logic/BaseInstaller.h logic/BaseInstaller.cpp @@ -628,6 +639,7 @@ SET(MULTIMC_UIS gui/pages/InstanceSettingsPage.ui gui/pages/NotesPage.ui gui/pages/ScreenshotsPage.ui + gui/pages/OtherLogsPage.ui # Dialogs gui/dialogs/SettingsDialog.ui diff --git a/gui/GuiUtil.cpp b/gui/GuiUtil.cpp new file mode 100644 index 00000000..72c09ffe --- /dev/null +++ b/gui/GuiUtil.cpp @@ -0,0 +1,38 @@ +#include "GuiUtil.h" + +#include <QClipboard> +#include <QDesktopServices> +#include <QApplication> + +#include "dialogs/ProgressDialog.h" +#include "logic/net/PasteUpload.h" +#include "dialogs/CustomMessageBox.h" + +void GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget) +{ + ProgressDialog dialog(parentWidget); + PasteUpload *paste = new PasteUpload(parentWidget, text); + dialog.exec(paste); + if (!paste->successful()) + { + CustomMessageBox::selectable(parentWidget, "Upload failed", paste->failReason(), + QMessageBox::Critical)->exec(); + } + else + { + const QString link = paste->pasteLink(); + setClipboardText(link); + QDesktopServices::openUrl(link); + CustomMessageBox::selectable( + parentWidget, QObject::tr("Upload finished"), + QObject::tr("The <a href=\"%1\">link to the uploaded log</a> has been opened in the default " + "browser and placed in your clipboard.").arg(link), + QMessageBox::Information)->exec(); + } + delete paste; +} + +void GuiUtil::setClipboardText(const QString &text) +{ + QApplication::clipboard()->setText(text); +} diff --git a/gui/GuiUtil.h b/gui/GuiUtil.h new file mode 100644 index 00000000..9f872f75 --- /dev/null +++ b/gui/GuiUtil.h @@ -0,0 +1,9 @@ +#pragma once + +#include <QWidget> + +namespace GuiUtil +{ +void uploadPaste(const QString &text, QWidget *parentWidget); +void setClipboardText(const QString &text); +} diff --git a/gui/pages/BasePage.h b/gui/pages/BasePage.h index 09af3a59..26c0b9f7 100644 --- a/gui/pages/BasePage.h +++ b/gui/pages/BasePage.h @@ -21,25 +21,27 @@ class BasePage { public: - virtual ~BasePage(){}; - virtual QString id() = 0; - virtual QString displayName() = 0; - virtual QIcon icon() = 0; + virtual ~BasePage(){} + virtual QString id() const = 0; + virtual QString displayName() const = 0; + virtual QIcon icon() const = 0; virtual bool apply() { return true; } - virtual bool shouldDisplay() + virtual bool shouldDisplay() const { return true; } - virtual QString helpPage() + virtual QString helpPage() const { return QString(); } virtual void opened() { - + } + virtual void closed() + { } int stackIndex = -1; int listIndex = -1; diff --git a/gui/pages/InstanceSettingsPage.cpp b/gui/pages/InstanceSettingsPage.cpp index 6e2ce238..25fe46e5 100644 --- a/gui/pages/InstanceSettingsPage.cpp +++ b/gui/pages/InstanceSettingsPage.cpp @@ -8,17 +8,17 @@ #include <QMessageBox> #include "ui_InstanceSettingsPage.h" -QString InstanceSettingsPage::displayName() +QString InstanceSettingsPage::displayName() const { return tr("Settings"); } -QIcon InstanceSettingsPage::icon() +QIcon InstanceSettingsPage::icon() const { return QIcon::fromTheme("settings"); } -QString InstanceSettingsPage::id() +QString InstanceSettingsPage::id() const { return "settings"; } @@ -31,7 +31,7 @@ InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent) loadSettings(); } -bool InstanceSettingsPage::shouldDisplay() +bool InstanceSettingsPage::shouldDisplay() const { return !m_instance->isRunning(); } diff --git a/gui/pages/InstanceSettingsPage.h b/gui/pages/InstanceSettingsPage.h index 2447168f..7052040c 100644 --- a/gui/pages/InstanceSettingsPage.h +++ b/gui/pages/InstanceSettingsPage.h @@ -34,12 +34,12 @@ class InstanceSettingsPage : public QWidget, public BasePage public: explicit InstanceSettingsPage(BaseInstance *inst, QWidget *parent = 0); virtual ~InstanceSettingsPage(); - virtual QString displayName() override; - virtual QIcon icon() override; - virtual QString id() override; + virtual QString displayName() const override; + virtual QIcon icon() const override; + virtual QString id() const override; virtual bool apply(); - virtual QString helpPage() override { return "Instance-settings"; } - virtual bool shouldDisplay(); + virtual QString helpPage() const override { return "Instance-settings"; } + virtual bool shouldDisplay() const; private slots: void on_javaDetectBtn_clicked(); diff --git a/gui/pages/LegacyJarModPage.cpp b/gui/pages/LegacyJarModPage.cpp index b1c0d49a..8acb2d50 100644 --- a/gui/pages/LegacyJarModPage.cpp +++ b/gui/pages/LegacyJarModPage.cpp @@ -49,22 +49,22 @@ LegacyJarModPage::~LegacyJarModPage() delete ui; } -QString LegacyJarModPage::displayName() +QString LegacyJarModPage::displayName() const { return tr("Jar Mods"); } -bool LegacyJarModPage::shouldDisplay() +bool LegacyJarModPage::shouldDisplay() const { return !m_inst->isRunning(); } -QIcon LegacyJarModPage::icon() +QIcon LegacyJarModPage::icon() const { return QIcon::fromTheme("plugin-red"); } -QString LegacyJarModPage::id() +QString LegacyJarModPage::id() const { return "jarmods"; } diff --git a/gui/pages/LegacyJarModPage.h b/gui/pages/LegacyJarModPage.h index 016f4a8f..261d9020 100644 --- a/gui/pages/LegacyJarModPage.h +++ b/gui/pages/LegacyJarModPage.h @@ -34,11 +34,11 @@ public: explicit LegacyJarModPage(LegacyInstance *inst, QWidget *parent = 0); virtual ~LegacyJarModPage(); - virtual QString displayName(); - virtual QIcon icon(); - virtual QString id(); - virtual QString helpPage() override { return "Legacy-jar-mods"; }; - virtual bool shouldDisplay(); + virtual QString displayName() const; + virtual QIcon icon() const; + virtual QString id() const; + virtual QString helpPage() const override { return "Legacy-jar-mods"; } + virtual bool shouldDisplay() const; private slots: diff --git a/gui/pages/LegacyUpgradePage.cpp b/gui/pages/LegacyUpgradePage.cpp index bb54210c..bc800bc8 100644 --- a/gui/pages/LegacyUpgradePage.cpp +++ b/gui/pages/LegacyUpgradePage.cpp @@ -2,17 +2,17 @@ #include <logic/LegacyInstance.h> #include "ui_LegacyUpgradePage.h" -QString LegacyUpgradePage::displayName() +QString LegacyUpgradePage::displayName() const { return tr("Upgrade"); } -QIcon LegacyUpgradePage::icon() +QIcon LegacyUpgradePage::icon() const { return QIcon::fromTheme("checkupdate"); } -QString LegacyUpgradePage::id() +QString LegacyUpgradePage::id() const { return "upgrade"; } @@ -33,7 +33,7 @@ void LegacyUpgradePage::on_upgradeButton_clicked() // now what? } -bool LegacyUpgradePage::shouldDisplay() +bool LegacyUpgradePage::shouldDisplay() const { return !m_inst->isRunning(); -}
\ No newline at end of file +} diff --git a/gui/pages/LegacyUpgradePage.h b/gui/pages/LegacyUpgradePage.h index eb816a7a..c9eede72 100644 --- a/gui/pages/LegacyUpgradePage.h +++ b/gui/pages/LegacyUpgradePage.h @@ -33,11 +33,11 @@ class LegacyUpgradePage : public QWidget, public BasePage public: explicit LegacyUpgradePage(LegacyInstance *inst, QWidget *parent = 0); virtual ~LegacyUpgradePage(); - virtual QString displayName() override; - virtual QIcon icon() override; - virtual QString id() override; - virtual QString helpPage() override { return "Legacy-upgrade"; }; - virtual bool shouldDisplay(); + virtual QString displayName() const override; + virtual QIcon icon() const override; + virtual QString id() const override; + virtual QString helpPage() const override { return "Legacy-upgrade"; } + virtual bool shouldDisplay() const; private slots: void on_upgradeButton_clicked(); diff --git a/gui/pages/LogPage.cpp b/gui/pages/LogPage.cpp index 65b84b03..a7a0171f 100644 --- a/gui/pages/LogPage.cpp +++ b/gui/pages/LogPage.cpp @@ -1,25 +1,23 @@ #include "LogPage.h" -#include <gui/dialogs/CustomMessageBox.h> -#include <gui/dialogs/ProgressDialog.h> -#include <logic/MinecraftProcess.h> -#include <QtGui/QIcon> #include "ui_LogPage.h" -#include "logic/net/PasteUpload.h" + +#include <QIcon> #include <QScrollBar> -#include <QtGui/QClipboard> -#include <QtGui/QDesktopServices> -QString LogPage::displayName() +#include "logic/MinecraftProcess.h" +#include "gui/GuiUtil.h" + +QString LogPage::displayName() const { return tr("Minecraft Log"); } -QIcon LogPage::icon() +QIcon LogPage::icon() const { return QIcon::fromTheme("refresh"); } -QString LogPage::id() +QString LogPage::id() const { return "console"; } @@ -42,42 +40,19 @@ bool LogPage::apply() return true; } -bool LogPage::shouldDisplay() +bool LogPage::shouldDisplay() const { return m_process->instance()->isRunning(); } void LogPage::on_btnPaste_clicked() { - auto text = ui->text->toPlainText(); - ProgressDialog dialog(this); - PasteUpload *paste = new PasteUpload(this, text); - dialog.exec(paste); - if (!paste->successful()) - { - CustomMessageBox::selectable(this, "Upload failed", paste->failReason(), - QMessageBox::Critical)->exec(); - } - else - { - QString link = paste->pasteLink(); - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(link); - QDesktopServices::openUrl(link); - CustomMessageBox::selectable( - this, tr("Upload finished"), - tr("The <a href=\"%1\">link to the uploaded log</a> has been opened in the default browser and placed in your clipboard.") - .arg(link), - QMessageBox::Information)->exec(); - } - delete paste; + GuiUtil::uploadPaste(ui->text->toPlainText(), this); } void LogPage::on_btnCopy_clicked() { - auto text = ui->text->toPlainText(); - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(text); + GuiUtil::setClipboardText(ui->text->toPlainText()); } void LogPage::on_btnClear_clicked() diff --git a/gui/pages/LogPage.h b/gui/pages/LogPage.h index 933e518b..72ca09ec 100644 --- a/gui/pages/LogPage.h +++ b/gui/pages/LogPage.h @@ -36,12 +36,12 @@ class LogPage : public QWidget, public BasePage public: explicit LogPage(MinecraftProcess *proc, QWidget *parent = 0); virtual ~LogPage(); - virtual QString displayName() override; - virtual QIcon icon() override; - virtual QString id() override; + virtual QString displayName() const override; + virtual QIcon icon() const override; + virtual QString id() const override; virtual bool apply(); - virtual QString helpPage() override { return "Minecraft-Log"; }; - virtual bool shouldDisplay(); + virtual QString helpPage() const override { return "Minecraft-Log"; } + virtual bool shouldDisplay() const; private: /** diff --git a/gui/pages/ModFolderPage.cpp b/gui/pages/ModFolderPage.cpp index 7702dbdd..a01e215d 100644 --- a/gui/pages/ModFolderPage.cpp +++ b/gui/pages/ModFolderPage.cpp @@ -33,17 +33,17 @@ #include "logic/Mod.h" #include <logic/VersionFilterData.h> -QString ModFolderPage::displayName() +QString ModFolderPage::displayName() const { return m_displayName; } -QIcon ModFolderPage::icon() +QIcon ModFolderPage::icon() const { return QIcon::fromTheme(m_iconName); } -QString ModFolderPage::id() +QString ModFolderPage::id() const { return m_id; } @@ -80,14 +80,14 @@ ModFolderPage::~ModFolderPage() delete ui; } -bool ModFolderPage::shouldDisplay() +bool ModFolderPage::shouldDisplay() const { if(m_inst) return !m_inst->isRunning(); return true; } -bool CoreModFolderPage::shouldDisplay() +bool CoreModFolderPage::shouldDisplay() const { if (ModFolderPage::shouldDisplay()) { diff --git a/gui/pages/ModFolderPage.h b/gui/pages/ModFolderPage.h index 13ae97f5..2103ce26 100644 --- a/gui/pages/ModFolderPage.h +++ b/gui/pages/ModFolderPage.h @@ -32,19 +32,26 @@ class ModFolderPage : public QWidget, public BasePage Q_OBJECT public: - explicit ModFolderPage(BaseInstance * inst, std::shared_ptr<ModList> mods, QString id, QString iconName, - QString displayName, QString helpPage = "" , QWidget *parent = 0); + explicit ModFolderPage(BaseInstance *inst, std::shared_ptr<ModList> mods, QString id, + QString iconName, QString displayName, QString helpPage = "", + QWidget *parent = 0); virtual ~ModFolderPage(); - virtual QString displayName() override; - virtual QIcon icon() override; - virtual QString id() override; - virtual QString helpPage() override { return m_helpName; }; - virtual bool shouldDisplay(); + virtual QString displayName() const override; + virtual QIcon icon() const override; + virtual QString id() const override; + virtual QString helpPage() const override + { + return m_helpName; + } + virtual bool shouldDisplay() const; + protected: bool eventFilter(QObject *obj, QEvent *ev); bool modListFilter(QKeyEvent *ev); + protected: - BaseInstance * m_inst; + BaseInstance *m_inst; + private: Ui::ModFolderPage *ui; std::shared_ptr<ModList> m_mods; @@ -53,10 +60,12 @@ private: QString m_displayName; QString m_helpName; -public slots: +public +slots: void modCurrent(const QModelIndex ¤t, const QModelIndex &previous); -private slots: +private +slots: void on_addModBtn_clicked(); void on_rmModBtn_clicked(); void on_viewModBtn_clicked(); @@ -68,6 +77,8 @@ public: explicit CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModList> mods, QString id, QString iconName, QString displayName, QString helpPage = "", QWidget *parent = 0); - virtual ~CoreModFolderPage(){}; - virtual bool shouldDisplay(); + virtual ~CoreModFolderPage() + { + } + virtual bool shouldDisplay() const; }; diff --git a/gui/pages/NotesPage.cpp b/gui/pages/NotesPage.cpp index b4746a77..d99014ff 100644 --- a/gui/pages/NotesPage.cpp +++ b/gui/pages/NotesPage.cpp @@ -1,17 +1,17 @@ #include "NotesPage.h" #include "ui_NotesPage.h" -QString NotesPage::displayName() +QString NotesPage::displayName() const { return tr("Notes"); } -QIcon NotesPage::icon() +QIcon NotesPage::icon() const { return QIcon::fromTheme("news"); } -QString NotesPage::id() +QString NotesPage::id() const { return "notes"; } diff --git a/gui/pages/NotesPage.h b/gui/pages/NotesPage.h index fe916f21..ad0a7701 100644 --- a/gui/pages/NotesPage.h +++ b/gui/pages/NotesPage.h @@ -33,11 +33,11 @@ class NotesPage : public QWidget, public BasePage public: explicit NotesPage(BaseInstance *inst, QWidget *parent = 0); virtual ~NotesPage(); - virtual QString displayName() override; - virtual QIcon icon() override; - virtual QString id() override; + virtual QString displayName() const override; + virtual QIcon icon() const override; + virtual QString id() const override; virtual bool apply(); - virtual QString helpPage() override { return "Notes"; }; + virtual QString helpPage() const override { return "Notes"; } private: Ui::NotesPage *ui; diff --git a/gui/pages/OtherLogsPage.cpp b/gui/pages/OtherLogsPage.cpp new file mode 100644 index 00000000..3ea1f170 --- /dev/null +++ b/gui/pages/OtherLogsPage.cpp @@ -0,0 +1,122 @@ +#include "OtherLogsPage.h" +#include "ui_OtherLogsPage.h" + +#include <QFileDialog> +#include <QMessageBox> + +#include "gui/GuiUtil.h" +#include "logic/RecursiveFileSystemWatcher.h" +#include "logic/BaseInstance.h" + +OtherLogsPage::OtherLogsPage(BaseInstance *instance, QWidget *parent) : + QWidget(parent), + ui(new Ui::OtherLogsPage), + m_instance(instance), + m_watcher(new RecursiveFileSystemWatcher(this)) +{ + ui->setupUi(this); + connect(m_watcher, &RecursiveFileSystemWatcher::filesChanged, [this]() + { + ui->selectLogBox->clear(); + ui->selectLogBox->addItems(m_watcher->files()); + ui->selectLogBox->addItem(tr("&Other"), true); + if (m_currentFile.isNull()) + { + ui->selectLogBox->setCurrentIndex(-1); + } + else + { + const int index = ui->selectLogBox->findText(m_currentFile); + ui->selectLogBox->setCurrentIndex(-1); + } + }); +} + +OtherLogsPage::~OtherLogsPage() +{ + delete ui; +} + +void OtherLogsPage::opened() +{ + m_watcher->enable(); +} +void OtherLogsPage::closed() +{ + m_watcher->disable(); +} + +void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index) +{ + QString file; + if (index != -1) + { + if (ui->selectLogBox->itemData(index).isValid()) + { + file = QFileDialog::getOpenFileName(this, tr("Open log file"), m_instance->minecraftRoot(), tr("*.log;;*.txt;;*")); + } + else + { + file = ui->selectLogBox->itemText(index); + } + } + + if (file.isEmpty() || !QFile::exists(file)) + { + m_currentFile = QString(); + setControlsEnabled(false); + } + else + { + m_currentFile = file; + on_btnReload_clicked(); + setControlsEnabled(true); + } +} + +void OtherLogsPage::on_btnReload_clicked() +{ + QFile file(m_currentFile); + if (!file.open(QFile::ReadOnly)) + { + setControlsEnabled(false); + ui->btnReload->setEnabled(true); // allow reload + m_currentFile = QString(); + QMessageBox::critical(this, tr("Error"), tr("Unable to open %1 for reading: %2").arg(m_currentFile, file.errorString())); + } + else + { + ui->text->setPlainText(QString::fromUtf8(file.readAll())); + } +} + +void OtherLogsPage::on_btnPaste_clicked() +{ + GuiUtil::uploadPaste(ui->text->toPlainText(), this); +} +void OtherLogsPage::on_btnCopy_clicked() +{ + GuiUtil::setClipboardText(ui->text->toPlainText()); +} +void OtherLogsPage::on_btnDelete_clicked() +{ + if (QMessageBox::question(this, tr("Delete"), tr("Do you really want to delete %1?").arg(m_currentFile), QMessageBox::Yes, QMessageBox::No) + == QMessageBox::No) + { + return; + } + QFile file(m_currentFile); + if (!file.remove()) + { + QMessageBox::critical(this, tr("Error"), tr("Unable to delete %1: %2").arg(m_currentFile, file.errorString())); + } +} + +void OtherLogsPage::setControlsEnabled(const bool enabled) +{ + ui->btnReload->setEnabled(enabled); + ui->btnDelete->setEnabled(enabled); + ui->btnCopy->setEnabled(enabled); + ui->btnPaste->setEnabled(enabled); + ui->text->setEnabled(enabled); +} diff --git a/gui/pages/OtherLogsPage.h b/gui/pages/OtherLogsPage.h new file mode 100644 index 00000000..e89b3bce --- /dev/null +++ b/gui/pages/OtherLogsPage.h @@ -0,0 +1,45 @@ +#pragma once + +#include <QWidget> + +#include "BasePage.h" + +namespace Ui { +class OtherLogsPage; +} + +class RecursiveFileSystemWatcher; + +class BaseInstance; + +class OtherLogsPage : public QWidget, public BasePage +{ + Q_OBJECT + +public: + explicit OtherLogsPage(BaseInstance *instance, QWidget *parent = 0); + ~OtherLogsPage(); + + QString id() const override { return "logs"; } + QString displayName() const override { return tr("Other logs"); } + QIcon icon() const override { return QIcon(); } // TODO + QString helpPage() const override { return "Minecraft-Logs"; } + void opened() override; + void closed() override; + +private +slots: + void on_selectLogBox_currentIndexChanged(const int index); + void on_btnReload_clicked(); + void on_btnPaste_clicked(); + void on_btnCopy_clicked(); + void on_btnDelete_clicked(); + +private: + Ui::OtherLogsPage *ui; + BaseInstance *m_instance; + RecursiveFileSystemWatcher *m_watcher; + QString m_currentFile; + + void setControlsEnabled(const bool enabled); +}; diff --git a/gui/pages/OtherLogsPage.ui b/gui/pages/OtherLogsPage.ui new file mode 100644 index 00000000..471c7d72 --- /dev/null +++ b/gui/pages/OtherLogsPage.ui @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>OtherLogsPage</class> + <widget class="QWidget" name="OtherLogsPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>640</width> + <height>480</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QPlainTextEdit" name="text"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QComboBox" name="selectLogBox"/> + </item> + <item> + <widget class="QPushButton" name="btnReload"> + <property name="text"> + <string>Reload</string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnPaste"> + <property name="toolTip"> + <string>Upload the log to paste.ee - it will stay online for a month</string> + </property> + <property name="text"> + <string>Upload Log</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnCopy"> + <property name="toolTip"> + <string>Copy the whole log into the clipboard</string> + </property> + <property name="text"> + <string>&Copy Log</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnDelete"> + <property name="toolTip"> + <string>Clear the log</string> + </property> + <property name="text"> + <string>Delete</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/gui/pages/ResourcePackPage.h b/gui/pages/ResourcePackPage.h index 06367905..b3c5df46 100644 --- a/gui/pages/ResourcePackPage.h +++ b/gui/pages/ResourcePackPage.h @@ -10,8 +10,8 @@ public: { } - virtual ~ResourcePackPage() {}; - virtual bool shouldDisplay() override + virtual ~ResourcePackPage() {} + virtual bool shouldDisplay() const override { return !m_inst->traits().contains("no-texturepacks") && !m_inst->traits().contains("texturepacks"); diff --git a/gui/pages/ScreenshotsPage.cpp b/gui/pages/ScreenshotsPage.cpp index ff4f0099..415aa576 100644 --- a/gui/pages/ScreenshotsPage.cpp +++ b/gui/pages/ScreenshotsPage.cpp @@ -221,17 +221,17 @@ public: } }; -QString ScreenshotsPage::displayName() +QString ScreenshotsPage::displayName() const { return tr("Screenshots"); } -QIcon ScreenshotsPage::icon() +QIcon ScreenshotsPage::icon() const { return QIcon::fromTheme("screenshots"); } -QString ScreenshotsPage::id() +QString ScreenshotsPage::id() const { return "screenshots"; } diff --git a/gui/pages/ScreenshotsPage.h b/gui/pages/ScreenshotsPage.h index 78307f6a..8b6d1e4d 100644 --- a/gui/pages/ScreenshotsPage.h +++ b/gui/pages/ScreenshotsPage.h @@ -47,10 +47,10 @@ public: }; virtual bool eventFilter(QObject *, QEvent *); - virtual QString displayName() override; - virtual QIcon icon() override; - virtual QString id() override; - virtual QString helpPage() override { return "Screenshots-management"; }; + virtual QString displayName() const override; + virtual QIcon icon() const override; + virtual QString id() const override; + virtual QString helpPage() const override { return "Screenshots-management"; } private slots: void on_uploadBtn_clicked(); diff --git a/gui/pages/TexturePackPage.h b/gui/pages/TexturePackPage.h index 69a47204..7e663789 100644 --- a/gui/pages/TexturePackPage.h +++ b/gui/pages/TexturePackPage.h @@ -9,8 +9,8 @@ public: tr("Texture packs"), "Texture-packs", parent) { } - virtual ~TexturePackPage() {}; - virtual bool shouldDisplay() override + virtual ~TexturePackPage() {} + virtual bool shouldDisplay() const override { return m_inst->traits().contains("texturepacks"); } diff --git a/gui/pages/VersionPage.cpp b/gui/pages/VersionPage.cpp index ec83ef87..1ea6b262 100644 --- a/gui/pages/VersionPage.cpp +++ b/gui/pages/VersionPage.cpp @@ -50,22 +50,22 @@ #include <QString> #include <QUrl> -QString VersionPage::displayName() +QString VersionPage::displayName() const { return tr("Version"); } -QIcon VersionPage::icon() +QIcon VersionPage::icon() const { return MMC->icons()->getIcon(m_inst->iconKey()); } -QString VersionPage::id() +QString VersionPage::id() const { return "version"; } -bool VersionPage::shouldDisplay() +bool VersionPage::shouldDisplay() const { return !m_inst->isRunning(); } diff --git a/gui/pages/VersionPage.h b/gui/pages/VersionPage.h index dfbb6741..d80b2a2a 100644 --- a/gui/pages/VersionPage.h +++ b/gui/pages/VersionPage.h @@ -33,11 +33,11 @@ class VersionPage : public QWidget, public BasePage public: explicit VersionPage(OneSixInstance *inst, QWidget *parent = 0); virtual ~VersionPage(); - virtual QString displayName() override; - virtual QIcon icon() override; - virtual QString id() override; - virtual QString helpPage() override { return "Instance-version"; }; - virtual bool shouldDisplay(); + virtual QString displayName() const override; + virtual QIcon icon() const override; + virtual QString id() const override; + virtual QString helpPage() const override { return "Instance-version"; } + virtual bool shouldDisplay() const; private slots: diff --git a/gui/widgets/PageContainer.cpp b/gui/widgets/PageContainer.cpp index 928e15dd..d5df72ce 100644 --- a/gui/widgets/PageContainer.cpp +++ b/gui/widgets/PageContainer.cpp @@ -45,14 +45,16 @@ protected: const QString pattern = filterRegExp().pattern(); const auto model = static_cast<PageModel *>(sourceModel()); const auto page = model->pages().at(sourceRow); - if(!page->shouldDisplay()) + if (!page->shouldDisplay()) return false; // Regular contents check, then check page-filter. return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); } }; -PageContainer::PageContainer(BasePageProviderPtr pageProvider, QString defaultId, QWidget *parent) : QWidget(parent) +PageContainer::PageContainer(BasePageProviderPtr pageProvider, QString defaultId, + QWidget *parent) + : QWidget(parent) { createUI(); m_model = new PageModel(this); @@ -60,12 +62,12 @@ PageContainer::PageContainer(BasePageProviderPtr pageProvider, QString defaultId int firstIndex = -1; int counter = 0; auto pages = pageProvider->getPages(); - for(auto page: pages) + for (auto page : pages) { page->stackIndex = m_pageStack->addWidget(dynamic_cast<QWidget *>(page)); page->listIndex = counter; counter++; - if(firstIndex == -1) + if (firstIndex == -1) { firstIndex = page->stackIndex; } @@ -79,22 +81,22 @@ PageContainer::PageContainer(BasePageProviderPtr pageProvider, QString defaultId m_pageList->setSelectionMode(QAbstractItemView::SingleSelection); m_pageList->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); m_pageList->setModel(m_proxyModel); - connect(m_pageList->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), - this, SLOT(currentChanged(QModelIndex))); + connect(m_pageList->selectionModel(), SIGNAL(currentRowChanged(QModelIndex, QModelIndex)), + this, SLOT(currentChanged(QModelIndex))); m_pageStack->setStackingMode(QStackedLayout::StackOne); m_pageList->setFocus(); // now find what we want to have selected... auto page = m_model->findPageEntryById(defaultId); QModelIndex index; - if(page) + if (page) { index = m_proxyModel->mapFromSource(m_model->index(page->listIndex)); } else { - index = m_proxyModel->index(0,0); + index = m_proxyModel->index(0, 0); } - if(index.isValid()) + if (index.isValid()) m_pageList->setCurrentIndex(index); } @@ -104,7 +106,7 @@ void PageContainer::createUI() m_filter = new QLineEdit; m_pageList = new PageView; m_header = new QLabel(); - m_iconHeader = new IconLabel(this, QIcon(), QSize(24,24)); + m_iconHeader = new IconLabel(this, QIcon(), QSize(24, 24)); QFont headerLabelFont = m_header->font(); headerLabelFont.setBold(true); @@ -143,10 +145,13 @@ void PageContainer::addButtons(QLayout *buttons) m_layout->addLayout(buttons, 2, 0, 1, 2); } - void PageContainer::showPage(int row) { - if(row != -1) + if (m_currentPage) + { + m_currentPage->closed(); + } + if (row != -1) { m_currentPage = m_model->pages().at(row); } @@ -154,7 +159,7 @@ void PageContainer::showPage(int row) { m_currentPage = nullptr; } - if(m_currentPage) + if (m_currentPage) { m_pageStack->setCurrentIndex(m_currentPage->stackIndex); m_header->setText(m_currentPage->displayName()); @@ -171,10 +176,10 @@ void PageContainer::showPage(int row) void PageContainer::help() { - if(m_currentPage) + if (m_currentPage) { QString pageId = m_currentPage->helpPage(); - if(pageId.isEmpty()) + if (pageId.isEmpty()) return; QDesktopServices::openUrl(QUrl("https://github.com/MultiMC/MultiMC5/wiki/" + pageId)); } @@ -185,11 +190,11 @@ void PageContainer::currentChanged(const QModelIndex ¤t) showPage(current.isValid() ? m_proxyModel->mapToSource(current).row() : -1); } -bool PageContainer::requestClose(QCloseEvent * event) +bool PageContainer::requestClose(QCloseEvent *event) { - for(auto page: m_model->pages()) + for (auto page : m_model->pages()) { - if(!page->apply()) + if (!page->apply()) return false; } return true; diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp index 3eb817a5..82d4e480 100644 --- a/logic/OneSixInstance.cpp +++ b/logic/OneSixInstance.cpp @@ -31,12 +31,13 @@ #include "logic/MinecraftProcess.h" #include "gui/pagedialog/PageDialog.h" #include "gui/pages/VersionPage.h" -#include <gui/pages/ModFolderPage.h> -#include <gui/pages/ResourcePackPage.h> -#include <gui/pages/TexturePackPage.h> -#include <gui/pages/InstanceSettingsPage.h> -#include <gui/pages/NotesPage.h> -#include <gui/pages/ScreenshotsPage.h> +#include "gui/pages/ModFolderPage.h" +#include "gui/pages/ResourcePackPage.h" +#include "gui/pages/TexturePackPage.h" +#include "gui/pages/InstanceSettingsPage.h" +#include "gui/pages/NotesPage.h" +#include "gui/pages/ScreenshotsPage.h" +#include "gui/pages/OtherLogsPage.h" OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *settings, QObject *parent) @@ -72,6 +73,7 @@ QList<BasePage *> OneSixInstance::getPages() values.append(new NotesPage(this)); values.append(new ScreenshotsPage(this)); values.append(new InstanceSettingsPage(this)); + values.append(new OtherLogsPage(this)); return values; } diff --git a/logic/RecursiveFileSystemWatcher.cpp b/logic/RecursiveFileSystemWatcher.cpp new file mode 100644 index 00000000..5cfa7e4e --- /dev/null +++ b/logic/RecursiveFileSystemWatcher.cpp @@ -0,0 +1,97 @@ +#include "RecursiveFileSystemWatcher.h" + +#include <QRegularExpression> + +RecursiveFileSystemWatcher::RecursiveFileSystemWatcher(QObject *parent) + : QObject(parent), + m_watcher(new QFileSystemWatcher(this)) +{ + connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &RecursiveFileSystemWatcher::fileChange); + connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &RecursiveFileSystemWatcher::directoryChange); +} + +void RecursiveFileSystemWatcher::setRootDir(const QDir &root) +{ + bool wasEnabled = m_isEnabled; + disable(); + m_root = root; + setFiles(scanRecursive(m_root)); + if (wasEnabled) + { + enable(); + } +} +void RecursiveFileSystemWatcher::setWatchFiles(const bool watchFiles) +{ + bool wasEnabled = m_isEnabled; + disable(); + m_watchFiles = watchFiles; + if (wasEnabled) + { + enable(); + } +} + +void RecursiveFileSystemWatcher::enable() +{ + Q_ASSERT(m_root != QDir::root()); + addFilesToWatcherRecursive(m_root); + m_isEnabled = true; +} +void RecursiveFileSystemWatcher::disable() +{ + m_isEnabled = false; + m_watcher->removePaths(m_watcher->files()); + m_watcher->removePaths(m_watcher->directories()); +} + +void RecursiveFileSystemWatcher::setFiles(const QStringList &files) +{ + if (files != m_files) + { + m_files = files; + emit filesChanged(); + } +} + +void RecursiveFileSystemWatcher::addFilesToWatcherRecursive(const QDir &dir) +{ + m_watcher->addPath(dir.absolutePath()); + for (const QFileInfo &info : dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) + { + addFilesToWatcherRecursive(info.absoluteDir()); + } + if (m_watchFiles) + { + for (const QFileInfo &info : dir.entryInfoList(QDir::Files)) + { + m_watcher->addPath(info.absoluteFilePath()); + } + } +} +QStringList RecursiveFileSystemWatcher::scanRecursive(const QDir &dir) +{ + QStringList ret; + QRegularExpression exp(m_exp); + for (const QFileInfo &info : dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files)) + { + if (info.isFile() && exp.match(info.absoluteFilePath()).hasMatch()) + { + ret.append(info.absoluteFilePath()); + } + else if (info.isDir()) + { + ret.append(scanRecursive(info.absoluteDir())); + } + } + return ret; +} + +void RecursiveFileSystemWatcher::fileChange(const QString &path) +{ + emit fileChanged(path); +} +void RecursiveFileSystemWatcher::directoryChange(const QString &path) +{ + setFiles(scanRecursive(m_root)); +} diff --git a/logic/RecursiveFileSystemWatcher.h b/logic/RecursiveFileSystemWatcher.h new file mode 100644 index 00000000..54fc1d12 --- /dev/null +++ b/logic/RecursiveFileSystemWatcher.h @@ -0,0 +1,51 @@ +#pragma once + +#include <QFileSystemWatcher> +#include <QDir> + +class RecursiveFileSystemWatcher : public QObject +{ + Q_OBJECT +public: + RecursiveFileSystemWatcher(QObject *parent); + + void setRootDir(const QDir &root); + QDir rootDir() const { return m_root; } + + // WARNING: setting this to true may be bad for performance + void setWatchFiles(const bool watchFiles); + bool watchFiles() const { return m_watchFiles; } + + void setFileExpression(const QString &exp) { m_exp = exp; } + QString fileExpression() const { return m_exp; } + + QStringList files() const { return m_files; } + +signals: + void filesChanged(); + void fileChanged(const QString &path); + +public +slots: + void enable(); + void disable(); + +private: + QDir m_root; + bool m_watchFiles = false; + bool m_isEnabled = false; + QString m_exp; + + QFileSystemWatcher *m_watcher; + + QStringList m_files; + void setFiles(const QStringList &scanRecursive); + + void addFilesToWatcherRecursive(const QDir &dir); + QStringList scanRecursive(const QDir &dir); + +private +slots: + void fileChange(const QString &path); + void directoryChange(const QString &path); +}; |