File indexing completed on 2024-05-19 05:11:18
0001 /* 0002 SPDX-FileCopyrightText: 2004 Reinhold Kainhofer <reinhold@kainhofer.com> 0003 SPDX-FileCopyrightText: 2010-2012 Sérgio Martins <iamsergio@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 #pragma once 0008 0009 #include "akonadi-calendar_export.h" 0010 0011 #include "itiphandler.h" 0012 #include <Akonadi/Collection> 0013 #include <Akonadi/Item> 0014 0015 #include <KCalendarCore/Incidence> 0016 0017 #include <QFlags> 0018 #include <QWidget> 0019 0020 #include <memory> 0021 0022 namespace Akonadi 0023 { 0024 class EntityTreeModel; 0025 class IncidenceChangerPrivate; 0026 0027 /** 0028 * @short IncidenceChanger is the preferred way to easily create, modify and delete incidences. 0029 * 0030 * It hides the communication with akonadi from the library user. 0031 * 0032 * It provides the following features that ItemCreateJob, ItemModifyJob and 0033 * ItemDeleteJob do not: 0034 * - Sending groupware ( iTip ) messages to attendees and organizers. 0035 * - Aware of recurrences, allowing to only change one occurrence. 0036 * - Undo/Redo 0037 * - Group operations which are executed in an atomic manner. 0038 * - Collection ACLs 0039 * - Error dialogs with calendaring lingo 0040 * 0041 * In the context of this API, "change", means "creation", "deletion" or incidence "modification". 0042 * 0043 * @code 0044 * IncidenceChanger *changer = new IncidenceChanger( parent ); 0045 * connect( changer, 0046 * SIGNAL(createFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)), 0047 * SLOT(slotCreateFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)) ); 0048 * 0049 * connect( changer, 0050 * SIGNAL(deleteFinished(int,QList<Akonadi::Item::Id>,Akonadi::IncidenceChanger::ResultCode,QString)), 0051 * SLOT(slotDeleteFinished(int,QList<Akonadi::Item::Id>,Akonadi::IncidenceChanger::ResultCode,QString)) ); 0052 * 0053 * connect( changer,SIGNAL(modifyFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)), 0054 * SLOT(slotModifyFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)) ); 0055 * 0056 * changer->setDestinationPolicy( IncidenceChanger::DestinationPolicyAsk ); 0057 * 0058 * KCalendarCore::Incidence::Ptr incidence = (...); 0059 * int changeId = changer->createIncidence( incidence, Akonadi::Collection() ); 0060 * 0061 * 0062 * if ( changeId == -1 ) 0063 * { 0064 * // Invalid parameters, incidence is null. 0065 * } 0066 * 0067 * @endcode 0068 * 0069 * @author Sérgio Martins <iamsergio@gmail.com> 0070 * @since 4.11 0071 */ 0072 0073 class History; 0074 0075 class AKONADI_CALENDAR_EXPORT IncidenceChanger : public QObject 0076 { 0077 Q_OBJECT 0078 public: 0079 /** 0080 * This enum describes result codes which are returned by createFinished(), 0081 * modifyfinished() and deleteFinished() signals. 0082 */ 0083 enum ResultCode { 0084 ResultCodeSuccess = 0, 0085 ResultCodeJobError, ///< ItemCreateJob, ItemModifyJob or ItemDeleteJob weren't successful 0086 ResultCodeAlreadyDeleted, ///< That incidence was already deleted, or currently being deleted. 0087 ResultCodeInvalidDefaultCollection, ///< Default collection is invalid and DestinationPolicyNeverAsk was used 0088 ResultCodeRolledback, ///< One change belonging to an atomic operation failed. All other changes were rolled back. 0089 ResultCodePermissions, ///< The parent collection doesn't have ACLs for this operation 0090 ResultCodeUserCanceled, ///< User canceled the operation 0091 ResultCodeInvalidUserCollection, ///< User somehow chose an invalid collection in the collection dialog ( should not happen ) 0092 ResultCodeModificationDiscarded, ///< A new modification came in, the old one is discarded 0093 ResultCodeDuplicateId ///< Duplicate Akonadi::Item::Ids must be unique in group operations 0094 }; 0095 0096 /** 0097 * This enum describes destination policies. 0098 * Destination policies control how the createIncidence() method chooses the 0099 * collection where the item will be created. 0100 */ 0101 enum DestinationPolicy { 0102 DestinationPolicyDefault, ///< The default collection is used, if it's invalid, the user is prompted. @see setDefaultCollection(). 0103 DestinationPolicyAsk, ///< User is always asked which collection to use. 0104 DestinationPolicyNeverAsk ///< The default collection is used, if it's invalid, an error is returned, and the incidence isn't added. 0105 }; 0106 0107 /** 0108 * Enum for controlling "Do you want to e-mail attendees" type of dialogs. 0109 * This is only honoured if groupware communication is active. 0110 * 0111 * @see groupwareCommunication() 0112 * @since 4.12 0113 */ 0114 enum InvitationPolicy { 0115 InvitationPolicySend = 0, ///< Invitation e-mails are sent without asking the user if he wants to. 0116 InvitationPolicyAsk, ///< The user is asked if an e-mail should be sent. This is the default. 0117 InvitationPolicyDontSend ///< E-mails aren't sent 0118 }; 0119 0120 /** 0121 * Flags describing whether invitation emails should signed and/or encrypted. 0122 */ 0123 enum InvitationPrivacy { 0124 InvitationPrivacyPlain = 0, ///< Invitation emails are not signed or encrpyted 0125 InvitationPrivacySign = 1, ///< Invitation emails are signed 0126 InvitationPrivacyEncrypt = 2 //< Invitation emails are encrypted 0127 }; 0128 Q_DECLARE_FLAGS(InvitationPrivacyFlags, InvitationPrivacy) 0129 0130 /** 0131 * This enum describes change types. 0132 */ 0133 enum ChangeType { 0134 ChangeTypeCreate, ///> Represents an incidence creation. 0135 ChangeTypeModify, ///> Represents an incidence modification. 0136 ChangeTypeDelete ///> Represents an incidence deletion. 0137 }; 0138 0139 /** 0140 * Creates a new IncidenceChanger instance. 0141 * creates a default ITIPHandlerComponentFactory object. 0142 * @param parent parent QObject 0143 */ 0144 explicit IncidenceChanger(QObject *parent = nullptr); 0145 0146 /** 0147 * Creates a new IncidenceChanger instance. 0148 * @param factory factory for creating dialogs and the mail transport job. To create a default 0149 * factory set factory == 0 0150 * @param parent parent QObject 0151 * @since 4.15 0152 */ 0153 explicit IncidenceChanger(ITIPHandlerComponentFactory *factory, QObject *parent); 0154 0155 /** 0156 * Destroys this IncidenceChanger instance. 0157 */ 0158 ~IncidenceChanger() override; 0159 0160 /** 0161 * Creates a new incidence. 0162 * 0163 * @param incidence Incidence to create, must be valid. 0164 * @param collection Collection where the incidence will be created. If invalid, one according 0165 * to the DestinationPolicy will be used. You can know which collection was 0166 * used by calling lastCollectionUsed(); 0167 * @param parent widget parent to be used in dialogs. 0168 * 0169 * @return Returns an integer which identifies this change. This identifier is useful 0170 * to correlate this operation with the IncidenceChanger::createFinished() signal. 0171 * 0172 * Returns -1 if @p incidence is invalid. The createFinished() signal 0173 * won't be emitted in this case. 0174 */ 0175 int 0176 createIncidence(const KCalendarCore::Incidence::Ptr &incidence, const Akonadi::Collection &collection = Akonadi::Collection(), QWidget *parent = nullptr); 0177 0178 /** 0179 * Creates a new incidence. 0180 * 0181 * @param item Item containing the incidence to create and metadata, such as tags. 0182 * @param collection Collection where the incidence will be created. If invalid, one according 0183 * to the DestinationPolicy will be used. You can know which collection was 0184 * used by calling lastCollectionUsed(); 0185 * @param parent widget parent to be used in dialogs. 0186 * 0187 * @return Returns an integer which identifies this change. This identifier is useful 0188 * to correlate this operation with the IncidenceChanger::createFinished() signal. 0189 * 0190 * Returns -1 if @p item is invalid. The createFinished() signal 0191 * won't be emitted in this case. 0192 */ 0193 int createFromItem(const Akonadi::Item &item, const Akonadi::Collection &collection = Akonadi::Collection(), QWidget *parent = nullptr); 0194 0195 /** 0196 * Deletes an incidence. If it's recurring, all occurrences are deleted. 0197 * 0198 * @param item Item to delete. Item must be valid. 0199 * @param parent Parent to be used in dialogs. 0200 * 0201 * @return Returns an integer which identifies this deletion. This identifier is useful 0202 * to correlate this deletion with the IncidenceChanger::deleteFinished() signal. 0203 * 0204 * Returns -1 if item is invalid. The deleteFinished() signal won't be emitted in this 0205 * case. 0206 */ 0207 int deleteIncidence(const Akonadi::Item &item, QWidget *parent = nullptr); 0208 0209 /** 0210 * Deletes a list of Items. 0211 * 0212 * @param items List of items do delete. They must be valid. 0213 * @param parent Parent to be used in dialogs. 0214 * @return Returns an integer which identifies this deletion. This identifier is useful 0215 * to correlate this operation with the IncidenceChanger::deleteFinished() signal. 0216 * 0217 * Returns -1 if any item is invalid or if @p items is empty. The deleteFinished() signal 0218 * won't be emitted in this case. 0219 */ 0220 int deleteIncidences(const Akonadi::Item::List &items, QWidget *parent = nullptr); 0221 0222 /** 0223 * Modifies an incidence. 0224 * 0225 * @param item A valid item, with the new payload. 0226 * @param originalPayload The payload before the modification. If invalid it won't be recorded 0227 * to the undo stack and groupware functionality won't be used for this 0228 * deletion. 0229 * @param parent Parent to be used in dialogs. 0230 * 0231 * @return Returns an integer which identifies this modification. This identifier is useful 0232 * to correlate this operation with the IncidenceChanger::modifyFinished() signal. 0233 * 0234 * Returns -1 if the item doesn't have a valid payload. The modifyFinished() signal 0235 * won't be emitted in this case. 0236 */ 0237 int modifyIncidence(const Akonadi::Item &item, 0238 const KCalendarCore::Incidence::Ptr &originalPayload = KCalendarCore::Incidence::Ptr(), 0239 QWidget *parent = nullptr); 0240 0241 /** 0242 * Some incidence operations require more than one change. Like dissociating 0243 * occurrences, which needs an incidence add and an incidence change. 0244 * 0245 * If you want to prevent that the same dialogs are presented multiple times 0246 * use this function to start a batch operation. 0247 * 0248 * If one change belonging to a batch operation fails, all other changes 0249 * are rolled back. 0250 * 0251 * @param operationDescription Describes what the atomic operation does. 0252 * This will be what incidenceChanger->history()->descriptionForNextUndo() 0253 * if you have history enabled. 0254 * 0255 * @see endAtomicOperation() 0256 */ 0257 void startAtomicOperation(const QString &operationDescription = QString()); 0258 0259 /** 0260 * Tells IncidenceChanger you finished doing changes that belong to a 0261 * batch operation. 0262 * 0263 * @see startAtomicOperation() 0264 */ 0265 void endAtomicOperation(); 0266 0267 /** 0268 * Sets the base ETM tree model 0269 * Used by the editor dialog's collection combobox, for instance. 0270 */ 0271 void setEntityTreeModel(Akonadi::EntityTreeModel *model); 0272 0273 /** 0274 * Returns the base ETM tree model 0275 */ 0276 Akonadi::EntityTreeModel *entityTreeModel() const; 0277 0278 /** 0279 * Sets the default collection. 0280 * @param collection The collection to be used in createIncidence() if the 0281 * proper destination policy is set. 0282 * @see createIncidence() 0283 * @see destinationPolicy() 0284 * @see defaultCollection() 0285 */ 0286 void setDefaultCollection(const Akonadi::Collection &collection); 0287 0288 /** 0289 * Returns the defaultCollection. 0290 * If none is set, an invalid Collection is returned. 0291 * @see setDefaultCollection() 0292 * @see DestinationPolicy 0293 */ 0294 [[nodiscard]] Akonadi::Collection defaultCollection() const; 0295 0296 /** 0297 * Sets the destination policy to use. The destination policy determines the 0298 * collection to use in createIncidence() 0299 * 0300 * @see createIncidence() 0301 * @see destinationPolicy() 0302 */ 0303 void setDestinationPolicy(DestinationPolicy destinationPolicy); 0304 0305 /** 0306 * Returns the current destination policy. 0307 * If none is set, DestinationPolicyDefault is returned. 0308 * @see setDestinationPolicy() 0309 * @see DestinationPolicy 0310 */ 0311 [[nodiscard]] DestinationPolicy destinationPolicy() const; 0312 0313 /** 0314 * Sets if IncidenceChanger should show error dialogs. 0315 */ 0316 void setShowDialogsOnError(bool enable); 0317 0318 /** 0319 * Returns true if error dialogs are shown by IncidenceChanger. 0320 * The default is true. 0321 * 0322 * @see setShowDialogsOnError() 0323 */ 0324 [[nodiscard]] bool showDialogsOnError() const; 0325 0326 /** 0327 * Sets if IncidenceChanger should honour collection's ACLs by disallowing changes if 0328 * necessary. 0329 */ 0330 void setRespectsCollectionRights(bool respect); 0331 0332 /** 0333 * Returns true if IncidenceChanger honors collection's ACLs by disallowing 0334 * changes if necessary. 0335 * 0336 * The default is true. 0337 * @see setRespectsCollectionRights() 0338 * @see ResultCode::ResultCodePermissions 0339 */ 0340 [[nodiscard]] bool respectsCollectionRights() const; 0341 0342 /** 0343 * Enable or disable history. 0344 * With history enabled all changes are recorded into the undo/redo stack. 0345 * 0346 * @see history() 0347 * @see historyEnabled() 0348 */ 0349 void setHistoryEnabled(bool enable); 0350 0351 /** 0352 * Returns true if changes are added into the undo stack. 0353 * Default is true. 0354 * 0355 * @see history() 0356 * @see historyEnabled() 0357 */ 0358 [[nodiscard]] bool historyEnabled() const; 0359 0360 /** 0361 * Returns a pointer to the history object. 0362 * It's always valid. 0363 * Ownership remains with IncidenceChanger. 0364 */ 0365 History *history() const; 0366 0367 /** 0368 * For performance reasons, IncidenceChanger internally caches the ids of the last deleted items, 0369 * to avoid creating useless delete jobs. 0370 * 0371 * This function exposes that functionality so it can be used in other scenarios. 0372 * One popular scenario is when you're using an ETM and the user is deleting items very fast, 0373 * ETM doesn't know about the deletions immediately, so it can happen that some items are 0374 * deleted more than once, resulting in an error. 0375 * 0376 * @return true if the item was deleted recently, false otherwise. 0377 */ 0378 [[nodiscard]] bool deletedRecently(Akonadi::Item::Id) const; 0379 0380 /** 0381 * Enables or disabled groupware communication. 0382 * With groupware communication enabled, invitations and update e-mails will be sent to each 0383 * attendee. 0384 */ 0385 void setGroupwareCommunication(bool enabled); 0386 0387 /** 0388 * Returns if we're using groupware communication. 0389 * Default is false. 0390 * @see setGroupwareCommuniation() 0391 */ 0392 [[nodiscard]] bool groupwareCommunication() const; 0393 0394 /** 0395 * Makes modifyIncidence() adjust recurrence parameters when modifying DTSTART. 0396 */ 0397 void setAutoAdjustRecurrence(bool enable); 0398 0399 /** 0400 * True if recurrence parameters are adjusted when modifying DTSTART. 0401 * Default is true. 0402 */ 0403 [[nodiscard]] bool autoAdjustRecurrence() const; 0404 0405 /** 0406 * Sets the invitation policy. 0407 * 0408 * @since 4.12 0409 */ 0410 void setInvitationPolicy(InvitationPolicy policy); 0411 0412 /** 0413 * Returns the invitation policy. 0414 * The default is InvitationPolicyAsk. 0415 * 0416 * @since 4.12 0417 */ 0418 [[nodiscard]] InvitationPolicy invitationPolicy() const; 0419 0420 /** 0421 * Returns the collection that the last createIncidence() used. 0422 * Will be invalid if no incidences were created yet. 0423 * 0424 * @see createIncidence(). 0425 */ 0426 [[nodiscard]] Akonadi::Collection lastCollectionUsed() const; 0427 0428 /** 0429 * Sets the invitation privacy flags. 0430 */ 0431 void setInvitationPrivacy(InvitationPrivacyFlags invitationPrivacy); 0432 0433 /** 0434 * Returns the invitation privacy policy. 0435 * Default value is InvitationPrivacyPlain. 0436 */ 0437 [[nodiscard]] InvitationPrivacyFlags invitationPrivacy() const; 0438 0439 Q_SIGNALS: 0440 /** 0441 * Emitted when IncidenceChanger creates an Incidence in akonadi. 0442 * 0443 * @param changeId the unique identifier of this change, returned by createIncidence(). 0444 * @param item the created item, might be invalid if the @p resultCode is not ResultCodeSuccess 0445 * @param resultCode success/error code 0446 * @param errorString if @p resultCode is not ResultCodeSuccess, contains an i18n'ed error 0447 * message. If you enabled error dialogs, this string was already presented to the user. 0448 */ 0449 void createFinished(int changeId, const Akonadi::Item &item, Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorString); 0450 /** 0451 * Emitted when IncidenceChanger modifies an Incidence in akonadi. 0452 * 0453 * @param changeId the unique identifier of this change, returned by modifyIncidence(). 0454 * @param item the modified item, might be invalid if the @p resultCode is not ResultCodeSuccess 0455 * @param resultCode success/error code 0456 * @param errorString if @p resultCode is not ResultCodeSuccess, contains an i18n'ed error 0457 * message. If you enabled error dialogs, this string was already presented to the user. 0458 */ 0459 void modifyFinished(int changeId, const Akonadi::Item &item, Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorString); 0460 /** 0461 * Emitted when IncidenceChanger deletes an Incidence in akonadi. 0462 * 0463 * @param changeId the unique identifier of this change, returned by deletedIncidence(). 0464 * @param itemIdList list of deleted item ids, might be emptu if the @p resultCode is not 0465 * ResultCodeSuccess 0466 * @param resultCode success/error code 0467 * @param errorString if @p resultCode is not ResultCodeSuccess, contains an i18n'ed error 0468 * message. If you enabled error dialogs, this string was already presented to the user. 0469 */ 0470 void deleteFinished(int changeId, const QList<Akonadi::Item::Id> &itemIdList, Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorString); 0471 0472 private: 0473 //@cond PRIVATE 0474 friend class HistoryPrivate; 0475 friend class AtomicOperation; 0476 // used internally by the History class 0477 explicit IncidenceChanger(bool enableHistory, QObject *parent = nullptr); 0478 0479 std::unique_ptr<IncidenceChangerPrivate> const d; 0480 //@endcond 0481 }; 0482 } 0483 0484 Q_DECLARE_OPERATORS_FOR_FLAGS(Akonadi::IncidenceChanger::InvitationPrivacyFlags) 0485 0486 Q_DECLARE_METATYPE(Akonadi::IncidenceChanger::DestinationPolicy) 0487 Q_DECLARE_METATYPE(Akonadi::IncidenceChanger::ResultCode) 0488 Q_DECLARE_METATYPE(Akonadi::IncidenceChanger::ChangeType)