diff --git a/api/logic/launch/LaunchTask.cpp b/api/logic/launch/LaunchTask.cpp index ea4ed43e..8d9596ec 100644 --- a/api/logic/launch/LaunchTask.cpp +++ b/api/logic/launch/LaunchTask.cpp @@ -150,6 +150,26 @@ void LaunchTask::proceed() m_steps[currentStep]->proceed(); } +bool LaunchTask::canAbort() const +{ + switch(state) + { + case LaunchTask::Aborted: + case LaunchTask::Failed: + case LaunchTask::Finished: + return false; + case LaunchTask::NotStarted: + return true; + case LaunchTask::Running: + case LaunchTask::Waiting: + { + auto step = m_steps[currentStep]; + return step->canAbort(); + } + } + return false; +} + bool LaunchTask::abort() { switch(state) diff --git a/api/logic/launch/LaunchTask.h b/api/logic/launch/LaunchTask.h index 981e25cf..e74620c7 100644 --- a/api/logic/launch/LaunchTask.h +++ b/api/logic/launch/LaunchTask.h @@ -80,7 +80,9 @@ public: /* methods */ /** * @brief abort launch */ - virtual bool abort() override; + bool abort() override; + + bool canAbort() const override; shared_qobject_ptr getLogModel(); diff --git a/application/InstanceWindow.cpp b/application/InstanceWindow.cpp index e3d4af66..b88048a8 100644 --- a/application/InstanceWindow.cpp +++ b/application/InstanceWindow.cpp @@ -168,18 +168,9 @@ void InstanceWindow::on_btnKillMinecraft_clicked() { if(m_instance->isRunning()) { - auto response = CustomMessageBox::selectable( - this, tr("Kill Minecraft?"), - tr("This can cause the instance to get corrupted and should only be used if Minecraft " - "is frozen for some reason"), - QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)->exec(); - if (response == QMessageBox::Yes) - { - m_proc->abort(); - } + MMC->kill(m_instance); } - // FIXME: duplicate logic between MainWindow and InstanceWindow - else if(saveAll()) + else { MMC->launch(m_instance, true, nullptr); } diff --git a/application/LaunchController.cpp b/application/LaunchController.cpp index eaeb9b28..62e582d8 100644 --- a/application/LaunchController.cpp +++ b/application/LaunchController.cpp @@ -288,3 +288,25 @@ void LaunchController::onProgressRequested(Task* task) m_launcher->proceed(); progDialog.execWithTask(task); } + +bool LaunchController::abort() +{ + if(!m_launcher) + { + return true; + } + if(!m_launcher->canAbort()) + { + return false; + } + auto response = CustomMessageBox::selectable( + m_parentWidget, tr("Kill Minecraft?"), + tr("This can cause the instance to get corrupted and should only be used if Minecraft " + "is frozen for some reason"), + QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)->exec(); + if (response == QMessageBox::Yes) + { + return m_launcher->abort(); + } + return false; +} diff --git a/application/LaunchController.h b/application/LaunchController.h index 81f3a0ab..84c65743 100644 --- a/application/LaunchController.h +++ b/application/LaunchController.h @@ -8,7 +8,7 @@ class LaunchController: public Task { Q_OBJECT public: - virtual void executeTask(); + void executeTask() override; LaunchController(QObject * parent = nullptr); virtual ~LaunchController(){}; @@ -37,6 +37,7 @@ public: { return m_instance->id(); } + bool abort() override; private: void login(); diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp index 4e649521..7b957c70 100644 --- a/application/MainWindow.cpp +++ b/application/MainWindow.cpp @@ -130,6 +130,26 @@ public: QStatusBar *statusBar; QToolBar *instanceToolBar; QToolBar *newsToolBar; + bool m_kill = false; + + void updateLaunchAction() + { + if(m_kill) + { + actionLaunchInstance->setText(tr("Kill")); + actionLaunchInstance->setToolTip(tr("Kill the running instance")); + } + else + { + actionLaunchInstance->setText(tr("Launch")); + actionLaunchInstance->setToolTip(tr("Launch the selected instance.")); + } + } + void setLaunchAction(bool kill) + { + m_kill = kill; + updateLaunchAction(); + } void setupUi(QMainWindow *MainWindow) { @@ -279,13 +299,13 @@ public: instanceToolBar->addAction(actionChangeInstIcon); instanceToolBar->addAction(actionLaunchInstance); instanceToolBar->addAction(actionLaunchInstanceOffline); - instanceToolBar->addAction(actionChangeInstGroup); instanceToolBar->addSeparator(); instanceToolBar->addAction(actionEditInstance); instanceToolBar->addAction(actionInstanceSettings); instanceToolBar->addAction(actionEditInstNotes); instanceToolBar->addAction(actionWorlds); instanceToolBar->addAction(actionScreenshots); + instanceToolBar->addAction(actionChangeInstGroup); instanceToolBar->addSeparator(); instanceToolBar->addAction(actionViewSelectedInstFolder); instanceToolBar->addAction(actionConfig_Folder); @@ -325,8 +345,7 @@ public: actionMoreNews->setToolTip(tr("Open the MultiMC development blog to read more news about MultiMC.")); actionAbout->setText(tr("About MultiMC")); actionAbout->setToolTip(tr("View information about MultiMC.")); - actionLaunchInstance->setText(tr("Play")); - actionLaunchInstance->setToolTip(tr("Launch the selected instance.")); + updateLaunchAction(); actionRenameInstance->setText(tr("Instance Name")); actionRenameInstance->setToolTip(tr("Rename the selected instance.")); actionChangeInstGroup->setText(tr("Change Group")); @@ -355,7 +374,7 @@ public: actionCopyInstance->setToolTip(tr("Copy the selected instance.")); actionManageAccounts->setText(tr("Manage Accounts")); actionManageAccounts->setToolTip(tr("Manage your Mojang or Minecraft accounts.")); - actionLaunchInstanceOffline->setText(tr("Play Offline")); + actionLaunchInstanceOffline->setText(tr("Launch Offline")); actionLaunchInstanceOffline->setToolTip(tr("Launch the selected instance in offline mode.")); actionScreenshots->setText(tr("Manage Screenshots")); actionScreenshots->setToolTip(tr("View and upload screenshots for this instance.")); @@ -662,8 +681,15 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos) void MainWindow::updateToolsMenu() { - QMenu *launchMenu = ui->actionLaunchInstance->menu(); QToolButton *launchButton = dynamic_cast(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstance)); + if(m_selectedInstance->isRunning()) + { + ui->actionLaunchInstance->setMenu(nullptr); + launchButton->setPopupMode(QToolButton::InstantPopup); + return; + } + + QMenu *launchMenu = ui->actionLaunchInstance->menu(); launchButton->setPopupMode(QToolButton::MenuButtonPopup); if (launchMenu) { @@ -837,7 +863,7 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *ev) { case Qt::Key_Enter: case Qt::Key_Return: - on_actionLaunchInstance_triggered(); + activateInstance(m_selectedInstance); return true; case Qt::Key_Delete: on_actionDeleteInstance_triggered(); @@ -1412,17 +1438,30 @@ void MainWindow::instanceActivated(QModelIndex index) if (!inst) return; - MMC->launch(inst); + activateInstance(inst); } void MainWindow::on_actionLaunchInstance_triggered() { - if (m_selectedInstance) + if (!m_selectedInstance) + { + return; + } + if(m_selectedInstance->isRunning()) + { + MMC->kill(m_selectedInstance); + } + else { MMC->launch(m_selectedInstance); } } +void MainWindow::activateInstance(InstancePtr instance) +{ + MMC->launch(instance); +} + void MainWindow::on_actionLaunchInstanceOffline_triggered() { if (m_selectedInstance) @@ -1460,7 +1499,16 @@ void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex & if (m_selectedInstance) { ui->instanceToolBar->setEnabled(true); - ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch()); + if(m_selectedInstance->isRunning()) + { + ui->actionLaunchInstance->setEnabled(true); + ui->setLaunchAction(true); + } + else + { + ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch()); + ui->setLaunchAction(false); + } ui->actionLaunchInstanceOffline->setEnabled(m_selectedInstance->canLaunch()); ui->actionExportInstance->setEnabled(m_selectedInstance->canExport()); renameButton->setText(m_selectedInstance->name()); diff --git a/application/MainWindow.h b/application/MainWindow.h index 3ee03a7f..459c17c2 100644 --- a/application/MainWindow.h +++ b/application/MainWindow.h @@ -162,6 +162,7 @@ private slots: void downloadUpdates(GoUpdate::Status status); private: + void activateInstance(InstancePtr instance); void setCatBackground(bool enabled); void updateInstanceToolIcon(QString new_icon); void setSelectedInstanceById(const QString &id); diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 93f7a33f..49c1d2c4 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -877,7 +877,7 @@ bool MultiMC::openJsonEditor(const QString &filename) } } -void MultiMC::launch(InstancePtr instance, bool online, BaseProfilerFactory *profiler) +bool MultiMC::launch(InstancePtr instance, bool online, BaseProfilerFactory *profiler) { if(instance->canLaunch()) { @@ -887,7 +887,7 @@ void MultiMC::launch(InstancePtr instance, bool online, BaseProfilerFactory *pro { if(!window->saveAll()) { - return; + return false; } } auto & controller = extras.controller; @@ -907,13 +907,33 @@ void MultiMC::launch(InstancePtr instance, bool online, BaseProfilerFactory *pro connect(controller.get(), &LaunchController::failed, this, &MultiMC::controllerFailed); controller->start(); m_runningInstances ++; + return true; } else if (instance->isRunning()) { showInstanceWindow(instance, "console"); + return true; } + return false; } +bool MultiMC::kill(InstancePtr instance) +{ + if (!instance->isRunning()) + { + qWarning() << "Attempted to kill instance" << instance->id() << "which isn't running."; + return false; + } + auto & extras = m_instanceExtras[instance->id()]; + auto & controller = extras.controller; + if(controller) + { + return controller->abort(); + } + return true; +} + + void MultiMC::controllerSucceeded() { auto controller = qobject_cast(QObject::sender()); diff --git a/application/MultiMC.h b/application/MultiMC.h index ae0ed531..9c9d0c8a 100644 --- a/application/MultiMC.h +++ b/application/MultiMC.h @@ -148,7 +148,8 @@ public: } public slots: - void launch(InstancePtr instance, bool online = true, BaseProfilerFactory *profiler = nullptr); + bool launch(InstancePtr instance, bool online = true, BaseProfilerFactory *profiler = nullptr); + bool kill(InstancePtr instance); private slots: /**