Skip to content

Commit

Permalink
Framework for task manager
Browse files Browse the repository at this point in the history
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
  • Loading branch information
nyalldawson committed Dec 5, 2016
1 parent dc697d0 commit ebae15f
Show file tree
Hide file tree
Showing 14 changed files with 1,488 additions and 0 deletions.
1 change: 1 addition & 0 deletions python/core/core.sip
Expand Up @@ -138,6 +138,7 @@
%Include qgsstatisticalsummary.sip
%Include qgsstringstatisticalsummary.sip
%Include qgsstringutils.sip
%Include qgstaskmanager.sip
%Include qgstextrenderer.sip
%Include qgstolerance.sip
%Include qgstracer.sip
Expand Down
174 changes: 174 additions & 0 deletions python/core/qgstaskmanager.sip
@@ -0,0 +1,174 @@
/** \ingroup core
* \class QgsTask
* \brief Interface class for long running tasks which will be handled by a QgsTaskManager
* \note Added in version 2.16
*/
class QgsTask : QObject
{

%TypeHeaderCode
#include <qgstaskmanager.h>
%End
public:

//! Status of tasks
enum TaskStatus
{
Running, /*!< Task is currently running */
Complete, /*!< Task successfully completed */
Terminated, /*!< Task was terminated or errored */
// Paused,
// Queued,
};

/** Constructor for QgsTask.
* @param description text description of task
*/
QgsTask( const QString& description = QString() );

//! Will be called when task has been terminated, either through
//! user interaction or other reason (eg application exit)
//! @note derived classes must ensure they call the base method
virtual void terminate();

//! Returns true if the task is active, ie it is not complete and has
//! not been terminated.
bool isActive() const;

//! Returns the current task status.
TaskStatus status() const;

//! Returns the task's description.
QString description() const;

//! Returns the task's progress (between 0.0 and 100.0)
double progress() const;

signals:

//! Will be emitted by task when its progress changes
//! @param progress percent of progress, from 0.0 - 100.0
//! @note derived classes should not emit this signal directly, instead they should call
//! setProgress()
void progressChanged( double progress );

//! Will be emitted by task when its status changes
//! @param status new task status
//! @note derived classes should not emit this signal directly, instead they should call
//! completed() or stopped()
void statusChanged( int status );

//! Will be emitted by task to indicate its completion.
//! @note derived classes should not emit this signal directly, instead they should call
//! completed()
void taskCompleted();

//! Will be emitted by task if it has terminated for any reason
//! other then completion.
//! @note derived classes should not emit this signal directly, instead they should call
//! stopped()//!
void taskStopped();

protected:

//! Sets the task's current progress. Should be called whenever the
//! task wants to update it's progress. Calling will automatically emit the progressChanged
//! signal.
//! @param progress percent of progress, from 0.0 - 100.0
void setProgress( double progress );

//! Sets the task as completed. Should be called when the task is complete.
//! Calling will automatically emit the statusChanged and taskCompleted signals.
void completed();

//! Sets the task as stopped. Should be called whenever the task ends for any
//! reason other than successful completion.
//! Calling will automatically emit the statusChanged and taskStopped signals.
void stopped();
};

/** \ingroup core
* \class QgsTaskManager
* \brief Task manager for managing a set of long-running QgsTask tasks. This class can be created directly,
* or accessed via a global instance.
* \note Added in version 2.16
*/
class QgsTaskManager : QObject
{
%TypeHeaderCode
#include <qgstaskmanager.h>
%End
public:

/** Returns the global task manager instance pointer, creating the object on the first call.
*/
static QgsTaskManager * instance();

/** Constructor for QgsTaskManager.
* @param parent parent QObject
*/
QgsTaskManager( QObject* parent /TransferThis/ = nullptr );

virtual ~QgsTaskManager();

/** Adds a task to the manager. Ownership of the task is transferred
* to the manager.
* @param task task to add
* @returns unique task ID
*/
long addTask( QgsTask* task /Transfer/ );

/** Deletes the specified task, first terminating it if it is currently
* running.
* @param id task ID
* @returns true if task was found and deleted
*/
bool deleteTask( long id );

/** Deletes the specified task, first terminating it if it is currently
* running.
* @param task task to delete
* @returns true if task was contained in manager and deleted
*/
bool deleteTask( QgsTask* task );

/** Returns the task with matching ID.
* @param id task ID
* @returns task if found, or nullptr
*/
QgsTask* task( long id ) const;

/** Returns all tasks tracked by the manager.
*/
QList<QgsTask*> tasks() const;

//! Returns the number of tasks tracked by the manager.
int count() const;

/** Returns the unique task ID corresponding to a task managed by the class.
* @param task task to find
* @returns task ID, or -1 if task not found
*/
long taskId( QgsTask* task ) const;

signals:

//! Will be emitted when a task reports a progress change
//! @param taskId ID of task
//! @param progress percent of progress, from 0.0 - 100.0
void progressChanged( long taskId, double progress );

//! Will be emitted when a task reports a status change
//! @param taskId ID of task
//! @param status new task status
void statusChanged( long taskId, int status );

//! Emitted when a new task has been added to the manager
//! @param taskId ID of task
void taskAdded( long taskId );

//! Emitted when a task is about to be deleted
//! @param taskId ID of task
void taskAboutToBeDeleted( long taskId );

};
1 change: 1 addition & 0 deletions python/gui/gui.sip
Expand Up @@ -161,6 +161,7 @@
%Include qgstablewidgetbase.sip
%Include qgstabwidget.sip
%Include qgstablewidgetitem.sip
%Include qgstaskmanagerwidget.sip
%Include qgstextannotationitem.sip
%Include qgstextformatwidget.sip
%Include qgstextpreview.sip
Expand Down
95 changes: 95 additions & 0 deletions python/gui/qgstaskmanagerwidget.sip
@@ -0,0 +1,95 @@
/** \ingroup gui
* \class QgsTaskManagerWidget
* A widget which displays tasks from a QgsTaskManager and allows for interaction with the manager
* @see QgsTaskManager
* @note introduced in QGIS 2.16
*/
class QgsTaskManagerWidget : QTreeView
{
%TypeHeaderCode
#include <qgstaskmanagerwidget.h>
%End
public:

/** Constructor for QgsTaskManagerWidget
* @param manager task manager associated with widget
* @param parent parent widget
*/
QgsTaskManagerWidget( QgsTaskManager* manager, QWidget* parent /TransferThis/ = nullptr );

};


