forked from qt-creator/qt-creator
TaskTree: Implement simple progress reporting
The progressMaximum is the number of tasks in tree. The progressValueChanged signal is emitted whenever task is done (advance by one) or when some number of tasks were skipped or stopped due to workflow policy or dynamic setup group handler. Change-Id: I403059a6466ae0534ef647c3c1c61c0318f10325 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -84,12 +84,12 @@ public:
|
|||||||
const TaskItem &task);
|
const TaskItem &task);
|
||||||
~TaskContainer();
|
~TaskContainer();
|
||||||
void start();
|
void start();
|
||||||
void selectChildren();
|
int selectChildren(); // returns the skipped child count
|
||||||
void stop();
|
void stop();
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
int taskCount() const;
|
int taskCount() const;
|
||||||
void childDone(bool success);
|
void childDone(bool success);
|
||||||
void invokeEndHandler(bool success);
|
void invokeEndHandler(bool success, bool propagateToParent = true);
|
||||||
void resetSuccessBit();
|
void resetSuccessBit();
|
||||||
void updateSuccessBit(bool success);
|
void updateSuccessBit(bool success);
|
||||||
|
|
||||||
@@ -135,11 +135,46 @@ public:
|
|||||||
: q(taskTree)
|
: q(taskTree)
|
||||||
, m_root(this, nullptr, root) {}
|
, m_root(this, nullptr, root) {}
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
m_progressValue = 0;
|
||||||
|
emitStartedAndProgress();
|
||||||
|
m_root.start();
|
||||||
|
}
|
||||||
|
void stop() {
|
||||||
|
if (!m_root.isRunning())
|
||||||
|
return;
|
||||||
|
// TODO: should we have canceled flag (passed to handler)?
|
||||||
|
// Just one done handler with result flag:
|
||||||
|
// FinishedWithSuccess, FinishedWithError, Canceled, TimedOut.
|
||||||
|
// Canceled either directly by user, or by workflow policy - doesn't matter, in both
|
||||||
|
// cases canceled from outside.
|
||||||
|
m_root.stop();
|
||||||
|
emitError();
|
||||||
|
}
|
||||||
|
void advanceProgress(int byValue) {
|
||||||
|
if (byValue == 0)
|
||||||
|
return;
|
||||||
|
QTC_CHECK(byValue > 0);
|
||||||
|
QTC_CHECK(m_progressValue + byValue <= m_root.taskCount());
|
||||||
|
m_progressValue += byValue;
|
||||||
|
emitProgress();
|
||||||
|
}
|
||||||
|
void emitStartedAndProgress() {
|
||||||
|
GuardLocker locker(m_guard);
|
||||||
|
emit q->started();
|
||||||
|
emit q->progressValueChanged(m_progressValue);
|
||||||
|
}
|
||||||
|
void emitProgress() {
|
||||||
|
GuardLocker locker(m_guard);
|
||||||
|
emit q->progressValueChanged(m_progressValue);
|
||||||
|
}
|
||||||
void emitDone() {
|
void emitDone() {
|
||||||
|
QTC_CHECK(m_progressValue == m_root.taskCount());
|
||||||
GuardLocker locker(m_guard);
|
GuardLocker locker(m_guard);
|
||||||
emit q->done();
|
emit q->done();
|
||||||
}
|
}
|
||||||
void emitError() {
|
void emitError() {
|
||||||
|
QTC_CHECK(m_progressValue == m_root.taskCount());
|
||||||
GuardLocker locker(m_guard);
|
GuardLocker locker(m_guard);
|
||||||
emit q->errorOccurred();
|
emit q->errorOccurred();
|
||||||
}
|
}
|
||||||
@@ -147,6 +182,7 @@ public:
|
|||||||
TaskTree *q = nullptr;
|
TaskTree *q = nullptr;
|
||||||
TaskNode m_root;
|
TaskNode m_root;
|
||||||
Guard m_guard;
|
Guard m_guard;
|
||||||
|
int m_progressValue = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
TaskContainer::TaskContainer(TaskTreePrivate *taskTreePrivate, TaskContainer *parentContainer,
|
TaskContainer::TaskContainer(TaskTreePrivate *taskTreePrivate, TaskContainer *parentContainer,
|
||||||
@@ -172,6 +208,7 @@ TaskContainer::~TaskContainer()
|
|||||||
|
|
||||||
void TaskContainer::start()
|
void TaskContainer::start()
|
||||||
{
|
{
|
||||||
|
m_currentIndex = 0;
|
||||||
m_groupConfig = {};
|
m_groupConfig = {};
|
||||||
m_selectedChildren.clear();
|
m_selectedChildren.clear();
|
||||||
|
|
||||||
@@ -187,11 +224,14 @@ void TaskContainer::start()
|
|||||||
|
|
||||||
if (m_groupConfig.action == GroupAction::StopWithDone || m_groupConfig.action == GroupAction::StopWithError) {
|
if (m_groupConfig.action == GroupAction::StopWithDone || m_groupConfig.action == GroupAction::StopWithError) {
|
||||||
const bool success = m_groupConfig.action == GroupAction::StopWithDone;
|
const bool success = m_groupConfig.action == GroupAction::StopWithDone;
|
||||||
|
const int skippedTaskCount = taskCount();
|
||||||
|
m_taskTreePrivate->advanceProgress(skippedTaskCount);
|
||||||
invokeEndHandler(success);
|
invokeEndHandler(success);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectChildren();
|
const int skippedTaskCount = selectChildren();
|
||||||
|
m_taskTreePrivate->advanceProgress(skippedTaskCount);
|
||||||
|
|
||||||
if (m_selectedChildren.isEmpty()) {
|
if (m_selectedChildren.isEmpty()) {
|
||||||
invokeEndHandler(true);
|
invokeEndHandler(true);
|
||||||
@@ -213,21 +253,35 @@ void TaskContainer::start()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskContainer::selectChildren()
|
int TaskContainer::selectChildren()
|
||||||
{
|
{
|
||||||
if (m_groupConfig.action != GroupAction::ContinueSelected) {
|
if (m_groupConfig.action != GroupAction::ContinueSelected) {
|
||||||
m_selectedChildren = m_children;
|
m_selectedChildren = m_children;
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
m_selectedChildren.clear();
|
m_selectedChildren.clear();
|
||||||
|
int skippedTaskCount = 0;
|
||||||
for (int i = 0; i < m_children.size(); ++i) {
|
for (int i = 0; i < m_children.size(); ++i) {
|
||||||
if (m_groupConfig.childrenToRun.contains(i))
|
if (m_groupConfig.childrenToRun.contains(i))
|
||||||
m_selectedChildren.append(m_children.at(i));
|
m_selectedChildren.append(m_children.at(i));
|
||||||
|
else
|
||||||
|
skippedTaskCount += m_children.at(i)->taskCount();
|
||||||
}
|
}
|
||||||
|
return skippedTaskCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskContainer::stop()
|
void TaskContainer::stop()
|
||||||
{
|
{
|
||||||
|
if (!isRunning())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_executeMode == TaskItem::ExecuteMode::Sequential) {
|
||||||
|
int skippedTaskCount = 0;
|
||||||
|
for (int i = m_currentIndex + 1; i < m_selectedChildren.size(); ++i)
|
||||||
|
skippedTaskCount += m_selectedChildren.at(i)->taskCount();
|
||||||
|
m_taskTreePrivate->advanceProgress(skippedTaskCount);
|
||||||
|
}
|
||||||
|
|
||||||
m_currentIndex = -1;
|
m_currentIndex = -1;
|
||||||
for (TaskNode *child : std::as_const(m_selectedChildren))
|
for (TaskNode *child : std::as_const(m_selectedChildren))
|
||||||
child->stop();
|
child->stop();
|
||||||
@@ -264,7 +318,7 @@ void TaskContainer::childDone(bool success)
|
|||||||
m_selectedChildren.at(m_currentIndex)->start();
|
m_selectedChildren.at(m_currentIndex)->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskContainer::invokeEndHandler(bool success)
|
void TaskContainer::invokeEndHandler(bool success, bool propagateToParent)
|
||||||
{
|
{
|
||||||
m_currentIndex = -1;
|
m_currentIndex = -1;
|
||||||
m_successBit = success;
|
m_successBit = success;
|
||||||
@@ -275,6 +329,10 @@ void TaskContainer::invokeEndHandler(bool success)
|
|||||||
GuardLocker locker(m_taskTreePrivate->m_guard);
|
GuardLocker locker(m_taskTreePrivate->m_guard);
|
||||||
m_groupHandler.m_errorHandler();
|
m_groupHandler.m_errorHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!propagateToParent)
|
||||||
|
return;
|
||||||
|
|
||||||
if (m_parentContainer) {
|
if (m_parentContainer) {
|
||||||
m_parentContainer->childDone(success);
|
m_parentContainer->childDone(success);
|
||||||
return;
|
return;
|
||||||
@@ -329,6 +387,7 @@ bool TaskNode::start()
|
|||||||
GuardLocker locker(m_container.m_taskTreePrivate->m_guard);
|
GuardLocker locker(m_container.m_taskTreePrivate->m_guard);
|
||||||
m_taskHandler.m_errorHandler(*m_task.get());
|
m_taskHandler.m_errorHandler(*m_task.get());
|
||||||
}
|
}
|
||||||
|
m_container.m_taskTreePrivate->advanceProgress(1);
|
||||||
|
|
||||||
m_task.release()->deleteLater();
|
m_task.release()->deleteLater();
|
||||||
|
|
||||||
@@ -342,8 +401,23 @@ bool TaskNode::start()
|
|||||||
|
|
||||||
void TaskNode::stop()
|
void TaskNode::stop()
|
||||||
{
|
{
|
||||||
m_task.reset();
|
if (!isRunning())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_task) {
|
||||||
m_container.stop();
|
m_container.stop();
|
||||||
|
m_container.invokeEndHandler(false, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: cancelHandler?
|
||||||
|
// TODO: call TaskInterface::stop() ?
|
||||||
|
if (m_taskHandler.m_errorHandler) {
|
||||||
|
GuardLocker locker(m_container.m_taskTreePrivate->m_guard);
|
||||||
|
m_taskHandler.m_errorHandler(*m_task.get());
|
||||||
|
}
|
||||||
|
m_container.m_taskTreePrivate->advanceProgress(1);
|
||||||
|
m_task.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TaskNode::isRunning() const
|
bool TaskNode::isRunning() const
|
||||||
@@ -422,14 +496,14 @@ void TaskTree::start()
|
|||||||
QTC_ASSERT(!isRunning(), qWarning("The TaskTree is already running, ignoring..."); return);
|
QTC_ASSERT(!isRunning(), qWarning("The TaskTree is already running, ignoring..."); return);
|
||||||
QTC_ASSERT(!d->m_guard.isLocked(), qWarning("The start() is called from one of the"
|
QTC_ASSERT(!d->m_guard.isLocked(), qWarning("The start() is called from one of the"
|
||||||
"TaskTree handlers, ingoring..."); return);
|
"TaskTree handlers, ingoring..."); return);
|
||||||
d->m_root.start();
|
d->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskTree::stop()
|
void TaskTree::stop()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!d->m_guard.isLocked(), qWarning("The stop() is called from one of the"
|
QTC_ASSERT(!d->m_guard.isLocked(), qWarning("The stop() is called from one of the"
|
||||||
"TaskTree handlers, ingoring..."); return);
|
"TaskTree handlers, ingoring..."); return);
|
||||||
d->m_root.stop();
|
d->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TaskTree::isRunning() const
|
bool TaskTree::isRunning() const
|
||||||
@@ -442,4 +516,9 @@ int TaskTree::taskCount() const
|
|||||||
return d->m_root.taskCount();
|
return d->m_root.taskCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TaskTree::progressValue() const
|
||||||
|
{
|
||||||
|
return d->m_progressValue;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|||||||
@@ -246,10 +246,14 @@ public:
|
|||||||
void stop();
|
void stop();
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
int taskCount() const;
|
int taskCount() const;
|
||||||
|
int progressMaximum() const { return taskCount(); }
|
||||||
|
int progressValue() const; // all finished / skipped / stopped tasks, groups itself excluded
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void started();
|
||||||
void done();
|
void done();
|
||||||
void errorOccurred();
|
void errorOccurred();
|
||||||
|
void progressValueChanged(int value); // updated whenever task finished / skipped / stopped
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TaskTreePrivate *d;
|
TaskTreePrivate *d;
|
||||||
|
|||||||
@@ -470,6 +470,7 @@ void tst_TaskTree::processTree()
|
|||||||
eventLoop.exec();
|
eventLoop.exec();
|
||||||
|
|
||||||
QVERIFY(!processTree.isRunning());
|
QVERIFY(!processTree.isRunning());
|
||||||
|
QCOMPARE(processTree.progressValue(), taskCount);
|
||||||
QCOMPARE(m_log, expectedLog);
|
QCOMPARE(m_log, expectedLog);
|
||||||
|
|
||||||
const int expectedDoneCount = success ? 1 : 0;
|
const int expectedDoneCount = success ? 1 : 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user