1 /***************************************************************************
2   qgsfeedback.h
3   --------------------------------------
4   Date                 : July 2016
5   Copyright            : (C) 2016 by Martin Dobias
6   Email                : wonder dot sk at gmail dot com
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 #ifndef QGSFEEDBACK_H
17 #define QGSFEEDBACK_H
18 
19 #include <QObject>
20 
21 #include "qgis_core.h"
22 #include "qgis_sip.h"
23 
24 /**
25  * \ingroup core
26  * \brief Base class for feedback objects to be used for cancellation of something running in a worker thread.
27  *
28  * The class may be used as is or it may be subclassed for extended functionality
29  * for a particular operation (e.g. report progress or pass some data for preview).
30  *
31  * When cancel() is called, the internal code has two options to check for cancellation state:
32  *
33  * - if the worker thread uses an event loop (e.g. for network communication), the code can make a queued connection to canceled() signal and handle the cancellation in its slot.
34  * - if the worker thread does not use an event loop, it can poll isCanceled() method regularly to see if the operation should be canceled.
35  *
36  * The class is meant to be created and destroyed in the main thread.
37  *
38  * For map rendering, the object may be created in constructor of a QgsMapLayerRenderer
39  * subclass and available with QgsMapLayerRenderer::feedback() method. When a map rendering job
40  * gets canceled, the cancel() method is called on the feedback object of all layers.
41  *
42  * \since QGIS 3.0
43  */
44 class CORE_EXPORT QgsFeedback : public QObject
45 {
46     Q_OBJECT
47   public:
48     //! Construct a feedback object
49     QgsFeedback( QObject *parent SIP_TRANSFERTHIS = nullptr )
QObject(parent)50       : QObject( parent )
51     {}
52 
53     //! Tells whether the operation has been canceled already
isCanceled()54     bool isCanceled() const SIP_HOLDGIL { return mCanceled; }
55 
56     /**
57      * Sets the current progress for the feedback object. The \a progress
58      * argument is in percentage and valid values range from 0-100.
59      * \see progress()
60      * \see progressChanged()
61      * \since QGIS 3.0
62      */
setProgress(double progress)63     void setProgress( double progress )
64     {
65       // avoid flooding with too many events
66       if ( static_cast< int >( mProgress * 10 ) != static_cast< int >( progress * 10 ) )
67         emit progressChanged( progress );
68 
69       mProgress = progress;
70     }
71 
72     /**
73      * Returns the current progress reported by the feedback object. Depending on how the
74      * feedback object is used progress reporting may not be supported. The returned value
75      * is in percentage and ranges from 0-100.
76      * \see setProgress()
77      * \see progressChanged()
78      * \since QGIS 3.0
79      */
progress()80     double progress() const SIP_HOLDGIL { return mProgress; }
81 
82   public slots:
83 
84     //! Tells the internal routines that the current operation should be canceled. This should be run by the main thread
cancel()85     void cancel()
86     {
87       if ( mCanceled )
88         return;  // only emit the signal once
89       mCanceled = true;
90       emit canceled();
91     }
92 
93   signals:
94     //! Internal routines can connect to this signal if they use event loop
95     void canceled();
96 
97     /**
98      * Emitted when the feedback object reports a progress change. Depending on how the
99      * feedback object is used progress reporting may not be supported. The \a progress
100      * argument is in percentage and ranges from 0-100.
101      * \see setProgress()
102      * \see progress()
103      * \since QGIS 3.0
104      */
105     void progressChanged( double progress );
106 
107   private:
108     //! Whether the operation has been canceled already. False by default.
109     bool mCanceled = false;
110 
111     double mProgress = 0.0;
112 };
113 
114 #endif // QGSFEEDBACK_H
115