1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qfuturewatcher.h"
41#include "qfuturewatcher_p.h"
42
43#include <QtCore/qcoreevent.h>
44#include <QtCore/qcoreapplication.h>
45#include <QtCore/qmetaobject.h>
46#include <QtCore/qthread.h>
47
48QT_BEGIN_NAMESPACE
49
50/*! \class QFutureWatcher
51 \reentrant
52 \since 4.4
53
54 \inmodule QtCore
55 \ingroup thread
56
57 \brief The QFutureWatcher class allows monitoring a QFuture using signals
58 and slots.
59
60 QFutureWatcher provides information and notifications about a QFuture. Use
61 the setFuture() function to start watching a particular QFuture. The
62 future() function returns the future set with setFuture().
63
64 For convenience, several of QFuture's functions are also available in
65 QFutureWatcher: progressValue(), progressMinimum(), progressMaximum(),
66 progressText(), isStarted(), isFinished(), isRunning(), isCanceled(),
67 isSuspending(), isSuspended(), waitForFinished(), result(), and resultAt().
68 The cancel(), setSuspended(), suspend(), resume(), and toggleSuspended() functions
69 are slots in QFutureWatcher.
70
71 Status changes are reported via the started(), finished(), canceled(),
72 suspending(), suspended(), resumed(), resultReadyAt(), and resultsReadyAt()
73 signals. Progress information is provided from the progressRangeChanged(),
74 void progressValueChanged(), and progressTextChanged() signals.
75
76 Throttling control is provided by the setPendingResultsLimit() function.
77 When the number of pending resultReadyAt() or resultsReadyAt() signals
78 exceeds the limit, the computation represented by the future will be
79 throttled automatically. The computation will resume once the number of
80 pending signals drops below the limit.
81
82 Example: Starting a computation and getting a slot callback when it's
83 finished:
84
85 \snippet code/src_corelib_thread_qfuturewatcher.cpp 0
86
87 Be aware that not all running asynchronous computations can be canceled or
88 suspended. For example, the future returned by QtConcurrent::run() cannot be
89 canceled; but the future returned by QtConcurrent::mappedReduced() can.
90
91 QFutureWatcher<void> is specialized to not contain any of the result
92 fetching functions. Any QFuture<T> can be watched by a
93 QFutureWatcher<void> as well. This is useful if only status or progress
94 information is needed; not the actual result data.
95
96 \sa QFuture, {Qt Concurrent}
97*/
98
99/*! \fn template <typename T> QFutureWatcher<T>::QFutureWatcher(QObject *parent)
100
101 Constructs a new QFutureWatcher with the given \a parent. Until a future is
102 set with setFuture(), the functions isStarted(), isCanceled(), and
103 isFinished() return \c true.
104*/
105QFutureWatcherBase::QFutureWatcherBase(QObject *parent)
106 :QObject(*new QFutureWatcherBasePrivate, parent)
107{ }
108
109/*! \fn template <typename T> QFutureWatcher<T>::~QFutureWatcher()
110
111 Destroys the QFutureWatcher.
112*/
113
114/*! \fn template <typename T> void QFutureWatcher<T>::cancel()
115
116 Cancels the asynchronous computation represented by the future(). Note that
117 the cancelation is asynchronous. Use waitForFinished() after calling
118 cancel() when you need synchronous cancelation.
119
120 Currently available results may still be accessed on a canceled QFuture,
121 but new results will \e not become available after calling this function.
122 Also, this QFutureWatcher will not deliver progress and result ready
123 signals once canceled. This includes the progressValueChanged(),
124 progressRangeChanged(), progressTextChanged(), resultReadyAt(), and
125 resultsReadyAt() signals.
126
127 Be aware that not all running asynchronous computations can be canceled.
128 For example, the QFuture returned by QtConcurrent::run() cannot be
129 canceled; but the QFuture returned by QtConcurrent::mappedReduced() can.
130*/
131void QFutureWatcherBase::cancel()
132{
133 futureInterface().cancel();
134}
135
136#if QT_DEPRECATED_SINCE(6, 0)
137/*! \fn template <typename T> void QFutureWatcher<T>::setPaused(bool paused)
138
139 \obsolete
140 Use setSuspended() instead.
141
142 If \a paused is true, this function pauses the asynchronous computation
143 represented by the future(). If the computation is already paused, this
144 function does nothing. QFutureWatcher will not immediately stop delivering
145 progress and result ready signals when the future is paused. At the moment
146 of pausing there may still be computations that are in progress and cannot
147 be stopped. Signals for such computations will still be delivered after
148 pause.
149
150 If \a paused is false, this function resumes the asynchronous computation.
151 If the computation was not previously paused, this function does nothing.
152
153 Be aware that not all computations can be paused. For example, the
154 QFuture returned by QtConcurrent::run() cannot be paused; but the QFuture
155 returned by QtConcurrent::mappedReduced() can.
156
157 \sa pause(), resume(), togglePaused()
158*/
159void QFutureWatcherBase::setPaused(bool paused)
160{
161 futureInterface().setSuspended(paused);
162}
163
164/*! \fn template <typename T> void QFutureWatcher<T>::pause()
165
166 \obsolete
167 Use suspend() instead.
168
169 Pauses the asynchronous computation represented by the future(). This is a
170 convenience method that simply calls setPaused(true).
171
172 \sa resume()
173*/
174void QFutureWatcherBase::pause()
175{
176 futureInterface().setSuspended(true);
177}
178
179#endif // QT_DEPRECATED_SINCE(6, 0)
180
181/*! \fn template <typename T> void QFutureWatcher<T>::setSuspended(bool suspend)
182
183 \since 6.0
184
185 If \a suspend is true, this function suspends the asynchronous computation
186 represented by the future(). If the computation is already suspended, this
187 function does nothing. QFutureWatcher will not immediately stop delivering
188 progress and result ready signals when the future is suspended. At the moment
189 of suspending there may still be computations that are in progress and cannot
190 be stopped. Signals for such computations will still be delivered.
191
192 If \a suspend is false, this function resumes the asynchronous computation.
193 If the computation was not previously suspended, this function does nothing.
194
195 Be aware that not all computations can be suspended. For example, the
196 QFuture returned by QtConcurrent::run() cannot be suspended; but the QFuture
197 returned by QtConcurrent::mappedReduced() can.
198
199 \sa suspend(), resume(), toggleSuspended()
200*/
201void QFutureWatcherBase::setSuspended(bool suspend)
202{
203 futureInterface().setSuspended(suspend);
204}
205
206/*! \fn template <typename T> void QFutureWatcher<T>::suspend()
207
208 \since 6.0
209
210 Suspends the asynchronous computation represented by this future. This is a
211 convenience method that simply calls setSuspended(true).
212
213 \sa resume()
214*/
215void QFutureWatcherBase::suspend()
216{
217 futureInterface().setSuspended(true);
218}
219
220/*! \fn template <typename T> void QFutureWatcher<T>::resume()
221
222 Resumes the asynchronous computation represented by the future(). This is
223 a convenience method that simply calls setSuspended(false).
224
225 \sa suspend()
226*/
227
228void QFutureWatcherBase::resume()
229{
230 futureInterface().setSuspended(false);
231}
232
233#if QT_DEPRECATED_SINCE(6, 0)
234/*! \fn template <typename T> void QFutureWatcher<T>::togglePaused()
235
236 \obsolete
237 Use toggleSuspended() instead.
238
239 Toggles the paused state of the asynchronous computation. In other words,
240 if the computation is currently paused, calling this function resumes it;
241 if the computation is running, it is paused. This is a convenience method
242 for calling setPaused(!isPaused()).
243
244 \sa setPaused(), pause(), resume()
245*/
246void QFutureWatcherBase::togglePaused()
247{
248 futureInterface().toggleSuspended();
249}
250#endif // QT_DEPRECATED_SINCE(6, 0)
251
252/*! \fn template <typename T> void QFutureWatcher<T>::toggleSuspended()
253
254 \since 6.0
255
256 Toggles the suspended state of the asynchronous computation. In other words,
257 if the computation is currently suspending or suspended, calling this
258 function resumes it; if the computation is running, it is suspended. This is a
259 convenience method for calling setSuspended(!(isSuspending() || isSuspended())).
260
261 \sa setSuspended(), suspend(), resume()
262*/
263void QFutureWatcherBase::toggleSuspended()
264{
265 futureInterface().toggleSuspended();
266}
267
268/*! \fn template <typename T> int QFutureWatcher<T>::progressValue() const
269
270 Returns the current progress value, which is between the progressMinimum()
271 and progressMaximum().
272
273 \sa progressMinimum(), progressMaximum()
274*/
275int QFutureWatcherBase::progressValue() const
276{
277 return futureInterface().progressValue();
278}
279
280/*! \fn template <typename T> int QFutureWatcher<T>::progressMinimum() const
281
282 Returns the minimum progressValue().
283
284 \sa progressValue(), progressMaximum()
285*/
286int QFutureWatcherBase::progressMinimum() const
287{
288 return futureInterface().progressMinimum();
289}
290
291/*! \fn template <typename T> int QFutureWatcher<T>::progressMaximum() const
292
293 Returns the maximum progressValue().
294
295 \sa progressValue(), progressMinimum()
296*/
297int QFutureWatcherBase::progressMaximum() const
298{
299 return futureInterface().progressMaximum();
300}
301
302/*! \fn template <typename T> QString QFutureWatcher<T>::progressText() const
303
304 Returns the (optional) textual representation of the progress as reported
305 by the asynchronous computation.
306
307 Be aware that not all computations provide a textual representation of the
308 progress, and as such, this function may return an empty string.
309*/
310QString QFutureWatcherBase::progressText() const
311{
312 return futureInterface().progressText();
313}
314
315/*! \fn template <typename T> bool QFutureWatcher<T>::isStarted() const
316
317 Returns \c true if the asynchronous computation represented by the future()
318 has been started, or if no future has been set; otherwise returns \c false.
319*/
320bool QFutureWatcherBase::isStarted() const
321{
322 return futureInterface().queryState(QFutureInterfaceBase::Started);
323}
324
325/*! \fn template <typename T> bool QFutureWatcher<T>::isFinished() const
326
327 Returns \c true if the asynchronous computation represented by the future()
328 has finished, or if no future has been set; otherwise returns \c false.
329*/
330bool QFutureWatcherBase::isFinished() const
331{
332 Q_D(const QFutureWatcherBase);
333 return d->finished;
334}
335
336/*! \fn template <typename T> bool QFutureWatcher<T>::isRunning() const
337
338 Returns \c true if the asynchronous computation represented by the future()
339 is currently running; otherwise returns \c false.
340*/
341bool QFutureWatcherBase::isRunning() const
342{
343 return futureInterface().queryState(QFutureInterfaceBase::Running);
344}
345
346/*! \fn template <typename T> bool QFutureWatcher<T>::isCanceled() const
347
348 Returns \c true if the asynchronous computation has been canceled with the
349 cancel() function, or if no future has been set; otherwise returns \c false.
350
351 Be aware that the computation may still be running even though this
352 function returns \c true. See cancel() for more details.
353*/
354bool QFutureWatcherBase::isCanceled() const
355{
356 return futureInterface().queryState(QFutureInterfaceBase::Canceled);
357}
358
359#if QT_DEPRECATED_SINCE(6, 0)
360
361/*! \fn template <typename T> bool QFutureWatcher<T>::isPaused() const
362
363 \obsolete
364 Use isSuspending() or isSuspended() instead.
365
366 Returns \c true if the asynchronous computation has been paused with the
367 pause() function; otherwise returns \c false.
368
369 Be aware that the computation may still be running even though this
370 function returns \c true. See setPaused() for more details. To check
371 if pause actually took effect, use isSuspended() instead.
372
373 \sa setPaused(), togglePaused(), isSuspended()
374*/
375
376bool QFutureWatcherBase::isPaused() const
377{
378QT_WARNING_PUSH
379QT_WARNING_DISABLE_DEPRECATED
380 return futureInterface().isPaused();
381QT_WARNING_POP
382}
383#endif // QT_DEPRECATED_SINCE(6, 0)
384
385/*! \fn template <typename T> bool QFutureWatcher<T>::isSuspending() const
386
387 \since 6.0
388
389 Returns \c true if the asynchronous computation has been suspended with the
390 suspend() function, but the work is not yet suspended, and computation is still
391 running. Returns \c false otherwise.
392
393 To check if suspension is actually in effect, use isSuspended() instead.
394
395 \sa setSuspended(), toggleSuspended(), isSuspended()
396*/
397bool QFutureWatcherBase::isSuspending() const
398{
399 return futureInterface().isSuspending();
400}
401
402/*! \fn template <typename T> bool QFutureWatcher<T>::isSuspended() const
403
404 \since 6.0
405
406 Returns \c true if a suspension of the asynchronous computation has been
407 requested, and it is in effect, meaning that no more results or progress
408 changes are expected.
409
410 \sa suspended(), setSuspended(), isSuspending()
411*/
412bool QFutureWatcherBase::isSuspended() const
413{
414 return futureInterface().isSuspended();
415}
416
417/*! \fn template <typename T> void QFutureWatcher<T>::waitForFinished()
418
419 Waits for the asynchronous computation to finish (including cancel()ed
420 computations), i.e. until isFinished() returns \c true.
421*/
422void QFutureWatcherBase::waitForFinished()
423{
424 futureInterface().waitForFinished();
425}
426
427bool QFutureWatcherBase::event(QEvent *event)
428{
429 Q_D(QFutureWatcherBase);
430 if (event->type() == QEvent::FutureCallOut) {
431 QFutureCallOutEvent *callOutEvent = static_cast<QFutureCallOutEvent *>(event);
432 d->sendCallOutEvent(callOutEvent);
433 return true;
434 }
435 return QObject::event(event);
436}
437
438/*! \fn template <typename T> void QFutureWatcher<T>::setPendingResultsLimit(int limit)
439
440 The setPendingResultsLimit() provides throttling control. When the number
441 of pending resultReadyAt() or resultsReadyAt() signals exceeds the
442 \a limit, the computation represented by the future will be throttled
443 automatically. The computation will resume once the number of pending
444 signals drops below the \a limit.
445*/
446void QFutureWatcherBase::setPendingResultsLimit(int limit)
447{
448 Q_D(QFutureWatcherBase);
449 d->maximumPendingResultsReady = limit;
450}
451
452void QFutureWatcherBase::connectNotify(const QMetaMethod &signal)
453{
454 Q_D(QFutureWatcherBase);
455 static const QMetaMethod resultReadyAtSignal = QMetaMethod::fromSignal(&QFutureWatcherBase::resultReadyAt);
456 if (signal == resultReadyAtSignal)
457 d->resultAtConnected.ref();
458#ifndef QT_NO_DEBUG
459 static const QMetaMethod finishedSignal = QMetaMethod::fromSignal(&QFutureWatcherBase::finished);
460 if (signal == finishedSignal) {
461 if (futureInterface().isRunning()) {
462 //connections should be established before calling stFuture to avoid race.
463 // (The future could finish before the connection is made.)
464 qWarning("QFutureWatcher::connect: connecting after calling setFuture() is likely to produce race");
465 }
466 }
467#endif
468}
469
470void QFutureWatcherBase::disconnectNotify(const QMetaMethod &signal)
471{
472 Q_D(QFutureWatcherBase);
473 static const QMetaMethod resultReadyAtSignal = QMetaMethod::fromSignal(&QFutureWatcherBase::resultReadyAt);
474 if (signal == resultReadyAtSignal)
475 d->resultAtConnected.deref();
476}
477
478/*!
479 \internal
480*/
481QFutureWatcherBasePrivate::QFutureWatcherBasePrivate()
482 : maximumPendingResultsReady(QThread::idealThreadCount() * 2),
483 resultAtConnected(0),
484 finished(true) /* the initial m_future is a canceledResult(), with Finished set */
485{ }
486
487/*!
488 \internal
489*/
490void QFutureWatcherBase::connectOutputInterface()
491{
492 futureInterface().d->connectOutputInterface(d_func());
493}
494
495/*!
496 \internal
497*/
498void QFutureWatcherBase::disconnectOutputInterface(bool pendingAssignment)
499{
500 if (pendingAssignment) {
501 Q_D(QFutureWatcherBase);
502 d->pendingResultsReady.storeRelaxed(0);
503 d->finished = false; /* May soon be amended, during connectOutputInterface() */
504 }
505
506 futureInterface().d->disconnectOutputInterface(d_func());
507}
508
509void QFutureWatcherBasePrivate::postCallOutEvent(const QFutureCallOutEvent &callOutEvent)
510{
511 Q_Q(QFutureWatcherBase);
512
513 if (callOutEvent.callOutType == QFutureCallOutEvent::ResultsReady) {
514 if (pendingResultsReady.fetchAndAddRelaxed(1) >= maximumPendingResultsReady)
515 q->futureInterface().d->internal_setThrottled(true);
516 }
517
518 QCoreApplication::postEvent(q, callOutEvent.clone());
519}
520
521void QFutureWatcherBasePrivate::callOutInterfaceDisconnected()
522{
523 QCoreApplication::removePostedEvents(q_func(), QEvent::FutureCallOut);
524}
525
526void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event)
527{
528 Q_Q(QFutureWatcherBase);
529
530 switch (event->callOutType) {
531 case QFutureCallOutEvent::Started:
532 emit q->started();
533 break;
534 case QFutureCallOutEvent::Finished:
535 finished = true;
536 emit q->finished();
537 break;
538 case QFutureCallOutEvent::Canceled:
539 pendingResultsReady.storeRelaxed(0);
540 emit q->canceled();
541 break;
542 case QFutureCallOutEvent::Suspending:
543 if (q->futureInterface().isCanceled())
544 break;
545 emit q->suspending();
546#if QT_DEPRECATED_SINCE(6, 0)
547QT_WARNING_PUSH
548QT_WARNING_DISABLE_DEPRECATED
549 emit q->paused();
550QT_WARNING_POP
551#endif
552 break;
553 case QFutureCallOutEvent::Suspended:
554 if (q->futureInterface().isCanceled())
555 break;
556 emit q->suspended();
557 break;
558 case QFutureCallOutEvent::Resumed:
559 if (q->futureInterface().isCanceled())
560 break;
561 emit q->resumed();
562 break;
563 case QFutureCallOutEvent::ResultsReady: {
564 if (q->futureInterface().isCanceled())
565 break;
566
567 if (pendingResultsReady.fetchAndAddRelaxed(-1) <= maximumPendingResultsReady)
568 q->futureInterface().setThrottled(false);
569
570 const int beginIndex = event->index1;
571 const int endIndex = event->index2;
572
573 emit q->resultsReadyAt(beginIndex, endIndex);
574
575 if (resultAtConnected.loadRelaxed() <= 0)
576 break;
577
578 for (int i = beginIndex; i < endIndex; ++i)
579 emit q->resultReadyAt(i);
580
581 } break;
582 case QFutureCallOutEvent::Progress:
583 if (q->futureInterface().isCanceled())
584 break;
585
586 emit q->progressValueChanged(event->index1);
587 if (!event->text.isNull()) // ###
588 emit q->progressTextChanged(event->text);
589 break;
590 case QFutureCallOutEvent::ProgressRange:
591 emit q->progressRangeChanged(event->index1, event->index2);
592 break;
593 default: break;
594 }
595}
596
597
598/*! \fn template <typename T> const T &QFutureWatcher<T>::result() const
599
600 Returns the first result in the future(). If the result is not immediately
601 available, this function will block and wait for the result to become
602 available. This is a convenience method for calling resultAt(0).
603
604 \sa resultAt()
605*/
606
607/*! \fn template <typename T> const T &QFutureWatcher<T>::resultAt(int index) const
608
609 Returns the result at \a index in the future(). If the result is not
610 immediately available, this function will block and wait for the result to
611 become available.
612
613 \sa result()
614*/
615
616/*! \fn template <typename T> void QFutureWatcher<T>::setFuture(const QFuture<T> &future)
617
618 Starts watching the given \a future.
619
620 One of the signals might be emitted for the current state of the
621 \a future. For example, if the future is already stopped, the
622 finished signal will be emitted.
623
624 To avoid a race condition, it is important to call this function
625 \e after doing the connections.
626*/
627
628/*! \fn template <typename T> QFuture<T> QFutureWatcher<T>::future() const
629
630 Returns the watched future.
631*/
632
633/*! \fn template <typename T> void QFutureWatcher<T>::started()
634
635 This signal is emitted when this QFutureWatcher starts watching the future
636 set with setFuture().
637*/
638
639/*!
640 \fn template <typename T> void QFutureWatcher<T>::finished()
641 This signal is emitted when the watched future finishes.
642*/
643
644/*!
645 \fn template <typename T> void QFutureWatcher<T>::canceled()
646 This signal is emitted if the watched future is canceled.
647*/
648
649/*! \fn template <typename T> void QFutureWatcher<T>::suspending()
650
651 \since 6.0
652
653 This signal is emitted when the state of the watched future is
654 set to suspended.
655
656 \note This signal only informs that suspension has been requested. It
657 doesn't indicate that all background operations are stopped. Signals
658 for computations that were in progress at the moment of suspending will
659 still be delivered. To be informed when suspension actually
660 took effect, use the suspended() signal.
661
662 \sa setSuspended(), suspend(), suspended()
663*/
664
665#if QT_DEPRECATED_SINCE(6, 0)
666/*! \fn template <typename T> void QFutureWatcher<T>::paused()
667
668 \obsolete
669 Use suspending() instead.
670
671 This signal is emitted when the state of the watched future is
672 set to paused.
673
674 \note This signal only informs that pause has been requested. It
675 doesn't indicate that all background operations are stopped. Signals
676 for computations that were in progress at the moment of pausing will
677 still be delivered. To to be informed when pause() actually
678 took effect, use the suspended() signal.
679
680 \sa setPaused(), pause(), suspended()
681*/
682#endif // QT_DEPRECATED_SINCE(6, 0)
683
684/*! \fn template <typename T> void QFutureWatcher<T>::suspended()
685
686 \since 6.0
687
688 This signal is emitted when suspend() took effect, meaning that there are
689 no more running computations. After receiving this signal no more result
690 ready or progress reporting signals are expected.
691
692 \sa setSuspended(), suspend(), suspended()
693*/
694
695/*! \fn template <typename T> void QFutureWatcher<T>::resumed()
696 This signal is emitted when the watched future is resumed.
697*/
698
699/*!
700 \fn template <typename T> void QFutureWatcher<T>::progressRangeChanged(int minimum, int maximum)
701
702 The progress range for the watched future has changed to \a minimum and
703 \a maximum
704*/
705
706/*!
707 \fn template <typename T> void QFutureWatcher<T>::progressValueChanged(int progressValue)
708
709 This signal is emitted when the watched future reports progress,
710 \a progressValue gives the current progress. In order to avoid overloading
711 the GUI event loop, QFutureWatcher limits the progress signal emission
712 rate. This means that listeners connected to this slot might not get all
713 progress reports the future makes. The last progress update (where
714 \a progressValue equals the maximum value) will always be delivered.
715*/
716
717/*! \fn template <typename T> void QFutureWatcher<T>::progressTextChanged(const QString &progressText)
718
719 This signal is emitted when the watched future reports textual progress
720 information, \a progressText.
721*/
722
723/*!
724 \fn template <typename T> void QFutureWatcher<T>::resultReadyAt(int index)
725
726 This signal is emitted when the watched future reports a ready result at
727 \a index. If the future reports multiple results, the index will indicate
728 which one it is. Results can be reported out-of-order. To get the result,
729 call resultAt(index);
730*/
731
732/*!
733 \fn template <typename T> void QFutureWatcher<T>::resultsReadyAt(int beginIndex, int endIndex);
734
735 This signal is emitted when the watched future reports ready results.
736 The results are indexed from \a beginIndex to \a endIndex.
737
738*/
739
740QT_END_NAMESPACE
741
742#include "moc_qfuturewatcher.cpp"
743