File indexing completed on 2024-05-12 04:38:17

0001 /*
0002     SPDX-FileCopyrightText: 2004 Till Adam <adam@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "progressmanager.h"
0008 #include "debug.h"
0009 
0010 #include <KLocalizedString>
0011 
0012 namespace KDevelop {
0013 
0014 unsigned int KDevelop::ProgressManager::uID = 42;
0015 
0016 ProgressItem::ProgressItem( ProgressItem *parent, const QString &id,
0017                             const QString &label, const QString &status,
0018                             bool canBeCanceled, bool usesCrypto )
0019     : mId( id ), mLabel( label ), mStatus( status ), mParent( parent ),
0020       mCanBeCanceled( canBeCanceled ), mProgress( 0 ), mTotal( 0 ),
0021       mCompleted( 0 ), mWaitingForKids( false ), mCanceled( false ),
0022       mUsesCrypto( usesCrypto ), mUsesBusyIndicator( false ), mCompletedCalled( false )
0023 {
0024 }
0025 
0026 ProgressItem::~ProgressItem()
0027 {
0028 }
0029 
0030 void ProgressItem::setComplete()
0031 {
0032     //   qCDebug(SHELL) << label();
0033     if ( mChildren.isEmpty() ) {
0034         if ( mCompletedCalled )
0035             return;
0036         if ( !mCanceled ) {
0037             setProgress( 100 );
0038         }
0039         mCompletedCalled = true;
0040         if ( parent() ) {
0041             parent()->removeChild( this );
0042         }
0043         emit progressItemCompleted( this );
0044     } else {
0045         mWaitingForKids = true;
0046     }
0047 }
0048 
0049 void ProgressItem::addChild( ProgressItem *kiddo )
0050 {
0051     mChildren.insert( kiddo, true );
0052 }
0053 
0054 void ProgressItem::removeChild( ProgressItem *kiddo )
0055 {
0056     if ( mChildren.isEmpty() ) {
0057         mWaitingForKids = false;
0058         return;
0059     }
0060 
0061     if ( mChildren.remove( kiddo ) == 0 ) {
0062         // do nothing if the specified item is not in the map
0063         return;
0064     }
0065 
0066     // in case we were waiting for the last kid to go away, now is the time
0067     if ( mChildren.count() == 0 && mWaitingForKids ) {
0068         emit progressItemCompleted( this );
0069     }
0070 }
0071 
0072 void ProgressItem::cancel()
0073 {
0074     if ( mCanceled || !mCanBeCanceled ) {
0075         return;
0076     }
0077 
0078     qCDebug(SHELL) << label();
0079     mCanceled = true;
0080     // Cancel all children.
0081     const QList<ProgressItem*> kids = mChildren.keys();
0082     for (ProgressItem* kid : kids) {
0083         if ( kid->canBeCanceled() ) {
0084             kid->cancel();
0085         }
0086     }
0087     setStatus( i18nc("@info", "Aborting..." ) );
0088     emit progressItemCanceled( this );
0089 }
0090 
0091 void ProgressItem::setProgress( unsigned int v )
0092 {
0093     mProgress = v;
0094     // qCDebug(SHELL) << label() << " :" << v;
0095     emit progressItemProgress( this, mProgress );
0096 }
0097 
0098 void ProgressItem::setLabel( const QString &v )
0099 {
0100     mLabel = v;
0101     emit progressItemLabel( this, mLabel );
0102 }
0103 
0104 void ProgressItem::setStatus( const QString &v )
0105 {
0106     mStatus = v;
0107     emit progressItemStatus( this, mStatus );
0108 }
0109 
0110 void ProgressItem::setUsesCrypto( bool v )
0111 {
0112     mUsesCrypto = v;
0113     emit progressItemUsesCrypto( this, v );
0114 }
0115 
0116 void ProgressItem::setUsesBusyIndicator( bool useBusyIndicator )
0117 {
0118     mUsesBusyIndicator = useBusyIndicator;
0119     emit progressItemUsesBusyIndicator( this, useBusyIndicator );
0120 }
0121 
0122 // ======================================
0123 
0124 struct ProgressManagerPrivate {
0125     ProgressManager instance;
0126 };
0127 
0128 Q_GLOBAL_STATIC( ProgressManagerPrivate, progressManagerPrivate )
0129 
0130 ProgressManager::ProgressManager()
0131     : QObject()
0132 {
0133 
0134 }
0135 
0136 ProgressManager::~ProgressManager()
0137 {
0138     for (auto* item : mTransactions)
0139         delete item;
0140 }
0141 
0142 ProgressManager *ProgressManager::instance()
0143 {
0144     return progressManagerPrivate.isDestroyed() ? nullptr : &progressManagerPrivate->instance ;
0145 }
0146 
0147 ProgressItem *ProgressManager::createProgressItemImpl( ProgressItem *parent,
0148                                                        const QString &id,
0149                                                        const QString &label,
0150                                                        const QString &status,
0151                                                        bool cancellable,
0152                                                        bool usesCrypto )
0153 {
0154     ProgressItem *t = nullptr;
0155     if ( !mTransactions.value( id ) ) {
0156         t = new ProgressItem ( parent, id, label, status, cancellable, usesCrypto );
0157         mTransactions.insert( id, t );
0158         if ( parent ) {
0159             ProgressItem *p = mTransactions.value( parent->id() );
0160             if ( p ) {
0161                 p->addChild( t );
0162             }
0163         }
0164         // connect all signals
0165         connect ( t, &ProgressItem::progressItemCompleted,
0166                   this, &ProgressManager::slotTransactionCompleted );
0167         connect ( t, &ProgressItem::progressItemProgress,
0168                   this, &ProgressManager::progressItemProgress );
0169         connect ( t, &ProgressItem::progressItemAdded,
0170                   this, &ProgressManager::progressItemAdded );
0171         connect ( t, &ProgressItem::progressItemCanceled,
0172                   this, &ProgressManager::progressItemCanceled );
0173         connect ( t, &ProgressItem::progressItemStatus,
0174                   this, &ProgressManager::progressItemStatus );
0175         connect ( t, &ProgressItem::progressItemLabel,
0176                   this, &ProgressManager::progressItemLabel );
0177         connect ( t, &ProgressItem::progressItemUsesCrypto,
0178                   this, &ProgressManager::progressItemUsesCrypto );
0179         connect ( t, &ProgressItem::progressItemUsesBusyIndicator,
0180                   this, &ProgressManager::progressItemUsesBusyIndicator );
0181 
0182         emit progressItemAdded( t );
0183     } else {
0184         // Hm, is this what makes the most sense?
0185         t = mTransactions.value( id );
0186     }
0187     return t;
0188 }
0189 
0190 ProgressItem *ProgressManager::createProgressItemImpl( const QString &parent,
0191                                                        const QString &id,
0192                                                        const QString &label,
0193                                                        const QString &status,
0194                                                        bool canBeCanceled,
0195                                                        bool usesCrypto )
0196 {
0197     ProgressItem *p = mTransactions.value( parent );
0198     return createProgressItemImpl( p, id, label, status, canBeCanceled, usesCrypto );
0199 }
0200 
0201 void ProgressManager::emitShowProgressDialogImpl()
0202 {
0203     emit showProgressDialog();
0204 }
0205 
0206 // slots
0207 
0208 void ProgressManager::slotTransactionCompleted( ProgressItem *item )
0209 {
0210     mTransactions.remove( item->id() );
0211     emit progressItemCompleted( item );
0212 }
0213 
0214 void ProgressManager::slotStandardCancelHandler( ProgressItem *item )
0215 {
0216     item->setComplete();
0217 }
0218 
0219 ProgressItem *ProgressManager::singleItem() const
0220 {
0221     ProgressItem *item = nullptr;
0222     for (ProgressItem* transactionItem : mTransactions) {
0223         // No single item for progress possible, as one of them is a busy indicator one.
0224         if (transactionItem->usesBusyIndicator())
0225             return nullptr;
0226 
0227         if (!transactionItem->parent()) {             // if it's a top level one, only those count
0228             if ( item ) {
0229                 return nullptr; // we found more than one
0230             } else {
0231                 item = transactionItem;
0232             }
0233         }
0234     }
0235     return item;
0236 }
0237 
0238 void ProgressManager::slotAbortAll()
0239 {
0240     QHashIterator<QString, ProgressItem *> it(mTransactions);
0241     while (it.hasNext()) {
0242         it.next();
0243         it.value()->cancel();
0244     }
0245 
0246 }
0247 
0248 } // namespace
0249 
0250 #include "moc_progressmanager.cpp"