feat: Use a single progress dialog when doing multiple tasks
This puts all mod downloading tasks inside a SequentialTask, which is, for more than one task, a multi step task. This is handled by the ProgressDialog by showing both the global progress of tasks executed, and the individual progress of each of them.
This commit is contained in:
parent
e22d54abd3
commit
9b8493c304
@ -1,7 +1,23 @@
|
|||||||
#include "SequentialTask.h"
|
#include "SequentialTask.h"
|
||||||
|
|
||||||
SequentialTask::SequentialTask(QObject *parent) : Task(parent), m_currentIndex(-1)
|
SequentialTask::SequentialTask(QObject* parent, const QString& task_name) : Task(parent), m_name(task_name), m_currentIndex(-1) {}
|
||||||
|
|
||||||
|
SequentialTask::~SequentialTask()
|
||||||
{
|
{
|
||||||
|
for(auto task : m_queue){
|
||||||
|
if(task)
|
||||||
|
task->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SequentialTask::getStepProgress() const -> qint64
|
||||||
|
{
|
||||||
|
return m_stepProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SequentialTask::getStepTotalProgress() const -> qint64
|
||||||
|
{
|
||||||
|
return m_stepTotalProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SequentialTask::addTask(Task::Ptr task)
|
void SequentialTask::addTask(Task::Ptr task)
|
||||||
@ -15,16 +31,24 @@ void SequentialTask::executeTask()
|
|||||||
startNext();
|
startNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SequentialTask::abort()
|
||||||
|
{
|
||||||
|
bool succeeded = true;
|
||||||
|
for (auto& task : m_queue) {
|
||||||
|
if (!task->abort()) succeeded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return succeeded;
|
||||||
|
}
|
||||||
|
|
||||||
void SequentialTask::startNext()
|
void SequentialTask::startNext()
|
||||||
{
|
{
|
||||||
if (m_currentIndex != -1)
|
if (m_currentIndex != -1) {
|
||||||
{
|
|
||||||
Task::Ptr previous = m_queue[m_currentIndex];
|
Task::Ptr previous = m_queue[m_currentIndex];
|
||||||
disconnect(previous.get(), 0, this, 0);
|
disconnect(previous.get(), 0, this, 0);
|
||||||
}
|
}
|
||||||
m_currentIndex++;
|
m_currentIndex++;
|
||||||
if (m_queue.isEmpty() || m_currentIndex >= m_queue.size())
|
if (m_queue.isEmpty() || m_currentIndex >= m_queue.size()) {
|
||||||
{
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -33,23 +57,27 @@ void SequentialTask::startNext()
|
|||||||
connect(next.get(), SIGNAL(status(QString)), this, SLOT(subTaskStatus(QString)));
|
connect(next.get(), SIGNAL(status(QString)), this, SLOT(subTaskStatus(QString)));
|
||||||
connect(next.get(), SIGNAL(progress(qint64, qint64)), this, SLOT(subTaskProgress(qint64, qint64)));
|
connect(next.get(), SIGNAL(progress(qint64, qint64)), this, SLOT(subTaskProgress(qint64, qint64)));
|
||||||
connect(next.get(), SIGNAL(succeeded()), this, SLOT(startNext()));
|
connect(next.get(), SIGNAL(succeeded()), this, SLOT(startNext()));
|
||||||
|
|
||||||
|
setStatus(tr("Executing task %1 out of %2").arg(m_currentIndex + 1).arg(m_queue.size()));
|
||||||
next->start();
|
next->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SequentialTask::subTaskFailed(const QString &msg)
|
void SequentialTask::subTaskFailed(const QString& msg)
|
||||||
{
|
{
|
||||||
emitFailed(msg);
|
emitFailed(msg);
|
||||||
}
|
}
|
||||||
void SequentialTask::subTaskStatus(const QString &msg)
|
void SequentialTask::subTaskStatus(const QString& msg)
|
||||||
{
|
{
|
||||||
setStatus(msg);
|
setStepStatus(m_queue[m_currentIndex]->getStatus());
|
||||||
}
|
}
|
||||||
void SequentialTask::subTaskProgress(qint64 current, qint64 total)
|
void SequentialTask::subTaskProgress(qint64 current, qint64 total)
|
||||||
{
|
{
|
||||||
if(total == 0)
|
if (total == 0) {
|
||||||
{
|
|
||||||
setProgress(0, 100);
|
setProgress(0, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setProgress(current, total);
|
setProgress(m_currentIndex, m_queue.count());
|
||||||
|
|
||||||
|
m_stepProgress = current;
|
||||||
|
m_stepTotalProgress = total;
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,21 @@ class SequentialTask : public Task
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit SequentialTask(QObject *parent = 0);
|
explicit SequentialTask(QObject *parent = nullptr, const QString& task_name = "");
|
||||||
virtual ~SequentialTask() {};
|
virtual ~SequentialTask();
|
||||||
|
|
||||||
|
inline auto isMultiStep() const -> bool override { return m_queue.size() > 1; };
|
||||||
|
auto getStepProgress() const -> qint64 override;
|
||||||
|
auto getStepTotalProgress() const -> qint64 override;
|
||||||
|
|
||||||
|
inline auto getStepStatus() const -> QString override { return m_step_status; }
|
||||||
|
|
||||||
void addTask(Task::Ptr task);
|
void addTask(Task::Ptr task);
|
||||||
|
|
||||||
protected:
|
protected slots:
|
||||||
void executeTask();
|
void executeTask() override;
|
||||||
|
public slots:
|
||||||
|
bool abort() override;
|
||||||
|
|
||||||
private
|
private
|
||||||
slots:
|
slots:
|
||||||
@ -24,7 +32,19 @@ slots:
|
|||||||
void subTaskStatus(const QString &msg);
|
void subTaskStatus(const QString &msg);
|
||||||
void subTaskProgress(qint64 current, qint64 total);
|
void subTaskProgress(qint64 current, qint64 total);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void stepStatus(QString status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void setStepStatus(QString status) { m_step_status = status; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_name;
|
||||||
|
QString m_step_status;
|
||||||
|
|
||||||
QQueue<Task::Ptr > m_queue;
|
QQueue<Task::Ptr > m_queue;
|
||||||
int m_currentIndex;
|
int m_currentIndex;
|
||||||
|
|
||||||
|
qint64 m_stepProgress = 0;
|
||||||
|
qint64 m_stepTotalProgress = 100;
|
||||||
};
|
};
|
||||||
|
@ -21,29 +21,27 @@
|
|||||||
|
|
||||||
#include "QObjectPtr.h"
|
#include "QObjectPtr.h"
|
||||||
|
|
||||||
class Task : public QObject
|
class Task : public QObject {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
using Ptr = shared_qobject_ptr<Task>;
|
using Ptr = shared_qobject_ptr<Task>;
|
||||||
|
|
||||||
enum class State
|
enum class State { Inactive, Running, Succeeded, Failed, AbortedByUser };
|
||||||
{
|
|
||||||
Inactive,
|
|
||||||
Running,
|
|
||||||
Succeeded,
|
|
||||||
Failed,
|
|
||||||
AbortedByUser
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Task(QObject *parent = 0);
|
explicit Task(QObject* parent = 0);
|
||||||
virtual ~Task() {};
|
virtual ~Task() = default;
|
||||||
|
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
bool isFinished() const;
|
bool isFinished() const;
|
||||||
bool wasSuccessful() const;
|
bool wasSuccessful() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* MultiStep tasks are combinations of multiple tasks into a single logical task.
|
||||||
|
* The main usage of this is in SequencialTask.
|
||||||
|
*/
|
||||||
|
virtual auto isMultiStep() const -> bool { return false; }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns the string that was passed to emitFailed as the error message when the task failed.
|
* Returns the string that was passed to emitFailed as the error message when the task failed.
|
||||||
* If the task hasn't failed, returns an empty string.
|
* If the task hasn't failed, returns an empty string.
|
||||||
@ -54,52 +52,45 @@ public:
|
|||||||
|
|
||||||
virtual bool canAbort() const { return false; }
|
virtual bool canAbort() const { return false; }
|
||||||
|
|
||||||
QString getStatus()
|
QString getStatus() { return m_status; }
|
||||||
{
|
virtual auto getStepStatus() const -> QString { return {}; }
|
||||||
return m_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 getProgress()
|
qint64 getProgress() { return m_progress; }
|
||||||
{
|
qint64 getTotalProgress() { return m_progressTotal; }
|
||||||
return m_progress;
|
virtual auto getStepProgress() const -> qint64 { return 0; }
|
||||||
}
|
virtual auto getStepTotalProgress() const -> qint64 { return 100; }
|
||||||
|
|
||||||
qint64 getTotalProgress()
|
protected:
|
||||||
{
|
void logWarning(const QString& line);
|
||||||
return m_progressTotal;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
void logWarning(const QString & line);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString describe();
|
QString describe();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void started();
|
void started();
|
||||||
void progress(qint64 current, qint64 total);
|
virtual void progress(qint64 current, qint64 total);
|
||||||
void finished();
|
void finished();
|
||||||
void succeeded();
|
void succeeded();
|
||||||
void failed(QString reason);
|
void failed(QString reason);
|
||||||
void status(QString status);
|
void status(QString status);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void start();
|
virtual void start();
|
||||||
virtual bool abort() { return false; };
|
virtual bool abort() { return false; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void executeTask() = 0;
|
virtual void executeTask() = 0;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
virtual void emitSucceeded();
|
virtual void emitSucceeded();
|
||||||
virtual void emitAborted();
|
virtual void emitAborted();
|
||||||
virtual void emitFailed(QString reason);
|
virtual void emitFailed(QString reason);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setStatus(const QString &status);
|
void setStatus(const QString& status);
|
||||||
void setProgress(qint64 current, qint64 total);
|
void setProgress(qint64 current, qint64 total);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
State m_state = State::Inactive;
|
State m_state = State::Inactive;
|
||||||
QStringList m_Warnings;
|
QStringList m_Warnings;
|
||||||
QString m_failReason = "";
|
QString m_failReason = "";
|
||||||
@ -107,4 +98,3 @@ private:
|
|||||||
int m_progress = 0;
|
int m_progress = 0;
|
||||||
int m_progressTotal = 100;
|
int m_progressTotal = 100;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,6 +81,12 @@ int ProgressDialog::execWithTask(Task *task)
|
|||||||
connect(task, SIGNAL(status(QString)), SLOT(changeStatus(const QString &)));
|
connect(task, SIGNAL(status(QString)), SLOT(changeStatus(const QString &)));
|
||||||
connect(task, SIGNAL(progress(qint64, qint64)), SLOT(changeProgress(qint64, qint64)));
|
connect(task, SIGNAL(progress(qint64, qint64)), SLOT(changeProgress(qint64, qint64)));
|
||||||
|
|
||||||
|
m_is_multi_step = task->isMultiStep();
|
||||||
|
if(!m_is_multi_step){
|
||||||
|
ui->globalStatusLabel->setHidden(true);
|
||||||
|
ui->globalProgressBar->setHidden(true);
|
||||||
|
}
|
||||||
|
|
||||||
// if this didn't connect to an already running task, invoke start
|
// if this didn't connect to an already running task, invoke start
|
||||||
if(!task->isRunning())
|
if(!task->isRunning())
|
||||||
{
|
{
|
||||||
@ -152,14 +158,24 @@ void ProgressDialog::onTaskSucceeded()
|
|||||||
|
|
||||||
void ProgressDialog::changeStatus(const QString &status)
|
void ProgressDialog::changeStatus(const QString &status)
|
||||||
{
|
{
|
||||||
ui->statusLabel->setText(status);
|
ui->statusLabel->setText(task->getStepStatus());
|
||||||
|
ui->globalStatusLabel->setText(status);
|
||||||
updateSize();
|
updateSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressDialog::changeProgress(qint64 current, qint64 total)
|
void ProgressDialog::changeProgress(qint64 current, qint64 total)
|
||||||
{
|
{
|
||||||
ui->taskProgressBar->setMaximum(total);
|
ui->globalProgressBar->setMaximum(total);
|
||||||
ui->taskProgressBar->setValue(current);
|
ui->globalProgressBar->setValue(current);
|
||||||
|
|
||||||
|
if(!m_is_multi_step){
|
||||||
|
ui->taskProgressBar->setMaximum(total);
|
||||||
|
ui->taskProgressBar->setValue(current);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ui->taskProgressBar->setMaximum(task->getStepProgress());
|
||||||
|
ui->taskProgressBar->setValue(task->getStepTotalProgress());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressDialog::keyPressEvent(QKeyEvent *e)
|
void ProgressDialog::keyPressEvent(QKeyEvent *e)
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Task;
|
class Task;
|
||||||
|
class SequentialTask;
|
||||||
|
|
||||||
namespace Ui
|
namespace Ui
|
||||||
{
|
{
|
||||||
@ -35,7 +36,7 @@ public:
|
|||||||
|
|
||||||
void updateSize();
|
void updateSize();
|
||||||
|
|
||||||
int execWithTask(Task *task);
|
int execWithTask(Task* task);
|
||||||
int execWithTask(std::unique_ptr<Task> &&task);
|
int execWithTask(std::unique_ptr<Task> &&task);
|
||||||
int execWithTask(std::unique_ptr<Task> &task);
|
int execWithTask(std::unique_ptr<Task> &task);
|
||||||
|
|
||||||
@ -68,4 +69,6 @@ private:
|
|||||||
Ui::ProgressDialog *ui;
|
Ui::ProgressDialog *ui;
|
||||||
|
|
||||||
Task *task;
|
Task *task;
|
||||||
|
|
||||||
|
bool m_is_multi_step = false;
|
||||||
};
|
};
|
||||||
|
@ -2,14 +2,6 @@
|
|||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>ProgressDialog</class>
|
<class>ProgressDialog</class>
|
||||||
<widget class="QDialog" name="ProgressDialog">
|
<widget class="QDialog" name="ProgressDialog">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>400</width>
|
|
||||||
<height>100</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>400</width>
|
<width>400</width>
|
||||||
@ -26,27 +18,7 @@
|
|||||||
<string>Please wait...</string>
|
<string>Please wait...</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QLabel" name="statusLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Task Status...</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QProgressBar" name="taskProgressBar">
|
|
||||||
<property name="value">
|
|
||||||
<number>24</number>
|
|
||||||
</property>
|
|
||||||
<property name="textVisible">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QPushButton" name="skipButton">
|
<widget class="QPushButton" name="skipButton">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
@ -59,6 +31,43 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="globalStatusLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Global Task Status...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="statusLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Task Status...</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QProgressBar" name="taskProgressBar">
|
||||||
|
<property name="value">
|
||||||
|
<number>24</number>
|
||||||
|
</property>
|
||||||
|
<property name="textVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QProgressBar" name="globalProgressBar">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>24</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
|
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
#include "ui/dialogs/ProgressDialog.h"
|
#include "ui/dialogs/ProgressDialog.h"
|
||||||
|
#include "tasks/SequentialTask.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// FIXME: wasteful
|
// FIXME: wasteful
|
||||||
@ -394,25 +395,25 @@ void ModFolderPage::on_actionInstall_mods_triggered()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ModDownloadDialog mdownload(m_mods, this, m_inst);
|
ModDownloadDialog mdownload(m_mods, this, m_inst);
|
||||||
if(mdownload.exec()) {
|
if (mdownload.exec()) {
|
||||||
for(auto task : mdownload.getTasks()){
|
SequentialTask* tasks = new SequentialTask(this);
|
||||||
connect(task, &Task::failed, [this, task](QString reason) {
|
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||||
task->deleteLater();
|
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
tasks->deleteLater();
|
||||||
});
|
});
|
||||||
connect(task, &Task::succeeded, [this, task]() {
|
connect(tasks, &Task::succeeded, [this, tasks]() {
|
||||||
QStringList warnings = task->warnings();
|
QStringList warnings = tasks->warnings();
|
||||||
if (warnings.count()) {
|
if (warnings.count()) { CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show(); }
|
||||||
CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'),
|
tasks->deleteLater();
|
||||||
QMessageBox::Warning)->show();
|
});
|
||||||
}
|
|
||||||
task->deleteLater();
|
for (auto task : mdownload.getTasks()) {
|
||||||
});
|
tasks->addTask(task);
|
||||||
ProgressDialog loadDialog(this);
|
|
||||||
loadDialog.setSkipButton(true, tr("Abort"));
|
|
||||||
loadDialog.execWithTask(task);
|
|
||||||
m_mods->update();
|
|
||||||
}
|
}
|
||||||
|
ProgressDialog loadDialog(this);
|
||||||
|
loadDialog.setSkipButton(true, tr("Abort"));
|
||||||
|
loadDialog.execWithTask(tasks);
|
||||||
|
m_mods->update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user