1 /* 2 progressmanager.h 3 4 This file is part of libkdepim. 5 6 SPDX-FileCopyrightText: 2004 Till Adam <adam@kde.org> 7 8 SPDX-License-Identifier: LGPL-2.0-or-later 9 */ 10 11 #pragma once 12 13 #include "kdepim_export.h" 14 15 #include <QHash> 16 #include <QMap> 17 #include <QObject> 18 #include <QPointer> 19 #include <QString> 20 21 namespace KPIM 22 { 23 class ProgressItem; 24 class ProgressManager; 25 using ProgressItemMap = QMap<ProgressItem *, bool>; 26 /** 27 * @brief The ProgressItem class 28 */ 29 class KDEPIM_EXPORT ProgressItem : public QObject 30 { 31 Q_OBJECT 32 friend class ProgressManager; 33 34 public: 35 enum CryptoStatus { Encrypted, Unencrypted, Unknown }; 36 37 /** 38 * @return The id string which uniquely identifies the operation 39 * represented by this item. 40 */ 41 Q_REQUIRED_RESULT const QString &id() const; 42 43 /** 44 * @return The parent item of this one, if there is one. 45 */ 46 Q_REQUIRED_RESULT ProgressItem *parent() const; 47 48 /** 49 * @return The user visible string to be used to represent this item. 50 */ 51 Q_REQUIRED_RESULT const QString &label() const; 52 53 /** 54 * @param v Set the user visible string identifying this item. 55 */ 56 void setLabel(const QString &v); 57 58 /** 59 * @return The string to be used for showing this item's current status. 60 */ 61 Q_REQUIRED_RESULT const QString &status() const; 62 /** 63 * Set the string to be used for showing this item's current status. 64 * @param v The status string. 65 */ 66 void setStatus(const QString &v); 67 68 /** 69 * @return Whether this item can be canceled. 70 */ 71 Q_REQUIRED_RESULT bool canBeCanceled() const; 72 73 /** 74 * @param b Set if can be canceled 75 */ 76 void setCanBeCanceled(bool b); 77 78 /** 79 * @return Whether this item uses secure communication 80 * (Account uses ssl, for example.). 81 */ 82 Q_REQUIRED_RESULT CryptoStatus cryptoStatus() const; 83 84 /** 85 * Set whether this item uses encrypted communication, so listeners 86 * can display a nice crypto icon. 87 * @param v The value. 88 */ 89 void setCryptoStatus(ProgressItem::CryptoStatus v); 90 91 /** 92 * @return whether this item uses a busy indicator instead of real progress display 93 */ 94 Q_REQUIRED_RESULT bool usesBusyIndicator() const; 95 96 /** 97 * Sets whether this item uses a busy indicator instead of real progress for its progress bar. 98 * If it uses a busy indicator, you are still responsible for calling setProgress() from time to 99 * time to update the busy indicator. 100 */ 101 void setUsesBusyIndicator(bool useBusyIndicator); 102 103 /** 104 * @return The current progress value of this item in percent. 105 */ 106 Q_REQUIRED_RESULT unsigned int progress() const; 107 108 /** 109 * Set the progress (percentage of completion) value of this item. 110 * @param v The percentage value. 111 */ 112 void setProgress(unsigned int v); 113 114 /** 115 * Tell the item it has finished. This will Q_EMIT progressItemCompleted() 116 * result in the destruction of the item after all slots connected to this 117 * signal have executed. This is the only way to get rid of an item and 118 * needs to be called even if the item is canceled. Don't use the item 119 * after this has been called on it. 120 */ 121 void setComplete(); 122 123 /** 124 * Reset the progress value of this item to 0 and the status string to 125 * the empty string. 126 */ 127 void reset(); 128 129 void cancel(); 130 131 // Often needed values for calculating progress. 132 void setTotalItems(unsigned int v); 133 Q_REQUIRED_RESULT unsigned int totalItems() const; 134 void setCompletedItems(unsigned int v); 135 void incCompletedItems(unsigned int v = 1); 136 Q_REQUIRED_RESULT unsigned int completedItems() const; 137 138 /** 139 * Recalculate progress according to total/completed items and update. 140 */ 141 void updateProgress(); 142 143 void addChild(ProgressItem *kiddo); 144 void removeChild(ProgressItem *kiddo); 145 146 bool canceled() const; 147 148 unsigned int typeProgressItem() const; 149 void setTypeProgressItem(unsigned int); 150 151 Q_SIGNALS: 152 /** 153 * Emitted when a new ProgressItem is added. 154 * @param The ProgressItem that was added. 155 */ 156 void progressItemAdded(KPIM::ProgressItem *); 157 158 /** 159 * Emitted when the progress value of an item changes. 160 * @param The item which got a new value. 161 * @param The value, for convenience. 162 */ 163 void progressItemProgress(KPIM::ProgressItem *, unsigned int); 164 165 /** 166 * Emitted when a progress item was completed. The item will be 167 * deleted afterwards, so slots connected to this are the last 168 * chance to work with this item. 169 * @param The completed item. 170 */ 171 void progressItemCompleted(KPIM::ProgressItem *); 172 173 /** 174 * Emitted when an item was canceled. It will _not_ go away immediately, 175 * only when the owner sets it complete, which will usually happen. Can be 176 * used to visually indicate the canceled status of an item. Should be used 177 * by the owner of the item to make sure it is set completed even if it is 178 * canceled. There is a ProgressManager::slotStandardCancelHandler which 179 * simply sets the item completed and can be used if no other work needs to 180 * be done on cancel. 181 * @param The canceled item; 182 */ 183 void progressItemCanceled(KPIM::ProgressItem *); 184 185 /** 186 * Emitted when the status message of an item changed. Should be used by 187 * progress dialogs to update the status message for an item. 188 * @param The updated item. 189 * @param The new message. 190 */ 191 void progressItemStatus(KPIM::ProgressItem *, const QString &); 192 193 /** 194 * Emitted when the label of an item changed. Should be used by 195 * progress dialogs to update the label of an item. 196 * @param The updated item. 197 * @param The new label. 198 */ 199 void progressItemLabel(KPIM::ProgressItem *, const QString &); 200 201 /** 202 * Emitted when the crypto status of an item changed. Should be used by 203 * progress dialogs to update the crypto indicator of an item. 204 * @param The updated item. 205 * @param The new state. 206 */ 207 void progressItemCryptoStatus(KPIM::ProgressItem *, KPIM::ProgressItem::CryptoStatus); 208 209 /** 210 * Emitted when the busy indicator state of an item changes. Should be used 211 * by progress dialogs so that they can adjust the display of the progress bar 212 * to the new mode. 213 * @param item The updated item 214 * @param value True if the item uses a busy indicator now, false otherwise 215 */ 216 void progressItemUsesBusyIndicator(KPIM::ProgressItem *item, bool value); 217 218 protected: 219 /* Only to be used by our good friend the ProgressManager */ 220 ProgressItem(ProgressItem *parent, const QString &id, const QString &label, const QString &status, bool isCancellable, CryptoStatus cryptoStatus); 221 ~ProgressItem() override; 222 223 private: 224 QString mId; 225 QString mLabel; 226 QString mStatus; 227 QPointer<ProgressItem> mParent; 228 bool mCanBeCanceled = false; 229 unsigned int mProgress = 0; 230 ProgressItemMap mChildren; 231 unsigned int mTotal = 0; 232 unsigned int mCompleted = 0; 233 CryptoStatus mCryptoStatus; 234 unsigned int mType = 0; 235 bool mWaitingForKids = false; 236 bool mCanceled = false; 237 bool mUsesBusyIndicator = false; 238 bool mCompletedCalled = false; 239 }; 240 241 struct ProgressManagerPrivate; 242 243 /** 244 * The ProgressManager singleton keeps track of all ongoing transactions 245 * and notifies observers (progress dialogs) when their progress percent value 246 * changes, when they are completed (by their owner), and when they are canceled. 247 * Each ProgressItem emits those signals individually and the singleton 248 * broadcasts them. Use the ::createProgressItem() statics to acquire an item 249 * and then call ->setProgress( int percent ) on it every time you want to 250 * update the item and ->setComplete() when the operation is done. This will 251 * delete the item. Connect to the item's progressItemCanceled() signal to be 252 * notified when the user cancels the transaction using one of the observing 253 * progress dialogs or by calling item->cancel() in some other way. The owner 254 * is responsible for calling setComplete() on the item, even if it is canceled. 255 * Use the standardCancelHandler() slot if that is all you want to do on cancel. 256 * 257 * Note that if you request an item with a certain id and there is already 258 * one with that id, there will not be a new one created but the existing 259 * one will be returned. This is convenient for accessing items that are 260 * needed regularly without the to store a pointer to them or to add child 261 * items to parents by id. 262 */ 263 class KDEPIM_EXPORT ProgressManager : public QObject 264 { 265 Q_OBJECT 266 267 friend struct ProgressManagerPrivate; 268 269 public: 270 ~ProgressManager() override; 271 272 /** 273 * @return The singleton instance of this class. 274 */ 275 static ProgressManager *instance(); 276 277 /** 278 * Use this to acquire a unique id number which can be used to discern 279 * an operation from all others going on at the same time. Use that 280 * number as the id string for your progressItem to ensure it is unique. 281 * @return 282 */ 283 static QString getUniqueID(); 284 285 /** 286 * Creates a ProgressItem with a unique id and the given label. 287 * This is the simplest way to acquire a progress item. It will not 288 * have a parent and will be set to be cancellable and not using crypto. 289 */ 290 static ProgressItem *createProgressItem(unsigned int progressType, const QString &label); 291 292 /** 293 * Creates a ProgressItem with a unique id and the given label. 294 * This is the simplest way to acquire a progress item. It will not 295 * have a parent and will be set to be cancellable and not using crypto. 296 */ 297 static ProgressItem *createProgressItem(const QString &label); 298 299 /** 300 * Creates a new progressItem with the given parent, id, label and initial 301 * status. 302 * 303 * @param parent Specify an already existing item as the parent of this one. 304 * @param id Used to identify this operation for cancel and progress info. 305 * @param label The text to be displayed by progress handlers 306 * @param status Additional text to be displayed for the item. 307 * @param canBeCanceled can the user cancel this operation? 308 * @param usesCrypto does the operation use secure transports (SSL) 309 * Cancelling the parent will cancel the children as well (if they can be 310 * canceled) and ongoing children prevent parents from finishing. 311 * @return The ProgressItem representing the operation. 312 */ 313 static ProgressItem *createProgressItem(ProgressItem *parent, 314 const QString &id, 315 const QString &label, 316 const QString &status = QString(), 317 bool canBeCanceled = true, 318 KPIM::ProgressItem::CryptoStatus cryptoStatus = KPIM::ProgressItem::Unencrypted); 319 320 /** 321 * Use this version if you have the id string of the parent and want to 322 * add a subjob to it. 323 */ 324 static ProgressItem *createProgressItem(const QString &parent, 325 const QString &id, 326 const QString &label, 327 const QString &status = QString(), 328 bool canBeCanceled = true, 329 KPIM::ProgressItem::CryptoStatus cryptoStatus = KPIM::ProgressItem::Unencrypted); 330 331 /** 332 * Version without a parent. 333 */ 334 static ProgressItem *createProgressItem(const QString &id, 335 const QString &label, 336 const QString &status = QString(), 337 bool canBeCanceled = true, 338 KPIM::ProgressItem::CryptoStatus cryptoStatus = KPIM::ProgressItem::Unencrypted); 339 340 /** 341 * @return true when there are no more progress items. 342 */ 343 bool isEmpty() const; 344 345 /** 346 * @return the only top level progressitem when there's only one. 347 * Returns 0 if there is no item, or more than one top level item. 348 * Since this is used to calculate the overall progress, it will also return 349 * 0 if there is an item which uses a busy indicator, since that will invalidate 350 * the overall progress. 351 */ 352 ProgressItem *singleItem() const; 353 354 /** 355 * Ask all listeners to show the progress dialog, because there is 356 * something that wants to be shown. 357 */ 358 static void emitShowProgressDialog(); 359 360 ProgressItem *progressItem(const QString &id) const; 361 362 Q_SIGNALS: 363 /** @see ProgressItem::progressItemAdded() */ 364 void progressItemAdded(KPIM::ProgressItem *); 365 /** @see ProgressItem::progressItemProgress() */ 366 void progressItemProgress(KPIM::ProgressItem *, unsigned int); 367 /** @see ProgressItem::progressItemCompleted() */ 368 void progressItemCompleted(KPIM::ProgressItem *); 369 /** @see ProgressItem::progressItemCanceled() */ 370 void progressItemCanceled(KPIM::ProgressItem *); 371 /** @see ProgressItem::progressItemStatus() */ 372 void progressItemStatus(KPIM::ProgressItem *, const QString &); 373 /** @see ProgressItem::progressItemLabel() */ 374 void progressItemLabel(KPIM::ProgressItem *, const QString &); 375 /** @see ProgressItem::progressItemCryptoStatus() */ 376 void progressItemCryptoStatus(KPIM::ProgressItem *, KPIM::ProgressItem::CryptoStatus); 377 /** @see ProgressItem::progressItemUsesBusyIndicator */ 378 void progressItemUsesBusyIndicator(KPIM::ProgressItem *, bool); 379 380 /** 381 * Emitted when an operation requests the listeners to be shown. 382 * Use emitShowProgressDialog() to trigger it. 383 */ 384 void showProgressDialog(); 385 386 public Q_SLOTS: 387 388 /** 389 * Calls setCompleted() on the item, to make sure it goes away. 390 * Provided for convenience. 391 * @param item the canceled item. 392 */ 393 void slotStandardCancelHandler(KPIM::ProgressItem *item); 394 395 /** 396 * Aborts all running jobs. Bound to "Esc" 397 */ 398 void slotAbortAll(); 399 400 private Q_SLOTS: 401 void slotTransactionCompleted(KPIM::ProgressItem *item); 402 403 private: 404 ProgressManager(); 405 // prevent unsolicited copies 406 ProgressManager(const ProgressManager &); 407 408 ProgressItem *createProgressItemImpl(ProgressItem *parent, 409 const QString &id, 410 const QString &label, 411 const QString &status, 412 bool cancellable, 413 ProgressItem::CryptoStatus cryptoStatus, 414 unsigned int progressType = 0); 415 416 ProgressItem *createProgressItemImpl(const QString &parent, 417 const QString &id, 418 const QString &label, 419 const QString &status, 420 bool cancellable, 421 ProgressItem::CryptoStatus cryptoStatus, 422 unsigned int progressType = 0); 423 void emitShowProgressDialogImpl(); 424 425 QHash<QString, ProgressItem *> mTransactions; 426 static unsigned int uID; 427 }; 428 } 429 430