/** \ingroup gui
* \class QgsTaskManagerModel
* A model representing a QgsTaskManager
* @see QgsTaskManager
* @note introduced in QGIS 2.16
*/
class QgsTaskManagerModel: QAbstractItemModel
{
%TypeHeaderCode
#include <qgstaskmanagerwidget.h>
%End
public:

/** Constructor for QgsTaskManagerModel
* @param manager task manager for model
* @param parent parent object
*/
explicit QgsTaskManagerModel( QgsTaskManager* manager, QObject* parent /TransferThis/ = nullptr );

//reimplemented QAbstractItemModel methods
QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const;
QModelIndex parent( const QModelIndex &index ) const;
int rowCount( const QModelIndex &parent = QModelIndex() ) const;
int columnCount( const QModelIndex &parent = QModelIndex() ) const;
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const;
Qt::ItemFlags flags( const QModelIndex & index ) const;
bool setData( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole );

};


/** \ingroup gui
* \class QgsProgressBarDelegate
* A delegate for showing a progress bar within a view
* @note introduced in QGIS 2.16
*/
class QgsProgressBarDelegate : QStyledItemDelegate
{
%TypeHeaderCode
#include <qgstaskmanagerwidget.h>
%End
public:

/** Constructor for QgsProgressBarDelegate
* @param parent parent object
*/
QgsProgressBarDelegate( QObject* parent /TransferThis/ = nullptr );

void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const;
};

/** \ingroup gui
* \class QgsProgressBarDelegate
* A delegate for showing task status within a view. Clicks on the delegate will cause the task to be cancelled (via the model).
* @note introduced in QGIS 2.16
*/
class QgsTaskStatusDelegate : QStyledItemDelegate
{
%TypeHeaderCode
#include <qgstaskmanagerwidget.h>
%End
public:

/** Constructor for QgsTaskStatusDelegate
* @param parent parent object
*/
QgsTaskStatusDelegate( QObject* parent /TransferThis/ = nullptr );

void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const;
bool editorEvent( QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index );
};
10 changes: 10 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -221,6 +221,8 @@
#include "qgsstatusbarscalewidget.h"
#include "qgsstyle.h"
#include "qgssvgannotationitem.h"
#include "qgstaskmanager.h"
#include "qgstaskmanagerwidget.h"
#include "qgssymbolselectordialog.h"
#include "qgstextannotationitem.h"
#include "qgstipgui.h"
Expand Down Expand Up @@ -851,6 +853,13 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
QMainWindow::addDockWidget( Qt::BottomDockWidgetArea, mUserInputDockWidget );
mUserInputDockWidget->setFloating( true );

// create the task manager dock on starting QGIS - this is like the browser
mTaskManagerDock = new QDockWidget( tr( "Task Manager" ), this );
mTaskManagerDock->setObjectName( "TaskManager" );
addDockWidget( Qt::RightDockWidgetArea, mTaskManagerDock );
mTaskManagerDock->setWidget( new QgsTaskManagerWidget( QgsTaskManager::instance(), mTaskManagerDock ) );
mTaskManagerDock->hide();

// create the GPS tool on starting QGIS - this is like the browser
mpGpsWidget = new QgsGPSInformationWidget( mMapCanvas );
//create the dock widget
Expand Down Expand Up @@ -1139,6 +1148,7 @@ QgisApp::QgisApp()
, mOverviewDock( nullptr )
, mpGpsDock( nullptr )
, mLogDock( nullptr )
, mTaskManagerDock( nullptr )
, mNonEditMapTool( nullptr )
, mScaleWidget( nullptr )
, mMagnifierWidget( nullptr )
Expand Down
1 change: 1 addition & 0 deletions src/app/qgisapp.h
Expand Up @@ -1560,6 +1560,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QgsDockWidget *mOverviewDock;
QgsDockWidget *mpGpsDock;
QgsDockWidget *mLogDock;
QDockWidget *mTaskManagerDock;

#ifdef Q_OS_MAC
//! Window menu action to select this window
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -211,6 +211,7 @@ SET(QGIS_CORE_SRCS
qgsstatisticalsummary.cpp
qgsstringstatisticalsummary.cpp
qgsstringutils.cpp
qgstaskmanager.cpp
qgstextlabelfeature.cpp
qgstextrenderer.cpp
qgstolerance.cpp
Expand Down Expand Up @@ -495,6 +496,7 @@ SET(QGIS_CORE_MOC_HDRS
qgsrelationmanager.h
qgsrunprocess.h
qgssnappingutils.h
qgstaskmanager.h
qgstracer.h
qgstrackedvectorlayertools.h
qgstransaction.h
Expand Down

0 comments on commit ebae15f

Please sign in to comment.