From efa8e26a3f3f7ba5e536cd10e86303b4fe1baba0 Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sat, 15 Feb 2014 14:19:35 +0100 Subject: [PATCH 01/19] Profiler support. Currently JProfiler and JVisualVM are implemented. --- CMakeLists.txt | 8 +++ MultiMC.cpp | 25 ++++++- MultiMC.h | 8 +++ gui/MainWindow.cpp | 56 +++++++++++++--- gui/MainWindow.h | 8 ++- gui/MainWindow.ui | 12 +++- gui/dialogs/SettingsDialog.cpp | 85 ++++++++++++++++++++++++ gui/dialogs/SettingsDialog.h | 5 ++ gui/dialogs/SettingsDialog.ui | 112 +++++++++++++++++++++++++++++++- logic/OneSixInstance.cpp | 1 - logic/profiler/BaseProfiler.cpp | 19 ++++++ logic/profiler/BaseProfiler.h | 39 +++++++++++ logic/profiler/JProfiler.cpp | 56 ++++++++++++++++ logic/profiler/JProfiler.h | 21 ++++++ logic/profiler/JVisualVM.cpp | 46 +++++++++++++ logic/profiler/JVisualVM.h | 21 ++++++ 16 files changed, 505 insertions(+), 17 deletions(-) create mode 100644 logic/profiler/BaseProfiler.cpp create mode 100644 logic/profiler/BaseProfiler.h create mode 100644 logic/profiler/JProfiler.cpp create mode 100644 logic/profiler/JProfiler.h create mode 100644 logic/profiler/JVisualVM.cpp create mode 100644 logic/profiler/JVisualVM.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e7dea67..2dd5dde5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -498,6 +498,14 @@ logic/assets/AssetsMigrateTask.h logic/assets/AssetsMigrateTask.cpp logic/assets/AssetsUtils.h logic/assets/AssetsUtils.cpp + +# Profiling +logic/profiler/BaseProfiler.h +logic/profiler/BaseProfiler.cpp +logic/profiler/JProfiler.h +logic/profiler/JProfiler.cpp +logic/profiler/JVisualVM.h +logic/profiler/JVisualVM.cpp ) diff --git a/MultiMC.cpp b/MultiMC.cpp index 598a3a80..b17afdc6 100644 --- a/MultiMC.cpp +++ b/MultiMC.cpp @@ -31,6 +31,9 @@ #include "logic/updater/UpdateChecker.h" #include "logic/updater/NotificationChecker.h" +#include "logic/profiler/JProfiler.h" +#include "logic/profiler/JVisualVM.h" + #include "pathutils.h" #include "cmdutils.h" #include @@ -41,8 +44,9 @@ using namespace Util::Commandline; MultiMC::MultiMC(int &argc, char **argv, bool root_override) - : QApplication(argc, argv), m_version{VERSION_MAJOR, VERSION_MINOR, VERSION_HOTFIX, - VERSION_BUILD, MultiMCVersion::VERSION_TYPE, VERSION_CHANNEL, BUILD_PLATFORM} + : QApplication(argc, argv), + m_version{VERSION_MAJOR, VERSION_MINOR, VERSION_HOTFIX, VERSION_BUILD, + MultiMCVersion::VERSION_TYPE, VERSION_CHANNEL, BUILD_PLATFORM} { setOrganizationName("MultiMC"); setApplicationName("MultiMC5"); @@ -211,6 +215,15 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override) // init proxy settings updateProxySettings(); + m_profilers.insert("jprofiler", + std::shared_ptr(new JProfilerFactory())); + m_profilers.insert("jvisualvm", + std::shared_ptr(new JVisualVMFactory())); + for (auto profiler : m_profilers.values()) + { + profiler->registerSettings(m_settings.get()); + } + // launch instance, if that's what should be done // WARNING: disabled until further notice /* @@ -426,6 +439,9 @@ void MultiMC::initGlobalSettings() m_settings->registerSetting("ConsoleWindowGeometry", ""); m_settings->registerSetting("SettingsGeometry", ""); + + // Profilers + m_settings->registerSetting("CurrentProfiler"); } void MultiMC::initHttpMetaCache() @@ -554,6 +570,11 @@ std::shared_ptr MultiMC::javalist() return m_javalist; } +std::shared_ptr MultiMC::currentProfiler() +{ + return m_profilers.value(m_settings->get("CurrentProfiler").toString()); +} + void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags) { // if we are going to update on exit, save the params now diff --git a/MultiMC.h b/MultiMC.h index 638a442f..69bfb4a4 100644 --- a/MultiMC.h +++ b/MultiMC.h @@ -22,6 +22,7 @@ class UpdateChecker; class NotificationChecker; class NewsChecker; class StatusChecker; +class BaseProfilerFactory; #if defined(MMC) #undef MMC @@ -127,6 +128,12 @@ public: std::shared_ptr javalist(); + QMap> profilers() + { + return m_profilers; + } + std::shared_ptr currentProfiler(); + void installUpdates(const QString updateFilesDir, UpdateFlags flags = None); /*! @@ -198,6 +205,7 @@ private: std::shared_ptr m_forgelist; std::shared_ptr m_minecraftlist; std::shared_ptr m_javalist; + QMap> m_profilers; QsLogging::DestinationPtr m_fileDestination; QsLogging::DestinationPtr m_debugDestination; diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 29f7c8e8..ddeb9947 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include "osutils.h" #include "userutils.h" @@ -97,6 +98,9 @@ #include #include +#include "logic/profiler/BaseProfiler.h" +#include "logic/OneSixInstance.h" + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { MultiMCPlatform::fixWM_CLASS(this); @@ -1078,7 +1082,7 @@ void MainWindow::on_actionLaunchInstanceOffline_triggered() } } -void MainWindow::doLaunch(bool online) +void MainWindow::doLaunch(bool online, bool profile) { if (!m_selectedInstance) return; @@ -1194,11 +1198,11 @@ void MainWindow::doLaunch(bool online) // update first if the server actually responded if (session->auth_server_online) { - updateInstance(m_selectedInstance, session); + updateInstance(m_selectedInstance, session, profile); } else { - launchInstance(m_selectedInstance, session); + launchInstance(m_selectedInstance, session, profile); } tryagain = false; } @@ -1206,22 +1210,22 @@ void MainWindow::doLaunch(bool online) } } -void MainWindow::updateInstance(BaseInstance *instance, AuthSessionPtr session) +void MainWindow::updateInstance(BaseInstance *instance, AuthSessionPtr session, bool profile) { auto updateTask = instance->doUpdate(); if (!updateTask) { - launchInstance(instance, session); + launchInstance(instance, session, profile); return; } ProgressDialog tDialog(this); - connect(updateTask.get(), &Task::succeeded, [this, instance, session] - { launchInstance(instance, session); }); + connect(updateTask.get(), &Task::succeeded, [this, instance, session, profile] + { launchInstance(instance, session, profile); }); connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString))); tDialog.exec(updateTask.get()); } -void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session) +void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, bool profile) { Q_ASSERT_X(instance != NULL, "launchInstance", "instance is NULL"); Q_ASSERT_X(session.get() != nullptr, "launchInstance", "session is NULL"); @@ -1237,6 +1241,33 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session) proc->setLogin(session); proc->launch(); + + if (profile && qobject_cast(instance)) + { + BaseProfiler *profiler = MMC->currentProfiler()->createProfiler( + qobject_cast(instance), this); + QProgressDialog dialog; + dialog.setMinimum(0); + dialog.setMaximum(0); + dialog.setValue(0); + dialog.setLabelText(tr("Waiting for profiler...")); + dialog.show(); + connect(profiler, &BaseProfiler::readyToLaunch, [&dialog, this](const QString &message) + { + dialog.accept(); + QMessageBox msg; + msg.setText(tr("The launch of Minecraft itself is delayed until you press the " + "button. This is the right time to setup the profiler, as the " + "profiler server is running now.\n\n%1").arg(message)); + msg.setWindowTitle(tr("Waiting")); + msg.setIcon(QMessageBox::Information); + msg.addButton(tr("Launch"), QMessageBox::AcceptRole); + msg.exec(); + proc->write("launch onesix\n"); + }); + profiler->beginProfiling(proc); + dialog.exec(); + } } void MainWindow::onGameUpdateError(QString error) @@ -1416,6 +1447,15 @@ void MainWindow::on_actionEditInstNotes_triggered() } } +void MainWindow::on_actionProfileInstance_triggered() +{ + if (m_selectedInstance) + { + NagUtils::checkJVMArgs(m_selectedInstance->settings().get("JvmArgs").toString(), this); + doLaunch(true, true); + } +} + void MainWindow::instanceEnded() { this->show(); diff --git a/gui/MainWindow.h b/gui/MainWindow.h index 4d9e165d..66d98bc5 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -107,22 +107,24 @@ slots: void on_actionEditInstNotes_triggered(); + void on_actionProfileInstance_triggered(); + /*! * Launches the currently selected instance with the default account. * If no default account is selected, prompts the user to pick an account. */ - void doLaunch(bool online = true); + void doLaunch(bool online = true, bool profile = false); /*! * Launches the given instance with the given account. * This function assumes that the given account has a valid, usable access token. */ - void launchInstance(BaseInstance *instance, AuthSessionPtr session); + void launchInstance(BaseInstance *instance, AuthSessionPtr session, bool profile = false); /*! * Prepares the given instance for launch with the given account. */ - void updateInstance(BaseInstance *instance, AuthSessionPtr account); + void updateInstance(BaseInstance *instance, AuthSessionPtr account, bool profile = false); void onGameUpdateError(QString error); diff --git a/gui/MainWindow.ui b/gui/MainWindow.ui index 8cf26d18..81f66136 100644 --- a/gui/MainWindow.ui +++ b/gui/MainWindow.ui @@ -108,6 +108,7 @@ + @@ -528,12 +529,19 @@ Launch the selected instance. + + + Profile + + + Starts a profiling session with the current instance + + - - + diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp index ef363f02..3039acc1 100644 --- a/gui/dialogs/SettingsDialog.cpp +++ b/gui/dialogs/SettingsDialog.cpp @@ -29,6 +29,8 @@ #include "logic/updater/UpdateChecker.h" +#include "logic/profiler/BaseProfiler.h" + #include #include #include @@ -368,6 +370,22 @@ void SettingsDialog::applySettings(SettingsObject *s) } s->set("PostExitCommand", ui->postExitCmdTextBox->text()); + + // Profilers + s->set("JProfilerPath", ui->jprofilerPathEdit->text()); + s->set("JVisualVMPath", ui->jvisualvmPathEdit->text()); + if (ui->profilerNoneBtn->isChecked()) + { + s->set("CurrentProfiler", QString()); + } + else if (ui->jprofilerBtn->isChecked()) + { + s->set("CurrentProfiler", "jprofiler"); + } + else if (ui->jvisualvmBtn->isChecked()) + { + s->set("CurrentProfiler", "jvisualvm"); + } } void SettingsDialog::loadSettings(SettingsObject *s) @@ -447,6 +465,23 @@ void SettingsDialog::loadSettings(SettingsObject *s) // Custom Commands ui->preLaunchCmdTextBox->setText(s->get("PreLaunchCommand").toString()); ui->postExitCmdTextBox->setText(s->get("PostExitCommand").toString()); + + // Profilers + ui->jprofilerPathEdit->setText(s->get("JProfilerPath").toString()); + ui->jvisualvmPathEdit->setText(s->get("JVisualVMPath").toString()); + const QString currentProfiler = s->get("CurrentProfiler").toString(); + if (currentProfiler.isEmpty()) + { + ui->profilerNoneBtn->setChecked(true); + } + else if (currentProfiler == "jprofiler") + { + ui->jprofilerBtn->setChecked(true); + } + else if (currentProfiler == "jvisualvm") + { + ui->jvisualvmBtn->setChecked(true); + } } void SettingsDialog::on_javaDetectBtn_clicked() @@ -503,3 +538,53 @@ void SettingsDialog::checkFinished(JavaCheckResult result) "or set the path to the java executable.")); } } + +void SettingsDialog::on_jprofilerPathBtn_clicked() +{ + QString raw_dir = QFileDialog::getExistingDirectory(this, tr("JProfiler Directory"), + ui->jprofilerPathEdit->text()); + QString cooked_dir = NormalizePath(raw_dir); + + // do not allow current dir - it's dirty. Do not allow dirs that don't exist + if (!cooked_dir.isEmpty() && QDir(cooked_dir).exists()) + { + ui->jprofilerPathEdit->setText(cooked_dir); + } +} +void SettingsDialog::on_jprofilerCheckBtn_clicked() +{ + if (!ui->jprofilerPathEdit->text().isEmpty()) + { + QString error; + if (!MMC->profilers()["jprofiler"]->check(ui->jprofilerPathEdit->text(), &error)) + { + QMessageBox::critical(this, tr("Error"), + tr("Error while checking JProfiler install:\n%1").arg(error)); + } + } +} + +void SettingsDialog::on_jvisualvmPathBtn_clicked() +{ + QString raw_dir = QFileDialog::getOpenFileName(this, tr("JVisualVM Executable"), + ui->jvisualvmPathEdit->text()); + QString cooked_dir = NormalizePath(raw_dir); + + // do not allow current dir - it's dirty. Do not allow dirs that don't exist + if (!cooked_dir.isEmpty() && QDir(cooked_dir).exists()) + { + ui->jvisualvmPathEdit->setText(cooked_dir); + } +} +void SettingsDialog::on_jvisualvmCheckBtn_clicked() +{ + if (!ui->jvisualvmPathEdit->text().isEmpty()) + { + QString error; + if (!MMC->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error)) + { + QMessageBox::critical(this, tr("Error"), + tr("Error while checking JVisualVM install:\n%1").arg(error)); + } + } +} diff --git a/gui/dialogs/SettingsDialog.h b/gui/dialogs/SettingsDialog.h index d7bbbeb3..60d569f9 100644 --- a/gui/dialogs/SettingsDialog.h +++ b/gui/dialogs/SettingsDialog.h @@ -75,6 +75,11 @@ slots: void checkFinished(JavaCheckResult result); + void on_jprofilerPathBtn_clicked(); + void on_jprofilerCheckBtn_clicked(); + void on_jvisualvmPathBtn_clicked(); + void on_jvisualvmCheckBtn_clicked(); + /*! * Updates the list of update channels in the combo box. */ diff --git a/gui/dialogs/SettingsDialog.ui b/gui/dialogs/SettingsDialog.ui index 54e7db7a..29cbbcba 100644 --- a/gui/dialogs/SettingsDialog.ui +++ b/gui/dialogs/SettingsDialog.ui @@ -863,6 +863,116 @@ + + + Profiling + + + + + + Active profiler + + + + + + None + + + + + + + JProfiler + + + + + + + JVisualVM + + + + + + + + + + JProfiler + + + + + + + + + + + ... + + + + + + + + + Check + + + + + + + + + + JVisualVM + + + + + + + + + + + ... + + + + + + + + + Check + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + @@ -938,7 +1048,7 @@ - + diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp index ae172f21..d987b693 100644 --- a/logic/OneSixInstance.cpp +++ b/logic/OneSixInstance.cpp @@ -228,7 +228,6 @@ MinecraftProcess *OneSixInstance::prepareForLaunch(AuthSessionPtr session) launchScript += "ext " + finfo.absoluteFilePath() + "\n"; } launchScript += "natives " + natives_dir.absolutePath() + "\n"; - launchScript += "launch onesix\n"; // create the process and set its parameters MinecraftProcess *proc = new MinecraftProcess(this); diff --git a/logic/profiler/BaseProfiler.cpp b/logic/profiler/BaseProfiler.cpp new file mode 100644 index 00000000..788e9614 --- /dev/null +++ b/logic/profiler/BaseProfiler.cpp @@ -0,0 +1,19 @@ +#include "BaseProfiler.h" + +BaseProfiler::BaseProfiler(OneSixInstance *instance, QObject *parent) + : QObject(parent), m_instance(instance) +{ +} + +BaseProfiler::~BaseProfiler() +{ +} + +void BaseProfiler::beginProfiling(MinecraftProcess *process) +{ + beginProfilingImpl(process); +} + +BaseProfilerFactory::~BaseProfilerFactory() +{ +} diff --git a/logic/profiler/BaseProfiler.h b/logic/profiler/BaseProfiler.h new file mode 100644 index 00000000..2986c8e1 --- /dev/null +++ b/logic/profiler/BaseProfiler.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +class OneSixInstance; +class SettingsObject; +class MinecraftProcess; + +class BaseProfiler : public QObject +{ + Q_OBJECT +public: + explicit BaseProfiler(OneSixInstance *instance, QObject *parent = 0); + virtual ~BaseProfiler(); + +public +slots: + void beginProfiling(MinecraftProcess *process); + +protected: + OneSixInstance *m_instance; + + virtual void beginProfilingImpl(MinecraftProcess *process) = 0; + +signals: + void readyToLaunch(const QString &message); +}; + +class BaseProfilerFactory +{ +public: + virtual ~BaseProfilerFactory(); + + virtual void registerSettings(SettingsObject *settings) = 0; + + virtual BaseProfiler *createProfiler(OneSixInstance *instance, QObject *parent = 0) = 0; + + virtual bool check(const QString &path, QString *error) = 0; +}; diff --git a/logic/profiler/JProfiler.cpp b/logic/profiler/JProfiler.cpp new file mode 100644 index 00000000..b9cf19a0 --- /dev/null +++ b/logic/profiler/JProfiler.cpp @@ -0,0 +1,56 @@ +#include "JProfiler.h" + +#include +#include + +#include "settingsobject.h" +#include "logic/MinecraftProcess.h" +#include "logic/OneSixInstance.h" +#include "MultiMC.h" + +JProfiler::JProfiler(OneSixInstance *instance, QObject *parent) : BaseProfiler(instance, parent) +{ +} + +void JProfiler::beginProfilingImpl(MinecraftProcess *process) +{ + int port = MMC->settings()->get("JProfilerPort").toInt(); + QProcess *profiler = new QProcess(this); + profiler->setArguments(QStringList() << "-d" << QString::number(process->pid()) << "--gui" + << "-p" << QString::number(port)); + profiler->setProgram(QDir(MMC->settings()->get("JProfilerPath").toString()) + .absoluteFilePath("bin/jpenable")); + connect(profiler, &QProcess::started, [this, port]() + { emit readyToLaunch(tr("Listening on port: %1").arg(port)); }); + connect(profiler, SIGNAL(finished(int)), profiler, SLOT(deleteLater())); + profiler->start(); + QMessageBox::information(0, tr("JProfiler"), + tr("JProfiler started and listening on port %1").arg(port)); +} + +void JProfilerFactory::registerSettings(SettingsObject *settings) +{ + settings->registerSetting("JProfilerPath"); + settings->registerSetting("JProfilerPort", 42042); +} + +BaseProfiler *JProfilerFactory::createProfiler(OneSixInstance *instance, QObject *parent) +{ + return new JProfiler(instance, parent); +} + +bool JProfilerFactory::check(const QString &path, QString *error) +{ + QDir dir(path); + if (!dir.exists()) + { + *error = QObject::tr("Path does not exist"); + return false; + } + if (!dir.exists("bin") || !dir.exists("bin/jprofiler") || !dir.exists("bin/agent.jar")) + { + *error = QObject::tr("Invalid JProfiler install"); + return false; + } + return true; +} diff --git a/logic/profiler/JProfiler.h b/logic/profiler/JProfiler.h new file mode 100644 index 00000000..9fa3591a --- /dev/null +++ b/logic/profiler/JProfiler.h @@ -0,0 +1,21 @@ +#pragma once + +#include "BaseProfiler.h" + +class JProfiler : public BaseProfiler +{ + Q_OBJECT +public: + JProfiler(OneSixInstance *instance, QObject *parent = 0); + +protected: + void beginProfilingImpl(MinecraftProcess *process); +}; + +class JProfilerFactory : public BaseProfilerFactory +{ +public: + void registerSettings(SettingsObject *settings) override; + BaseProfiler *createProfiler(OneSixInstance *instance, QObject *parent = 0) override; + bool check(const QString &path, QString *error) override; +}; diff --git a/logic/profiler/JVisualVM.cpp b/logic/profiler/JVisualVM.cpp new file mode 100644 index 00000000..31cc51b1 --- /dev/null +++ b/logic/profiler/JVisualVM.cpp @@ -0,0 +1,46 @@ +#include "JVisualVM.h" + +#include +#include + +#include "settingsobject.h" +#include "logic/MinecraftProcess.h" +#include "logic/OneSixInstance.h" + +JVisualVM::JVisualVM(OneSixInstance *instance, QObject *parent) : BaseProfiler(instance, parent) +{ +} + +void JVisualVM::beginProfilingImpl(MinecraftProcess *process) +{ + QProcess *profiler = new QProcess(this); + profiler->setArguments(QStringList() << "--jdkhome" + << m_instance->settings().get("JavaPath").toString() + << "--openpid" << QString::number(process->pid())); + profiler->setProgram("jvisualvm"); + connect(profiler, &QProcess::started, [this]() + { emit readyToLaunch(tr("JVisualVM started")); }); + connect(profiler, SIGNAL(finished(int)), profiler, SLOT(deleteLater())); + profiler->start(); +} + +void JVisualVMFactory::registerSettings(SettingsObject *settings) +{ + settings->registerSetting("JVisualVMPath"); +} + +BaseProfiler *JVisualVMFactory::createProfiler(OneSixInstance *instance, QObject *parent) +{ + return new JVisualVM(instance, parent); +} + +bool JVisualVMFactory::check(const QString &path, QString *error) +{ + QString resolved = QStandardPaths::findExecutable(path); + if (resolved.isEmpty() && !QDir::isAbsolutePath(path)) + { + *error = QObject::tr("Invalid path to JVisualVM"); + return false; + } + return true; +} diff --git a/logic/profiler/JVisualVM.h b/logic/profiler/JVisualVM.h new file mode 100644 index 00000000..e72b75d9 --- /dev/null +++ b/logic/profiler/JVisualVM.h @@ -0,0 +1,21 @@ +#pragma once + +#include "BaseProfiler.h" + +class JVisualVM : public BaseProfiler +{ + Q_OBJECT +public: + JVisualVM(OneSixInstance *instance, QObject *parent = 0); + +protected: + void beginProfilingImpl(MinecraftProcess *process); +}; + +class JVisualVMFactory : public BaseProfilerFactory +{ +public: + void registerSettings(SettingsObject *settings) override; + BaseProfiler *createProfiler(OneSixInstance *instance, QObject *parent = 0) override; + bool check(const QString &path, QString *error) override; +}; From 6f6d912d07901efebf5f399ee94c458acdc1369b Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sat, 15 Feb 2014 15:20:12 +0100 Subject: [PATCH 02/19] Underp and fix some stuff. Works nicer now. --- logic/profiler/JProfiler.cpp | 2 -- logic/profiler/JVisualVM.cpp | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/logic/profiler/JProfiler.cpp b/logic/profiler/JProfiler.cpp index b9cf19a0..aa6a866a 100644 --- a/logic/profiler/JProfiler.cpp +++ b/logic/profiler/JProfiler.cpp @@ -24,8 +24,6 @@ void JProfiler::beginProfilingImpl(MinecraftProcess *process) { emit readyToLaunch(tr("Listening on port: %1").arg(port)); }); connect(profiler, SIGNAL(finished(int)), profiler, SLOT(deleteLater())); profiler->start(); - QMessageBox::information(0, tr("JProfiler"), - tr("JProfiler started and listening on port %1").arg(port)); } void JProfilerFactory::registerSettings(SettingsObject *settings) diff --git a/logic/profiler/JVisualVM.cpp b/logic/profiler/JVisualVM.cpp index 31cc51b1..ef46890a 100644 --- a/logic/profiler/JVisualVM.cpp +++ b/logic/profiler/JVisualVM.cpp @@ -14,9 +14,7 @@ JVisualVM::JVisualVM(OneSixInstance *instance, QObject *parent) : BaseProfiler(i void JVisualVM::beginProfilingImpl(MinecraftProcess *process) { QProcess *profiler = new QProcess(this); - profiler->setArguments(QStringList() << "--jdkhome" - << m_instance->settings().get("JavaPath").toString() - << "--openpid" << QString::number(process->pid())); + profiler->setArguments(QStringList() << "--openpid" << QString::number(process->pid())); profiler->setProgram("jvisualvm"); connect(profiler, &QProcess::started, [this]() { emit readyToLaunch(tr("JVisualVM started")); }); From c0e58fbfb213c05f0259dab9bf5b7aabd6f373cf Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sat, 15 Feb 2014 18:15:41 +0100 Subject: [PATCH 03/19] Try to be cross-platform --- logic/profiler/BaseProfiler.cpp | 11 +++++++++++ logic/profiler/BaseProfiler.h | 3 +++ logic/profiler/JProfiler.cpp | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/logic/profiler/BaseProfiler.cpp b/logic/profiler/BaseProfiler.cpp index 788e9614..7934f6b4 100644 --- a/logic/profiler/BaseProfiler.cpp +++ b/logic/profiler/BaseProfiler.cpp @@ -1,5 +1,7 @@ #include "BaseProfiler.h" +#include + BaseProfiler::BaseProfiler(OneSixInstance *instance, QObject *parent) : QObject(parent), m_instance(instance) { @@ -14,6 +16,15 @@ void BaseProfiler::beginProfiling(MinecraftProcess *process) beginProfilingImpl(process); } +qint64 BaseProfiler::pid(QProcess *process) +{ +#ifdef Q_OS_UNIX + return process->pid(); +#else + return (qint64)process->pid(); +#endif +} + BaseProfilerFactory::~BaseProfilerFactory() { } diff --git a/logic/profiler/BaseProfiler.h b/logic/profiler/BaseProfiler.h index 2986c8e1..e7bc4c2d 100644 --- a/logic/profiler/BaseProfiler.h +++ b/logic/profiler/BaseProfiler.h @@ -5,6 +5,7 @@ class OneSixInstance; class SettingsObject; class MinecraftProcess; +class QProcess; class BaseProfiler : public QObject { @@ -22,6 +23,8 @@ protected: virtual void beginProfilingImpl(MinecraftProcess *process) = 0; + qint64 pid(QProcess *process); + signals: void readyToLaunch(const QString &message); }; diff --git a/logic/profiler/JProfiler.cpp b/logic/profiler/JProfiler.cpp index aa6a866a..eddf46d9 100644 --- a/logic/profiler/JProfiler.cpp +++ b/logic/profiler/JProfiler.cpp @@ -16,7 +16,7 @@ void JProfiler::beginProfilingImpl(MinecraftProcess *process) { int port = MMC->settings()->get("JProfilerPort").toInt(); QProcess *profiler = new QProcess(this); - profiler->setArguments(QStringList() << "-d" << QString::number(process->pid()) << "--gui" + profiler->setArguments(QStringList() << "-d" << QString::number(pid(process)) << "--gui" << "-p" << QString::number(port)); profiler->setProgram(QDir(MMC->settings()->get("JProfilerPath").toString()) .absoluteFilePath("bin/jpenable")); From 3b236483dfe00f87c5f3b03220d78620f0f99f4d Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sat, 15 Feb 2014 19:07:01 +0100 Subject: [PATCH 04/19] Another attempt at fixing windows build --- logic/profiler/BaseProfiler.cpp | 10 +++++++--- logic/profiler/JVisualVM.cpp | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/logic/profiler/BaseProfiler.cpp b/logic/profiler/BaseProfiler.cpp index 7934f6b4..94891fc4 100644 --- a/logic/profiler/BaseProfiler.cpp +++ b/logic/profiler/BaseProfiler.cpp @@ -1,6 +1,9 @@ #include "BaseProfiler.h" #include +#ifdef Q_OS_WIN +#include +#endif BaseProfiler::BaseProfiler(OneSixInstance *instance, QObject *parent) : QObject(parent), m_instance(instance) @@ -18,10 +21,11 @@ void BaseProfiler::beginProfiling(MinecraftProcess *process) qint64 BaseProfiler::pid(QProcess *process) { -#ifdef Q_OS_UNIX - return process->pid(); +#ifdef Q_OS_WIN + struct _PROCESS_INFORMATION *procinfo = process->pid(); + return procinfo->dwProcessId; #else - return (qint64)process->pid(); + return process->pid(); #endif } diff --git a/logic/profiler/JVisualVM.cpp b/logic/profiler/JVisualVM.cpp index ef46890a..a1aa6951 100644 --- a/logic/profiler/JVisualVM.cpp +++ b/logic/profiler/JVisualVM.cpp @@ -14,7 +14,7 @@ JVisualVM::JVisualVM(OneSixInstance *instance, QObject *parent) : BaseProfiler(i void JVisualVM::beginProfilingImpl(MinecraftProcess *process) { QProcess *profiler = new QProcess(this); - profiler->setArguments(QStringList() << "--openpid" << QString::number(process->pid())); + profiler->setArguments(QStringList() << "--openpid" << QString::number(pid(process))); profiler->setProgram("jvisualvm"); connect(profiler, &QProcess::started, [this]() { emit readyToLaunch(tr("JVisualVM started")); }); From 8219dbf612f4e6f603d304348fc388e364602f98 Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sat, 15 Feb 2014 22:26:44 +0100 Subject: [PATCH 05/19] Underp. Don't depend on OneSix. Nicer "menu" style choosing. --- MultiMC.cpp | 8 --- MultiMC.h | 1 - depends/launcher/org/multimc/EntryPoint.java | 10 +++- gui/MainWindow.cpp | 62 ++++++++++++-------- gui/MainWindow.h | 9 ++- gui/MainWindow.ui | 9 --- gui/dialogs/SettingsDialog.cpp | 25 -------- gui/dialogs/SettingsDialog.ui | 38 +----------- logic/OneSixInstance.cpp | 1 + logic/profiler/BaseProfiler.cpp | 2 +- logic/profiler/BaseProfiler.h | 11 ++-- logic/profiler/JProfiler.cpp | 16 ++++- logic/profiler/JProfiler.h | 6 +- logic/profiler/JVisualVM.cpp | 17 +++++- logic/profiler/JVisualVM.h | 6 +- 15 files changed, 96 insertions(+), 125 deletions(-) diff --git a/MultiMC.cpp b/MultiMC.cpp index b17afdc6..e3f60049 100644 --- a/MultiMC.cpp +++ b/MultiMC.cpp @@ -439,9 +439,6 @@ void MultiMC::initGlobalSettings() m_settings->registerSetting("ConsoleWindowGeometry", ""); m_settings->registerSetting("SettingsGeometry", ""); - - // Profilers - m_settings->registerSetting("CurrentProfiler"); } void MultiMC::initHttpMetaCache() @@ -570,11 +567,6 @@ std::shared_ptr MultiMC::javalist() return m_javalist; } -std::shared_ptr MultiMC::currentProfiler() -{ - return m_profilers.value(m_settings->get("CurrentProfiler").toString()); -} - void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags) { // if we are going to update on exit, save the params now diff --git a/MultiMC.h b/MultiMC.h index 69bfb4a4..854de59b 100644 --- a/MultiMC.h +++ b/MultiMC.h @@ -132,7 +132,6 @@ public: { return m_profilers; } - std::shared_ptr currentProfiler(); void installUpdates(const QString updateFilesDir, UpdateFlags flags = None); diff --git a/depends/launcher/org/multimc/EntryPoint.java b/depends/launcher/org/multimc/EntryPoint.java index e2721ffa..9e4ea0c1 100644 --- a/depends/launcher/org/multimc/EntryPoint.java +++ b/depends/launcher/org/multimc/EntryPoint.java @@ -61,27 +61,31 @@ public class EntryPoint private Action parseLine(String inData) throws ParseException { String[] pair = inData.split(" ", 2); + + if(pair.length == 1 && pair[0].equals("launch")) + return Action.Launch; + if(pair.length != 2) throw new ParseException(); String command = pair[0]; String param = pair[1]; - if(command.equals("launch")) + if(command.equals("launcher")) { if(param.equals("legacy")) { m_launcher = new LegacyLauncher(); Utils.log("Using legacy launcher."); Utils.log(); - return Action.Launch; + return Action.Proceed; } if(param.equals("onesix")) { m_launcher = new OneSixLauncher(); Utils.log("Using onesix launcher."); Utils.log(); - return Action.Launch; + return Action.Proceed; } else throw new ParseException(); diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index ddeb9947..b4811579 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -99,7 +99,6 @@ #include #include "logic/profiler/BaseProfiler.h" -#include "logic/OneSixInstance.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { @@ -1082,7 +1081,7 @@ void MainWindow::on_actionLaunchInstanceOffline_triggered() } } -void MainWindow::doLaunch(bool online, bool profile) +void MainWindow::doLaunch(bool online, BaseProfilerFactory *profiler) { if (!m_selectedInstance) return; @@ -1198,11 +1197,11 @@ void MainWindow::doLaunch(bool online, bool profile) // update first if the server actually responded if (session->auth_server_online) { - updateInstance(m_selectedInstance, session, profile); + updateInstance(m_selectedInstance, session, profiler); } else { - launchInstance(m_selectedInstance, session, profile); + launchInstance(m_selectedInstance, session, profiler); } tryagain = false; } @@ -1210,22 +1209,22 @@ void MainWindow::doLaunch(bool online, bool profile) } } -void MainWindow::updateInstance(BaseInstance *instance, AuthSessionPtr session, bool profile) +void MainWindow::updateInstance(BaseInstance *instance, AuthSessionPtr session, BaseProfilerFactory *profiler) { auto updateTask = instance->doUpdate(); if (!updateTask) { - launchInstance(instance, session, profile); + launchInstance(instance, session, profiler); return; } ProgressDialog tDialog(this); - connect(updateTask.get(), &Task::succeeded, [this, instance, session, profile] - { launchInstance(instance, session, profile); }); + connect(updateTask.get(), &Task::succeeded, [this, instance, session, profiler] + { launchInstance(instance, session, profiler); }); connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString))); tDialog.exec(updateTask.get()); } -void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, bool profile) +void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, BaseProfilerFactory *profiler) { Q_ASSERT_X(instance != NULL, "launchInstance", "instance is NULL"); Q_ASSERT_X(session.get() != nullptr, "launchInstance", "session is NULL"); @@ -1242,17 +1241,22 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, proc->setLogin(session); proc->launch(); - if (profile && qobject_cast(instance)) + if (profiler) { - BaseProfiler *profiler = MMC->currentProfiler()->createProfiler( - qobject_cast(instance), this); + QString error; + if (!profiler->check(&error)) + { + QMessageBox::critical(this, tr("Error"), tr("Couldn't start profiler: %1").arg(error)); + return; + } + BaseProfiler *profilerInstance = profiler->createProfiler(instance, this); QProgressDialog dialog; dialog.setMinimum(0); dialog.setMaximum(0); dialog.setValue(0); dialog.setLabelText(tr("Waiting for profiler...")); dialog.show(); - connect(profiler, &BaseProfiler::readyToLaunch, [&dialog, this](const QString &message) + connect(profilerInstance, &BaseProfiler::readyToLaunch, [&dialog, this](const QString &message) { dialog.accept(); QMessageBox msg; @@ -1263,11 +1267,15 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, msg.setIcon(QMessageBox::Information); msg.addButton(tr("Launch"), QMessageBox::AcceptRole); msg.exec(); - proc->write("launch onesix\n"); + proc->write("launch\n"); }); - profiler->beginProfiling(proc); + profilerInstance->beginProfiling(proc); dialog.exec(); } + else + { + proc->write("launch\n"); + } } void MainWindow::onGameUpdateError(QString error) @@ -1408,6 +1416,21 @@ void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex & m_statusLeft->setText(m_selectedInstance->getStatusbarDescription()); updateInstanceToolIcon(m_selectedInstance->iconKey()); + if (ui->actionLaunchInstance->menu()) + { + ui->actionLaunchInstance->menu()->deleteLater(); + } + QMenu *launchMenu = new QMenu; + QAction *normalLaunch = launchMenu->addAction(tr("Launch")); + connect(normalLaunch, &QAction::triggered, [this](){doLaunch();}); + launchMenu->addSeparator()->setText(tr("Profilers")); + for (auto profiler : MMC->profilers().values()) + { + QAction *profilerAction = launchMenu->addAction(profiler->name()); + connect(profilerAction, &QAction::triggered, [this, profiler](){doLaunch(true, profiler.get());}); + } + ui->actionLaunchInstance->setMenu(launchMenu); + MMC->settings()->set("SelectedInstance", m_selectedInstance->id()); } else @@ -1447,15 +1470,6 @@ void MainWindow::on_actionEditInstNotes_triggered() } } -void MainWindow::on_actionProfileInstance_triggered() -{ - if (m_selectedInstance) - { - NagUtils::checkJVMArgs(m_selectedInstance->settings().get("JvmArgs").toString(), this); - doLaunch(true, true); - } -} - void MainWindow::instanceEnded() { this->show(); diff --git a/gui/MainWindow.h b/gui/MainWindow.h index 66d98bc5..682c711d 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -29,6 +29,7 @@ class LabeledToolButton; class QLabel; class MinecraftProcess; class ConsoleWindow; +class BaseProfilerFactory; namespace Ui { @@ -107,24 +108,22 @@ slots: void on_actionEditInstNotes_triggered(); - void on_actionProfileInstance_triggered(); - /*! * Launches the currently selected instance with the default account. * If no default account is selected, prompts the user to pick an account. */ - void doLaunch(bool online = true, bool profile = false); + void doLaunch(bool online = true, BaseProfilerFactory *profiler = 0); /*! * Launches the given instance with the given account. * This function assumes that the given account has a valid, usable access token. */ - void launchInstance(BaseInstance *instance, AuthSessionPtr session, bool profile = false); + void launchInstance(BaseInstance *instance, AuthSessionPtr session, BaseProfilerFactory *profiler = 0); /*! * Prepares the given instance for launch with the given account. */ - void updateInstance(BaseInstance *instance, AuthSessionPtr account, bool profile = false); + void updateInstance(BaseInstance *instance, AuthSessionPtr account, BaseProfilerFactory *profiler = 0); void onGameUpdateError(QString error); diff --git a/gui/MainWindow.ui b/gui/MainWindow.ui index 81f66136..90c86075 100644 --- a/gui/MainWindow.ui +++ b/gui/MainWindow.ui @@ -108,7 +108,6 @@ - @@ -529,14 +528,6 @@ Launch the selected instance. - - - Profile - - - Starts a profiling session with the current instance - - diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp index 3039acc1..ba2052c6 100644 --- a/gui/dialogs/SettingsDialog.cpp +++ b/gui/dialogs/SettingsDialog.cpp @@ -374,18 +374,6 @@ void SettingsDialog::applySettings(SettingsObject *s) // Profilers s->set("JProfilerPath", ui->jprofilerPathEdit->text()); s->set("JVisualVMPath", ui->jvisualvmPathEdit->text()); - if (ui->profilerNoneBtn->isChecked()) - { - s->set("CurrentProfiler", QString()); - } - else if (ui->jprofilerBtn->isChecked()) - { - s->set("CurrentProfiler", "jprofiler"); - } - else if (ui->jvisualvmBtn->isChecked()) - { - s->set("CurrentProfiler", "jvisualvm"); - } } void SettingsDialog::loadSettings(SettingsObject *s) @@ -469,19 +457,6 @@ void SettingsDialog::loadSettings(SettingsObject *s) // Profilers ui->jprofilerPathEdit->setText(s->get("JProfilerPath").toString()); ui->jvisualvmPathEdit->setText(s->get("JVisualVMPath").toString()); - const QString currentProfiler = s->get("CurrentProfiler").toString(); - if (currentProfiler.isEmpty()) - { - ui->profilerNoneBtn->setChecked(true); - } - else if (currentProfiler == "jprofiler") - { - ui->jprofilerBtn->setChecked(true); - } - else if (currentProfiler == "jvisualvm") - { - ui->jvisualvmBtn->setChecked(true); - } } void SettingsDialog::on_javaDetectBtn_clicked() diff --git a/gui/dialogs/SettingsDialog.ui b/gui/dialogs/SettingsDialog.ui index 29cbbcba..8d9a7f87 100644 --- a/gui/dialogs/SettingsDialog.ui +++ b/gui/dialogs/SettingsDialog.ui @@ -20,7 +20,7 @@ Settings - + :/icons/toolbar/settings:/icons/toolbar/settings @@ -33,7 +33,7 @@ QTabWidget::Rounded - 0 + 5 @@ -868,36 +868,6 @@ Profiling - - - - Active profiler - - - - - - None - - - - - - - JProfiler - - - - - - - JVisualVM - - - - - - @@ -1010,9 +980,7 @@ postExitCmdTextBox settingsTabs - - - + buttonBox diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp index d987b693..dbae891d 100644 --- a/logic/OneSixInstance.cpp +++ b/logic/OneSixInstance.cpp @@ -228,6 +228,7 @@ MinecraftProcess *OneSixInstance::prepareForLaunch(AuthSessionPtr session) launchScript += "ext " + finfo.absoluteFilePath() + "\n"; } launchScript += "natives " + natives_dir.absolutePath() + "\n"; + launchScript += "launcher onesix\n"; // create the process and set its parameters MinecraftProcess *proc = new MinecraftProcess(this); diff --git a/logic/profiler/BaseProfiler.cpp b/logic/profiler/BaseProfiler.cpp index 94891fc4..4765c67d 100644 --- a/logic/profiler/BaseProfiler.cpp +++ b/logic/profiler/BaseProfiler.cpp @@ -5,7 +5,7 @@ #include #endif -BaseProfiler::BaseProfiler(OneSixInstance *instance, QObject *parent) +BaseProfiler::BaseProfiler(BaseInstance *instance, QObject *parent) : QObject(parent), m_instance(instance) { } diff --git a/logic/profiler/BaseProfiler.h b/logic/profiler/BaseProfiler.h index e7bc4c2d..4c5f63fc 100644 --- a/logic/profiler/BaseProfiler.h +++ b/logic/profiler/BaseProfiler.h @@ -2,7 +2,7 @@ #include -class OneSixInstance; +class BaseInstance; class SettingsObject; class MinecraftProcess; class QProcess; @@ -11,7 +11,7 @@ class BaseProfiler : public QObject { Q_OBJECT public: - explicit BaseProfiler(OneSixInstance *instance, QObject *parent = 0); + explicit BaseProfiler(BaseInstance *instance, QObject *parent = 0); virtual ~BaseProfiler(); public @@ -19,7 +19,7 @@ slots: void beginProfiling(MinecraftProcess *process); protected: - OneSixInstance *m_instance; + BaseInstance *m_instance; virtual void beginProfilingImpl(MinecraftProcess *process) = 0; @@ -34,9 +34,12 @@ class BaseProfilerFactory public: virtual ~BaseProfilerFactory(); + virtual QString name() const = 0; + virtual void registerSettings(SettingsObject *settings) = 0; - virtual BaseProfiler *createProfiler(OneSixInstance *instance, QObject *parent = 0) = 0; + virtual BaseProfiler *createProfiler(BaseInstance *instance, QObject *parent = 0) = 0; + virtual bool check(QString *error) = 0; virtual bool check(const QString &path, QString *error) = 0; }; diff --git a/logic/profiler/JProfiler.cpp b/logic/profiler/JProfiler.cpp index eddf46d9..cec614ae 100644 --- a/logic/profiler/JProfiler.cpp +++ b/logic/profiler/JProfiler.cpp @@ -5,10 +5,10 @@ #include "settingsobject.h" #include "logic/MinecraftProcess.h" -#include "logic/OneSixInstance.h" +#include "logic/BaseInstance.h" #include "MultiMC.h" -JProfiler::JProfiler(OneSixInstance *instance, QObject *parent) : BaseProfiler(instance, parent) +JProfiler::JProfiler(BaseInstance *instance, QObject *parent) : BaseProfiler(instance, parent) { } @@ -32,13 +32,23 @@ void JProfilerFactory::registerSettings(SettingsObject *settings) settings->registerSetting("JProfilerPort", 42042); } -BaseProfiler *JProfilerFactory::createProfiler(OneSixInstance *instance, QObject *parent) +BaseProfiler *JProfilerFactory::createProfiler(BaseInstance *instance, QObject *parent) { return new JProfiler(instance, parent); } +bool JProfilerFactory::check(QString *error) +{ + return check(MMC->settings()->get("JProfilerPath").toString(), error); +} + bool JProfilerFactory::check(const QString &path, QString *error) { + if (path.isEmpty()) + { + *error = QObject::tr("Empty path"); + return false; + } QDir dir(path); if (!dir.exists()) { diff --git a/logic/profiler/JProfiler.h b/logic/profiler/JProfiler.h index 9fa3591a..8a5bc561 100644 --- a/logic/profiler/JProfiler.h +++ b/logic/profiler/JProfiler.h @@ -6,7 +6,7 @@ class JProfiler : public BaseProfiler { Q_OBJECT public: - JProfiler(OneSixInstance *instance, QObject *parent = 0); + JProfiler(BaseInstance *instance, QObject *parent = 0); protected: void beginProfilingImpl(MinecraftProcess *process); @@ -15,7 +15,9 @@ protected: class JProfilerFactory : public BaseProfilerFactory { public: + QString name() const override { return "JProfiler"; } void registerSettings(SettingsObject *settings) override; - BaseProfiler *createProfiler(OneSixInstance *instance, QObject *parent = 0) override; + BaseProfiler *createProfiler(BaseInstance *instance, QObject *parent = 0) override; + bool check(QString *error) override; bool check(const QString &path, QString *error) override; }; diff --git a/logic/profiler/JVisualVM.cpp b/logic/profiler/JVisualVM.cpp index a1aa6951..3850ff40 100644 --- a/logic/profiler/JVisualVM.cpp +++ b/logic/profiler/JVisualVM.cpp @@ -5,9 +5,10 @@ #include "settingsobject.h" #include "logic/MinecraftProcess.h" -#include "logic/OneSixInstance.h" +#include "logic/BaseInstance.h" +#include "MultiMC.h" -JVisualVM::JVisualVM(OneSixInstance *instance, QObject *parent) : BaseProfiler(instance, parent) +JVisualVM::JVisualVM(BaseInstance *instance, QObject *parent) : BaseProfiler(instance, parent) { } @@ -27,13 +28,23 @@ void JVisualVMFactory::registerSettings(SettingsObject *settings) settings->registerSetting("JVisualVMPath"); } -BaseProfiler *JVisualVMFactory::createProfiler(OneSixInstance *instance, QObject *parent) +BaseProfiler *JVisualVMFactory::createProfiler(BaseInstance *instance, QObject *parent) { return new JVisualVM(instance, parent); } +bool JVisualVMFactory::check(QString *error) +{ + return check(MMC->settings()->get("JVisualVMPath").toString(), error); +} + bool JVisualVMFactory::check(const QString &path, QString *error) { + if (path.isEmpty()) + { + *error = QObject::tr("Empty path"); + return false; + } QString resolved = QStandardPaths::findExecutable(path); if (resolved.isEmpty() && !QDir::isAbsolutePath(path)) { diff --git a/logic/profiler/JVisualVM.h b/logic/profiler/JVisualVM.h index e72b75d9..154180b4 100644 --- a/logic/profiler/JVisualVM.h +++ b/logic/profiler/JVisualVM.h @@ -6,7 +6,7 @@ class JVisualVM : public BaseProfiler { Q_OBJECT public: - JVisualVM(OneSixInstance *instance, QObject *parent = 0); + JVisualVM(BaseInstance *instance, QObject *parent = 0); protected: void beginProfilingImpl(MinecraftProcess *process); @@ -15,7 +15,9 @@ protected: class JVisualVMFactory : public BaseProfilerFactory { public: + QString name() const override { return "JVisualVM"; } void registerSettings(SettingsObject *settings) override; - BaseProfiler *createProfiler(OneSixInstance *instance, QObject *parent = 0) override; + BaseProfiler *createProfiler(BaseInstance *instance, QObject *parent = 0) override; + bool check(QString *error) override; bool check(const QString &path, QString *error) override; }; From 7ceb2cacb129d5924087f616cfc0b949689ed4fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 16 Feb 2014 00:10:45 +0100 Subject: [PATCH 06/19] Fix a few bugs in profilers. * Legacy was launching before the profiler. * Some clarity changes. * Report problem with empty strings as profiler paths. --- depends/launcher/org/multimc/EntryPoint.java | 30 +++++++++++++++++--- gui/MainWindow.cpp | 7 +++-- gui/dialogs/SettingsDialog.cpp | 30 +++++++++++--------- logic/LegacyInstance.cpp | 2 +- logic/MinecraftProcess.cpp | 16 ++++++++++- logic/MinecraftProcess.h | 12 +++++++- 6 files changed, 73 insertions(+), 24 deletions(-) diff --git a/depends/launcher/org/multimc/EntryPoint.java b/depends/launcher/org/multimc/EntryPoint.java index 9e4ea0c1..f9fe68d6 100644 --- a/depends/launcher/org/multimc/EntryPoint.java +++ b/depends/launcher/org/multimc/EntryPoint.java @@ -29,7 +29,8 @@ public class EntryPoint private enum Action { Proceed, - Launch + Launch, + Abort } public static void main(String[] args) @@ -62,8 +63,17 @@ public class EntryPoint { String[] pair = inData.split(" ", 2); - if(pair.length == 1 && pair[0].equals("launch")) - return Action.Launch; + if(pair.length == 1) + { + String command = pair[0]; + if (pair[0].equals("launch")) + return Action.Launch; + + else if (pair[0].equals("abort")) + return Action.Abort; + + else throw new ParseException(); + } if(pair.length != 2) throw new ParseException(); @@ -109,6 +119,7 @@ public class EntryPoint return 1; } boolean isListening = true; + boolean isAborted = false; // Main loop while (isListening) { @@ -119,7 +130,13 @@ public class EntryPoint inData = buffer.readLine(); if (inData != null) { - if(parseLine(inData) == Action.Launch) + Action a = parseLine(inData); + if(a == Action.Abort) + { + isListening = false; + isAborted = true; + } + if(a == Action.Launch) { isListening = false; } @@ -138,6 +155,11 @@ public class EntryPoint return 1; } } + if(isAborted) + { + System.err.println("Launch aborted by MultiMC."); + return 1; + } if(m_launcher != null) { return m_launcher.launch(m_params); diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index b4811579..7c61ca9d 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -1239,7 +1239,7 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, connect(console, SIGNAL(isClosing()), this, SLOT(instanceEnded())); proc->setLogin(session); - proc->launch(); + proc->arm(); if (profiler) { @@ -1247,6 +1247,7 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, if (!profiler->check(&error)) { QMessageBox::critical(this, tr("Error"), tr("Couldn't start profiler: %1").arg(error)); + proc->abort(); return; } BaseProfiler *profilerInstance = profiler->createProfiler(instance, this); @@ -1267,14 +1268,14 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, msg.setIcon(QMessageBox::Information); msg.addButton(tr("Launch"), QMessageBox::AcceptRole); msg.exec(); - proc->write("launch\n"); + proc->launch(); }); profilerInstance->beginProfiling(proc); dialog.exec(); } else { - proc->write("launch\n"); + proc->launch(); } } diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp index ba2052c6..7afb6565 100644 --- a/gui/dialogs/SettingsDialog.cpp +++ b/gui/dialogs/SettingsDialog.cpp @@ -528,14 +528,15 @@ void SettingsDialog::on_jprofilerPathBtn_clicked() } void SettingsDialog::on_jprofilerCheckBtn_clicked() { - if (!ui->jprofilerPathEdit->text().isEmpty()) + QString error; + if (!MMC->profilers()["jprofiler"]->check(ui->jprofilerPathEdit->text(), &error)) { - QString error; - if (!MMC->profilers()["jprofiler"]->check(ui->jprofilerPathEdit->text(), &error)) - { - QMessageBox::critical(this, tr("Error"), - tr("Error while checking JProfiler install:\n%1").arg(error)); - } + QMessageBox::critical(this, tr("Error"), + tr("Error while checking JProfiler install:\n%1").arg(error)); + } + else + { + QMessageBox::information(this, tr("OK"), tr("JProfiler setup seems to be OK")); } } @@ -553,13 +554,14 @@ void SettingsDialog::on_jvisualvmPathBtn_clicked() } void SettingsDialog::on_jvisualvmCheckBtn_clicked() { - if (!ui->jvisualvmPathEdit->text().isEmpty()) + QString error; + if (!MMC->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error)) { - QString error; - if (!MMC->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error)) - { - QMessageBox::critical(this, tr("Error"), - tr("Error while checking JVisualVM install:\n%1").arg(error)); - } + QMessageBox::critical(this, tr("Error"), + tr("Error while checking JVisualVM install:\n%1").arg(error)); + } + else + { + QMessageBox::information(this, tr("OK"), tr("JVisualVM setup seems to be OK")); } } diff --git a/logic/LegacyInstance.cpp b/logic/LegacyInstance.cpp index a9f0d112..6cd17fea 100644 --- a/logic/LegacyInstance.cpp +++ b/logic/LegacyInstance.cpp @@ -77,7 +77,7 @@ MinecraftProcess *LegacyInstance::prepareForLaunch(AuthSessionPtr account) launchScript += "windowTitle " + windowTitle() + "\n"; launchScript += "windowParams " + windowParams + "\n"; launchScript += "lwjgl " + lwjgl + "\n"; - launchScript += "launch legacy\n"; + launchScript += "launcher legacy\n"; } proc->setLaunchScript(launchScript); diff --git a/logic/MinecraftProcess.cpp b/logic/MinecraftProcess.cpp index 70a9d55f..89cd71ed 100644 --- a/logic/MinecraftProcess.cpp +++ b/logic/MinecraftProcess.cpp @@ -288,7 +288,7 @@ void MinecraftProcess::killMinecraft() kill(); } -void MinecraftProcess::launch() +void MinecraftProcess::arm() { emit log("MultiMC version: " + MMC->version().toString() + "\n\n"); emit log("Minecraft folder is:\n" + workingDirectory() + "\n\n"); @@ -374,3 +374,17 @@ void MinecraftProcess::launch() QByteArray bytes = launchScript.toUtf8(); writeData(bytes.constData(), bytes.length()); } + +void MinecraftProcess::launch() +{ + QString launchString("launch\n"); + QByteArray bytes = launchString.toUtf8(); + writeData(bytes.constData(), bytes.length()); +} + +void MinecraftProcess::abort() +{ + QString launchString("abort\n"); + QByteArray bytes = launchString.toUtf8(); + writeData(bytes.constData(), bytes.length()); +} diff --git a/logic/MinecraftProcess.h b/logic/MinecraftProcess.h index 26214026..56340962 100644 --- a/logic/MinecraftProcess.h +++ b/logic/MinecraftProcess.h @@ -55,10 +55,20 @@ public: MinecraftProcess(BaseInstance *inst); /** - * @brief launch minecraft + * @brief start the launcher part with the provided launch script + */ + void arm(); + + /** + * @brief launch the armed instance! */ void launch(); + /** + * @brief abort launch! + */ + void abort(); + BaseInstance *instance() { return m_instance; From 82b35b5445d88d67c89c6547b24053d31dc35b9c Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sun, 16 Feb 2014 08:54:52 +0100 Subject: [PATCH 07/19] Fix stuff. Make sure different ways of aborting profiling work. --- gui/MainWindow.cpp | 12 ++++++++++++ gui/dialogs/SettingsDialog.ui | 8 +++++--- logic/profiler/BaseProfiler.cpp | 15 +++++++++++++++ logic/profiler/BaseProfiler.h | 4 ++++ logic/profiler/JProfiler.cpp | 11 ++++++++++- logic/profiler/JVisualVM.cpp | 12 +++++++++++- 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 7c61ca9d..b28e753f 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -1256,6 +1256,7 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, dialog.setMaximum(0); dialog.setValue(0); dialog.setLabelText(tr("Waiting for profiler...")); + connect(&dialog, &QDialog::rejected, profilerInstance, &BaseProfiler::abortProfiling); dialog.show(); connect(profilerInstance, &BaseProfiler::readyToLaunch, [&dialog, this](const QString &message) { @@ -1270,6 +1271,17 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, msg.exec(); proc->launch(); }); + connect(profilerInstance, &BaseProfiler::abortLaunch, [&dialog, this](const QString &message) + { + dialog.accept(); + QMessageBox msg; + msg.setText(tr("Couldn't start the profiler: %1").arg(message)); + msg.setWindowTitle(tr("Error")); + msg.setIcon(QMessageBox::Critical); + msg.addButton(QMessageBox::Ok); + msg.exec(); + proc->abort(); + }); profilerInstance->beginProfiling(proc); dialog.exec(); } diff --git a/gui/dialogs/SettingsDialog.ui b/gui/dialogs/SettingsDialog.ui index 8d9a7f87..acf360a3 100644 --- a/gui/dialogs/SettingsDialog.ui +++ b/gui/dialogs/SettingsDialog.ui @@ -20,7 +20,7 @@ Settings - + :/icons/toolbar/settings:/icons/toolbar/settings @@ -33,7 +33,7 @@ QTabWidget::Rounded - 5 + 0 @@ -980,7 +980,9 @@ postExitCmdTextBox settingsTabs - + + + buttonBox diff --git a/logic/profiler/BaseProfiler.cpp b/logic/profiler/BaseProfiler.cpp index 4765c67d..1a377818 100644 --- a/logic/profiler/BaseProfiler.cpp +++ b/logic/profiler/BaseProfiler.cpp @@ -19,6 +19,21 @@ void BaseProfiler::beginProfiling(MinecraftProcess *process) beginProfilingImpl(process); } +void BaseProfiler::abortProfiling() +{ + abortProfiling(); +} + +void BaseProfiler::abortProfilingImpl() +{ + if (!m_profilerProcess) + { + return; + } + m_profilerProcess->terminate(); + m_profilerProcess->deleteLater(); +} + qint64 BaseProfiler::pid(QProcess *process) { #ifdef Q_OS_WIN diff --git a/logic/profiler/BaseProfiler.h b/logic/profiler/BaseProfiler.h index 4c5f63fc..e0d1d5f6 100644 --- a/logic/profiler/BaseProfiler.h +++ b/logic/profiler/BaseProfiler.h @@ -17,16 +17,20 @@ public: public slots: void beginProfiling(MinecraftProcess *process); + void abortProfiling(); protected: BaseInstance *m_instance; + QProcess *m_profilerProcess; virtual void beginProfilingImpl(MinecraftProcess *process) = 0; + virtual void abortProfilingImpl(); qint64 pid(QProcess *process); signals: void readyToLaunch(const QString &message); + void abortLaunch(const QString &message); }; class BaseProfilerFactory diff --git a/logic/profiler/JProfiler.cpp b/logic/profiler/JProfiler.cpp index cec614ae..34f927ce 100644 --- a/logic/profiler/JProfiler.cpp +++ b/logic/profiler/JProfiler.cpp @@ -22,7 +22,16 @@ void JProfiler::beginProfilingImpl(MinecraftProcess *process) .absoluteFilePath("bin/jpenable")); connect(profiler, &QProcess::started, [this, port]() { emit readyToLaunch(tr("Listening on port: %1").arg(port)); }); - connect(profiler, SIGNAL(finished(int)), profiler, SLOT(deleteLater())); + connect(profiler, + static_cast(&QProcess::finished), + [this](int exit, QProcess::ExitStatus status) + { + if (exit != 0 || status == QProcess::CrashExit) + { + emit abortLaunch(tr("Profiler aborted")); + } + m_profilerProcess->deleteLater(); + }); profiler->start(); } diff --git a/logic/profiler/JVisualVM.cpp b/logic/profiler/JVisualVM.cpp index 3850ff40..89098f73 100644 --- a/logic/profiler/JVisualVM.cpp +++ b/logic/profiler/JVisualVM.cpp @@ -19,8 +19,18 @@ void JVisualVM::beginProfilingImpl(MinecraftProcess *process) profiler->setProgram("jvisualvm"); connect(profiler, &QProcess::started, [this]() { emit readyToLaunch(tr("JVisualVM started")); }); - connect(profiler, SIGNAL(finished(int)), profiler, SLOT(deleteLater())); + connect(profiler, + static_cast(&QProcess::finished), + [this](int exit, QProcess::ExitStatus status) + { + if (exit != 0 || status == QProcess::CrashExit) + { + emit abortLaunch(tr("Profiler aborted")); + } + m_profilerProcess->deleteLater(); + }); profiler->start(); + m_profilerProcess = profiler; } void JVisualVMFactory::registerSettings(SettingsObject *settings) From 994972bf5da5584186e6e82c36287afeb6c1e23a Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sun, 16 Feb 2014 09:30:38 +0100 Subject: [PATCH 08/19] More fixes. --- gui/MainWindow.cpp | 2 +- logic/profiler/BaseProfiler.cpp | 4 +++- logic/profiler/JProfiler.cpp | 9 +++++++-- logic/profiler/JVisualVM.cpp | 8 ++++++-- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index b28e753f..b05c58f7 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -1256,7 +1256,7 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, dialog.setMaximum(0); dialog.setValue(0); dialog.setLabelText(tr("Waiting for profiler...")); - connect(&dialog, &QDialog::rejected, profilerInstance, &BaseProfiler::abortProfiling); + connect(&dialog, &QProgressDialog::canceled, profilerInstance, &BaseProfiler::abortProfiling); dialog.show(); connect(profilerInstance, &BaseProfiler::readyToLaunch, [&dialog, this](const QString &message) { diff --git a/logic/profiler/BaseProfiler.cpp b/logic/profiler/BaseProfiler.cpp index 1a377818..b58e88be 100644 --- a/logic/profiler/BaseProfiler.cpp +++ b/logic/profiler/BaseProfiler.cpp @@ -21,7 +21,7 @@ void BaseProfiler::beginProfiling(MinecraftProcess *process) void BaseProfiler::abortProfiling() { - abortProfiling(); + abortProfilingImpl(); } void BaseProfiler::abortProfilingImpl() @@ -32,6 +32,8 @@ void BaseProfiler::abortProfilingImpl() } m_profilerProcess->terminate(); m_profilerProcess->deleteLater(); + m_profilerProcess = 0; + emit abortLaunch(tr("Profiler aborted")); } qint64 BaseProfiler::pid(QProcess *process) diff --git a/logic/profiler/JProfiler.cpp b/logic/profiler/JProfiler.cpp index 34f927ce..1cd8d128 100644 --- a/logic/profiler/JProfiler.cpp +++ b/logic/profiler/JProfiler.cpp @@ -26,13 +26,18 @@ void JProfiler::beginProfilingImpl(MinecraftProcess *process) static_cast(&QProcess::finished), [this](int exit, QProcess::ExitStatus status) { - if (exit != 0 || status == QProcess::CrashExit) + if (status == QProcess::CrashExit) { emit abortLaunch(tr("Profiler aborted")); } - m_profilerProcess->deleteLater(); + if (m_profilerProcess) + { + m_profilerProcess->deleteLater(); + m_profilerProcess = 0; + } }); profiler->start(); + m_profilerProcess = profiler; } void JProfilerFactory::registerSettings(SettingsObject *settings) diff --git a/logic/profiler/JVisualVM.cpp b/logic/profiler/JVisualVM.cpp index 89098f73..c4bc851b 100644 --- a/logic/profiler/JVisualVM.cpp +++ b/logic/profiler/JVisualVM.cpp @@ -16,7 +16,7 @@ void JVisualVM::beginProfilingImpl(MinecraftProcess *process) { QProcess *profiler = new QProcess(this); profiler->setArguments(QStringList() << "--openpid" << QString::number(pid(process))); - profiler->setProgram("jvisualvm"); + profiler->setProgram(MMC->settings()->get("JVisualVMPath").toString()); connect(profiler, &QProcess::started, [this]() { emit readyToLaunch(tr("JVisualVM started")); }); connect(profiler, @@ -27,7 +27,11 @@ void JVisualVM::beginProfilingImpl(MinecraftProcess *process) { emit abortLaunch(tr("Profiler aborted")); } - m_profilerProcess->deleteLater(); + if (m_profilerProcess) + { + m_profilerProcess->deleteLater(); + m_profilerProcess = 0; + } }); profiler->start(); m_profilerProcess = profiler; From 616c37269053bc4f111792dbb9374cc119a58339 Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sun, 16 Feb 2014 10:46:14 +0100 Subject: [PATCH 09/19] Fix more stuff. Detached tools, only MCEdit for now. --- CMakeLists.txt | 6 +++- MultiMC.cpp | 7 ++++ MultiMC.h | 6 ++++ gui/MainWindow.cpp | 29 ++++++++++++++- gui/dialogs/SettingsDialog.cpp | 28 +++++++++++++++ gui/dialogs/SettingsDialog.h | 2 ++ gui/dialogs/SettingsDialog.ui | 34 ++++++++++++++++-- logic/BaseExternalTool.cpp | 47 +++++++++++++++++++++++++ logic/BaseExternalTool.h | 56 +++++++++++++++++++++++++++++ logic/MCEditTool.cpp | 62 +++++++++++++++++++++++++++++++++ logic/MCEditTool.h | 23 ++++++++++++ logic/profiler/BaseProfiler.cpp | 22 ++---------- logic/profiler/BaseProfiler.h | 21 +++-------- logic/profiler/JProfiler.cpp | 2 +- logic/profiler/JProfiler.h | 2 +- logic/profiler/JVisualVM.cpp | 2 +- logic/profiler/JVisualVM.h | 2 +- 17 files changed, 307 insertions(+), 44 deletions(-) create mode 100644 logic/BaseExternalTool.cpp create mode 100644 logic/BaseExternalTool.h create mode 100644 logic/MCEditTool.cpp create mode 100644 logic/MCEditTool.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dd5dde5..58d01eb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -499,7 +499,11 @@ logic/assets/AssetsMigrateTask.cpp logic/assets/AssetsUtils.h logic/assets/AssetsUtils.cpp -# Profiling +# Profiling and tools +logic/BaseExternalTool.h +logic/BaseExternalTool.cpp +logic/MCEditTool.h +logic/MCEditTool.cpp logic/profiler/BaseProfiler.h logic/profiler/BaseProfiler.cpp logic/profiler/JProfiler.h diff --git a/MultiMC.cpp b/MultiMC.cpp index e3f60049..c813c425 100644 --- a/MultiMC.cpp +++ b/MultiMC.cpp @@ -33,6 +33,7 @@ #include "logic/profiler/JProfiler.h" #include "logic/profiler/JVisualVM.h" +#include "logic/MCEditTool.h" #include "pathutils.h" #include "cmdutils.h" @@ -223,6 +224,12 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override) { profiler->registerSettings(m_settings.get()); } + m_tools.insert("mcedit", + std::shared_ptr(new MCEditFactory())); + for (auto tool : m_tools.values()) + { + tool->registerSettings(m_settings.get()); + } // launch instance, if that's what should be done // WARNING: disabled until further notice diff --git a/MultiMC.h b/MultiMC.h index 854de59b..753ab3b4 100644 --- a/MultiMC.h +++ b/MultiMC.h @@ -23,6 +23,7 @@ class NotificationChecker; class NewsChecker; class StatusChecker; class BaseProfilerFactory; +class BaseDetachedToolFactory; #if defined(MMC) #undef MMC @@ -132,6 +133,10 @@ public: { return m_profilers; } + QMap> tools() + { + return m_tools; + } void installUpdates(const QString updateFilesDir, UpdateFlags flags = None); @@ -205,6 +210,7 @@ private: std::shared_ptr m_minecraftlist; std::shared_ptr m_javalist; QMap> m_profilers; + QMap> m_tools; QsLogging::DestinationPtr m_fileDestination; QsLogging::DestinationPtr m_debugDestination; diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index b05c58f7..3f469061 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -1440,7 +1440,34 @@ void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex & for (auto profiler : MMC->profilers().values()) { QAction *profilerAction = launchMenu->addAction(profiler->name()); - connect(profilerAction, &QAction::triggered, [this, profiler](){doLaunch(true, profiler.get());}); + QString error; + if (!profiler->check(&error)) + { + profilerAction->setDisabled(true); + profilerAction->setToolTip(tr("Profiler not setup correctly. Go into settings, \"External Tools\".")); + } + else + { + connect(profilerAction, &QAction::triggered, [this, profiler](){doLaunch(true, profiler.get());}); + } + } + launchMenu->addSeparator()->setText(tr("Tools")); + for (auto tool : MMC->tools().values()) + { + QAction *toolAction = launchMenu->addAction(tool->name()); + QString error; + if (!tool->check(&error)) + { + toolAction->setDisabled(true); + toolAction->setToolTip(tr("Tool not setup correctly. Go into settings, \"External Tools\".")); + } + else + { + connect(toolAction, &QAction::triggered, [this, tool]() + { + tool->createDetachedTool(m_selectedInstance, this)->run(); + }); + } } ui->actionLaunchInstance->setMenu(launchMenu); diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp index 7afb6565..9423d7eb 100644 --- a/gui/dialogs/SettingsDialog.cpp +++ b/gui/dialogs/SettingsDialog.cpp @@ -374,6 +374,7 @@ void SettingsDialog::applySettings(SettingsObject *s) // Profilers s->set("JProfilerPath", ui->jprofilerPathEdit->text()); s->set("JVisualVMPath", ui->jvisualvmPathEdit->text()); + s->set("MCEditPath", ui->mceditPathEdit->text()); } void SettingsDialog::loadSettings(SettingsObject *s) @@ -457,6 +458,7 @@ void SettingsDialog::loadSettings(SettingsObject *s) // Profilers ui->jprofilerPathEdit->setText(s->get("JProfilerPath").toString()); ui->jvisualvmPathEdit->setText(s->get("JVisualVMPath").toString()); + ui->mceditPathEdit->setText(s->get("MCEditPath").toString()); } void SettingsDialog::on_javaDetectBtn_clicked() @@ -565,3 +567,29 @@ void SettingsDialog::on_jvisualvmCheckBtn_clicked() QMessageBox::information(this, tr("OK"), tr("JVisualVM setup seems to be OK")); } } + +void SettingsDialog::on_mceditPathBtn_clicked() +{ + QString raw_dir = QFileDialog::getOpenFileName(this, tr("MCEdit Path"), + ui->jvisualvmPathEdit->text()); + QString cooked_dir = NormalizePath(raw_dir); + + // do not allow current dir - it's dirty. Do not allow dirs that don't exist + if (!cooked_dir.isEmpty() && QDir(cooked_dir).exists()) + { + ui->mceditPathEdit->setText(cooked_dir); + } +} +void SettingsDialog::on_mceditCheckBtn_clicked() +{ + QString error; + if (!MMC->tools()["mcedit"]->check(ui->mceditPathEdit->text(), &error)) + { + QMessageBox::critical(this, tr("Error"), + tr("Error while checking MCEdit install:\n%1").arg(error)); + } + else + { + QMessageBox::information(this, tr("OK"), tr("MCEdit setup seems to be OK")); + } +} diff --git a/gui/dialogs/SettingsDialog.h b/gui/dialogs/SettingsDialog.h index 60d569f9..d8495fdd 100644 --- a/gui/dialogs/SettingsDialog.h +++ b/gui/dialogs/SettingsDialog.h @@ -79,6 +79,8 @@ slots: void on_jprofilerCheckBtn_clicked(); void on_jvisualvmPathBtn_clicked(); void on_jvisualvmCheckBtn_clicked(); + void on_mceditPathBtn_clicked(); + void on_mceditCheckBtn_clicked(); /*! * Updates the list of update channels in the combo box. diff --git a/gui/dialogs/SettingsDialog.ui b/gui/dialogs/SettingsDialog.ui index acf360a3..fbfa7aed 100644 --- a/gui/dialogs/SettingsDialog.ui +++ b/gui/dialogs/SettingsDialog.ui @@ -863,9 +863,9 @@ - + - Profiling + External Tools @@ -928,6 +928,36 @@ + + + + MCEdit + + + + + + + + + + + ... + + + + + + + + + Check + + + + + + diff --git a/logic/BaseExternalTool.cpp b/logic/BaseExternalTool.cpp new file mode 100644 index 00000000..6dffb4d6 --- /dev/null +++ b/logic/BaseExternalTool.cpp @@ -0,0 +1,47 @@ +#include "BaseExternalTool.h" + +#include +#ifdef Q_OS_WIN +#include +#endif + +BaseExternalTool::BaseExternalTool(BaseInstance *instance, QObject *parent) + : QObject(parent), m_instance(instance) +{ +} + +BaseExternalTool::~BaseExternalTool() +{ +} + +qint64 BaseExternalTool::pid(QProcess *process) +{ +#ifdef Q_OS_WIN + struct _PROCESS_INFORMATION *procinfo = process->pid(); + return procinfo->dwProcessId; +#else + return process->pid(); +#endif +} + + +BaseDetachedTool::BaseDetachedTool(BaseInstance *instance, QObject *parent) + : BaseExternalTool(instance, parent) +{ + +} + +void BaseDetachedTool::run() +{ + runImpl(); +} + + +BaseExternalToolFactory::~BaseExternalToolFactory() +{ +} + +BaseDetachedTool *BaseDetachedToolFactory::createDetachedTool(BaseInstance *instance, QObject *parent) +{ + return qobject_cast(createTool(instance, parent)); +} diff --git a/logic/BaseExternalTool.h b/logic/BaseExternalTool.h new file mode 100644 index 00000000..184b1f80 --- /dev/null +++ b/logic/BaseExternalTool.h @@ -0,0 +1,56 @@ +#pragma once + +#include + +class BaseInstance; +class SettingsObject; +class MinecraftProcess; +class QProcess; + +class BaseExternalTool : public QObject +{ + Q_OBJECT +public: + explicit BaseExternalTool(BaseInstance *instance, QObject *parent = 0); + virtual ~BaseExternalTool(); + +protected: + BaseInstance *m_instance; + + qint64 pid(QProcess *process); +}; + +class BaseDetachedTool : public BaseExternalTool +{ + Q_OBJECT +public: + explicit BaseDetachedTool(BaseInstance *instance, QObject *parent = 0); + +public +slots: + void run(); + +protected: + virtual void runImpl() = 0; +}; + +class BaseExternalToolFactory +{ +public: + virtual ~BaseExternalToolFactory(); + + virtual QString name() const = 0; + + virtual void registerSettings(SettingsObject *settings) = 0; + + virtual BaseExternalTool *createTool(BaseInstance *instance, QObject *parent = 0) = 0; + + virtual bool check(QString *error) = 0; + virtual bool check(const QString &path, QString *error) = 0; +}; + +class BaseDetachedToolFactory : public BaseExternalToolFactory +{ +public: + virtual BaseDetachedTool *createDetachedTool(BaseInstance *instance, QObject *parent = 0); +}; diff --git a/logic/MCEditTool.cpp b/logic/MCEditTool.cpp new file mode 100644 index 00000000..93ffb7a5 --- /dev/null +++ b/logic/MCEditTool.cpp @@ -0,0 +1,62 @@ +#include "MCEditTool.h" + +#include +#include +#include + +#include "settingsobject.h" +#include "logic/BaseInstance.h" +#include "MultiMC.h" + +MCEditTool::MCEditTool(BaseInstance *instance, QObject *parent) + : BaseDetachedTool(instance, parent) +{ +} + +void MCEditTool::runImpl() +{ + const QString mceditPath = MMC->settings()->get("MCEditPath").toString(); + const QString save = QFileDialog::getExistingDirectory( + MMC->activeWindow(), tr("MCEdit"), + QDir(m_instance->minecraftRoot()).absoluteFilePath("saves")); + if (save.isEmpty()) + { + return; + } + const QString program = + QDir(mceditPath).absoluteFilePath("mcedit.py"); + QProcess::startDetached(program, QStringList() << save, mceditPath); +} + +void MCEditFactory::registerSettings(SettingsObject *settings) +{ + settings->registerSetting("MCEditPath"); +} +BaseExternalTool *MCEditFactory::createTool(BaseInstance *instance, QObject *parent) +{ + return new MCEditTool(instance, parent); +} +bool MCEditFactory::check(QString *error) +{ + return check(MMC->settings()->get("MCEditPath").toString(), error); +} +bool MCEditFactory::check(const QString &path, QString *error) +{ + if (path.isEmpty()) + { + *error = QObject::tr("Path is empty"); + return false; + } + const QDir dir(path); + if (!dir.exists()) + { + *error = QObject::tr("Path does not exist"); + return false; + } + if (!dir.exists("mcedit.py")) + { + *error = QObject::tr("Path does not contain mcedit.py"); + return false; + } + return true; +} diff --git a/logic/MCEditTool.h b/logic/MCEditTool.h new file mode 100644 index 00000000..b0ed1ad4 --- /dev/null +++ b/logic/MCEditTool.h @@ -0,0 +1,23 @@ +#pragma once + +#include "BaseExternalTool.h" + +class MCEditTool : public BaseDetachedTool +{ + Q_OBJECT +public: + explicit MCEditTool(BaseInstance *instance, QObject *parent = 0); + +protected: + void runImpl() override; +}; + +class MCEditFactory : public BaseDetachedToolFactory +{ +public: + QString name() const override { return "MCEdit"; } + void registerSettings(SettingsObject *settings) override; + BaseExternalTool *createTool(BaseInstance *instance, QObject *parent = 0) override; + bool check(QString *error) override; + bool check(const QString &path, QString *error) override; +}; diff --git a/logic/profiler/BaseProfiler.cpp b/logic/profiler/BaseProfiler.cpp index b58e88be..9aaca793 100644 --- a/logic/profiler/BaseProfiler.cpp +++ b/logic/profiler/BaseProfiler.cpp @@ -1,16 +1,9 @@ #include "BaseProfiler.h" #include -#ifdef Q_OS_WIN -#include -#endif BaseProfiler::BaseProfiler(BaseInstance *instance, QObject *parent) - : QObject(parent), m_instance(instance) -{ -} - -BaseProfiler::~BaseProfiler() + : BaseExternalTool(instance, parent) { } @@ -36,16 +29,7 @@ void BaseProfiler::abortProfilingImpl() emit abortLaunch(tr("Profiler aborted")); } -qint64 BaseProfiler::pid(QProcess *process) -{ -#ifdef Q_OS_WIN - struct _PROCESS_INFORMATION *procinfo = process->pid(); - return procinfo->dwProcessId; -#else - return process->pid(); -#endif -} - -BaseProfilerFactory::~BaseProfilerFactory() +BaseProfiler *BaseProfilerFactory::createProfiler(BaseInstance *instance, QObject *parent) { + return qobject_cast(createTool(instance, parent)); } diff --git a/logic/profiler/BaseProfiler.h b/logic/profiler/BaseProfiler.h index e0d1d5f6..082cb65a 100644 --- a/logic/profiler/BaseProfiler.h +++ b/logic/profiler/BaseProfiler.h @@ -1,18 +1,17 @@ #pragma once -#include +#include "logic/BaseExternalTool.h" class BaseInstance; class SettingsObject; class MinecraftProcess; class QProcess; -class BaseProfiler : public QObject +class BaseProfiler : public BaseExternalTool { Q_OBJECT public: explicit BaseProfiler(BaseInstance *instance, QObject *parent = 0); - virtual ~BaseProfiler(); public slots: @@ -20,30 +19,18 @@ slots: void abortProfiling(); protected: - BaseInstance *m_instance; QProcess *m_profilerProcess; virtual void beginProfilingImpl(MinecraftProcess *process) = 0; virtual void abortProfilingImpl(); - qint64 pid(QProcess *process); - signals: void readyToLaunch(const QString &message); void abortLaunch(const QString &message); }; -class BaseProfilerFactory +class BaseProfilerFactory : public BaseExternalToolFactory { public: - virtual ~BaseProfilerFactory(); - - virtual QString name() const = 0; - - virtual void registerSettings(SettingsObject *settings) = 0; - - virtual BaseProfiler *createProfiler(BaseInstance *instance, QObject *parent = 0) = 0; - - virtual bool check(QString *error) = 0; - virtual bool check(const QString &path, QString *error) = 0; + virtual BaseProfiler *createProfiler(BaseInstance *instance, QObject *parent = 0); }; diff --git a/logic/profiler/JProfiler.cpp b/logic/profiler/JProfiler.cpp index 1cd8d128..bb851f0b 100644 --- a/logic/profiler/JProfiler.cpp +++ b/logic/profiler/JProfiler.cpp @@ -46,7 +46,7 @@ void JProfilerFactory::registerSettings(SettingsObject *settings) settings->registerSetting("JProfilerPort", 42042); } -BaseProfiler *JProfilerFactory::createProfiler(BaseInstance *instance, QObject *parent) +BaseExternalTool *JProfilerFactory::createTool(BaseInstance *instance, QObject *parent) { return new JProfiler(instance, parent); } diff --git a/logic/profiler/JProfiler.h b/logic/profiler/JProfiler.h index 8a5bc561..88a02462 100644 --- a/logic/profiler/JProfiler.h +++ b/logic/profiler/JProfiler.h @@ -17,7 +17,7 @@ class JProfilerFactory : public BaseProfilerFactory public: QString name() const override { return "JProfiler"; } void registerSettings(SettingsObject *settings) override; - BaseProfiler *createProfiler(BaseInstance *instance, QObject *parent = 0) override; + BaseExternalTool *createTool(BaseInstance *instance, QObject *parent = 0) override; bool check(QString *error) override; bool check(const QString &path, QString *error) override; }; diff --git a/logic/profiler/JVisualVM.cpp b/logic/profiler/JVisualVM.cpp index c4bc851b..7b79b2e8 100644 --- a/logic/profiler/JVisualVM.cpp +++ b/logic/profiler/JVisualVM.cpp @@ -42,7 +42,7 @@ void JVisualVMFactory::registerSettings(SettingsObject *settings) settings->registerSetting("JVisualVMPath"); } -BaseProfiler *JVisualVMFactory::createProfiler(BaseInstance *instance, QObject *parent) +BaseExternalTool *JVisualVMFactory::createTool(BaseInstance *instance, QObject *parent) { return new JVisualVM(instance, parent); } diff --git a/logic/profiler/JVisualVM.h b/logic/profiler/JVisualVM.h index 154180b4..af94fe55 100644 --- a/logic/profiler/JVisualVM.h +++ b/logic/profiler/JVisualVM.h @@ -17,7 +17,7 @@ class JVisualVMFactory : public BaseProfilerFactory public: QString name() const override { return "JVisualVM"; } void registerSettings(SettingsObject *settings) override; - BaseProfiler *createProfiler(BaseInstance *instance, QObject *parent = 0) override; + BaseExternalTool *createTool(BaseInstance *instance, QObject *parent = 0) override; bool check(QString *error) override; bool check(const QString &path, QString *error) override; }; From c88c639b8efdcdfe87c2ce44fa270889826b38ef Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sun, 16 Feb 2014 11:49:55 +0100 Subject: [PATCH 10/19] Fix for windows and update tool menu after closing settings dialog --- gui/MainWindow.cpp | 88 +++++++++++++++++++++++--------------------- gui/MainWindow.h | 2 + logic/MCEditTool.cpp | 14 +++++-- 3 files changed, 60 insertions(+), 44 deletions(-) diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 3f469061..16c88201 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -360,6 +360,51 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos) myMenu.exec(view->mapToGlobal(pos)); } +void MainWindow::updateToolsMenu() +{ + if (ui->actionLaunchInstance->menu()) + { + ui->actionLaunchInstance->menu()->deleteLater(); + } + QMenu *launchMenu = new QMenu(this); + QAction *normalLaunch = launchMenu->addAction(tr("Launch")); + connect(normalLaunch, &QAction::triggered, [this](){doLaunch();}); + launchMenu->addSeparator()->setText(tr("Profilers")); + for (auto profiler : MMC->profilers().values()) + { + QAction *profilerAction = launchMenu->addAction(profiler->name()); + QString error; + if (!profiler->check(&error)) + { + profilerAction->setDisabled(true); + profilerAction->setToolTip(tr("Profiler not setup correctly. Go into settings, \"External Tools\".")); + } + else + { + connect(profilerAction, &QAction::triggered, [this, profiler](){doLaunch(true, profiler.get());}); + } + } + launchMenu->addSeparator()->setText(tr("Tools")); + for (auto tool : MMC->tools().values()) + { + QAction *toolAction = launchMenu->addAction(tool->name()); + QString error; + if (!tool->check(&error)) + { + toolAction->setDisabled(true); + toolAction->setToolTip(tr("Tool not setup correctly. Go into settings, \"External Tools\".")); + } + else + { + connect(toolAction, &QAction::triggered, [this, tool]() + { + tool->createDetachedTool(m_selectedInstance, this)->run(); + }); + } + } + ui->actionLaunchInstance->setMenu(launchMenu); +} + void MainWindow::repopulateAccountsMenu() { accountMenu->clear(); @@ -933,6 +978,7 @@ void MainWindow::on_actionSettings_triggered() // FIXME: quick HACK to make this work. improve, optimize. proxymodel->invalidate(); proxymodel->sort(0); + updateToolsMenu(); } void MainWindow::on_actionManageAccounts_triggered() @@ -1429,47 +1475,7 @@ void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex & m_statusLeft->setText(m_selectedInstance->getStatusbarDescription()); updateInstanceToolIcon(m_selectedInstance->iconKey()); - if (ui->actionLaunchInstance->menu()) - { - ui->actionLaunchInstance->menu()->deleteLater(); - } - QMenu *launchMenu = new QMenu; - QAction *normalLaunch = launchMenu->addAction(tr("Launch")); - connect(normalLaunch, &QAction::triggered, [this](){doLaunch();}); - launchMenu->addSeparator()->setText(tr("Profilers")); - for (auto profiler : MMC->profilers().values()) - { - QAction *profilerAction = launchMenu->addAction(profiler->name()); - QString error; - if (!profiler->check(&error)) - { - profilerAction->setDisabled(true); - profilerAction->setToolTip(tr("Profiler not setup correctly. Go into settings, \"External Tools\".")); - } - else - { - connect(profilerAction, &QAction::triggered, [this, profiler](){doLaunch(true, profiler.get());}); - } - } - launchMenu->addSeparator()->setText(tr("Tools")); - for (auto tool : MMC->tools().values()) - { - QAction *toolAction = launchMenu->addAction(tool->name()); - QString error; - if (!tool->check(&error)) - { - toolAction->setDisabled(true); - toolAction->setToolTip(tr("Tool not setup correctly. Go into settings, \"External Tools\".")); - } - else - { - connect(toolAction, &QAction::triggered, [this, tool]() - { - tool->createDetachedTool(m_selectedInstance, this)->run(); - }); - } - } - ui->actionLaunchInstance->setMenu(launchMenu); + updateToolsMenu(); MMC->settings()->set("SelectedInstance", m_selectedInstance->id()); } diff --git a/gui/MainWindow.h b/gui/MainWindow.h index 682c711d..7a29977d 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -141,6 +141,8 @@ slots: void showInstanceContextMenu(const QPoint&); + void updateToolsMenu(); + public slots: void instanceActivated(QModelIndex); diff --git a/logic/MCEditTool.cpp b/logic/MCEditTool.cpp index 93ffb7a5..14dc1b96 100644 --- a/logic/MCEditTool.cpp +++ b/logic/MCEditTool.cpp @@ -23,8 +23,16 @@ void MCEditTool::runImpl() { return; } - const QString program = - QDir(mceditPath).absoluteFilePath("mcedit.py"); + QDir mceditDir(mceditPath); + QString program; + if (mceditDir.exists("mcedit.py")) + { + program = mceditDir.absoluteFilePath("mcedit.py"); + } + else if (mceditDir.exists("mcedit.exe")) + { + program = mceditDir.absoluteFilePath("mcedit.exe"); + } QProcess::startDetached(program, QStringList() << save, mceditPath); } @@ -53,7 +61,7 @@ bool MCEditFactory::check(const QString &path, QString *error) *error = QObject::tr("Path does not exist"); return false; } - if (!dir.exists("mcedit.py")) + if (!dir.exists("mcedit.py") && !dir.exists("mcedit.exe")) { *error = QObject::tr("Path does not contain mcedit.py"); return false; From 2e64d0308c96b18532918d36794368eb1deb24cd Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sun, 16 Feb 2014 11:56:02 +0100 Subject: [PATCH 11/19] Use a combobox instead of a file dialog --- logic/MCEditTool.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/logic/MCEditTool.cpp b/logic/MCEditTool.cpp index 14dc1b96..5694f654 100644 --- a/logic/MCEditTool.cpp +++ b/logic/MCEditTool.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "settingsobject.h" #include "logic/BaseInstance.h" @@ -16,10 +17,12 @@ MCEditTool::MCEditTool(BaseInstance *instance, QObject *parent) void MCEditTool::runImpl() { const QString mceditPath = MMC->settings()->get("MCEditPath").toString(); - const QString save = QFileDialog::getExistingDirectory( - MMC->activeWindow(), tr("MCEdit"), - QDir(m_instance->minecraftRoot()).absoluteFilePath("saves")); - if (save.isEmpty()) + const QDir saves = QDir(m_instance->minecraftRoot() + "/saves"); + bool ok = true; + const QString save = QInputDialog::getItem( + MMC->activeWindow(), tr("MCEdit"), tr("Choose which world to open:"), + saves.entryList(QDir::Dirs | QDir::NoDotAndDotDot), 0, false, &ok); + if (save.isEmpty() || !ok) { return; } @@ -33,7 +36,7 @@ void MCEditTool::runImpl() { program = mceditDir.absoluteFilePath("mcedit.exe"); } - QProcess::startDetached(program, QStringList() << save, mceditPath); + QProcess::startDetached(program, QStringList() << saves.absoluteFilePath(save), mceditPath); } void MCEditFactory::registerSettings(SettingsObject *settings) From c608841f770729a22e38cb4df8c3555062ac04dc Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sun, 16 Feb 2014 12:00:38 +0100 Subject: [PATCH 12/19] Attempt to find jvisualvm --- logic/profiler/JVisualVM.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/logic/profiler/JVisualVM.cpp b/logic/profiler/JVisualVM.cpp index 7b79b2e8..02938028 100644 --- a/logic/profiler/JVisualVM.cpp +++ b/logic/profiler/JVisualVM.cpp @@ -39,7 +39,12 @@ void JVisualVM::beginProfilingImpl(MinecraftProcess *process) void JVisualVMFactory::registerSettings(SettingsObject *settings) { - settings->registerSetting("JVisualVMPath"); + QString defaultValue = QStandardPaths::findExecutable("jvisualvm"); + if (defaultValue.isNull()) + { + defaultValue = QStandardPaths::findExecutable("visualvm"); + } + settings->registerSetting("JVisualVMPath", defaultValue); } BaseExternalTool *JVisualVMFactory::createTool(BaseInstance *instance, QObject *parent) From 1dc34269bde4611d1a1c76f01df6dacd85f79c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 16 Feb 2014 12:04:26 +0100 Subject: [PATCH 13/19] Fix path selections for tools (settings dialog) --- gui/dialogs/SettingsDialog.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp index 9423d7eb..d20c0aa7 100644 --- a/gui/dialogs/SettingsDialog.cpp +++ b/gui/dialogs/SettingsDialog.cpp @@ -527,6 +527,10 @@ void SettingsDialog::on_jprofilerPathBtn_clicked() { ui->jprofilerPathEdit->setText(cooked_dir); } + else + { + // FIXME: see below... + } } void SettingsDialog::on_jprofilerCheckBtn_clicked() { @@ -546,12 +550,18 @@ void SettingsDialog::on_jvisualvmPathBtn_clicked() { QString raw_dir = QFileDialog::getOpenFileName(this, tr("JVisualVM Executable"), ui->jvisualvmPathEdit->text()); - QString cooked_dir = NormalizePath(raw_dir); + QString cooked_path = NormalizePath(raw_dir); + QFileInfo finfo(cooked_path); // do not allow current dir - it's dirty. Do not allow dirs that don't exist - if (!cooked_dir.isEmpty() && QDir(cooked_dir).exists()) + if (!cooked_path.isEmpty() && finfo.isExecutable() && finfo.isFile()) { - ui->jvisualvmPathEdit->setText(cooked_dir); + ui->jvisualvmPathEdit->setText(cooked_path); + } + else + { + // FIXME: report error here, or run the checker instead of that condition above. + // ideally unify all the sanity checks and put them into the relevant classes } } void SettingsDialog::on_jvisualvmCheckBtn_clicked() @@ -570,8 +580,8 @@ void SettingsDialog::on_jvisualvmCheckBtn_clicked() void SettingsDialog::on_mceditPathBtn_clicked() { - QString raw_dir = QFileDialog::getOpenFileName(this, tr("MCEdit Path"), - ui->jvisualvmPathEdit->text()); + QString raw_dir = QFileDialog::getExistingDirectory(this, tr("MCEdit Path"), + ui->mceditPathEdit->text()); QString cooked_dir = NormalizePath(raw_dir); // do not allow current dir - it's dirty. Do not allow dirs that don't exist @@ -579,6 +589,9 @@ void SettingsDialog::on_mceditPathBtn_clicked() { ui->mceditPathEdit->setText(cooked_dir); } + { + // FIXME: as above. + } } void SettingsDialog::on_mceditCheckBtn_clicked() { From f26b7dedad70a46769b4c96122a7615b328a9fbb Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sun, 16 Feb 2014 12:08:39 +0100 Subject: [PATCH 14/19] Only show folders that really are worlds --- logic/BaseExternalTool.cpp | 30 ++++++++++++++++++++++++++++++ logic/BaseExternalTool.h | 1 + logic/MCEditTool.cpp | 12 +++--------- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/logic/BaseExternalTool.cpp b/logic/BaseExternalTool.cpp index 6dffb4d6..081c3ef0 100644 --- a/logic/BaseExternalTool.cpp +++ b/logic/BaseExternalTool.cpp @@ -1,10 +1,16 @@ #include "BaseExternalTool.h" #include +#include +#include + #ifdef Q_OS_WIN #include #endif +#include "BaseInstance.h" +#include "MultiMC.h" + BaseExternalTool::BaseExternalTool(BaseInstance *instance, QObject *parent) : QObject(parent), m_instance(instance) { @@ -24,6 +30,30 @@ qint64 BaseExternalTool::pid(QProcess *process) #endif } +QString BaseExternalTool::getSave() const +{ + QDir saves(m_instance->minecraftRoot() + "/saves"); + QStringList worlds = saves.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + QMutableListIterator it(worlds); + while (it.hasNext()) + { + it.next(); + if (!QDir(saves.absoluteFilePath(it.value())).exists("level.dat")) + { + it.remove(); + } + } + bool ok = true; + const QString save = QInputDialog::getItem( + MMC->activeWindow(), tr("MCEdit"), tr("Choose which world to open:"), + worlds, 0, false, &ok); + if (ok) + { + return saves.absoluteFilePath(save); + } + return QString(); +} + BaseDetachedTool::BaseDetachedTool(BaseInstance *instance, QObject *parent) : BaseExternalTool(instance, parent) diff --git a/logic/BaseExternalTool.h b/logic/BaseExternalTool.h index 184b1f80..e8965bfd 100644 --- a/logic/BaseExternalTool.h +++ b/logic/BaseExternalTool.h @@ -18,6 +18,7 @@ protected: BaseInstance *m_instance; qint64 pid(QProcess *process); + QString getSave() const; }; class BaseDetachedTool : public BaseExternalTool diff --git a/logic/MCEditTool.cpp b/logic/MCEditTool.cpp index 5694f654..c4edece5 100644 --- a/logic/MCEditTool.cpp +++ b/logic/MCEditTool.cpp @@ -2,8 +2,6 @@ #include #include -#include -#include #include "settingsobject.h" #include "logic/BaseInstance.h" @@ -17,12 +15,8 @@ MCEditTool::MCEditTool(BaseInstance *instance, QObject *parent) void MCEditTool::runImpl() { const QString mceditPath = MMC->settings()->get("MCEditPath").toString(); - const QDir saves = QDir(m_instance->minecraftRoot() + "/saves"); - bool ok = true; - const QString save = QInputDialog::getItem( - MMC->activeWindow(), tr("MCEdit"), tr("Choose which world to open:"), - saves.entryList(QDir::Dirs | QDir::NoDotAndDotDot), 0, false, &ok); - if (save.isEmpty() || !ok) + const QString save = getSave(); + if (save.isNull()) { return; } @@ -36,7 +30,7 @@ void MCEditTool::runImpl() { program = mceditDir.absoluteFilePath("mcedit.exe"); } - QProcess::startDetached(program, QStringList() << saves.absoluteFilePath(save), mceditPath); + QProcess::startDetached(program, QStringList() << save, mceditPath); } void MCEditFactory::registerSettings(SettingsObject *settings) From 9c87bc6c4b99f0c93f2b18039208dcf9f3fb4d79 Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sun, 16 Feb 2014 12:52:35 +0100 Subject: [PATCH 15/19] Restructure --- CMakeLists.txt | 22 +++++++++++----------- MultiMC.cpp | 6 +++--- gui/MainWindow.cpp | 2 +- gui/dialogs/SettingsDialog.cpp | 2 +- logic/{ => tools}/BaseExternalTool.cpp | 2 +- logic/{ => tools}/BaseExternalTool.h | 0 logic/{profiler => tools}/BaseProfiler.cpp | 0 logic/{profiler => tools}/BaseProfiler.h | 2 +- logic/{profiler => tools}/JProfiler.cpp | 0 logic/{profiler => tools}/JProfiler.h | 0 logic/{profiler => tools}/JVisualVM.cpp | 0 logic/{profiler => tools}/JVisualVM.h | 0 logic/{ => tools}/MCEditTool.cpp | 0 logic/{ => tools}/MCEditTool.h | 0 14 files changed, 18 insertions(+), 18 deletions(-) rename logic/{ => tools}/BaseExternalTool.cpp (97%) rename logic/{ => tools}/BaseExternalTool.h (100%) rename logic/{profiler => tools}/BaseProfiler.cpp (100%) rename logic/{profiler => tools}/BaseProfiler.h (95%) rename logic/{profiler => tools}/JProfiler.cpp (100%) rename logic/{profiler => tools}/JProfiler.h (100%) rename logic/{profiler => tools}/JVisualVM.cpp (100%) rename logic/{profiler => tools}/JVisualVM.h (100%) rename logic/{ => tools}/MCEditTool.cpp (100%) rename logic/{ => tools}/MCEditTool.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58d01eb8..43c02efc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -499,17 +499,17 @@ logic/assets/AssetsMigrateTask.cpp logic/assets/AssetsUtils.h logic/assets/AssetsUtils.cpp -# Profiling and tools -logic/BaseExternalTool.h -logic/BaseExternalTool.cpp -logic/MCEditTool.h -logic/MCEditTool.cpp -logic/profiler/BaseProfiler.h -logic/profiler/BaseProfiler.cpp -logic/profiler/JProfiler.h -logic/profiler/JProfiler.cpp -logic/profiler/JVisualVM.h -logic/profiler/JVisualVM.cpp +# Tools +logic/tools/BaseExternalTool.h +logic/tools/BaseExternalTool.cpp +logic/tools/MCEditTool.h +logic/tools/MCEditTool.cpp +logic/tools/BaseProfiler.h +logic/tools/BaseProfiler.cpp +logic/tools/JProfiler.h +logic/tools/JProfiler.cpp +logic/tools/JVisualVM.h +logic/tools/JVisualVM.cpp ) diff --git a/MultiMC.cpp b/MultiMC.cpp index c813c425..294a4926 100644 --- a/MultiMC.cpp +++ b/MultiMC.cpp @@ -31,9 +31,9 @@ #include "logic/updater/UpdateChecker.h" #include "logic/updater/NotificationChecker.h" -#include "logic/profiler/JProfiler.h" -#include "logic/profiler/JVisualVM.h" -#include "logic/MCEditTool.h" +#include "logic/tools/JProfiler.h" +#include "logic/tools/JVisualVM.h" +#include "logic/tools/MCEditTool.h" #include "pathutils.h" #include "cmdutils.h" diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 16c88201..ebbace52 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -98,7 +98,7 @@ #include #include -#include "logic/profiler/BaseProfiler.h" +#include "logic/tools/BaseProfiler.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp index d20c0aa7..cd5aba74 100644 --- a/gui/dialogs/SettingsDialog.cpp +++ b/gui/dialogs/SettingsDialog.cpp @@ -29,7 +29,7 @@ #include "logic/updater/UpdateChecker.h" -#include "logic/profiler/BaseProfiler.h" +#include "logic/tools/BaseProfiler.h" #include #include diff --git a/logic/BaseExternalTool.cpp b/logic/tools/BaseExternalTool.cpp similarity index 97% rename from logic/BaseExternalTool.cpp rename to logic/tools/BaseExternalTool.cpp index 081c3ef0..69cddd00 100644 --- a/logic/BaseExternalTool.cpp +++ b/logic/tools/BaseExternalTool.cpp @@ -8,7 +8,7 @@ #include #endif -#include "BaseInstance.h" +#include "logic/BaseInstance.h" #include "MultiMC.h" BaseExternalTool::BaseExternalTool(BaseInstance *instance, QObject *parent) diff --git a/logic/BaseExternalTool.h b/logic/tools/BaseExternalTool.h similarity index 100% rename from logic/BaseExternalTool.h rename to logic/tools/BaseExternalTool.h diff --git a/logic/profiler/BaseProfiler.cpp b/logic/tools/BaseProfiler.cpp similarity index 100% rename from logic/profiler/BaseProfiler.cpp rename to logic/tools/BaseProfiler.cpp diff --git a/logic/profiler/BaseProfiler.h b/logic/tools/BaseProfiler.h similarity index 95% rename from logic/profiler/BaseProfiler.h rename to logic/tools/BaseProfiler.h index 082cb65a..ec57578e 100644 --- a/logic/profiler/BaseProfiler.h +++ b/logic/tools/BaseProfiler.h @@ -1,6 +1,6 @@ #pragma once -#include "logic/BaseExternalTool.h" +#include "BaseExternalTool.h" class BaseInstance; class SettingsObject; diff --git a/logic/profiler/JProfiler.cpp b/logic/tools/JProfiler.cpp similarity index 100% rename from logic/profiler/JProfiler.cpp rename to logic/tools/JProfiler.cpp diff --git a/logic/profiler/JProfiler.h b/logic/tools/JProfiler.h similarity index 100% rename from logic/profiler/JProfiler.h rename to logic/tools/JProfiler.h diff --git a/logic/profiler/JVisualVM.cpp b/logic/tools/JVisualVM.cpp similarity index 100% rename from logic/profiler/JVisualVM.cpp rename to logic/tools/JVisualVM.cpp diff --git a/logic/profiler/JVisualVM.h b/logic/tools/JVisualVM.h similarity index 100% rename from logic/profiler/JVisualVM.h rename to logic/tools/JVisualVM.h diff --git a/logic/MCEditTool.cpp b/logic/tools/MCEditTool.cpp similarity index 100% rename from logic/MCEditTool.cpp rename to logic/tools/MCEditTool.cpp diff --git a/logic/MCEditTool.h b/logic/tools/MCEditTool.h similarity index 100% rename from logic/MCEditTool.h rename to logic/tools/MCEditTool.h From e4ecc31e07d6b16983cc038fee906417f58482d7 Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sun, 16 Feb 2014 13:02:59 +0100 Subject: [PATCH 16/19] Links to the tools --- gui/dialogs/SettingsDialog.ui | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/gui/dialogs/SettingsDialog.ui b/gui/dialogs/SettingsDialog.ui index fbfa7aed..7d94446e 100644 --- a/gui/dialogs/SettingsDialog.ui +++ b/gui/dialogs/SettingsDialog.ui @@ -895,6 +895,13 @@ + + + + <html><head/><body><p><a href="http://www.ej-technologies.com/products/jprofiler/overview.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.ej-technologies.com/products/jprofiler/overview.html</span></a></p></body></html> + + + @@ -925,6 +932,13 @@ + + + + <html><head/><body><p><a href="http://visualvm.java.net/"><span style=" text-decoration: underline; color:#0000ff;">http://visualvm.java.net/</span></a></p></body></html> + + + @@ -955,6 +969,13 @@ + + + + <html><head/><body><p><a href="http://www.mcedit.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.mcedit.net/</span></a></p></body></html> + + + From dd2d8f48face27a0f43502206fc5ed8fc0dd6a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 16 Feb 2014 14:42:44 +0100 Subject: [PATCH 17/19] Nicer way of selecting tool folders and executables --- gui/dialogs/SettingsDialog.cpp | 202 ++++++++++++++++++++------------- gui/dialogs/SettingsDialog.ui | 6 +- 2 files changed, 129 insertions(+), 79 deletions(-) diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp index cd5aba74..4b0b117d 100644 --- a/gui/dialogs/SettingsDialog.cpp +++ b/gui/dialogs/SettingsDialog.cpp @@ -48,12 +48,14 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::Se ui->jsonEditorTextBox->setClearButtonEnabled(true); #endif - restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("SettingsGeometry").toByteArray())); + restoreGeometry( + QByteArray::fromBase64(MMC->settings()->get("SettingsGeometry").toByteArray())); loadSettings(MMC->settings().get()); updateCheckboxStuff(); - QObject::connect(MMC->updateChecker().get(), &UpdateChecker::channelListLoaded, this, &SettingsDialog::refreshUpdateChannelList); + QObject::connect(MMC->updateChecker().get(), &UpdateChecker::channelListLoaded, this, + &SettingsDialog::refreshUpdateChannelList); if (MMC->updateChecker()->hasChannels()) { @@ -64,6 +66,9 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::Se MMC->updateChecker()->updateChanList(); } connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int))); + ui->mceditLink->setOpenExternalLinks(true); + ui->jvisualvmLink->setOpenExternalLinks(true); + ui->jprofilerLink->setOpenExternalLinks(true); } SettingsDialog::~SettingsDialog() @@ -86,8 +91,10 @@ void SettingsDialog::updateCheckboxStuff() { ui->windowWidthSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked()); ui->windowHeightSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked()); - ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() && !ui->proxyDefaultBtn->isChecked()); - ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() && !ui->proxyDefaultBtn->isChecked()); + ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() && + !ui->proxyDefaultBtn->isChecked()); + ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() && + !ui->proxyDefaultBtn->isChecked()); } void SettingsDialog::on_ftbLauncherBrowseBtn_clicked() @@ -105,8 +112,8 @@ void SettingsDialog::on_ftbLauncherBrowseBtn_clicked() void SettingsDialog::on_ftbBrowseBtn_clicked() { - QString raw_dir = QFileDialog::getExistingDirectory(this, tr("FTB Directory"), - ui->ftbBox->text()); + QString raw_dir = + QFileDialog::getExistingDirectory(this, tr("FTB Directory"), ui->ftbBox->text()); QString cooked_dir = NormalizePath(raw_dir); // do not allow current dir - it's dirty. Do not allow dirs that don't exist @@ -172,11 +179,11 @@ void SettingsDialog::on_jsonEditorBrowseBtn_clicked() QString raw_file = QFileDialog::getOpenFileName( this, tr("JSON Editor"), ui->jsonEditorTextBox->text().isEmpty() - #if defined(Q_OS_LINUX) +#if defined(Q_OS_LINUX) ? QString("/usr/bin") - #else +#else ? QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).first() - #endif +#endif : ui->jsonEditorTextBox->text()); QString cooked_file = NormalizePath(raw_file); @@ -186,14 +193,14 @@ void SettingsDialog::on_jsonEditorBrowseBtn_clicked() } // it has to exist and be an executable - if (QFileInfo(cooked_file).exists() && - QFileInfo(cooked_file).isExecutable()) + if (QFileInfo(cooked_file).exists() && QFileInfo(cooked_file).isExecutable()) { ui->jsonEditorTextBox->setText(cooked_file); } else { - QMessageBox::warning(this, tr("Invalid"), tr("The file chosen does not seem to be an executable")); + QMessageBox::warning(this, tr("Invalid"), + tr("The file chosen does not seem to be an executable")); } } @@ -225,9 +232,11 @@ void SettingsDialog::proxyChanged(int) void SettingsDialog::refreshUpdateChannelList() { - // Stop listening for selection changes. It's going to change a lot while we update it and we don't need to update the + // Stop listening for selection changes. It's going to change a lot while we update it and + // we don't need to update the // description label constantly. - QObject::disconnect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateChannelSelectionChanged(int))); + QObject::disconnect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this, + SLOT(updateChannelSelectionChanged(int))); QList channelList = MMC->updateChecker()->getChannelList(); ui->updateChannelComboBox->clear(); @@ -235,29 +244,34 @@ void SettingsDialog::refreshUpdateChannelList() for (int i = 0; i < channelList.count(); i++) { UpdateChecker::ChannelListEntry entry = channelList.at(i); - - // When it comes to selection, we'll rely on the indexes of a channel entry being the same in the + + // When it comes to selection, we'll rely on the indexes of a channel entry being the + // same in the // combo box as it is in the update checker's channel list. - // This probably isn't very safe, but the channel list doesn't change often enough (or at all) for + // This probably isn't very safe, but the channel list doesn't change often enough (or + // at all) for // this to be a big deal. Hope it doesn't break... ui->updateChannelComboBox->addItem(entry.name); - // If the update channel we just added was the selected one, set the current index in the combo box to it. + // If the update channel we just added was the selected one, set the current index in + // the combo box to it. if (entry.id == m_currentUpdateChannel) { QLOG_DEBUG() << "Selected index" << i << "channel id" << m_currentUpdateChannel; selection = i; } } - + ui->updateChannelComboBox->setCurrentIndex(selection); // Start listening for selection changes again and update the description label. - QObject::connect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateChannelSelectionChanged(int))); + QObject::connect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this, + SLOT(updateChannelSelectionChanged(int))); refreshUpdateChannelDesc(); // Now that we've updated the channel list, we can enable the combo box. - // It starts off disabled so that if the channel list hasn't been loaded, it will be disabled. + // It starts off disabled so that if the channel list hasn't been loaded, it will be + // disabled. ui->updateChannelComboBox->setEnabled(true); } @@ -271,7 +285,7 @@ void SettingsDialog::refreshUpdateChannelDesc() // Get the channel list. QList channelList = MMC->updateChecker()->getChannelList(); int selectedIndex = ui->updateChannelComboBox->currentIndex(); - if(selectedIndex < 0) + if (selectedIndex < 0) { return; } @@ -291,7 +305,8 @@ void SettingsDialog::refreshUpdateChannelDesc() void SettingsDialog::applySettings(SettingsObject *s) { // Language - s->set("Language", ui->languageBox->itemData(ui->languageBox->currentIndex()).toLocale().bcp47Name()); + s->set("Language", + ui->languageBox->itemData(ui->languageBox->currentIndex()).toLocale().bcp47Name()); // Updates s->set("AutoUpdate", ui->autoUpdateCheckBox->isChecked()); @@ -311,7 +326,8 @@ void SettingsDialog::applySettings(SettingsObject *s) // Editors QString jsonEditor = ui->jsonEditorTextBox->text(); - if (!jsonEditor.isEmpty() && (!QFileInfo(jsonEditor).exists() || !QFileInfo(jsonEditor).isExecutable())) + if (!jsonEditor.isEmpty() && + (!QFileInfo(jsonEditor).exists() || !QFileInfo(jsonEditor).isExecutable())) { QString found = QStandardPaths::findExecutable(jsonEditor); if (!found.isEmpty()) @@ -332,10 +348,14 @@ void SettingsDialog::applySettings(SettingsObject *s) // Proxy QString proxyType = "None"; - if (ui->proxyDefaultBtn->isChecked()) proxyType = "Default"; - else if (ui->proxyNoneBtn->isChecked()) proxyType = "None"; - else if (ui->proxySOCKS5Btn->isChecked()) proxyType = "SOCKS5"; - else if (ui->proxyHTTPBtn->isChecked()) proxyType = "HTTP"; + if (ui->proxyDefaultBtn->isChecked()) + proxyType = "Default"; + else if (ui->proxyNoneBtn->isChecked()) + proxyType = "None"; + else if (ui->proxySOCKS5Btn->isChecked()) + proxyType = "SOCKS5"; + else if (ui->proxyHTTPBtn->isChecked()) + proxyType = "HTTP"; s->set("ProxyType", proxyType); s->set("ProxyAddr", ui->proxyAddrEdit->text()); @@ -386,11 +406,10 @@ void SettingsDialog::loadSettings(SettingsObject *s) QDir(MMC->root() + "/translations").entryList(QStringList() << "*.qm", QDir::Files)) { QLocale locale(lang.section(QRegExp("[_\.]"), 1)); - ui->languageBox->addItem( - QLocale::languageToString(locale.language()), - locale); + ui->languageBox->addItem(QLocale::languageToString(locale.language()), locale); } - ui->languageBox->setCurrentIndex(ui->languageBox->findData(QLocale(s->get("Language").toString()))); + ui->languageBox->setCurrentIndex( + ui->languageBox->findData(QLocale(s->get("Language").toString()))); // Updates ui->autoUpdateCheckBox->setChecked(s->get("AutoUpdate").toBool()); @@ -437,10 +456,14 @@ void SettingsDialog::loadSettings(SettingsObject *s) // Proxy QString proxyType = s->get("ProxyType").toString(); - if (proxyType == "Default") ui->proxyDefaultBtn->setChecked(true); - else if (proxyType == "None") ui->proxyNoneBtn->setChecked(true); - else if (proxyType == "SOCKS5") ui->proxySOCKS5Btn->setChecked(true); - else if (proxyType == "HTTP") ui->proxyHTTPBtn->setChecked(true); + if (proxyType == "Default") + ui->proxyDefaultBtn->setChecked(true); + else if (proxyType == "None") + ui->proxyNoneBtn->setChecked(true); + else if (proxyType == "SOCKS5") + ui->proxySOCKS5Btn->setChecked(true); + else if (proxyType == "HTTP") + ui->proxyHTTPBtn->setChecked(true); ui->proxyAddrEdit->setText(s->get("ProxyAddr").toString()); ui->proxyPortEdit->setValue(s->get("ProxyPort").value()); @@ -518,19 +541,28 @@ void SettingsDialog::checkFinished(JavaCheckResult result) void SettingsDialog::on_jprofilerPathBtn_clicked() { - QString raw_dir = QFileDialog::getExistingDirectory(this, tr("JProfiler Directory"), - ui->jprofilerPathEdit->text()); - QString cooked_dir = NormalizePath(raw_dir); - - // do not allow current dir - it's dirty. Do not allow dirs that don't exist - if (!cooked_dir.isEmpty() && QDir(cooked_dir).exists()) + QString raw_dir = ui->jprofilerPathEdit->text(); + QString error; + do { - ui->jprofilerPathEdit->setText(cooked_dir); - } - else - { - // FIXME: see below... - } + raw_dir = QFileDialog::getExistingDirectory(this, tr("JProfiler Directory"), raw_dir); + if (raw_dir.isEmpty()) + { + break; + } + QString cooked_dir = NormalizePath(raw_dir); + if (!MMC->profilers()["jprofiler"]->check(cooked_dir, &error)) + { + QMessageBox::critical(this, tr("Error"), + tr("Error while checking JProfiler install:\n%1").arg(error)); + continue; + } + else + { + ui->jprofilerPathEdit->setText(cooked_dir); + break; + } + } while (1); } void SettingsDialog::on_jprofilerCheckBtn_clicked() { @@ -538,7 +570,7 @@ void SettingsDialog::on_jprofilerCheckBtn_clicked() if (!MMC->profilers()["jprofiler"]->check(ui->jprofilerPathEdit->text(), &error)) { QMessageBox::critical(this, tr("Error"), - tr("Error while checking JProfiler install:\n%1").arg(error)); + tr("Error while checking JProfiler install:\n%1").arg(error)); } else { @@ -548,21 +580,28 @@ void SettingsDialog::on_jprofilerCheckBtn_clicked() void SettingsDialog::on_jvisualvmPathBtn_clicked() { - QString raw_dir = QFileDialog::getOpenFileName(this, tr("JVisualVM Executable"), - ui->jvisualvmPathEdit->text()); - QString cooked_path = NormalizePath(raw_dir); - QFileInfo finfo(cooked_path); - - // do not allow current dir - it's dirty. Do not allow dirs that don't exist - if (!cooked_path.isEmpty() && finfo.isExecutable() && finfo.isFile()) + QString raw_dir = ui->jvisualvmPathEdit->text(); + QString error; + do { - ui->jvisualvmPathEdit->setText(cooked_path); - } - else - { - // FIXME: report error here, or run the checker instead of that condition above. - // ideally unify all the sanity checks and put them into the relevant classes - } + raw_dir = QFileDialog::getOpenFileName(this, tr("JVisualVM Executable"), raw_dir); + if (raw_dir.isEmpty()) + { + break; + } + QString cooked_dir = NormalizePath(raw_dir); + if (!MMC->profilers()["jvisualvm"]->check(cooked_dir, &error)) + { + QMessageBox::critical(this, tr("Error"), + tr("Error while checking MCEdit install:\n%1").arg(error)); + continue; + } + else + { + ui->jvisualvmPathEdit->setText(cooked_dir); + break; + } + } while (1); } void SettingsDialog::on_jvisualvmCheckBtn_clicked() { @@ -570,7 +609,7 @@ void SettingsDialog::on_jvisualvmCheckBtn_clicked() if (!MMC->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error)) { QMessageBox::critical(this, tr("Error"), - tr("Error while checking JVisualVM install:\n%1").arg(error)); + tr("Error while checking JVisualVM install:\n%1").arg(error)); } else { @@ -580,26 +619,37 @@ void SettingsDialog::on_jvisualvmCheckBtn_clicked() void SettingsDialog::on_mceditPathBtn_clicked() { - QString raw_dir = QFileDialog::getExistingDirectory(this, tr("MCEdit Path"), - ui->mceditPathEdit->text()); - QString cooked_dir = NormalizePath(raw_dir); - - // do not allow current dir - it's dirty. Do not allow dirs that don't exist - if (!cooked_dir.isEmpty() && QDir(cooked_dir).exists()) + QString raw_dir = ui->mceditPathEdit->text(); + QString error; + do { - ui->mceditPathEdit->setText(cooked_dir); - } - { - // FIXME: as above. - } + raw_dir = QFileDialog::getExistingDirectory(this, tr("MCEdit Path"), raw_dir); + if (raw_dir.isEmpty()) + { + break; + } + QString cooked_dir = NormalizePath(raw_dir); + if (!MMC->tools()["mcedit"]->check(cooked_dir, &error)) + { + QMessageBox::critical(this, tr("Error"), + tr("Error while checking MCEdit install:\n%1").arg(error)); + continue; + } + else + { + ui->mceditPathEdit->setText(cooked_dir); + break; + } + } while (1); } + void SettingsDialog::on_mceditCheckBtn_clicked() { QString error; if (!MMC->tools()["mcedit"]->check(ui->mceditPathEdit->text(), &error)) { QMessageBox::critical(this, tr("Error"), - tr("Error while checking MCEdit install:\n%1").arg(error)); + tr("Error while checking MCEdit install:\n%1").arg(error)); } else { diff --git a/gui/dialogs/SettingsDialog.ui b/gui/dialogs/SettingsDialog.ui index 7d94446e..e8da8582 100644 --- a/gui/dialogs/SettingsDialog.ui +++ b/gui/dialogs/SettingsDialog.ui @@ -896,7 +896,7 @@ - + <html><head/><body><p><a href="http://www.ej-technologies.com/products/jprofiler/overview.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.ej-technologies.com/products/jprofiler/overview.html</span></a></p></body></html> @@ -933,7 +933,7 @@ - + <html><head/><body><p><a href="http://visualvm.java.net/"><span style=" text-decoration: underline; color:#0000ff;">http://visualvm.java.net/</span></a></p></body></html> @@ -970,7 +970,7 @@ - + <html><head/><body><p><a href="http://www.mcedit.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.mcedit.net/</span></a></p></body></html> From 16d378687c24f9572b70c96ffd81e4b7f710777b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 16 Feb 2014 14:53:03 +0100 Subject: [PATCH 18/19] Fix some external tool related string sin the settings dialog. --- gui/dialogs/SettingsDialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp index 4b0b117d..fd67b22f 100644 --- a/gui/dialogs/SettingsDialog.cpp +++ b/gui/dialogs/SettingsDialog.cpp @@ -593,7 +593,7 @@ void SettingsDialog::on_jvisualvmPathBtn_clicked() if (!MMC->profilers()["jvisualvm"]->check(cooked_dir, &error)) { QMessageBox::critical(this, tr("Error"), - tr("Error while checking MCEdit install:\n%1").arg(error)); + tr("Error while checking JVisualVM install:\n%1").arg(error)); continue; } else @@ -623,7 +623,7 @@ void SettingsDialog::on_mceditPathBtn_clicked() QString error; do { - raw_dir = QFileDialog::getExistingDirectory(this, tr("MCEdit Path"), raw_dir); + raw_dir = QFileDialog::getExistingDirectory(this, tr("MCEdit Directory"), raw_dir); if (raw_dir.isEmpty()) { break; From a354e8bfae812b23b85b65c4a5b7e860cb18080c Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Fri, 21 Feb 2014 20:13:12 +0100 Subject: [PATCH 19/19] Fix MCEdit on OSX --- gui/dialogs/SettingsDialog.cpp | 5 +++++ logic/tools/MCEditTool.cpp | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp index fd67b22f..d79bb558 100644 --- a/gui/dialogs/SettingsDialog.cpp +++ b/gui/dialogs/SettingsDialog.cpp @@ -623,7 +623,12 @@ void SettingsDialog::on_mceditPathBtn_clicked() QString error; do { +#ifdef Q_OS_OSX +#warning stuff + raw_dir = QFileDialog::getOpenFileName(this, tr("MCEdit Application"), raw_dir); +#else raw_dir = QFileDialog::getExistingDirectory(this, tr("MCEdit Directory"), raw_dir); +#endif if (raw_dir.isEmpty()) { break; diff --git a/logic/tools/MCEditTool.cpp b/logic/tools/MCEditTool.cpp index c4edece5..e22a5d4a 100644 --- a/logic/tools/MCEditTool.cpp +++ b/logic/tools/MCEditTool.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include "settingsobject.h" #include "logic/BaseInstance.h" @@ -20,6 +22,13 @@ void MCEditTool::runImpl() { return; } +#ifdef Q_OS_OSX + QProcess *process = new QProcess(); + connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), process, SLOT(deleteLater())); + process->setProgram(mceditPath); + process->setArguments(QStringList() << save); + process->start(); +#else QDir mceditDir(mceditPath); QString program; if (mceditDir.exists("mcedit.py")) @@ -31,6 +40,7 @@ void MCEditTool::runImpl() program = mceditDir.absoluteFilePath("mcedit.exe"); } QProcess::startDetached(program, QStringList() << save, mceditPath); +#endif } void MCEditFactory::registerSettings(SettingsObject *settings) @@ -58,9 +68,9 @@ bool MCEditFactory::check(const QString &path, QString *error) *error = QObject::tr("Path does not exist"); return false; } - if (!dir.exists("mcedit.py") && !dir.exists("mcedit.exe")) + if (!dir.exists("mcedit.py") && !dir.exists("mcedit.exe") && !dir.exists("Contents")) { - *error = QObject::tr("Path does not contain mcedit.py"); + *error = QObject::tr("Path does not seem to be a MCEdit path"); return false; } return true;