21 #include "calendarbase.h"
22 #include "calendarbase_p.h"
23 #include "incidencechanger.h"
26 #include <akonadi/item.h>
27 #include <akonadi/collection.h>
29 #include <KSystemTimeZones>
31 using namespace Akonadi;
32 using namespace KCalCore;
34 static QString itemToString(
const Akonadi::Item &item)
36 const KCalCore::Incidence::Ptr &incidence = CalendarUtils::incidence(item);
38 QTextStream stream(&str);
40 <<
"; summary=" << incidence->summary() <<
"; uid=" << incidence->uid() <<
"; type="
41 << incidence->type() <<
"; recurs=" << incidence->recurs() <<
"; recurrenceId="
42 << incidence->recurrenceId().toString() <<
"; dtStart=" << incidence->dtStart().toString()
43 <<
"; dtEnd=" << incidence->dateTime(Incidence::RoleEnd).toString()
44 <<
"; parentCollection=" << item.storageCollectionId() << item.parentCollection().displayName();
49 CalendarBasePrivate::CalendarBasePrivate(
CalendarBase *qq ) : QObject()
50 , mIncidenceChanger( new IncidenceChanger() )
51 , mBatchInsertionCancelled( false )
52 , mListensForNewItems( false )
55 connect( mIncidenceChanger,
56 SIGNAL(createFinished(
int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)),
57 SLOT(slotCreateFinished(
int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)) );
59 connect( mIncidenceChanger,
60 SIGNAL(deleteFinished(
int,QVector<Akonadi::Item::Id>,Akonadi::IncidenceChanger::ResultCode,QString)),
61 SLOT(slotDeleteFinished(
int,QVector<Akonadi::Item::Id>,Akonadi::IncidenceChanger::ResultCode,QString)) );
63 connect( mIncidenceChanger,
64 SIGNAL(modifyFinished(
int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)),
65 SLOT(slotModifyFinished(
int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)) );
67 mIncidenceChanger->setDestinationPolicy( IncidenceChanger::DestinationPolicyAsk );
68 mIncidenceChanger->setGroupwareCommunication(
false );
69 mIncidenceChanger->setHistoryEnabled(
false );
72 CalendarBasePrivate::~CalendarBasePrivate()
74 delete mIncidenceChanger;
75 mIncidenceChanger = 0;
78 void CalendarBasePrivate::internalInsert(
const Akonadi::Item &item )
80 Q_ASSERT( item.isValid() );
81 Q_ASSERT( item.hasPayload<KCalCore::Incidence::Ptr>() );
82 KCalCore::Incidence::Ptr incidence = CalendarUtils::incidence( item );
85 kError() <<
"Incidence is null. id=" << item.id()
86 <<
"; hasPayload()=" << item.hasPayload()
87 <<
"; has incidence=" << item.hasPayload<KCalCore::Incidence::Ptr>()
88 <<
"; mime type=" << item.mimeType();
94 const QString uid = incidence->instanceIdentifier();
96 if ( uid.isEmpty() ) {
98 kError() <<
"Incidence has empty UID. id=" << item.id()
99 <<
"; summary=" << incidence->summary()
100 <<
"Please fix it. Ignoring this incidence.";
104 if ( mItemIdByUid.contains( uid ) && mItemIdByUid[uid] != item.id() ) {
107 kWarning() <<
"Discarding duplicate incidence with instanceIdentifier=" << uid
108 <<
"and summary " << incidence->summary()
109 <<
"; recurrenceId() =" << incidence->recurrenceId()
110 <<
"; new id=" << item.id()
111 <<
"; existing id=" << mItemIdByUid[uid];
115 if ( incidence->type() == KCalCore::Incidence::TypeEvent && !incidence->dtStart().isValid() ) {
117 kWarning() <<
"Discarding event with invalid DTSTART. identifier="
118 << incidence->instanceIdentifier() <<
"; summary=" << incidence->summary();
128 mItemById.insert( item.id(), item );
129 mItemIdByUid.insert( uid, item.id() );
130 mItemsByCollection.insert( item.storageCollectionId(), item );
132 if ( !incidence->hasRecurrenceId() ) {
134 const QString parentUid = incidence->relatedTo();
135 if ( !parentUid.isEmpty() ) {
136 mParentUidToChildrenUid[parentUid].append( incidence->uid() );
137 mUidToParent.insert( uid, parentUid );
141 incidence->setCustomProperty(
"VOLATILE",
"AKONADI-ID", QString::number( item.id() ) );
143 const bool result = q->MemoryCalendar::addIncidence( incidence );
145 kError() <<
"Error adding incidence " << itemToString( item );
150 void CalendarBasePrivate::internalRemove(
const Akonadi::Item &item )
152 Q_ASSERT( item.isValid() );
154 Incidence::Ptr tmp = CalendarUtils::incidence(item);
156 kError() <<
"CalendarBase::internalRemove1: incidence is null, item.id=" << item.id();
161 Incidence::Ptr incidence = q->incidence( tmp->uid(), tmp->recurrenceId() );
166 mItemById.remove( item.id() );
168 mItemIdByUid.remove( incidence->instanceIdentifier() );
170 mItemsByCollection.remove( item.storageCollectionId(), item );
172 if ( !incidence->hasRecurrenceId() ) {
173 const QString uid = incidence->uid();
174 const QString parentUid = incidence->relatedTo();
175 mParentUidToChildrenUid.remove( uid );
176 if ( !parentUid.isEmpty() ) {
177 mParentUidToChildrenUid[parentUid].removeAll( uid );
178 mUidToParent.remove( uid );
182 const bool result = q->MemoryCalendar::deleteIncidence( incidence );
184 kError() <<
"Error removing incidence " << itemToString(item);
188 kWarning() <<
"CalendarBase::internalRemove2: incidence is null, item.id=" << itemToString(item);
192 void CalendarBasePrivate::deleteAllIncidencesOfType(
const QString &mimeType )
194 kWarning() <<
"Refusing to delete your Incidences.";
208 void CalendarBasePrivate::slotDeleteFinished(
int changeId,
209 const QVector<Akonadi::Item::Id> &itemIds,
210 IncidenceChanger::ResultCode resultCode,
211 const QString &errorMessage )
213 Q_UNUSED( changeId );
214 if ( resultCode == IncidenceChanger::ResultCodeSuccess ) {
215 foreach (
const Akonadi::Item::Id &
id, itemIds ) {
216 if ( mItemById.contains(
id ) )
217 internalRemove( mItemById.value(
id ) );
220 emit q->deleteFinished( resultCode == IncidenceChanger::ResultCodeSuccess, errorMessage );
223 void CalendarBasePrivate::slotCreateFinished(
int changeId,
224 const Akonadi::Item &item,
225 IncidenceChanger::ResultCode resultCode,
226 const QString &errorMessage )
228 Q_UNUSED( changeId );
230 if ( resultCode == IncidenceChanger::ResultCodeSuccess && !mListensForNewItems) {
231 Q_ASSERT( item.isValid() );
232 Q_ASSERT( item.hasPayload<KCalCore::Incidence::Ptr>() );
233 internalInsert( item );
235 emit q->createFinished( resultCode == IncidenceChanger::ResultCodeSuccess, errorMessage );
238 void CalendarBasePrivate::slotModifyFinished(
int changeId,
239 const Akonadi::Item &item,
240 IncidenceChanger::ResultCode resultCode,
241 const QString &errorMessage )
243 Q_UNUSED( changeId );
245 QString message = errorMessage;
246 if ( resultCode == IncidenceChanger::ResultCodeSuccess ) {
247 KCalCore::Incidence::Ptr incidence = CalendarUtils::incidence( item );
248 Q_ASSERT( incidence );
249 KCalCore::Incidence::Ptr localIncidence = q->incidence( incidence->instanceIdentifier() );
251 if ( localIncidence ) {
253 *(
static_cast<KCalCore::IncidenceBase*
>( localIncidence.data() ) ) = *( incidence.data() );
256 kWarning() <<
"CalendarBasePrivate::slotModifyFinished() Incidence was deleted already probably? id=" << item.id();
257 message = QLatin1String(
"Could not find incidence to update, probably was deleted recently." );
258 resultCode = IncidenceChanger::ResultCodeAlreadyDeleted;
261 emit q->modifyFinished( resultCode == IncidenceChanger::ResultCodeSuccess, message );
264 void CalendarBasePrivate::handleUidChange(
const Akonadi::Item &oldItem,
265 const Akonadi::Item &newItem,
const QString &newIdentifier )
267 Q_ASSERT( oldItem.isValid() );
268 Incidence::Ptr newIncidence = CalendarUtils::incidence( newItem );
269 Q_ASSERT( newIncidence );
270 Incidence::Ptr oldIncidence = CalendarUtils::incidence( oldItem );
271 Q_ASSERT( oldIncidence );
273 const QString newUid = newIncidence->uid();
274 if ( mItemIdByUid.contains( newIdentifier ) ) {
275 Incidence::Ptr oldIncidence = CalendarUtils::incidence( oldItem );
276 kWarning() <<
"New uid shouldn't be known: " << newIdentifier <<
"; id="
277 << newItem.id() <<
"; oldItem.id=" << mItemIdByUid[newIdentifier]
278 <<
"; new summary= " << newIncidence->summary()
279 <<
"; new recurrenceId=" << newIncidence->recurrenceId()
280 <<
"; oldIncidence" << oldIncidence;
281 if ( oldIncidence ) {
282 kWarning() <<
"; oldIncidence uid=" << oldIncidence->uid()
283 <<
"; oldIncidence recurrenceId = " << oldIncidence->recurrenceId()
284 <<
"; oldIncidence summary = " << oldIncidence->summary();
290 mItemIdByUid[newIdentifier] = newItem.id();
293 oldIncidence = q->MemoryCalendar::incidence( oldIncidence->uid() );
294 Q_ASSERT( oldIncidence );
296 if ( newIncidence->instanceIdentifier() == oldIncidence->instanceIdentifier() ) {
297 kWarning() <<
"New uid=" << newIncidence->uid() <<
"; old uid=" << oldIncidence->uid()
298 <<
"; new recurrenceId="
299 << newIncidence->recurrenceId()
300 <<
"; old recurrenceId=" << oldIncidence->recurrenceId()
301 <<
"; new summary = " << newIncidence->summary()
302 <<
"; old summary = " << oldIncidence->summary()
303 <<
"; id = " << newItem.id();
308 mItemIdByUid.remove( oldIncidence->instanceIdentifier() );
309 const QString oldUid = oldIncidence->uid();
311 if ( mParentUidToChildrenUid.contains( oldUid ) ) {
312 Q_ASSERT( !mParentUidToChildrenUid.contains( newIdentifier ) );
313 QStringList children = mParentUidToChildrenUid.value( oldUid );
314 mParentUidToChildrenUid.insert( newIdentifier, children );
315 mParentUidToChildrenUid.remove( oldUid );
319 q->setObserversEnabled(
false );
320 q->MemoryCalendar::deleteIncidence( oldIncidence );
321 q->MemoryCalendar::addIncidence( newIncidence );
323 newIncidence->setUid(oldUid);
324 q->setObserversEnabled(
true );
325 newIncidence->setUid(newUid);
328 void CalendarBasePrivate::handleParentChanged(
const KCalCore::Incidence::Ptr &newIncidence )
330 Q_ASSERT( newIncidence );
332 if ( newIncidence->hasRecurrenceId() ) {
336 const QString originalParentUid = mUidToParent.value( newIncidence->uid() );
337 const QString newParentUid = newIncidence->relatedTo();
339 if ( originalParentUid == newParentUid ) {
343 if ( !originalParentUid.isEmpty() ) {
345 Q_ASSERT( mParentUidToChildrenUid.contains( originalParentUid ) );
346 mParentUidToChildrenUid[originalParentUid].removeAll( newIncidence->uid() );
349 mUidToParent.remove( newIncidence->uid() );
351 if ( !newParentUid.isEmpty() ) {
353 Q_ASSERT( !mParentUidToChildrenUid[newParentUid].contains( newIncidence->uid() ) );
354 mParentUidToChildrenUid[newParentUid].append( newIncidence->uid() );
355 mUidToParent.insert( newIncidence->uid(), newParentUid );
360 , d_ptr( new CalendarBasePrivate( this ) )
363 setDeletionTracking(
false );
367 QObject *parent ) : MemoryCalendar( KSystemTimeZones::local() )
371 setDeletionTracking(
false );
382 if ( d->mItemById.contains(
id ) ) {
383 i = d->mItemById[id];
385 kDebug() <<
"Can't find any item with id " << id;
398 if ( d->mItemIdByUid.contains( uid ) ) {
399 const Akonadi::Item::Id
id = d->mItemIdByUid[uid];
400 if ( !d->mItemById.contains(
id ) ) {
401 kError() <<
"Item with id " <<
id <<
"(uid=" << uid <<
") not found, but in uid map";
402 Q_ASSERT_X(
false,
"CalendarBase::item",
"not in mItemById" );
404 i = d->mItemById[id];
406 kDebug() <<
"Can't find any incidence with uid " << uid;
413 return incidence ?
item( incidence->instanceIdentifier() ) : Item();
419 return d->mItemById.values();
424 Akonadi::Item::List
items;
426 foreach(
const KCalCore::Incidence::Ptr &incidence, incidences ) {
428 items <<
item( incidence->instanceIdentifier() );
430 items << Akonadi::Item();
440 KCalCore::Incidence::List childs;
442 if ( d->mItemById.contains( parentId ) ) {
443 const Akonadi::Item item = d->mItemById.value( parentId );
444 Q_ASSERT( item.isValid() );
445 KCalCore::Incidence::Ptr parent = CalendarUtils::incidence(item);
460 KCalCore::Incidence::List children;
461 const QStringList uids = d->mParentUidToChildrenUid.value( parentUid );
462 Q_FOREACH(
const QString &uid, uids ) {
463 Incidence::Ptr child = incidence( uid );
465 children.append( child );
467 kWarning() <<
"Invalid child with uid " << uid;
475 Akonadi::Item::List childs;
477 if ( d->mItemById.contains( parentId ) ) {
478 const Akonadi::Item item = d->mItemById.value( parentId );
479 Q_ASSERT( item.isValid() );
480 KCalCore::Incidence::Ptr parent = CalendarUtils::incidence(item);
495 Akonadi::Item::List children;
496 const QStringList uids = d->mParentUidToChildrenUid.value( parentUid );
497 Q_FOREACH(
const QString &uid, uids ) {
498 Akonadi::Item child =
item( uid );
499 if ( child.isValid() && child.hasPayload<KCalCore::Incidence::Ptr>() )
500 children.append( child );
502 kWarning() <<
"Invalid child with uid " << uid;
520 d->deleteAllIncidencesOfType( Event::eventMimeType() );
536 d->deleteAllIncidencesOfType( Todo::todoMimeType() );
552 d->deleteAllIncidencesOfType( Journal::journalMimeType() );
561 if ( batchAdding() && d->mBatchInsertionCancelled ) {
567 if ( batchAdding() && d->mCollectionForBatchInsertion.isValid() ) {
568 collection = d->mCollectionForBatchInsertion;
571 if ( incidence->hasRecurrenceId() && !collection.
isValid() ) {
573 Item mainItem =
item( incidence->uid() );
574 if ( mainItem.isValid() ) {
575 collection =
Collection( mainItem.storageCollectionId() );
579 const int changeId = d->mIncidenceChanger->createIncidence( incidence, collection );
581 if ( batchAdding() ) {
583 if ( changeId != -1 && !lastCollection.
isValid() ) {
584 d->mBatchInsertionCancelled =
true;
585 }
else if ( lastCollection.
isValid() && !d->mCollectionForBatchInsertion.isValid() ) {
586 d->mCollectionForBatchInsertion = d->mIncidenceChanger->lastCollectionUsed();
590 return changeId != -1;
596 Q_ASSERT( incidence );
597 Akonadi::Item item_ =
item( incidence->instanceIdentifier() );
598 return -1 != d->mIncidenceChanger->deleteIncidence( item_ );
604 Q_ASSERT( newIncidence );
605 Akonadi::Item item_ =
item( newIncidence->instanceIdentifier() );
606 item_.setPayload<KCalCore::Incidence::Ptr>( newIncidence );
607 return -1 != d->mIncidenceChanger->modifyIncidence( item_ );
613 d->mWeakPointer = pointer;
619 return d->mWeakPointer;
625 return d->mIncidenceChanger;
630 KCalCore::MemoryCalendar::startBatchAdding();
637 d->mBatchInsertionCancelled =
false;
638 KCalCore::MemoryCalendar::endBatchAdding();
641 #include "calendarbase.moc"
642 #include "calendarbase_p.moc"
void deleteAllJournals()
Reimplementation of KCalCore::Calendar::deleteAllJournals() that does nothing.
void startBatchAdding()
Call this to tell the calendar that you're adding a batch of incidences.
Represents a collection of PIM items.
Akonadi::Item::List items() const
Returns the list of items contained in this calendar.
Akonadi::Item item(const QString &uid) const
Returns the Item containing the incidence with uid uid or an invalid Item if the incidence isn't foun...
Can change items in this collection.
bool addTodo(const KCalCore::Todo::Ptr &todo)
Adds a Todo to the calendar.
bool deleteEvent(const KCalCore::Event::Ptr &event)
Deletes an Event from the calendar.
Akonadi::Item::List itemList(const KCalCore::Incidence::List &incidenceList) const
Returns the item list that corresponds to the incidenceList.
Collection parentCollection() const
Returns the parent collection of this object.
bool addJournal(const KCalCore::Journal::Ptr &journal)
Adds a Journal to the calendar.
bool deleteIncidence(const KCalCore::Incidence::Ptr &)
Deletes an incidence from the calendar.
bool deleteTodo(const KCalCore::Todo::Ptr &todo)
Deletes a Todo from the calendar.
~CalendarBase()
Destroys the calendar.
bool deleteJournal(const KCalCore::Journal::Ptr &journal)
Deletes a Journal from the calendar.
Rights rights() const
Returns the rights the user has on the collection.
CalendarBase(QObject *parent=0)
Constructs a CalendarBase object.
bool addEvent(const KCalCore::Event::Ptr &event)
Adds an Event to the calendar.
bool modifyIncidence(const KCalCore::Incidence::Ptr &newIncidence)
Modifies an incidence.
Akonadi::Item::List childItems(const QString &parentUid) const
Returns the child items of the parent identified by parentUid.
KCalCore::Incidence::List childIncidences(const QString &parentUid) const
Returns the child incidences of the parent identified by parentUid.
void deleteAllEvents()
Reimplementation of KCalCore::Calendar::deleteAllEvents() that does nothing.
QWeakPointer< CalendarBase > weakPointer() const
Returns the weak pointer set with setWeakPointer().
Akonadi::IncidenceChanger * incidenceChanger() const
Returns the IncidenceChanger used by this calendar to make changes in akonadi.
void endBatchAdding()
Tells the Calendar that you stoped adding a batch of incidences.
bool addIncidence(const KCalCore::Incidence::Ptr &incidence)
Adds an incidence to the calendar.
The base class for all akonadi aware calendars.
bool isValid() const
Returns whether the entity is valid.
void deleteAllTodos()
Reimplementation of KCalCore::Calendar::deleteAllTodos() that does nothing.
void setWeakPointer(const QWeakPointer< Akonadi::CalendarBase > &pointer)
Sets the weak pointer that's associated with this instance.