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>
32 using namespace Akonadi;
33 using namespace KCalCore;
35 static QString itemToString(
const Akonadi::Item &item)
37 const KCalCore::Incidence::Ptr &incidence = CalendarUtils::incidence(item);
39 QTextStream stream(&str);
41 <<
"; summary=" << incidence->summary() <<
"; uid=" << incidence->uid() <<
"; type="
42 << incidence->type() <<
"; recurs=" << incidence->recurs() <<
"; recurrenceId="
43 << incidence->recurrenceId().toString() <<
"; dtStart=" << incidence->dtStart().toString()
44 <<
"; dtEnd=" << incidence->dateTime(Incidence::RoleEnd).toString()
45 <<
"; parentCollection=" << item.storageCollectionId() << item.parentCollection().displayName();
50 CalendarBasePrivate::CalendarBasePrivate(
CalendarBase *qq) : QObject()
51 , mIncidenceChanger(new IncidenceChanger())
52 , mBatchInsertionCancelled(false)
53 , mListensForNewItems(false)
54 , mLastCreationCancelled(false)
57 connect(mIncidenceChanger,
58 SIGNAL(createFinished(
int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)),
59 SLOT(slotCreateFinished(
int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)));
61 connect(mIncidenceChanger,
62 SIGNAL(deleteFinished(
int,QVector<Akonadi::Item::Id>,Akonadi::IncidenceChanger::ResultCode,QString)),
63 SLOT(slotDeleteFinished(
int,QVector<Akonadi::Item::Id>,Akonadi::IncidenceChanger::ResultCode,QString)));
65 connect(mIncidenceChanger,
66 SIGNAL(modifyFinished(
int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)),
67 SLOT(slotModifyFinished(
int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)));
69 mIncidenceChanger->setDestinationPolicy(IncidenceChanger::DestinationPolicyAsk);
70 mIncidenceChanger->setGroupwareCommunication(
false);
71 mIncidenceChanger->setHistoryEnabled(
false);
74 CalendarBasePrivate::~CalendarBasePrivate()
76 delete mIncidenceChanger;
77 mIncidenceChanger = 0;
80 void CalendarBasePrivate::internalInsert(
const Akonadi::Item &item)
82 Q_ASSERT(item.isValid());
83 Q_ASSERT(item.hasPayload<KCalCore::Incidence::Ptr>());
84 KCalCore::Incidence::Ptr incidence = CalendarUtils::incidence(item);
87 kError() <<
"Incidence is null. id=" << item.id()
88 <<
"; hasPayload()=" << item.hasPayload()
89 <<
"; has incidence=" << item.hasPayload<KCalCore::Incidence::Ptr>()
90 <<
"; mime type=" << item.mimeType();
96 const QString uid = incidence->instanceIdentifier();
100 kError() <<
"Incidence has empty UID. id=" << item.id()
101 <<
"; summary=" << incidence->summary()
102 <<
"Please fix it. Ignoring this incidence.";
106 if (mItemIdByUid.contains(uid) && mItemIdByUid[uid] != item.id()) {
109 kWarning() <<
"Discarding duplicate incidence with instanceIdentifier=" << uid
110 <<
"and summary " << incidence->summary()
111 <<
"; recurrenceId() =" << incidence->recurrenceId()
112 <<
"; new id=" << item.id()
113 <<
"; existing id=" << mItemIdByUid[uid];
117 if (incidence->type() == KCalCore::Incidence::TypeEvent && !incidence->dtStart().isValid()) {
119 kWarning() <<
"Discarding event with invalid DTSTART. identifier="
120 << incidence->instanceIdentifier() <<
"; summary=" << incidence->summary();
130 mItemById.insert(item.id(), item);
131 mItemIdByUid.insert(uid, item.id());
132 mItemsByCollection.insert(item.storageCollectionId(), item);
134 if (!incidence->hasRecurrenceId()) {
136 const QString parentUid = incidence->relatedTo();
137 if (!parentUid.isEmpty()) {
138 mParentUidToChildrenUid[parentUid].append(incidence->uid());
139 mUidToParent.insert(uid, parentUid);
143 incidence->setCustomProperty(
"VOLATILE",
"AKONADI-ID", QString::number(item.id()));
145 const bool result = q->MemoryCalendar::addIncidence(incidence);
147 kError() <<
"Error adding incidence " << itemToString(item);
152 void CalendarBasePrivate::internalRemove(
const Akonadi::Item &item)
154 Q_ASSERT(item.isValid());
156 Incidence::Ptr tmp = CalendarUtils::incidence(item);
158 kError() <<
"CalendarBase::internalRemove1: incidence is null, item.id=" << item.id();
163 Incidence::Ptr incidence = q->incidence(tmp->uid(), tmp->recurrenceId());
168 mItemById.remove(item.id());
170 mItemIdByUid.remove(incidence->instanceIdentifier());
172 mItemsByCollection.remove(item.storageCollectionId(), item);
174 if (!incidence->hasRecurrenceId()) {
175 const QString uid = incidence->uid();
176 const QString parentUid = incidence->relatedTo();
177 mParentUidToChildrenUid.remove(uid);
178 if (!parentUid.isEmpty()) {
179 mParentUidToChildrenUid[parentUid].removeAll(uid);
180 mUidToParent.remove(uid);
184 const bool result = q->MemoryCalendar::deleteIncidence(incidence);
186 kError() <<
"Error removing incidence " << itemToString(item);
190 kWarning() <<
"CalendarBase::internalRemove2: incidence is null, item.id=" << itemToString(item);
194 void CalendarBasePrivate::deleteAllIncidencesOfType(
const QString &mimeType)
196 kWarning() <<
"Refusing to delete your Incidences.";
210 void CalendarBasePrivate::slotDeleteFinished(
int changeId,
211 const QVector<Akonadi::Item::Id> &itemIds,
212 IncidenceChanger::ResultCode resultCode,
213 const QString &errorMessage)
216 if (resultCode == IncidenceChanger::ResultCodeSuccess) {
217 foreach(
const Akonadi::Item::Id &
id, itemIds) {
218 if (mItemById.contains(
id))
219 internalRemove(mItemById.value(
id));
223 emit q->deleteFinished(resultCode == IncidenceChanger::ResultCodeSuccess, errorMessage);
226 void CalendarBasePrivate::slotCreateFinished(
int changeId,
227 const Akonadi::Item &item,
228 IncidenceChanger::ResultCode resultCode,
229 const QString &errorMessage)
233 if (resultCode == IncidenceChanger::ResultCodeSuccess && !mListensForNewItems) {
234 Q_ASSERT(item.isValid());
235 Q_ASSERT(item.hasPayload<KCalCore::Incidence::Ptr>());
236 internalInsert(item);
239 mLastCreationCancelled = (resultCode == IncidenceChanger::ResultCodeUserCanceled);
241 emit q->createFinished(resultCode == IncidenceChanger::ResultCodeSuccess, errorMessage);
244 void CalendarBasePrivate::slotModifyFinished(
int changeId,
245 const Akonadi::Item &item,
246 IncidenceChanger::ResultCode resultCode,
247 const QString &errorMessage)
251 QString message = errorMessage;
252 if (resultCode == IncidenceChanger::ResultCodeSuccess) {
253 KCalCore::Incidence::Ptr incidence = CalendarUtils::incidence(item);
255 KCalCore::Incidence::Ptr localIncidence = q->incidence(incidence->instanceIdentifier());
257 if (localIncidence) {
259 *(
static_cast<KCalCore::IncidenceBase*
>(localIncidence.data())) = *(incidence.data());
262 kWarning() <<
"CalendarBasePrivate::slotModifyFinished() Incidence was deleted already probably? id=" << item.id();
263 message = i18n(
"Could not find incidence to update, it probably was deleted recently.");
264 resultCode = IncidenceChanger::ResultCodeAlreadyDeleted;
267 emit q->modifyFinished(resultCode == IncidenceChanger::ResultCodeSuccess, message);
270 void CalendarBasePrivate::handleUidChange(
const Akonadi::Item &oldItem,
271 const Akonadi::Item &newItem,
const QString &newIdentifier)
273 Q_ASSERT(oldItem.isValid());
274 Incidence::Ptr newIncidence = CalendarUtils::incidence(newItem);
275 Q_ASSERT(newIncidence);
276 Incidence::Ptr oldIncidence = CalendarUtils::incidence(oldItem);
277 Q_ASSERT(oldIncidence);
279 const QString newUid = newIncidence->uid();
280 if (mItemIdByUid.contains(newIdentifier)) {
281 Incidence::Ptr oldIncidence = CalendarUtils::incidence(oldItem);
282 kWarning() <<
"New uid shouldn't be known: " << newIdentifier <<
"; id="
283 << newItem.id() <<
"; oldItem.id=" << mItemIdByUid[newIdentifier]
284 <<
"; new summary= " << newIncidence->summary()
285 <<
"; new recurrenceId=" << newIncidence->recurrenceId()
286 <<
"; oldIncidence" << oldIncidence;
288 kWarning() <<
"; oldIncidence uid=" << oldIncidence->uid()
289 <<
"; oldIncidence recurrenceId = " << oldIncidence->recurrenceId()
290 <<
"; oldIncidence summary = " << oldIncidence->summary();
296 mItemIdByUid[newIdentifier] = newItem.id();
299 oldIncidence = q->MemoryCalendar::incidence(oldIncidence->uid());
303 kWarning() <<
"Couldn't find old incidence";
308 if (newIncidence->instanceIdentifier() == oldIncidence->instanceIdentifier()) {
309 kWarning() <<
"New uid=" << newIncidence->uid() <<
"; old uid=" << oldIncidence->uid()
310 <<
"; new recurrenceId="
311 << newIncidence->recurrenceId()
312 <<
"; old recurrenceId=" << oldIncidence->recurrenceId()
313 <<
"; new summary = " << newIncidence->summary()
314 <<
"; old summary = " << oldIncidence->summary()
315 <<
"; id = " << newItem.id();
320 mItemIdByUid.remove(oldIncidence->instanceIdentifier());
321 const QString oldUid = oldIncidence->uid();
323 if (mParentUidToChildrenUid.contains(oldUid)) {
324 Q_ASSERT(!mParentUidToChildrenUid.contains(newIdentifier));
325 QStringList children = mParentUidToChildrenUid.value(oldUid);
326 mParentUidToChildrenUid.insert(newIdentifier, children);
327 mParentUidToChildrenUid.remove(oldUid);
331 q->setObserversEnabled(
false);
332 q->MemoryCalendar::deleteIncidence(oldIncidence);
333 q->MemoryCalendar::addIncidence(newIncidence);
335 newIncidence->setUid(oldUid);
336 q->setObserversEnabled(
true);
337 newIncidence->setUid(newUid);
340 void CalendarBasePrivate::handleParentChanged(
const KCalCore::Incidence::Ptr &newIncidence)
342 Q_ASSERT(newIncidence);
344 if (newIncidence->hasRecurrenceId()) {
348 const QString originalParentUid = mUidToParent.value(newIncidence->uid());
349 const QString newParentUid = newIncidence->relatedTo();
351 if (originalParentUid == newParentUid) {
355 if (!originalParentUid.isEmpty()) {
357 Q_ASSERT(mParentUidToChildrenUid.contains(originalParentUid));
358 mParentUidToChildrenUid[originalParentUid].removeAll(newIncidence->uid());
361 mUidToParent.remove(newIncidence->uid());
363 if (!newParentUid.isEmpty()) {
365 Q_ASSERT(!mParentUidToChildrenUid[newParentUid].contains(newIncidence->uid()));
366 mParentUidToChildrenUid[newParentUid].append(newIncidence->uid());
367 mUidToParent.insert(newIncidence->uid(), newParentUid);
372 , d_ptr(new CalendarBasePrivate(this))
375 setDeletionTracking(
false);
379 QObject *parent) : MemoryCalendar(KSystemTimeZones::local())
383 setDeletionTracking(
false);
394 if (d->mItemById.contains(
id)) {
395 i = d->mItemById[id];
397 kDebug() <<
"Can't find any item with id " << id;
410 if (d->mItemIdByUid.contains(uid)) {
411 const Akonadi::Item::Id
id = d->mItemIdByUid[uid];
412 if (!d->mItemById.contains(
id)) {
413 kError() <<
"Item with id " <<
id <<
"(uid=" << uid <<
") not found, but in uid map";
414 Q_ASSERT_X(
false,
"CalendarBase::item",
"not in mItemById");
416 i = d->mItemById[id];
418 kDebug() <<
"Can't find any incidence with uid " << uid;
425 return incidence ?
item(incidence->instanceIdentifier()) : Item();
431 return d->mItemById.values();
437 return d->mItemsByCollection.values(
id);
442 Akonadi::Item::List
items;
444 foreach(
const KCalCore::Incidence::Ptr &incidence, incidences) {
446 items <<
item(incidence->instanceIdentifier());
448 items << Akonadi::Item();
458 KCalCore::Incidence::List childs;
460 if (d->mItemById.contains(parentId)) {
461 const Akonadi::Item item = d->mItemById.value(parentId);
462 Q_ASSERT(item.isValid());
463 KCalCore::Incidence::Ptr parent = CalendarUtils::incidence(item);
478 KCalCore::Incidence::List children;
479 const QStringList uids = d->mParentUidToChildrenUid.value(parentUid);
480 Q_FOREACH(
const QString &uid, uids) {
481 Incidence::Ptr child = incidence(uid);
483 children.append(child);
485 kWarning() <<
"Invalid child with uid " << uid;
493 Akonadi::Item::List childs;
495 if (d->mItemById.contains(parentId)) {
496 const Akonadi::Item item = d->mItemById.value(parentId);
497 Q_ASSERT(item.isValid());
498 KCalCore::Incidence::Ptr parent = CalendarUtils::incidence(item);
513 Akonadi::Item::List children;
514 const QStringList uids = d->mParentUidToChildrenUid.value(parentUid);
515 Q_FOREACH(
const QString &uid, uids) {
516 Akonadi::Item child =
item(uid);
517 if (child.isValid() && child.hasPayload<KCalCore::Incidence::Ptr>())
518 children.append(child);
520 kWarning() <<
"Invalid child with uid " << uid;
538 d->deleteAllIncidencesOfType(Event::eventMimeType());
554 d->deleteAllIncidencesOfType(Todo::todoMimeType());
570 d->deleteAllIncidencesOfType(Journal::journalMimeType());
579 if (batchAdding() && d->mBatchInsertionCancelled) {
583 d->mLastCreationCancelled =
false;
587 if (batchAdding() && d->mCollectionForBatchInsertion.isValid()) {
588 collection = d->mCollectionForBatchInsertion;
591 if (incidence->hasRecurrenceId() && !collection.
isValid()) {
593 Item mainItem =
item(incidence->uid());
594 if (mainItem.isValid()) {
595 collection =
Collection(mainItem.storageCollectionId());
599 const int changeId = d->mIncidenceChanger->createIncidence(incidence, collection);
603 if (changeId != -1 && !lastCollection.
isValid()) {
604 d->mBatchInsertionCancelled =
true;
605 }
else if (lastCollection.
isValid() && !d->mCollectionForBatchInsertion.isValid()) {
606 d->mCollectionForBatchInsertion = d->mIncidenceChanger->lastCollectionUsed();
610 return changeId != -1;
617 Akonadi::Item item_ =
item(incidence->instanceIdentifier());
618 return -1 != d->mIncidenceChanger->deleteIncidence(item_);
624 Q_ASSERT(newIncidence);
625 Akonadi::Item item_ =
item(newIncidence->instanceIdentifier());
626 item_.setPayload<KCalCore::Incidence::Ptr>(newIncidence);
627 return -1 != d->mIncidenceChanger->modifyIncidence(item_);
633 d->mWeakPointer = pointer;
639 return d->mWeakPointer;
645 return d->mIncidenceChanger;
650 KCalCore::MemoryCalendar::startBatchAdding();
657 d->mBatchInsertionCancelled =
false;
658 KCalCore::MemoryCalendar::endBatchAdding();
661 #include "moc_calendarbase.cpp"
662 #include "moc_calendarbase_p.cpp"
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.
qint64 Id
Describes the unique id type.
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.
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.