1 /***************************************************************************
2 Copyright (C) 2005-2009 Robby Stephenson <robby@periapsis.org>
3 ***************************************************************************/
4
5 /***************************************************************************
6 * *
7 * This program is free software; you can redistribute it and/or *
8 * modify it under the terms of the GNU General Public License as *
9 * published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) version 3 or any later version *
11 * accepted by the membership of KDE e.V. (or its successor approved *
12 * by the membership of KDE e.V.), which shall act as a proxy *
13 * defined in Section 14 of version 3 of the license. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
22 * *
23 ***************************************************************************/
24
25 #include "progressmanager.h"
26 #include "tellico_debug.h"
27
28 #include <QTimer>
29
30 using Tellico::ProgressItem;
31 using Tellico::ProgressManager;
32 ProgressManager* ProgressManager::s_self = nullptr;
33
34 template<typename T>
35 inline
qHash(const QPointer<T> & pointer_)36 uint qHash(const QPointer<T>& pointer_) {
37 return qHash(pointer_.data());
38 }
39
Done(QObject * obj)40 ProgressItem::Done::Done(QObject* obj) : m_object(obj) {
41 // myDebug() << "**Done Item for" << m_object->metaObject()->className();
42 }
43
~Done()44 ProgressItem::Done::~Done() {
45 // m_object might have been deleted, so check for existence
46 if(m_object) {
47 ProgressManager::self()->setDone(m_object);
48 }
49 }
50
51 /* *********************************************** */
52
ProgressItem(const QString & label_,bool canCancel_)53 ProgressItem::ProgressItem(const QString& label_, bool canCancel_)
54 : m_label(label_)
55 , m_canCancel(canCancel_)
56 , m_progress(0)
57 , m_total(0)
58 , m_cancelled(false)
59 , m_done(false) {
60 }
61
~ProgressItem()62 ProgressItem::~ProgressItem() {
63 }
64
setProgress(qulonglong steps_)65 void ProgressItem::setProgress(qulonglong steps_) {
66 if(m_done) {
67 myDebug() << "Setting progress on item already done";
68 return;
69 }
70 m_progress = steps_;
71 emit signalProgress(this);
72
73 if(m_progress >= m_total) {
74 setDone();
75 }
76 }
77
setTotalSteps(qulonglong steps_)78 void ProgressItem::setTotalSteps(qulonglong steps_) {
79 m_total = steps_;
80 emit signalTotalSteps(this);
81 }
82
setDone()83 void ProgressItem::setDone() {
84 if(!m_cancelled) {
85 m_progress = m_total;
86 }
87 if(m_done) {
88 myDebug() << "ProgressItem::setDone() - Progress item is already done";
89 } else {
90 m_done = true;
91 emit signalDone(this);
92 }
93 // make sure the deleting doesn't interfere with anything
94 QTimer::singleShot(3000, this, &QObject::deleteLater);
95 }
96
cancel()97 void ProgressItem::cancel() {
98 if(!m_canCancel || m_cancelled) {
99 return;
100 }
101
102 m_cancelled = true;
103 emit signalCancelled(this);
104 }
105
106 /* *********************************************** */
107
ProgressManager()108 ProgressManager::ProgressManager() : QObject() {
109 }
110
~ProgressManager()111 ProgressManager::~ProgressManager() {
112 }
113
setProgress(QObject * owner_,qulonglong steps_)114 void ProgressManager::setProgress(QObject* owner_, qulonglong steps_) {
115 Q_ASSERT(owner_);
116 if(!owner_ || !m_items.contains(owner_)) {
117 return;
118 }
119
120 m_items[owner_] ->setProgress(steps_);
121 // slotUpdateTotalProgress(); // called in ProgressItem::setProgress()
122 // emit signalItemProgress(m_items[owner_]);
123 }
124
setTotalSteps(QObject * owner_,qulonglong steps_)125 void ProgressManager::setTotalSteps(QObject* owner_, qulonglong steps_) {
126 Q_ASSERT(owner_);
127 if(!owner_ || !m_items.contains(owner_)) {
128 return;
129 }
130
131 m_items[owner_]->setTotalSteps(steps_);
132 // updateTotalProgress(); // called in ProgressItem::setTotalSteps()
133 }
134
setDone(QObject * owner_)135 void ProgressManager::setDone(QObject* owner_) {
136 Q_ASSERT(owner_);
137 if(!owner_ || !m_items.contains(owner_)) {
138 return;
139 }
140 setDone(m_items[owner_]);
141 }
142
setDone(ProgressItem * item_)143 void ProgressManager::setDone(ProgressItem* item_) {
144 if(!item_) {
145 myDebug() << "null ProgressItem!";
146 return;
147 }
148 item_->setDone();
149 }
150
slotItemDone(ProgressItem * item_)151 void ProgressManager::slotItemDone(ProgressItem* item_) {
152 for(ProgressMap::Iterator it = m_items.begin(); it != m_items.end(); ++it) {
153 if(it.value() == item_) {
154 m_items.erase(it);
155 break;
156 }
157 }
158 slotUpdateTotalProgress();
159 }
160
newProgressItemImpl(QObject * owner_,const QString & label_,bool canCancel_)161 ProgressItem& ProgressManager::newProgressItemImpl(QObject* owner_,
162 const QString& label_,
163 bool canCancel_) {
164 Q_ASSERT(owner_);
165 // myDebug() << "Progress Item for" << owner_->metaObject()->className() << ":" << label_;
166 if(m_items.contains(owner_)) {
167 return *m_items[owner_];
168 }
169
170 ProgressItem* item = new ProgressItem(label_, canCancel_);
171 m_items.insert(owner_, item);
172
173 connect(item, &Tellico::ProgressItem::signalTotalSteps,
174 this, &Tellico::ProgressManager::slotUpdateTotalProgress);
175 connect(item, &Tellico::ProgressItem::signalProgress,
176 this, &Tellico::ProgressManager::slotUpdateTotalProgress);
177 connect(item, &Tellico::ProgressItem::signalDone,
178 this, &Tellico::ProgressManager::slotItemDone);
179
180 return *item;
181 }
182
slotUpdateTotalProgress()183 void ProgressManager::slotUpdateTotalProgress() {
184 qulonglong progress = 0;
185 qulonglong total = 0;
186
187 for(ProgressMap::ConstIterator it = m_items.constBegin(); it != m_items.constEnd(); ++it) {
188 if(it.value()) {
189 progress += (*it)->progress();
190 total += (*it)->totalSteps();
191 }
192 }
193
194 if(total == 0) {
195 if(!m_items.isEmpty()) {
196 emit signalTotalProgress(100);
197 }
198 return;
199 }
200
201 emit signalTotalProgress(100*progress/total);
202 }
203
slotCancelAll()204 void ProgressManager::slotCancelAll() {
205 for(ProgressMap::Iterator it = m_items.begin(), end = m_items.end(); it != end; ++it) {
206 if(it.value()) {
207 it.value()->cancel();
208 }
209 }
210 }
211
anyCanBeCancelled() const212 bool ProgressManager::anyCanBeCancelled() const {
213 for(ProgressMap::ConstIterator it = m_items.constBegin(), end = m_items.constEnd(); it != end; ++it) {
214 if(it.value() && it.value()->canCancel()) {
215 return true;
216 }
217 }
218 return false;
219 }
220