File indexing completed on 2024-04-28 05:08:26

0001 /***************************************************************************
0002     Copyright (C) 2005-2009 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include "progressmanager.h"
0026 #include "tellico_debug.h"
0027 
0028 #include <QTimer>
0029 
0030 using Tellico::ProgressItem;
0031 using Tellico::ProgressManager;
0032 ProgressManager* ProgressManager::s_self = nullptr;
0033 
0034 template<typename T>
0035 inline
0036 uint qHash(const QPointer<T>& pointer_) {
0037   return qHash(pointer_.data());
0038 }
0039 
0040 ProgressItem::Done::Done(QObject* obj) : m_object(obj) {
0041 //  myDebug() << "**Done Item for" << m_object->metaObject()->className();
0042 }
0043 
0044 ProgressItem::Done::~Done() {
0045   // m_object might have been deleted, so check for existence
0046   if(m_object) {
0047     ProgressManager::self()->setDone(m_object);
0048   }
0049 }
0050 
0051 /* *********************************************** */
0052 
0053 ProgressItem::ProgressItem(const QString& label_, bool canCancel_)
0054     : m_label(label_)
0055     , m_canCancel(canCancel_)
0056     , m_progress(0)
0057     , m_total(0)
0058     , m_cancelled(false)
0059     , m_done(false) {
0060 }
0061 
0062 ProgressItem::~ProgressItem() {
0063 }
0064 
0065 void ProgressItem::setProgress(qulonglong steps_) {
0066   if(m_done) {
0067     myDebug() << "Setting progress on item already done";
0068     return;
0069   }
0070   m_progress = steps_;
0071   emit signalProgress(this);
0072 
0073   if(m_progress >= m_total) {
0074     setDone();
0075   }
0076 }
0077 
0078 void ProgressItem::setTotalSteps(qulonglong steps_) {
0079   m_total = steps_;
0080   emit signalTotalSteps(this);
0081 }
0082 
0083 void ProgressItem::setDone() {
0084   if(!m_cancelled) {
0085     m_progress = m_total;
0086   }
0087   if(m_done) {
0088     myDebug() << "ProgressItem::setDone() - Progress item is already done";
0089   } else {
0090     m_done = true;
0091     emit signalDone(this);
0092   }
0093   // make sure the deleting doesn't interfere with anything
0094   QTimer::singleShot(3000, this, &QObject::deleteLater);
0095 }
0096 
0097 void ProgressItem::cancel() {
0098   if(!m_canCancel || m_cancelled) {
0099     return;
0100   }
0101 
0102   m_cancelled = true;
0103   emit signalCancelled(this);
0104 }
0105 
0106 /* *********************************************** */
0107 
0108 ProgressManager::ProgressManager() : QObject() {
0109 }
0110 
0111 ProgressManager::~ProgressManager() {
0112 }
0113 
0114 void ProgressManager::setProgress(QObject* owner_, qulonglong steps_) {
0115   Q_ASSERT(owner_);
0116   if(!owner_ || !m_items.contains(owner_)) {
0117     return;
0118   }
0119 
0120   m_items[owner_] ->setProgress(steps_);
0121 //  slotUpdateTotalProgress(); // called in ProgressItem::setProgress()
0122 //  emit signalItemProgress(m_items[owner_]);
0123 }
0124 
0125 void ProgressManager::setTotalSteps(QObject* owner_, qulonglong steps_) {
0126   Q_ASSERT(owner_);
0127   if(!owner_ || !m_items.contains(owner_)) {
0128     return;
0129   }
0130 
0131   m_items[owner_]->setTotalSteps(steps_);
0132 //  updateTotalProgress(); // called in ProgressItem::setTotalSteps()
0133 }
0134 
0135 void ProgressManager::setDone(QObject* owner_) {
0136   Q_ASSERT(owner_);
0137   if(!owner_ || !m_items.contains(owner_)) {
0138     return;
0139   }
0140   setDone(m_items[owner_]);
0141 }
0142 
0143 void ProgressManager::setDone(ProgressItem* item_) {
0144   if(!item_) {
0145     myDebug() << "null ProgressItem!";
0146     return;
0147   }
0148   item_->setDone();
0149 }
0150 
0151 void ProgressManager::slotItemDone(ProgressItem* item_) {
0152   for(ProgressMap::Iterator it = m_items.begin(); it != m_items.end(); ++it) {
0153     if(it.value() == item_) {
0154       m_items.erase(it);
0155       break;
0156     }
0157   }
0158   slotUpdateTotalProgress();
0159 }
0160 
0161 ProgressItem& ProgressManager::newProgressItemImpl(QObject* owner_,
0162                                                    const QString& label_,
0163                                                    bool canCancel_) {
0164   Q_ASSERT(owner_);
0165 //  myDebug() << "Progress Item for" << owner_->metaObject()->className() << ":" << label_;
0166   if(m_items.contains(owner_)) {
0167     return *m_items[owner_];
0168   }
0169 
0170   ProgressItem* item = new ProgressItem(label_, canCancel_);
0171   m_items.insert(owner_, item);
0172 
0173   connect(item, &Tellico::ProgressItem::signalTotalSteps,
0174           this, &Tellico::ProgressManager::slotUpdateTotalProgress);
0175   connect(item, &Tellico::ProgressItem::signalProgress,
0176           this, &Tellico::ProgressManager::slotUpdateTotalProgress);
0177   connect(item, &Tellico::ProgressItem::signalDone,
0178           this, &Tellico::ProgressManager::slotItemDone);
0179 
0180   return *item;
0181 }
0182 
0183 void ProgressManager::slotUpdateTotalProgress() {
0184   qulonglong progress = 0;
0185   qulonglong total = 0;
0186 
0187   for(ProgressMap::ConstIterator it = m_items.constBegin(); it != m_items.constEnd(); ++it) {
0188     if(it.value()) {
0189       progress += (*it)->progress();
0190       total += (*it)->totalSteps();
0191     }
0192   }
0193 
0194   if(total == 0) {
0195     if(!m_items.isEmpty()) {
0196       emit signalTotalProgress(100);
0197     }
0198     return;
0199   }
0200 
0201   emit signalTotalProgress(100*progress/total);
0202 }
0203 
0204 void ProgressManager::slotCancelAll() {
0205   for(ProgressMap::Iterator it = m_items.begin(), end = m_items.end(); it != end; ++it) {
0206     if(it.value()) {
0207       it.value()->cancel();
0208     }
0209   }
0210 }
0211 
0212 bool ProgressManager::anyCanBeCancelled() const {
0213   for(ProgressMap::ConstIterator it = m_items.constBegin(), end = m_items.constEnd(); it != end; ++it) {
0214     if(it.value() && it.value()->canCancel()) {
0215       return true;
0216     }
0217   }
0218   return false;
0219 }