File indexing completed on 2024-05-12 04:38:18
0001 /* 0002 SPDX-FileCopyrightText: 2004 Till Adam <adam@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef KDEVPLATFORM_PROGRESSMANAGER_H 0008 #define KDEVPLATFORM_PROGRESSMANAGER_H 0009 0010 #include <QObject> 0011 #include <QString> 0012 #include <QMap> 0013 #include <QHash> 0014 #include <QPointer> 0015 namespace Akonadi { 0016 class AgentInstance; 0017 } 0018 0019 namespace KDevelop { 0020 0021 class ProgressItem; 0022 class ProgressManager; 0023 using ProgressItemMap = QMap<ProgressItem*, bool>; 0024 0025 class ProgressItem : public QObject 0026 { 0027 Q_OBJECT 0028 friend class ProgressManager; 0029 0030 public: 0031 0032 /** 0033 * @return The id string which uniquely identifies the operation 0034 * represented by this item. 0035 */ 0036 const QString &id() const { return mId; } 0037 0038 /** 0039 * @return The parent item of this one, if there is one. 0040 */ 0041 ProgressItem *parent() const { return mParent.data(); } 0042 0043 /** 0044 * @return The user visible string to be used to represent this item. 0045 */ 0046 const QString &label() const { return mLabel; } 0047 0048 /** 0049 * @param v Set the user visible string identifying this item. 0050 */ 0051 void setLabel( const QString &v ); 0052 0053 /** 0054 * @return The string to be used for showing this item's current status. 0055 */ 0056 const QString &status() const { return mStatus; } 0057 /** 0058 * Set the string to be used for showing this item's current status. 0059 * @param v The status string. 0060 */ 0061 void setStatus( const QString &v ); 0062 0063 /** 0064 * @return Whether this item can be canceled. 0065 */ 0066 bool canBeCanceled() const { return mCanBeCanceled; } 0067 0068 /** 0069 * @return Whether this item uses secure communication 0070 * (Account uses ssl, for example.). 0071 */ 0072 bool usesCrypto() const { return mUsesCrypto; } 0073 0074 /** 0075 * Set whether this item uses crypted communication, so listeners 0076 * can display a nice crypto icon. 0077 * @param v The value. 0078 */ 0079 void setUsesCrypto( bool v ); 0080 0081 /** 0082 * @return whether this item uses a busy indicator instead of real progress display 0083 */ 0084 bool usesBusyIndicator() const { return mUsesBusyIndicator; } 0085 0086 /** 0087 * Sets whether this item uses a busy indicator instead of real progress for its progress bar. 0088 * If it uses a busy indicator, you are still responsible for calling setProgress() from time to 0089 * time to update the busy indicator. 0090 */ 0091 void setUsesBusyIndicator( bool useBusyIndicator ); 0092 0093 /** 0094 * @return The current progress value of this item in percent. 0095 */ 0096 unsigned int progress() const { return mProgress; } 0097 0098 /** 0099 * Set the progress (percentage of completion) value of this item. 0100 * @param v The percentage value. 0101 */ 0102 void setProgress( unsigned int v ); 0103 0104 /** 0105 * Tell the item it has finished. This will emit progressItemCompleted() 0106 * result in the destruction of the item after all slots connected to this 0107 * signal have executed. This is the only way to get rid of an item and 0108 * needs to be called even if the item is canceled. Don't use the item 0109 * after this has been called on it. 0110 */ 0111 void setComplete(); 0112 0113 /** 0114 * Reset the progress value of this item to 0 and the status string to 0115 * the empty string. 0116 */ 0117 void reset() 0118 { 0119 setProgress( 0 ); 0120 setStatus( QString() ); 0121 mCompleted = 0; 0122 } 0123 0124 void cancel(); 0125 0126 // Often needed values for calculating progress. 0127 void setTotalItems( unsigned int v ) { mTotal = v; } 0128 unsigned int totalItems() const { return mTotal; } 0129 void setCompletedItems( unsigned int v ) { mCompleted = v; } 0130 void incCompletedItems( unsigned int v = 1 ) { mCompleted += v; } 0131 unsigned int completedItems() const { return mCompleted; } 0132 0133 /** 0134 * Recalculate progress according to total/completed items and update. 0135 */ 0136 void updateProgress() 0137 { 0138 setProgress( mTotal? mCompleted * 100 / mTotal : 0 ); 0139 } 0140 0141 void addChild( ProgressItem *kiddo ); 0142 void removeChild( ProgressItem *kiddo ); 0143 0144 bool canceled() const { return mCanceled; } 0145 void setBusy( bool busy ); 0146 0147 Q_SIGNALS: 0148 /** 0149 * Emitted when a new ProgressItem is added. 0150 * @param item The ProgressItem that was added. 0151 */ 0152 void progressItemAdded( KDevelop::ProgressItem* item ); 0153 0154 /** 0155 * Emitted when the progress value of an item changes. 0156 * @param item The item which got a new value. 0157 * @param value The value, for convenience. 0158 */ 0159 void progressItemProgress( KDevelop::ProgressItem* item, unsigned int value ); 0160 0161 /** 0162 * Emitted when a progress item was completed. The item will be 0163 * deleted afterwards, so slots connected to this are the last 0164 * chance to work with this item. 0165 * @param item The completed item. 0166 */ 0167 void progressItemCompleted( KDevelop::ProgressItem* item ); 0168 0169 /** 0170 * Emitted when an item was canceled. It will _not_ go away immediately, 0171 * only when the owner sets it complete, which will usually happen. Can be 0172 * used to visually indicate the canceled status of an item. Should be used 0173 * by the owner of the item to make sure it is set completed even if it is 0174 * canceled. There is a ProgressManager::slotStandardCancelHandler which 0175 * simply sets the item completed and can be used if no other work needs to 0176 * be done on cancel. 0177 * @param item The canceled item; 0178 */ 0179 void progressItemCanceled( KDevelop::ProgressItem* item ); 0180 0181 /** 0182 * Emitted when the status message of an item changed. Should be used by 0183 * progress dialogs to update the status message for an item. 0184 * @param item The updated item. 0185 * @param message The new message. 0186 */ 0187 void progressItemStatus( KDevelop::ProgressItem* item, const QString& message ); 0188 0189 /** 0190 * Emitted when the label of an item changed. Should be used by 0191 * progress dialogs to update the label of an item. 0192 * @param item The updated item. 0193 * @param label The new label. 0194 */ 0195 void progressItemLabel( KDevelop::ProgressItem* item, const QString& label ); 0196 0197 /** 0198 * Emitted when the crypto status of an item changed. Should be used by 0199 * progress dialogs to update the crypto indicator of an item. 0200 * @param item The updated item. 0201 * @param state The new state. 0202 */ 0203 void progressItemUsesCrypto( KDevelop::ProgressItem* item, bool state ); 0204 0205 /** 0206 * Emitted when the busy indicator state of an item changes. Should be used 0207 * by progress dialogs so that they can adjust the display of the progress bar 0208 * to the new mode. 0209 * @param item The updated item 0210 * @param value True if the item uses a busy indicator now, false otherwise 0211 */ 0212 void progressItemUsesBusyIndicator( KDevelop::ProgressItem *item, bool value ); 0213 0214 protected: 0215 /* Only to be used by our good friend the ProgressManager */ 0216 ProgressItem( ProgressItem *parent, const QString &id, const QString &label, 0217 const QString &status, bool isCancellable, bool usesCrypto ); 0218 ~ProgressItem() override; 0219 0220 private: 0221 const QString mId; 0222 QString mLabel; 0223 QString mStatus; 0224 QPointer<ProgressItem> mParent; 0225 const bool mCanBeCanceled; 0226 unsigned int mProgress; 0227 ProgressItemMap mChildren; 0228 unsigned int mTotal; 0229 unsigned int mCompleted; 0230 bool mWaitingForKids; 0231 bool mCanceled; 0232 bool mUsesCrypto; 0233 bool mUsesBusyIndicator; 0234 bool mCompletedCalled; 0235 }; 0236 0237 struct ProgressManagerPrivate; 0238 0239 /** 0240 * The ProgressManager singleton keeps track of all ongoing transactions 0241 * and notifies observers (progress dialogs) when their progress percent value 0242 * changes, when they are completed (by their owner), and when they are canceled. 0243 * Each ProgressItem emits those signals individually and the singleton 0244 * broadcasts them. Use the createProgressItem() statics to acquire an item 0245 * and then call ->setProgress( int percent ) on it every time you want to 0246 * update the item and ->setComplete() when the operation is done. This will 0247 * delete the item. Connect to the item's progressItemCanceled() signal to be 0248 * notified when the user cancels the transaction using one of the observing 0249 * progress dialogs or by calling item->cancel() in some other way. The owner 0250 * is responsible for calling setComplete() on the item, even if it is canceled. 0251 * Use the standardCancelHandler() slot if that is all you want to do on cancel. 0252 * 0253 * Note that if you request an item with a certain id and there is already 0254 * one with that id, there will not be a new one created but the existing 0255 * one will be returned. This is convenient for accessing items that are 0256 * needed regularly without the to store a pointer to them or to add child 0257 * items to parents by id. 0258 */ 0259 class ProgressManager : public QObject 0260 { 0261 0262 Q_OBJECT 0263 0264 friend struct ProgressManagerPrivate; 0265 0266 public: 0267 ~ProgressManager() override; 0268 0269 /** 0270 * @return The singleton instance of this class. 0271 */ 0272 static ProgressManager *instance(); 0273 0274 /** 0275 * @return a unique id number which can be used to discern 0276 * an operation from all others going on at the same time. Use that 0277 * number as the id string for your <i>progressItem</i> to ensure it is unique. 0278 */ 0279 static QString createUniqueID() 0280 { 0281 return QString::number( ++uID ); 0282 } 0283 0284 /** 0285 * Creates a ProgressItem with a unique id and the given label. 0286 * This is the simplest way to acquire a progress item. It will not 0287 * have a parent and will be set to be cancellable and not using crypto. 0288 */ 0289 static ProgressItem *createProgressItem( const QString &label ) 0290 { 0291 return instance()->createProgressItemImpl( nullptr, createUniqueID(), label, 0292 QString(), true, false ); 0293 } 0294 0295 /** 0296 * Creates a new progressItem with the given parent, id, label and initial 0297 * status. 0298 * 0299 * @param parent Specify an already existing item as the parent of this one. 0300 * @param id Used to identify this operation for cancel and progress info. 0301 * @param label The text to be displayed by progress handlers 0302 * @param status Additional text to be displayed for the item. 0303 * @param canBeCanceled can the user cancel this operation? 0304 * @param usesCrypto does the operation use secure transports (SSL) 0305 * Cancelling the parent will cancel the children as well (if they can be 0306 * canceled) and ongoing children prevent parents from finishing. 0307 * @return The ProgressItem representing the operation. 0308 */ 0309 static ProgressItem *createProgressItem( ProgressItem *parent, 0310 const QString &id, 0311 const QString &label, 0312 const QString &status = QString(), 0313 bool canBeCanceled = true, 0314 bool usesCrypto = false ) 0315 { 0316 return instance()->createProgressItemImpl( parent, id, label, status, 0317 canBeCanceled, usesCrypto ); 0318 } 0319 0320 /** 0321 * Use this version if you have the id string of the parent and want to 0322 * add a subjob to it. 0323 */ 0324 static ProgressItem *createProgressItem( const QString &parent, 0325 const QString &id, 0326 const QString &label, 0327 const QString &status = QString(), 0328 bool canBeCanceled = true, 0329 bool usesCrypto = false ) 0330 { 0331 return instance()->createProgressItemImpl( parent, id, label, 0332 status, canBeCanceled, usesCrypto ); 0333 } 0334 0335 /** 0336 * Version without a parent. 0337 */ 0338 static ProgressItem *createProgressItem( const QString &id, 0339 const QString &label, 0340 const QString &status = QString(), 0341 bool canBeCanceled = true, 0342 bool usesCrypto = false ) 0343 { 0344 return instance()->createProgressItemImpl( nullptr, id, label, status, 0345 canBeCanceled, usesCrypto ); 0346 } 0347 0348 /** 0349 * Version for Akonadi agents. 0350 * This connects all the proper signals so that you do not have to 0351 * worry about updating the progress or reacting to progressItemCanceled(). 0352 */ 0353 static ProgressItem *createProgressItem( ProgressItem *parent, 0354 const Akonadi::AgentInstance &agent, 0355 const QString &id, 0356 const QString &label, 0357 const QString &status = QString(), 0358 bool canBeCanceled = true, 0359 bool usesCrypto = false ) 0360 { 0361 return instance()->createProgressItemForAgent( parent, agent, id, label, 0362 status, canBeCanceled, usesCrypto ); 0363 } 0364 0365 /** 0366 * @return true when there are no more progress items. 0367 */ 0368 bool isEmpty() const 0369 { 0370 return mTransactions.isEmpty(); 0371 } 0372 0373 /** 0374 * @return the only top level progressitem when there's only one. 0375 * Returns 0 if there is no item, or more than one top level item. 0376 * Since this is used to calculate the overall progress, it will also return 0377 * 0 if there is an item which uses a busy indicator, since that will invalidate 0378 * the overall progress. 0379 */ 0380 ProgressItem *singleItem() const; 0381 0382 /** 0383 * Ask all listeners to show the progress dialog, because there is 0384 * something that wants to be shown. 0385 */ 0386 static void emitShowProgressDialog() 0387 { 0388 instance()->emitShowProgressDialogImpl(); 0389 } 0390 0391 Q_SIGNALS: 0392 /** @see ProgressItem::progressItemAdded() */ 0393 void progressItemAdded( KDevelop::ProgressItem * ); 0394 /** @see ProgressItem::progressItemProgress() */ 0395 void progressItemProgress( KDevelop::ProgressItem *, unsigned int ); 0396 /** @see ProgressItem::progressItemCompleted() */ 0397 void progressItemCompleted( KDevelop::ProgressItem * ); 0398 /** @see ProgressItem::progressItemCanceled() */ 0399 void progressItemCanceled( KDevelop::ProgressItem * ); 0400 /** @see ProgressItem::progressItemStatus() */ 0401 void progressItemStatus( KDevelop::ProgressItem *, const QString & ); 0402 /** @see ProgressItem::progressItemLabel() */ 0403 void progressItemLabel( KDevelop::ProgressItem *, const QString & ); 0404 /** @see ProgressItem::progressItemUsesCrypto() */ 0405 void progressItemUsesCrypto( KDevelop::ProgressItem *, bool ); 0406 /** @see ProgressItem::progressItemUsesBusyIndicator */ 0407 void progressItemUsesBusyIndicator( KDevelop::ProgressItem*, bool ); 0408 0409 /** 0410 * Emitted when an operation requests the listeners to be shown. 0411 * Use emitShowProgressDialog() to trigger it. 0412 */ 0413 void showProgressDialog(); 0414 0415 public Q_SLOTS: 0416 0417 /** 0418 * Calls setCompleted() on the item, to make sure it goes away. 0419 * Provided for convenience. 0420 * @param item the canceled item. 0421 */ 0422 void slotStandardCancelHandler( KDevelop::ProgressItem *item ); 0423 0424 /** 0425 * Aborts all running jobs. Bound to "Esc" 0426 */ 0427 void slotAbortAll(); 0428 0429 private Q_SLOTS: 0430 void slotTransactionCompleted( KDevelop::ProgressItem *item ); 0431 0432 private: 0433 ProgressManager(); 0434 // prevent unsolicited copies 0435 ProgressManager( const ProgressManager & ); 0436 0437 virtual ProgressItem *createProgressItemImpl( ProgressItem *parent, 0438 const QString &id, 0439 const QString &label, 0440 const QString &status, 0441 bool cancellable, 0442 bool usesCrypto ); 0443 virtual ProgressItem *createProgressItemImpl( const QString &parent, 0444 const QString &id, 0445 const QString &label, 0446 const QString &status, 0447 bool cancellable, 0448 bool usesCrypto ); 0449 ProgressItem *createProgressItemForAgent( ProgressItem *parent, 0450 const Akonadi::AgentInstance &instance, 0451 const QString &id, 0452 const QString &label, 0453 const QString &status, 0454 bool cancellable, 0455 bool usesCrypto ); 0456 void emitShowProgressDialogImpl(); 0457 0458 QHash< QString, ProgressItem* > mTransactions; 0459 static unsigned int uID; 0460 }; 0461 0462 } 0463 0464 #endif // __KDevelop_PROGRESSMANAGER_H__