Better wording
[kdepim.git] / calendarsupport / incidencechanger.cpp
blobdfb8a3065e8997e512609936fcc5f595450aad96
1 /*
2 Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 As a special exception, permission is given to link this program
19 with any edition of Qt, and distribute the resulting executable,
20 without including the source code for Qt in the source distribution.
22 #include "incidencechanger.h"
23 #include "incidencechanger_p.h"
24 #include "calendar.h"
25 #include "calendaradaptor.h"
26 #include "dndfactory.h"
27 #include "kcalprefs.h"
28 #include "mailscheduler.h"
29 #include "utils.h"
31 #include <Akonadi/ItemCreateJob>
32 #include <Akonadi/ItemDeleteJob>
33 #include <Akonadi/ItemModifyJob>
35 #include <KMessageBox>
37 using namespace CalendarSupport;
39 InvitationHandler::Action actionFromStatus( InvitationHandler::SendResult result )
41 //enum SendResult {
42 // Canceled, /**< Sending was canceled by the user, meaning there are
43 // local changes of which other attendees are not aware. */
44 // FailKeepUpdate, /**< Sending failed, the changes to the incidence must be kept. */
45 // FailAbortUpdate, /**< Sending failed, the changes to the incidence must be undone. */
46 // NoSendingNeeded, /**< In some cases it is not needed to send an invitation
47 // (e.g. when we are the only attendee) */
48 // Success
49 switch ( result ) {
50 case InvitationHandler::ResultCanceled:
51 return InvitationHandler::ActionDontSendMessage;
52 case InvitationHandler::ResultSuccess:
53 return InvitationHandler::ActionSendMessage;
54 default:
55 return InvitationHandler::ActionAsk;
59 bool IncidenceChanger::Private::myAttendeeStatusChanged( const KCalCore::Incidence::Ptr &newInc,
60 const KCalCore::Incidence::Ptr &oldInc )
62 Q_ASSERT( newInc );
63 Q_ASSERT( oldInc );
64 KCalCore::Attendee::Ptr oldMe = oldInc->attendeeByMails( KCalPrefs::instance()->allEmails() );
65 KCalCore::Attendee::Ptr newMe = newInc->attendeeByMails( KCalPrefs::instance()->allEmails() );
67 return oldMe && newMe && ( oldMe->status() != newMe->status() );
70 void IncidenceChanger::Private::queueChange( Change *change )
72 Q_ASSERT( change );
73 // If there's already a change queued we just discard it
74 // and send the newer change, which already includes
75 // previous modifications
76 const Akonadi::Item::Id id = change->newItem.id();
77 if ( mQueuedChanges.contains( id ) ) {
78 delete mQueuedChanges.take( id );
81 mQueuedChanges[id] = change;
84 void IncidenceChanger::Private::cancelChanges( Akonadi::Item::Id id )
86 delete mQueuedChanges.take( id );
87 delete mCurrentChanges.take( id );
90 void IncidenceChanger::Private::performNextChange( Akonadi::Item::Id id )
92 delete mCurrentChanges.take( id );
94 if ( mQueuedChanges.contains( id ) ) {
95 performChange( mQueuedChanges.take( id ) );
99 bool IncidenceChanger::Private::performChange( Change *change )
101 Q_ASSERT( change );
102 Akonadi::Item newItem = change->newItem;
103 const KCalCore::Incidence::Ptr oldinc = change->oldInc;
104 const KCalCore::Incidence::Ptr newinc = CalendarSupport::incidence( newItem );
106 kDebug() << "id=" << newItem.id()
107 << "uid=" << newinc->uid()
108 << "version=" << newItem.revision()
109 << "summary=" << newinc->summary()
110 << "old summary" << oldinc->summary()
111 << "type=" << int( newinc->type() )
112 << "storageCollectionId=" << newItem.storageCollectionId();
114 // There's not any job modifying this item, so mCurrentChanges[item.id] can't exist
115 Q_ASSERT( !mCurrentChanges.contains( newItem.id() ) );
117 // Check if the item was deleted, we already check in changeIncidence() but
118 // this change could be already in the queue when the item was deleted
119 if ( !mCalendar->incidence( newItem.id() ).isValid() ||
120 mDeletedItemIds.contains( newItem.id() ) ) {
121 kDebug() << "Incidence deleted";
122 // return true, the user doesn't want to see errors because he was too fast
123 return true;
126 if ( newinc.data() == oldinc.data() ) {
127 // Don't do anything
128 kDebug() << "Incidence not changed";
129 return true;
130 } else {
132 if ( mLatestRevisionByItemId.contains( newItem.id() ) &&
133 mLatestRevisionByItemId[newItem.id()] > newItem.revision() ) {
134 /* When a ItemModifyJob ends, the application can still modify the old items if the user
135 * is quick because the ETM wasn't updated yet, and we'll get a STORE error, because
136 * we are not modifying the latest revision.
138 * When a job ends, we keep the new revision in m_latestVersionByItemId
139 * so we can update the item's revision
141 newItem.setRevision( mLatestRevisionByItemId[newItem.id()] );
144 kDebug() << "Changing incidence";
145 const int revision = newinc->revision();
146 newinc->setRevision( revision + 1 );
147 // FIXME: Use a generic method for this! Ideally, have an interface class
148 // for group cheduling. Each implementation could then just do what
149 // it wants with the event. If no groupware is used,use the null
150 // pattern...
151 if ( KCalPrefs::instance()->mUseGroupwareCommunication ) {
152 InvitationHandler handler( mCalendar );
153 handler.setDialogParent( change->parent );
155 if ( mOperationStatus.contains( change->atomicOperationId ) ) {
156 handler.setDefaultAction(
157 actionFromStatus( mOperationStatus.value( change->atomicOperationId ) ) );
160 const bool modify = handler.handleIncidenceAboutToBeModified( newinc );
161 if ( !modify ) {
162 if ( newinc->type() == oldinc->type() ) {
163 KCalCore::IncidenceBase *i1 = newinc.data();
164 KCalCore::IncidenceBase *i2 = oldinc.data();
165 *i1 = *i2;
167 return false;
172 // FIXME: if that's a groupware incidence, and I'm not the organizer,
173 // send out a mail to the organizer with a counterproposal instead
174 // of actually changing the incidence. Then no locking is needed.
175 // FIXME: if that's a groupware incidence, and the incidence was
176 // never locked, we can't unlock it with endChange().
178 mCurrentChanges[newItem.id()] = change;
180 // Don't write back remote revision since we can't make sure it is the current one
181 // fixes problems with DAV resource
182 newItem.setRemoteRevision( QString() );
184 Akonadi::ItemModifyJob *job = new Akonadi::ItemModifyJob( newItem );
185 // TODO_SERGIO:
186 // Remove this Qt::QueuedConnection after removing all job.exec()'s inside mailclient.cpp
187 connect( job, SIGNAL(result(KJob*)),
188 this, SLOT(changeIncidenceFinished(KJob*)), Qt::QueuedConnection );
189 return true;
192 void IncidenceChanger::Private::changeIncidenceFinished( KJob *j )
194 // we should probably update the revision number here,or internally in the Event
195 // itself when certain things change. need to verify with ical documentation.
196 const Akonadi::ItemModifyJob* job = qobject_cast<const Akonadi::ItemModifyJob*>( j );
197 Q_ASSERT( job );
199 const Akonadi::Item newItem = job->item();
201 if ( !mCurrentChanges.contains( newItem.id() ) ) {
202 kDebug() << "Item was deleted? Great.";
203 cancelChanges( newItem.id() );
204 emit incidenceChangeFinished( Akonadi::Item(), newItem, UNKNOWN_MODIFIED, true );
205 return;
208 const Private::Change *change = mCurrentChanges[newItem.id()];
209 const KCalCore::Incidence::Ptr oldInc = change->oldInc;
211 Akonadi::Item oldItem;
212 oldItem.setPayload<KCalCore::Incidence::Ptr>( oldInc );
213 oldItem.setMimeType( oldInc->mimeType() );
214 oldItem.setId( newItem.id() );
215 const KCalCore::Incidence::Ptr newInc = CalendarSupport::incidence( newItem );
217 if ( job->error() ) {
218 kWarning() << "Item modify failed:" << job->errorString();
220 KMessageBox::sorry( change->parent,
221 i18n( "Unable to save changes for incidence %1 \"%2\": %3",
222 i18n( newInc->typeStr() ),
223 newInc->summary(),
224 job->errorString() ) );
225 emit incidenceChangeFinished( oldItem, newItem, change->action, false );
226 } else {
227 if ( KCalPrefs::instance()->mUseGroupwareCommunication ) {
228 InvitationHandler handler( mCalendar );
229 handler.setDialogParent( change->parent );
231 if ( mOperationStatus.contains( change->atomicOperationId ) ) {
232 handler.setDefaultAction(
233 actionFromStatus( mOperationStatus.value( change->atomicOperationId ) ) );
235 const bool attendeeStatusChanged = myAttendeeStatusChanged( oldInc, newInc );
236 InvitationHandler::SendResult result =
237 handler.sendIncidenceModifiedMessage( KCalCore::iTIPRequest,
238 newInc,
239 attendeeStatusChanged );
240 if ( change->atomicOperationId ) {
241 mOperationStatus.insert( change->atomicOperationId, result );
245 emit incidenceChangeFinished( oldItem, newItem, change->action, true );
248 mLatestRevisionByItemId[newItem.id()] = newItem.revision();
250 // execute any other modification if it exists
251 qRegisterMetaType<Akonadi::Item::Id>( "Akonadi::Item::Id" );
252 QMetaObject::invokeMethod( this, "performNextChange",
253 Qt::QueuedConnection,
254 Q_ARG( Akonadi::Item::Id, newItem.id() ) );
257 IncidenceChanger::IncidenceChanger( CalendarSupport::Calendar *cal,
258 QObject *parent,
259 Akonadi::Entity::Id defaultCollectionId )
260 : QObject( parent ), d( new Private( defaultCollectionId, cal ) )
262 connect( d,
263 SIGNAL(incidenceChangeFinished(Akonadi::Item,Akonadi::Item,CalendarSupport::IncidenceChanger::WhatChanged,bool)),
264 SIGNAL(incidenceChangeFinished(Akonadi::Item,Akonadi::Item,CalendarSupport::IncidenceChanger::WhatChanged,bool)) );
267 IncidenceChanger::~IncidenceChanger()
269 delete d;
272 bool IncidenceChanger::sendGroupwareMessage( const Akonadi::Item &aitem,
273 KCalCore::iTIPMethod method,
274 HowChanged action,
275 QWidget *parent,
276 uint atomicOperationId )
278 const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( aitem );
279 if ( !incidence ) {
280 kDebug() << "Invalid incidence";
281 return false;
283 if ( KCalPrefs::instance()->thatIsMe( incidence->organizer()->email() ) &&
284 incidence->attendeeCount() > 0 &&
285 !KCalPrefs::instance()->mUseGroupwareCommunication ) {
286 emit schedule( method, aitem );
287 return true;
288 } else if ( KCalPrefs::instance()->mUseGroupwareCommunication ) {
289 InvitationHandler handler( d->mCalendar );
290 handler.setDialogParent( parent );
291 if ( d->mOperationStatus.contains( atomicOperationId ) ) {
292 handler.setDefaultAction(
293 actionFromStatus( d->mOperationStatus.value( atomicOperationId ) ) );
295 InvitationHandler::SendResult status;
296 switch ( action ) {
297 case INCIDENCEADDED:
298 status = handler.sendIncidenceCreatedMessage( method, incidence );
299 break;
300 case INCIDENCEEDITED:
301 status = handler.sendIncidenceModifiedMessage( method, incidence, false );
302 break;
303 case INCIDENCEDELETED:
304 status = handler.sendIncidenceDeletedMessage( method, incidence );
305 case NOCHANGE:
306 break;
309 if ( atomicOperationId && action != NOCHANGE ) {
310 d->mOperationStatus.insert( atomicOperationId, status );
312 return ( status != InvitationHandler::ResultFailAbortUpdate );
314 return true;
317 void IncidenceChanger::cancelAttendees( const Akonadi::Item &aitem )
319 const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( aitem );
320 Q_ASSERT( incidence );
321 if ( KCalPrefs::instance()->mUseGroupwareCommunication ) {
322 if ( KMessageBox::questionYesNo(
324 i18n( "Some attendees were removed from the incidence. "
325 "Shall cancel messages be sent to these attendees?" ),
326 i18n( "Attendees Removed" ), KGuiItem( i18n( "Send Messages" ) ),
327 KGuiItem( i18n( "Do Not Send" ) ) ) == KMessageBox::Yes ) {
328 // don't use Akonadi::Groupware::sendICalMessage here, because that asks just
329 // a very general question "Other people are involved, send message to
330 // them?", which isn't helpful at all in this situation. Afterwards, it
331 // would only call the Akonadi::MailScheduler::performTransaction, so do this
332 // manually.
333 // FIXME: Groupware scheduling should be factored out to it's own class
334 // anyway
335 CalendarSupport::MailScheduler scheduler(
336 static_cast<CalendarSupport::Calendar*>(d->mCalendar) );
337 scheduler.performTransaction( incidence, KCalCore::iTIPCancel );
342 bool IncidenceChanger::deleteIncidence( const Akonadi::Item &aitem,
343 uint atomicOperationId,
344 QWidget *parent )
346 const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( aitem );
347 if ( !incidence ) {
348 kDebug() << "Invalid incidence";
349 return false;
352 kDebug() << "Deleting incidence " << incidence->summary() << "; id = " << aitem.id();
354 if ( !isNotDeleted( aitem.id() ) ) {
355 kDebug() << "Item already deleted, skipping and returning true";
356 return true;
359 if ( !( d->mCalendar->hasDeleteRights( aitem ) ) ) {
360 kWarning() << "insufficient rights to delete incidence";
361 return false;
364 const bool doDelete = sendGroupwareMessage( aitem, KCalCore::iTIPCancel,
365 INCIDENCEDELETED, parent, atomicOperationId );
366 if( !doDelete ) {
367 kDebug() << "Groupware says no";
368 return false;
371 d->mDeletedItemIds.append( aitem.id() );
373 emit incidenceToBeDeleted( aitem );
374 d->cancelChanges( aitem.id() ); //abort changes to this incidence cause we will just delete it
375 Akonadi::ItemDeleteJob *job = new Akonadi::ItemDeleteJob( aitem );
376 connect( job, SIGNAL(result(KJob*)), this, SLOT(deleteIncidenceFinished(KJob*)) );
377 return true;
380 void IncidenceChanger::deleteIncidenceFinished( KJob *j )
382 // todo, cancel changes?
383 kDebug();
384 const Akonadi::ItemDeleteJob *job = qobject_cast<const Akonadi::ItemDeleteJob*>( j );
385 Q_ASSERT( job );
386 const Akonadi::Item::List items = job->deletedItems();
387 Q_ASSERT( items.count() == 1 );
388 KCalCore::Incidence::Ptr tmp = CalendarSupport::incidence( items.first() );
389 Q_ASSERT( tmp );
390 if ( job->error() ) {
391 KMessageBox::sorry( 0, //PENDING(AKONADI_PORT) set parent
392 i18n( "Unable to delete incidence %1 \"%2\": %3",
393 i18n( tmp->typeStr() ),
394 tmp->summary(),
395 job->errorString() ) );
396 d->mDeletedItemIds.removeOne( items.first().id() );
397 emit incidenceDeleteFinished( items.first(), false );
398 return;
400 if ( !KCalPrefs::instance()->thatIsMe( tmp->organizer()->email() ) ) {
401 const QStringList myEmails = KCalPrefs::instance()->allEmails();
402 bool notifyOrganizer = false;
403 for ( QStringList::ConstIterator it = myEmails.begin(); it != myEmails.end(); ++it ) {
404 QString email = *it;
405 KCalCore::Attendee::Ptr me( tmp->attendeeByMail( email ) );
406 if ( me ) {
407 if ( me->status() == KCalCore::Attendee::Accepted ||
408 me->status() == KCalCore::Attendee::Delegated ) {
409 notifyOrganizer = true;
411 KCalCore::Attendee::Ptr newMe( new KCalCore::Attendee( *me ) );
412 newMe->setStatus( KCalCore::Attendee::Declined );
413 tmp->clearAttendees();
414 tmp->addAttendee( newMe );
415 break;
419 if ( KCalPrefs::instance()->useGroupwareCommunication() && notifyOrganizer ) {
420 CalendarSupport::MailScheduler scheduler( d->mCalendar );
421 scheduler.performTransaction( tmp, KCalCore::iTIPReply );
424 d->mLatestRevisionByItemId.remove( items.first().id() );
425 emit incidenceDeleteFinished( items.first(), true );
428 bool IncidenceChanger::cutIncidences( const Akonadi::Item::List &list, QWidget *parent )
430 Akonadi::Item::List::ConstIterator it;
431 bool doDelete = true;
432 Akonadi::Item::List itemsToCut;
433 const uint atomicOperationId = startAtomicOperation();
434 for ( it = list.constBegin(); it != list.constEnd(); ++it ) {
435 if ( CalendarSupport::hasIncidence( ( *it ) ) ) {
436 doDelete = sendGroupwareMessage( *it, KCalCore::iTIPCancel,
437 INCIDENCEDELETED, parent, atomicOperationId );
439 if ( doDelete ) {
440 emit incidenceToBeDeleted( *it );
441 itemsToCut.append( *it );
446 endAtomicOperation( atomicOperationId );
448 #ifndef QT_NO_DRAGANDDROP
449 CalendarAdaptor::Ptr cal( new CalendarAdaptor( d->mCalendar, parent ) );
450 CalendarSupport::DndFactory factory( cal, true/*delete calendarAdaptor*/ );
452 if ( factory.cutIncidences( itemsToCut ) ) {
453 #endif
454 for ( it = itemsToCut.constBegin(); it != itemsToCut.constEnd(); ++it ) {
455 emit incidenceDeleteFinished( *it, true );
457 return !itemsToCut.isEmpty();
458 #ifndef QT_NO_DRAGANDDROP
459 } else {
460 return false;
462 #endif
465 bool IncidenceChanger::cutIncidence( const Akonadi::Item &item, QWidget *parent )
467 Akonadi::Item::List items;
468 items.append( item );
469 return cutIncidences( items, parent );
472 void IncidenceChanger::setDefaultCollectionId( Akonadi::Entity::Id defaultCollectionId )
474 d->mDefaultCollectionId = defaultCollectionId;
477 bool IncidenceChanger::changeIncidence( const KCalCore::Incidence::Ptr &oldinc,
478 const Akonadi::Item &newItem,
479 WhatChanged action,
480 QWidget *parent,
481 uint atomicOperationId )
483 if ( !CalendarSupport::hasIncidence( newItem ) || !newItem.isValid() ) {
484 kDebug() << "Skipping invalid item id=" << newItem.id();
485 return false;
488 if ( !d->mCalendar->hasChangeRights( newItem ) ) {
489 kWarning() << "insufficient rights to change incidence";
490 return false;
493 if ( !isNotDeleted( newItem.id() ) ) {
494 kDebug() << "Skipping change, the item got deleted";
495 return false;
498 Private::Change *change = new Private::Change();
499 change->action = action;
500 change->newItem = newItem;
501 change->oldInc = oldinc;
502 change->parent = parent;
503 change->atomicOperationId = atomicOperationId;
505 if ( d->mCurrentChanges.contains( newItem.id() ) ) {
506 d->queueChange( change );
507 } else {
508 d->performChange( change );
510 return true;
513 bool IncidenceChanger::addIncidence( const KCalCore::Incidence::Ptr &incidence,
514 QWidget *parent,
515 Akonadi::Collection &selectedCollection,
516 int &dialogCode,
517 uint atomicOperationId )
519 const Akonadi::Collection defaultCollection = d->mCalendar->collection( d->mDefaultCollectionId );
521 const QString incidenceMimeType = incidence->mimeType();
522 const bool defaultIsOk = defaultCollection.contentMimeTypes().contains( incidenceMimeType ) &&
523 defaultCollection.rights() & Akonadi::Collection::CanCreateItem;
525 if ( d->mDestinationPolicy == ASK_DESTINATION ||
526 !defaultCollection.isValid() ||
527 !defaultIsOk ) {
528 QStringList mimeTypes( incidenceMimeType );
529 selectedCollection = CalendarSupport::selectCollection( parent,
530 dialogCode,
531 mimeTypes,
532 defaultCollection );
533 } else {
534 dialogCode = QDialog::Accepted;
535 selectedCollection = defaultCollection;
538 if ( selectedCollection.isValid() ) {
539 return addIncidence( incidence, selectedCollection, parent, atomicOperationId );
540 } else {
541 kError() << "Selected collection isn't valid.";
542 return false;
546 bool IncidenceChanger::addIncidence( const KCalCore::Incidence::Ptr &incidence,
547 const Akonadi::Collection &collection,
548 QWidget *parent,
549 uint atomicOperationId )
551 Q_UNUSED( parent );
553 if ( !incidence || !collection.isValid() ) {
554 kError() << "Incidence or collection isn't valid. collection.isValid() == "
555 << collection.isValid();
556 return false;
559 if ( !( collection.rights() & Akonadi::Collection::CanCreateItem ) ) {
560 kWarning() << "insufficient rights to create incidence";
561 return false;
564 Akonadi::Item item;
565 item.setPayload<KCalCore::Incidence::Ptr>( incidence );
567 item.setMimeType( incidence->mimeType() );
568 Akonadi::ItemCreateJob *job = new Akonadi::ItemCreateJob( item, collection );
570 Private::AddInfo addInfo;
571 addInfo.parent = parent;
572 addInfo.atomicOperationId = atomicOperationId;
574 // so the jobs sees this info
575 d->mAddInfoForJob.insert( job, addInfo );
577 // The connection needs to be queued to be sure addIncidenceFinished
578 // is called after the kjob finished it's eventloop. That's needed
579 // because Akonadi::Groupware uses synchronous job->exec() calls.
580 connect( job, SIGNAL(result(KJob*)),
581 this, SLOT(addIncidenceFinished(KJob*)), Qt::QueuedConnection );
582 return true;
585 void IncidenceChanger::addIncidenceFinished( KJob *j )
587 kDebug();
588 const Akonadi::ItemCreateJob *job = qobject_cast<const Akonadi::ItemCreateJob*>( j );
589 Q_ASSERT( job );
590 KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( job->item() );
592 if ( job->error() ) {
593 KMessageBox::sorry(
594 0, //PENDING(AKONADI_PORT) set parent, ideally the one passed in addIncidence...
595 i18n( "Unable to save %1 \"%2\": %3",
596 i18n( incidence->typeStr() ),
597 incidence->summary(),
598 job->errorString() ) );
599 emit incidenceAddFinished( job->item(), false );
600 return;
603 if ( KCalPrefs::instance()->useGroupwareCommunication() ) {
604 Q_ASSERT( incidence );
605 InvitationHandler handler( d->mCalendar );
606 //handler.setDialogParent( 0 ); // PENDING(AKONADI_PORT) set parent,
607 //ideally the one passed in addIncidence...
608 const InvitationHandler::SendResult status =
609 handler.sendIncidenceCreatedMessage( KCalCore::iTIPRequest, incidence );
611 if ( status == InvitationHandler::ResultFailAbortUpdate ) {
612 // TODO: At this point we'd need to delete the incidence again.
613 kError() << "Sending invitations failed, but did not delete the incidence";
616 const uint atomicOperationId = d->mAddInfoForJob[j].atomicOperationId;
617 if ( atomicOperationId ) {
618 d->mOperationStatus.insert( atomicOperationId, status );
621 emit incidenceAddFinished( job->item(), true );
624 void IncidenceChanger::setDestinationPolicy( DestinationPolicy destinationPolicy )
626 d->mDestinationPolicy = destinationPolicy;
629 IncidenceChanger::DestinationPolicy IncidenceChanger::destinationPolicy() const
631 return d->mDestinationPolicy;
634 bool IncidenceChanger::isNotDeleted( Akonadi::Item::Id id ) const
636 if ( d->mCalendar->incidence( id ).isValid() ) {
637 // it's inside the calendar, but maybe it's being deleted by a job or was
638 // deleted but the ETM doesn't know yet
639 return !d->mDeletedItemIds.contains( id );
640 } else {
641 // not inside the calendar, i don't know it
642 return false;
646 void IncidenceChanger::setCalendar( CalendarSupport::Calendar *calendar )
648 d->mCalendar = calendar;
651 uint IncidenceChanger::startAtomicOperation()
653 static unsigned int latestAtomicOperationId = 0;
655 return ++latestAtomicOperationId;
658 void IncidenceChanger::endAtomicOperation( uint atomicOperationId )
660 d->mOperationStatus.remove( atomicOperationId );
663 bool IncidenceChanger::changeInProgress( Akonadi::Item::Id id )
665 return d->mCurrentChanges.contains( id );