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