Warning, file /office/calligra/libs/widgetutils/KoProgressUpdater.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org> 0003 * Copyright (C) 2009 Boudewijn Rempt <boud@valdyas.org> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Library General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public License 0016 * along with this library; see the file COPYING.LIB. If not, write to 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 #include "KoProgressUpdater.h" 0021 0022 #include <QApplication> 0023 #include <QString> 0024 #include <QTextStream> 0025 #include <QTimer> 0026 0027 #include "KoUpdaterPrivate_p.h" 0028 #include "KoUpdater.h" 0029 #include "KoProgressProxy.h" 0030 0031 0032 // 4 updates per second should be enough 0033 #define PROGRESSUPDATER_GUITIMERINTERVAL 250 0034 0035 class Q_DECL_HIDDEN KoProgressUpdater::Private 0036 { 0037 public: 0038 0039 Private(KoProgressUpdater *_parent, KoProgressProxy *p, Mode _mode, 0040 QTextStream *output_ = 0) 0041 : parent(_parent) 0042 , progressBar(p) 0043 , mode(_mode) 0044 , totalWeight(0) 0045 , currentProgress(0) 0046 , updated(false) 0047 , output(output_) 0048 , updateGuiTimer(_parent) 0049 , canceled(false) 0050 { 0051 } 0052 0053 KoProgressUpdater *parent; 0054 KoProgressProxy *progressBar; 0055 Mode mode; 0056 int totalWeight; 0057 int currentProgress; 0058 bool updated; // is true whenever the progress needs to be recomputed 0059 QTextStream *output; 0060 QTimer updateGuiTimer; // fires regularly to update the progress bar widget 0061 QList<QPointer<KoUpdaterPrivate> > subtasks; 0062 QList<QPointer<KoUpdater> > subTaskWrappers; // We delete these 0063 QTime referenceTime; 0064 0065 static void logEvents(QTextStream& out, KoProgressUpdater::Private *updater, 0066 const QTime& startTime, const QString& prefix); 0067 bool canceled; 0068 }; 0069 0070 // NOTE: do not make the KoProgressUpdater object part of the QObject 0071 // hierarchy. Do not make KoProgressProxy its parent (note that KoProgressProxy 0072 // is not necessarily castable to QObject ). This prevents proper functioning 0073 // of progress reporting in multi-threaded environments. 0074 KoProgressUpdater::KoProgressUpdater(KoProgressProxy *progressBar, 0075 Mode mode, QTextStream *output) 0076 : d (new Private(this, progressBar, mode, output)) 0077 { 0078 Q_ASSERT(d->progressBar); 0079 connect(&d->updateGuiTimer, SIGNAL(timeout()), SLOT(updateUi())); 0080 } 0081 0082 KoProgressUpdater::~KoProgressUpdater() 0083 { 0084 if (d->output) { 0085 Private::logEvents(*d->output, d, referenceTime(), ""); 0086 } 0087 d->progressBar->setValue(d->progressBar->maximum()); 0088 0089 // make sure to stop the timer to avoid accessing 0090 // the data we are going to delete right now 0091 d->updateGuiTimer.stop(); 0092 0093 qDeleteAll(d->subtasks); 0094 d->subtasks.clear(); 0095 0096 qDeleteAll(d->subTaskWrappers); 0097 d->subTaskWrappers.clear(); 0098 0099 delete d; 0100 } 0101 0102 void KoProgressUpdater::setReferenceTime(const QTime &referenceTime) 0103 { 0104 d->referenceTime = referenceTime; 0105 } 0106 0107 QTime KoProgressUpdater::referenceTime() const 0108 { 0109 return d->referenceTime; 0110 } 0111 0112 void KoProgressUpdater::start(int range, const QString &text) 0113 { 0114 d->updateGuiTimer.start(PROGRESSUPDATER_GUITIMERINTERVAL); 0115 0116 qDeleteAll(d->subtasks); 0117 d->subtasks.clear(); 0118 0119 qDeleteAll(d->subTaskWrappers); 0120 d->subTaskWrappers.clear(); 0121 0122 d->progressBar->setRange(0, range-1); 0123 d->progressBar->setValue(0); 0124 0125 if(!text.isEmpty()) { 0126 d->progressBar->setFormat(text); 0127 } 0128 d->totalWeight = 0; 0129 d->canceled = false; 0130 } 0131 0132 QPointer<KoUpdater> KoProgressUpdater::startSubtask(int weight, 0133 const QString &name) 0134 { 0135 KoUpdaterPrivate *p = new KoUpdaterPrivate(this, weight, name); 0136 d->totalWeight += weight; 0137 d->subtasks.append(p); 0138 connect(p, SIGNAL(sigUpdated()), SLOT(update())); 0139 0140 QPointer<KoUpdater> updater = new KoUpdater(p); 0141 d->subTaskWrappers.append(updater); 0142 0143 if (!d->updateGuiTimer.isActive()) { 0144 // we maybe need to restart the timer if it was stopped in updateUi() cause 0145 // other sub-tasks created before this one finished already. 0146 d->updateGuiTimer.start(PROGRESSUPDATER_GUITIMERINTERVAL); 0147 } 0148 0149 return updater; 0150 } 0151 0152 void KoProgressUpdater::cancel() 0153 { 0154 foreach(KoUpdaterPrivate *updater, d->subtasks) { 0155 updater->setProgress(100); 0156 updater->interrupt(); 0157 } 0158 d->canceled = true; 0159 updateUi(); 0160 } 0161 0162 void KoProgressUpdater::update() 0163 { 0164 d->updated = true; 0165 if (d->mode == Unthreaded) { 0166 qApp->processEvents(); 0167 } 0168 } 0169 0170 void KoProgressUpdater::updateUi() 0171 { 0172 // This function runs in the app main thread. All the progress 0173 // updates arrive at the KoUpdaterPrivate instances through 0174 // queued connections, so until we relinquish control to the 0175 // event loop, the progress values cannot change, and that 0176 // won't happen until we return from this function (which is 0177 // triggered by a timer) 0178 0179 if (d->updated) { 0180 int totalProgress = 0; 0181 foreach(QPointer<KoUpdaterPrivate> updater, d->subtasks) { 0182 if (updater->interrupted()) { 0183 d->currentProgress = -1; 0184 return; 0185 } 0186 0187 int progress = updater->progress(); 0188 if (progress > 100 || progress < 0) { 0189 progress = updater->progress(); 0190 } 0191 0192 totalProgress += progress *updater->weight(); 0193 } 0194 0195 d->currentProgress = totalProgress / d->totalWeight; 0196 d->updated = false; 0197 } 0198 0199 if (d->currentProgress == -1) { 0200 d->progressBar->setValue( d->progressBar->maximum() ); 0201 // should we hide the progressbar after a little while? 0202 return; 0203 } 0204 0205 if (d->currentProgress >= d->progressBar->maximum()) { 0206 // we're done 0207 d->updateGuiTimer.stop(); // 10 updates/second should be enough? 0208 } 0209 d->progressBar->setValue(d->currentProgress); 0210 } 0211 0212 bool KoProgressUpdater::interrupted() const 0213 { 0214 return d->canceled; 0215 } 0216 0217 bool KoProgressUpdater::hasOutput() const 0218 { 0219 return d->output != 0; 0220 } 0221 0222 void KoProgressUpdater::Private::logEvents(QTextStream& out, 0223 KoProgressUpdater::Private *updater, 0224 const QTime& startTime, 0225 const QString& prefix) { 0226 // initial implementation: write out the names of all events 0227 foreach (QPointer<KoUpdaterPrivate> p, updater->subtasks) { 0228 if (!p) continue; 0229 foreach (const KoUpdaterPrivate::TimePoint &tp, p->getPoints()) { 0230 out << prefix+p->objectName() << '\t' 0231 << startTime.msecsTo(tp.time) << '\t' << tp.value << endl; 0232 } 0233 } 0234 }