Remove support for signal based completion/termination
Also unfortunately disable a lot of the test suite as a result,
since it's not easily translatable
Switch from QtConcurrent::run to QThreadPool::start
QtConcurrent doesn't give us anyway to cancel queued but not
started tasks. QThreadPool does (and also allows us to specify
task priority)
Now, a QgsTask can have subtask QgsTasks set by calling
QgsTask::addSubTask. Sub tasks can have their own set of
dependent tasks.
Subtasks are not visible to users, and users only see the overall
progress and status of the parent task.
This allows creation of tasks which are themselves built off
many smaller component tasks. The task manager will still handle
firing up and scheduling the subtasks, so eg subtasks can run
in parallel (if their dependancies allow this).
Subtasks can themselves have subtasks.
This change is designed to allow the processing concept of
algorithms and modeller algorithms to be translatable
directly to the task manager architecture.
called when the task has completed (successfully or otherwise).
This allows for simpler task design when the signal/slot
based approach is not required. Just implement run() with your
heavy lifting, and finished() to do whatever follow up stuff
should happen after the task is complete. finished is always
called from the main thread, so it's safe to do GUI operations
here.
Python based tasks using the simplified QgsTask.fromFunction
approach can now set a on_finished argument to a function
to call when the task is complete.
eg:
def calculate(task):
# pretend this is some complex maths and stuff we want
# to run in the background
return 5*6
def calculation_finished(result, value=None):
if result == QgsTask.ResultSuccess:
iface.messageBar().pushMessage(
'the magic number is {}'.format(value))
elif result == QgsTask.ResultFail:
iface.messageBar().pushMessage(
'couldn\'t work it out, sorry')
task = QgsTask.fromFunction('my task', calculate,
on_finished=calculation_finished)
QgsTaskManager.instance().addTask(task)
Multiple values can also be returned, eg:
def calculate(task):
return (4, 8, 15)
def calculation_finished(result, count=None, max=None, sum=None):
# here:
# count = 4
# max = 8
# sum = 15
task = QgsTask.fromFunction('my task', calculate,
on_finished=calculation_finished)
QgsTaskManager.instance().addTask(task)
QgsTask subclasses can now return a result (success or fail)
directly from QgsTask::run. If they do so then there's no
need for them to manually call completed() or stopped()
to report their completion.
Alternatively, tasks can also return the ResultPending value
to indicate that the task is still operating and will
manually report its completion by calling completed() or
stopped(). This may be useful for tasks which rely on external
events for completion, eg downloading a file. In this case
Qt slots could be created which are connected to the download
completion or termination and which call completed() or
stopped() to indicate the task has finished operations.
Adds new classes:
- QgsTask. An interface for long-running background tasks
- QgsTaskManager. Handles groups of tasks - also available as a global
instance for tracking application wide tasks
- QgsTaskManagerWidget. A list view for showing active tasks and their
progress, and for cancelling them
A new dock widget has been added with a task manager widget showing
global tasks