forked from qt-creator/qt-creator
TaskProgress: Improve fluency of progress
Change-Id: I8efb0242c035223bb52cb2684a30b57f44b489f2 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -9,18 +9,33 @@
|
|||||||
#include <utils/tasktree.h>
|
#include <utils/tasktree.h>
|
||||||
|
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QtMath>
|
||||||
|
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
static const int ProgressResolution = 100; // 100 discrete values
|
||||||
|
static const int TimerInterval = 100; // 100 ms
|
||||||
|
|
||||||
class TaskProgressPrivate : public QObject
|
class TaskProgressPrivate : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit TaskProgressPrivate(TaskProgress *progress, TaskTree *taskTree);
|
explicit TaskProgressPrivate(TaskProgress *progress, TaskTree *taskTree);
|
||||||
~TaskProgressPrivate();
|
~TaskProgressPrivate();
|
||||||
|
|
||||||
|
void advanceTick();
|
||||||
|
void advanceProgress(int newValue);
|
||||||
|
void updateProgress();
|
||||||
|
|
||||||
|
int m_currentTick = 0;
|
||||||
|
int m_expectedTime = 1; // 1 second
|
||||||
|
|
||||||
|
int m_currentProgress = 0; // from TaskTree (max value = task count)
|
||||||
|
|
||||||
TaskTree *m_taskTree = nullptr;
|
TaskTree *m_taskTree = nullptr;
|
||||||
|
QTimer m_timer;
|
||||||
QFutureWatcher<void> m_watcher;
|
QFutureWatcher<void> m_watcher;
|
||||||
QFutureInterface<void> m_futureInterface;
|
QFutureInterface<void> m_futureInterface;
|
||||||
QString m_displayName;
|
QString m_displayName;
|
||||||
@@ -29,7 +44,10 @@ public:
|
|||||||
TaskProgressPrivate::TaskProgressPrivate(TaskProgress *progress, TaskTree *taskTree)
|
TaskProgressPrivate::TaskProgressPrivate(TaskProgress *progress, TaskTree *taskTree)
|
||||||
: QObject(progress)
|
: QObject(progress)
|
||||||
, m_taskTree(taskTree)
|
, m_taskTree(taskTree)
|
||||||
|
, m_timer(progress)
|
||||||
{
|
{
|
||||||
|
m_timer.setInterval(TimerInterval);
|
||||||
|
connect(&m_timer, &QTimer::timeout, &m_timer, [this] { advanceTick(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskProgressPrivate::~TaskProgressPrivate()
|
TaskProgressPrivate::~TaskProgressPrivate()
|
||||||
@@ -42,6 +60,30 @@ TaskProgressPrivate::~TaskProgressPrivate()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TaskProgressPrivate::advanceTick()
|
||||||
|
{
|
||||||
|
++m_currentTick;
|
||||||
|
updateProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskProgressPrivate::advanceProgress(int newValue)
|
||||||
|
{
|
||||||
|
m_currentProgress = newValue;
|
||||||
|
m_currentTick = 0;
|
||||||
|
updateProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskProgressPrivate::updateProgress()
|
||||||
|
{
|
||||||
|
// This maps expectation to atan(1) to Pi/4 ~= 0.78, i.e. snaps
|
||||||
|
// from 78% to 100% when expectations are met at the time the
|
||||||
|
// future finishes. That's not bad for a random choice.
|
||||||
|
const double mapped = atan2(double(m_currentTick) * TimerInterval / 1000.0,
|
||||||
|
double(m_expectedTime));
|
||||||
|
const double progress = ProgressResolution * 2 * mapped / M_PI;
|
||||||
|
m_futureInterface.setProgressValue(ProgressResolution * m_currentProgress + progress);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class Core::TaskProgress
|
\class Core::TaskProgress
|
||||||
|
|
||||||
@@ -60,20 +102,25 @@ TaskProgress::TaskProgress(TaskTree *taskTree)
|
|||||||
});
|
});
|
||||||
connect(d->m_taskTree, &TaskTree::started, this, [this] {
|
connect(d->m_taskTree, &TaskTree::started, this, [this] {
|
||||||
d->m_futureInterface = QFutureInterface<void>();
|
d->m_futureInterface = QFutureInterface<void>();
|
||||||
d->m_futureInterface.setProgressRange(0, d->m_taskTree->progressMaximum());
|
d->m_futureInterface.setProgressRange(
|
||||||
|
0, d->m_taskTree->progressMaximum() * ProgressResolution);
|
||||||
d->m_watcher.setFuture(d->m_futureInterface.future());
|
d->m_watcher.setFuture(d->m_futureInterface.future());
|
||||||
d->m_futureInterface.reportStarted();
|
d->m_futureInterface.reportStarted();
|
||||||
|
d->advanceProgress(0);
|
||||||
|
|
||||||
const auto id = Id::fromString(d->m_displayName + ".action");
|
const auto id = Id::fromString(d->m_displayName + ".action");
|
||||||
ProgressManager::addTask(d->m_futureInterface.future(), d->m_displayName, id);
|
ProgressManager::addTask(d->m_futureInterface.future(), d->m_displayName, id);
|
||||||
|
d->m_timer.start();
|
||||||
});
|
});
|
||||||
connect(d->m_taskTree, &TaskTree::progressValueChanged, this, [this](int value) {
|
connect(d->m_taskTree, &TaskTree::progressValueChanged, this, [this](int value) {
|
||||||
d->m_futureInterface.setProgressValue(value);
|
d->advanceProgress(value);
|
||||||
});
|
});
|
||||||
connect(d->m_taskTree, &TaskTree::done, this, [this] {
|
connect(d->m_taskTree, &TaskTree::done, this, [this] {
|
||||||
|
d->m_timer.stop();
|
||||||
d->m_futureInterface.reportFinished();
|
d->m_futureInterface.reportFinished();
|
||||||
});
|
});
|
||||||
connect(d->m_taskTree, &TaskTree::errorOccurred, this, [this] {
|
connect(d->m_taskTree, &TaskTree::errorOccurred, this, [this] {
|
||||||
|
d->m_timer.stop();
|
||||||
d->m_futureInterface.reportCanceled();
|
d->m_futureInterface.reportCanceled();
|
||||||
d->m_futureInterface.reportFinished();
|
d->m_futureInterface.reportFinished();
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user