OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / coreplugin / progressmanager / progressmanager.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "progressmanager_p.h"
34 #include "progressview.h"
35 #include "coreconstants.h"
36 #include "icore.h"
37
38 #include <utils/qtcassert.h>
39
40 using namespace Core;
41 using namespace Core::Internal;
42
43 /*!
44     \mainclass
45     \class Core::ProgressManager
46     \brief The ProgressManager class is used to show a user interface
47     for running tasks in Qt Creator.
48
49     It tracks the progress of a task that it is told
50     about, and shows a progress indicator in the left hand tool bar
51     of Qt Creator's main window to the user.
52     The progress indicator also allows the user to cancel the task.
53
54     You get the single instance of this class via the
55     Core::ICore::progressManager() method.
56
57     \section1 Registering a task
58     The ProgressManager API uses QtConcurrent as the basis for defining
59     tasks. A task consists of the following properties:
60
61     \table
62     \header
63         \o Property
64         \o Type
65         \o Description
66     \row
67         \o Task abstraction
68         \o \c QFuture<void>
69         \o A \c QFuture object that represents the task which is
70            responsible for reporting the state of the task. See below
71            for coding patterns how to create this object for your
72            specific task.
73     \row
74         \o Title
75         \o \c QString
76         \o A very short title describing your task. This is shown
77            as a title over the progress bar.
78     \row
79         \o Type
80         \o \c QString
81         \o A string identifier that is used to group different tasks that
82            belong together.
83            For example, all the search operations use the same type
84            identifier.
85     \row
86         \o Flags
87         \o \l ProgressManager::ProgressFlags
88         \o Additional flags that specify how the progress bar should
89            be presented to the user.
90     \endtable
91
92     To register a task you create your \c QFuture<void> object, and call
93     addTask(). This method returns a
94     \l{Core::FutureProgress}{FutureProgress}
95     object that you can use to further customize the progress bar's appearance.
96     See the \l{Core::FutureProgress}{FutureProgress} documentation for
97     details.
98
99     In the following you will learn about two common patterns how to
100     create the \c QFuture<void> object for your task.
101
102     \section2 Create a threaded task with QtConcurrent
103     The first option is to directly use QtConcurrent to actually
104     start a task concurrently in a different thread.
105     QtConcurrent has several different methods to run e.g.
106     a class method in a different thread. Qt Creator itself
107     adds a few more in \c{src/libs/qtconcurrent/runextensions.h}.
108     The QtConcurrent methods to run a concurrent task return a
109     \c QFuture object. This is what you want to give the
110     ProgressManager in the addTask() method.
111
112     Have a look at e.g Locator::ILocatorFilter. Locator filters implement
113     a method \c refresh which takes a \c QFutureInterface object
114     as a parameter. These methods look something like:
115     \code
116     void Filter::refresh(QFutureInterface<void> &future) {
117         future.setProgressRange(0, MAX);
118         ...
119         while (!future.isCanceled()) {
120             // Do a part of the long stuff
121             ...
122             future.setProgressValue(currentProgress);
123             ...
124         }
125     }
126     \endcode
127
128     The actual refresh, which calls all the filters' refresh methods
129     in a different thread, looks like this:
130     \code
131     QFuture<void> task = QtConcurrent::run(&ILocatorFilter::refresh, filters);
132     Core::FutureProgress *progress = Core::ICore::instance()
133             ->progressManager()->addTask(task, tr("Indexing"),
134                                          Locator::Constants::TASK_INDEX);
135     \endcode
136     First, we tell QtConcurrent to start a thread which calls all the filters'
137     refresh method. After that we register the returned QFuture object
138     with the ProgressManager.
139
140     \section2 Manually create QtConcurrent objects for your thread
141     If your task has its own means to create and run a thread,
142     you need to create the necessary objects yourselves, and
143     report the start/stop state.
144
145     \code
146     // We are already running in a different thread here
147     QFutureInterface<void> *progressObject = new QFutureInterface<void>;
148     progressObject->setProgressRange(0, MAX);
149     Core::ICore::instance()->progressManager()->addTask(
150         progressObject->future(),
151         tr("DoIt"), MYTASKTYPE);
152     progressObject->reportStarted();
153     // Do something
154     ...
155     progressObject->setProgressValue(currentProgress);
156     ...
157     // We have done what we needed to do
158     progressObject->reportFinished();
159     delete progressObject;
160     \endcode
161     In the first line we create the QFutureInterface object that will be
162     our way for reporting the task's state.
163     The first thing we report is the expected range of the progress values.
164     We register the task with the ProgressManager, using the internal
165     QFuture object that has been created for our QFutureInterface object.
166     Next we report that the task has begun and start doing our actual
167     work, regularly reporting the progress via the methods
168     in QFutureInterface. After the long taking operation has finished,
169     we report so through the QFutureInterface object, and delete it
170     afterwards.
171
172     \section1 Customizing progress appearance
173
174     You can set a custom widget to show below the progress bar itself,
175     using the FutureProgress object returned by the addTask() method.
176     Also use this object to get notified when the user clicks on the
177     progress indicator.
178 */
179
180 /*!
181     \enum Core::ProgressManager::ProgressFlag
182     Additional flags that specify details in behavior. The
183     default for a task is to not have any of these flags set.
184     \value KeepOnFinish
185         The progress indicator stays visible after the task has finished.
186     \value ShowInApplicationIcon
187         The progress indicator for this task is additionally
188         shown in the application icon in the system's task bar or dock, on
189         platforms that support that (at the moment Windows 7 and Mac OS X).
190 */
191
192 /*!
193     \fn Core::ProgressManager::ProgressManager(QObject *parent = 0)
194     \internal
195 */
196
197 /*!
198     \fn Core::ProgressManager::~ProgressManager()
199     \internal
200 */
201
202 /*!
203     \fn FutureProgress *Core::ProgressManager::addTask(const QFuture<void> &future, const QString &title, const QString &type, ProgressFlags flags = 0)
204
205     Shows a progress indicator for task given by the QFuture object \a future.
206     The progress indicator shows the specified \a title along with the progress bar.
207     The \a type of a task will specify a logical grouping with other
208     running tasks. Via the \a flags parameter you can e.g. let the
209     progress indicator stay visible after the task has finished.
210     Returns an object that represents the created progress indicator,
211     which can be used to further customize. The FutureProgress object's
212     life is managed by the ProgressManager and is guaranteed to live
213 */
214
215 /*!
216     \fn void Core::ProgressManager::setApplicationLabel(const QString &text)
217
218     Shows the given \a text in a platform dependent way in the application
219     icon in the system's task bar or dock. This is used
220     to show the number of build errors on Windows 7 and Mac OS X.
221 */
222
223 /*!
224     \fn void Core::ProgressManager::cancelTasks(const QString &type)
225
226     Schedules a cancel for all running tasks of the given \a type.
227     Please note that the cancel functionality depends on the
228     running task to actually check the \c QFutureInterface::isCanceled
229     property.
230 */
231
232 /*!
233     \fn void Core::ProgressManager::taskStarted(const QString &type)
234
235     Sent whenever a task of a given \a type is started.
236 */
237
238 /*!
239     \fn void Core::ProgressManager::allTasksFinished(const QString &type)
240
241     Sent when all tasks of a \a type have finished.
242 */
243
244 ProgressManagerPrivate::ProgressManagerPrivate(QObject *parent)
245   : ProgressManager(parent),
246     m_applicationTask(0)
247 {
248     m_progressView = new ProgressView;
249     ICore *core = ICore::instance();
250     connect(core, SIGNAL(coreAboutToClose()), this, SLOT(cancelAllRunningTasks()));
251 }
252
253 ProgressManagerPrivate::~ProgressManagerPrivate()
254 {
255     cleanup();
256 }
257
258 void ProgressManagerPrivate::cancelTasks(const QString &type)
259 {
260     bool found = false;
261     QMap<QFutureWatcher<void> *, QString>::iterator task = m_runningTasks.begin();
262     while (task != m_runningTasks.end()) {
263         if (task.value() != type) {
264             ++task;
265             continue;
266         }
267         found = true;
268         disconnect(task.key(), SIGNAL(finished()), this, SLOT(taskFinished()));
269         if (m_applicationTask == task.key())
270             disconnectApplicationTask();
271         task.key()->cancel();
272         delete task.key();
273         task = m_runningTasks.erase(task);
274     }
275     if (found) {
276         emit allTasksFinished(type);
277     }
278 }
279
280 void ProgressManagerPrivate::cancelAllRunningTasks()
281 {
282     QMap<QFutureWatcher<void> *, QString>::const_iterator task = m_runningTasks.constBegin();
283     while (task != m_runningTasks.constEnd()) {
284         disconnect(task.key(), SIGNAL(finished()), this, SLOT(taskFinished()));
285         if (m_applicationTask == task.key())
286             disconnectApplicationTask();
287         task.key()->cancel();
288         delete task.key();
289         ++task;
290     }
291     m_runningTasks.clear();
292 }
293
294 FutureProgress *ProgressManagerPrivate::addTask(const QFuture<void> &future, const QString &title,
295                                                 const QString &type, ProgressFlags flags)
296 {
297     QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
298     m_runningTasks.insert(watcher, type);
299     connect(watcher, SIGNAL(finished()), this, SLOT(taskFinished()));
300     if (flags & ShowInApplicationIcon) {
301         if (m_applicationTask)
302             disconnectApplicationTask();
303         m_applicationTask = watcher;
304         setApplicationProgressRange(future.progressMinimum(), future.progressMaximum());
305         setApplicationProgressValue(future.progressValue());
306         connect(m_applicationTask, SIGNAL(progressRangeChanged(int,int)),
307                 this, SLOT(setApplicationProgressRange(int,int)));
308         connect(m_applicationTask, SIGNAL(progressValueChanged(int)),
309                 this, SLOT(setApplicationProgressValue(int)));
310         setApplicationProgressVisible(true);
311     }
312     watcher->setFuture(future);
313     emit taskStarted(type);
314     return m_progressView->addTask(future, title, type, flags);
315 }
316
317 QWidget *ProgressManagerPrivate::progressView()
318 {
319     return m_progressView;
320 }
321
322 void ProgressManagerPrivate::taskFinished()
323 {
324     QObject *taskObject = sender();
325     QTC_ASSERT(taskObject, return);
326     QFutureWatcher<void> *task = static_cast<QFutureWatcher<void> *>(taskObject);
327     if (m_applicationTask == task)
328         disconnectApplicationTask();
329     QString type = m_runningTasks.value(task);
330     m_runningTasks.remove(task);
331     delete task;
332
333     if (!m_runningTasks.key(type, 0)) {
334         emit allTasksFinished(type);
335     }
336 }
337
338 void ProgressManagerPrivate::disconnectApplicationTask()
339 {
340     disconnect(m_applicationTask, SIGNAL(progressRangeChanged(int,int)),
341             this, SLOT(setApplicationProgressRange(int,int)));
342     disconnect(m_applicationTask, SIGNAL(progressValueChanged(int)),
343             this, SLOT(setApplicationProgressValue(int)));
344     setApplicationProgressVisible(false);
345     m_applicationTask = 0;
346 }