File indexing completed on 2024-05-12 05:10:42
0001 /* 0002 SPDX-FileCopyrightText: 2011 Sérgio Martins <sergio.martins@kdab.com> 0003 SPDX-FileCopyrightText: 2012 Sérgio Martins <iamsergio@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "calendarbase.h" 0009 #include "akonadicalendar_debug.h" 0010 #include "calendarbase_p.h" 0011 #include "calendarutils.h" 0012 #include "incidencechanger.h" 0013 #include <Akonadi/CollectionFetchJob> 0014 0015 #include <KLocalizedString> 0016 #include <QTimeZone> 0017 0018 using namespace Akonadi; 0019 using namespace KCalendarCore; 0020 0021 static QString itemToString(const Akonadi::Item &item) 0022 { 0023 const KCalendarCore::Incidence::Ptr &incidence = CalendarUtils::incidence(item); 0024 QString str; 0025 QTextStream stream(&str); 0026 stream << item.id() << "; summary=" << incidence->summary() << "; uid=" << incidence->uid() << "; type=" << incidence->type() 0027 << "; recurs=" << incidence->recurs() << "; recurrenceId=" << incidence->recurrenceId().toString() << "; dtStart=" << incidence->dtStart().toString() 0028 << "; dtEnd=" << incidence->dateTime(Incidence::RoleEnd).toString() << "; parentCollection=" << item.storageCollectionId() 0029 << item.parentCollection().displayName(); 0030 0031 return str; 0032 } 0033 0034 CalendarBasePrivate::CalendarBasePrivate(CalendarBase *qq) 0035 : QObject() 0036 , mIncidenceChanger(new IncidenceChanger()) 0037 , q(qq) 0038 { 0039 connect(mIncidenceChanger, &IncidenceChanger::createFinished, this, &CalendarBasePrivate::slotCreateFinished); 0040 0041 connect(mIncidenceChanger, &IncidenceChanger::deleteFinished, this, &CalendarBasePrivate::slotDeleteFinished); 0042 0043 connect(mIncidenceChanger, &IncidenceChanger::modifyFinished, this, &CalendarBasePrivate::slotModifyFinished); 0044 0045 mIncidenceChanger->setDestinationPolicy(IncidenceChanger::DestinationPolicyAsk); 0046 mIncidenceChanger->setGroupwareCommunication(false); 0047 mIncidenceChanger->setHistoryEnabled(false); 0048 } 0049 0050 CalendarBasePrivate::~CalendarBasePrivate() 0051 { 0052 delete mIncidenceChanger; 0053 } 0054 0055 void CalendarBasePrivate::internalInsert(const Akonadi::Item &item) 0056 { 0057 Q_ASSERT(item.isValid()); 0058 Q_ASSERT(item.hasPayload<KCalendarCore::Incidence::Ptr>()); 0059 KCalendarCore::Incidence::Ptr incidence = CalendarUtils::incidence(item); 0060 0061 if (!incidence) { 0062 qCritical() << "Incidence is null. id=" << item.id() << "; hasPayload()=" << item.hasPayload() 0063 << "; has incidence=" << item.hasPayload<KCalendarCore::Incidence::Ptr>() << "; mime type=" << item.mimeType(); 0064 Q_ASSERT(false); 0065 return; 0066 } 0067 0068 // qCDebug(AKONADICALENDAR_LOG) << "Inserting incidence in calendar. id=" << item.id() << "uid=" << incidence->uid(); 0069 const QString uid = incidence->instanceIdentifier(); 0070 0071 if (uid.isEmpty()) { 0072 // This code path should never happen 0073 qCritical() << "Incidence has empty UID. id=" << item.id() << "; summary=" << incidence->summary() << "Please fix it. Ignoring this incidence."; 0074 return; 0075 } 0076 0077 if (mItemIdByUid.contains(uid) && mItemIdByUid[uid] != item.id()) { 0078 // We only allow duplicate UIDs if they have the same item id, for example 0079 // when using virtual folders. 0080 #if 0 0081 qCWarning(AKONADICALENDAR_LOG) << "Discarding duplicate incidence with instanceIdentifier=" << uid 0082 << "and summary " << incidence->summary() 0083 << "; recurrenceId() =" << incidence->recurrenceId() 0084 << "; new id=" << item.id() 0085 << "; existing id=" << mItemIdByUid[uid]; 0086 #endif 0087 return; 0088 } 0089 0090 if (incidence->type() == KCalendarCore::Incidence::TypeEvent && !incidence->dtStart().isValid()) { 0091 // TODO: make the parser discard them would also be a good idea 0092 qCWarning(AKONADICALENDAR_LOG) << "Discarding event with invalid DTSTART. identifier=" << incidence->instanceIdentifier() 0093 << "; summary=" << incidence->summary(); 0094 return; 0095 } 0096 0097 Akonadi::Collection collection = item.parentCollection(); 0098 if (collection.isValid()) { 0099 // Some items don't have collection set 0100 if (item.storageCollectionId() != collection.id() && item.storageCollectionId() > -1) { 0101 if (mCollections.contains(item.storageCollectionId())) { 0102 collection = mCollections.value(item.storageCollectionId()); 0103 incidence->setReadOnly(!(collection.rights() & Akonadi::Collection::CanChangeItem)); 0104 } else if (!mCollectionJobs.key(item.storageCollectionId())) { 0105 collection = Akonadi::Collection(item.storageCollectionId()); 0106 auto job = new Akonadi::CollectionFetchJob(collection, Akonadi::CollectionFetchJob::Base, this); 0107 QObject::connect(job, &KJob::result, this, &CalendarBasePrivate::collectionFetchResult); 0108 mCollectionJobs.insert(job, collection.id()); 0109 } 0110 } else { 0111 mCollections.insert(collection.id(), collection); 0112 incidence->setReadOnly(!(collection.rights() & Akonadi::Collection::CanChangeItem)); 0113 } 0114 } 0115 0116 mItemById.insert(item.id(), item); 0117 mItemIdByUid.insert(uid, item.id()); 0118 mItemsByCollection.insert(item.storageCollectionId(), item); 0119 0120 if (!incidence->hasRecurrenceId()) { 0121 // Insert parent relationships 0122 const QString parentUid = incidence->relatedTo(); 0123 if (!parentUid.isEmpty()) { 0124 mParentUidToChildrenUid[parentUid].append(incidence->uid()); 0125 mUidToParent.insert(uid, parentUid); 0126 } 0127 } 0128 0129 incidence->setCustomProperty("VOLATILE", "AKONADI-ID", QString::number(item.id())); 0130 incidence->setCustomProperty("VOLATILE", "COLLECTION-ID", QString::number(item.storageCollectionId())); 0131 // Must be the last one due to re-entrancy 0132 const bool result = q->MemoryCalendar::addIncidence(incidence); 0133 if (!result) { 0134 qCritical() << "Error adding incidence " << itemToString(item); 0135 Q_ASSERT(false); 0136 } 0137 } 0138 0139 void CalendarBasePrivate::collectionFetchResult(KJob *job) 0140 { 0141 Akonadi::Collection::Id colid = mCollectionJobs.take(job); 0142 0143 if (job->error()) { 0144 qWarning() << "Error occurred: " << job->errorString(); 0145 return; 0146 } 0147 0148 auto fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job); 0149 0150 const Akonadi::Collection collection = fetchJob->collections().at(0); 0151 if (collection.id() != colid) { 0152 qCritical() << "Fetched the wrong collection, should fetch: " << colid << "fetched: " << collection.id(); 0153 } 0154 0155 bool isReadOnly = !(collection.rights() & Akonadi::Collection::CanChangeItem); 0156 const auto lst = mItemsByCollection.values(collection.id()); 0157 for (const Akonadi::Item &item : lst) { 0158 KCalendarCore::Incidence::Ptr incidence = CalendarUtils::incidence(item); 0159 incidence->setReadOnly(isReadOnly); 0160 } 0161 0162 mCollections.insert(collection.id(), collection); 0163 0164 if (mCollectionJobs.isEmpty()) { 0165 Q_EMIT fetchFinished(); 0166 } 0167 } 0168 0169 void CalendarBasePrivate::internalRemove(const Akonadi::Item &item) 0170 { 0171 Q_ASSERT(item.isValid()); 0172 0173 Incidence::Ptr tmp = CalendarUtils::incidence(item); 0174 if (!tmp) { 0175 qCritical() << "CalendarBase::internalRemove1: incidence is null, item.id=" << item.id(); 0176 return; 0177 } 0178 0179 // We want the one stored in the calendar 0180 Incidence::Ptr incidence = q->incidence(tmp->uid(), tmp->recurrenceId()); 0181 0182 // Null incidence means it was deleted via CalendarBase::deleteIncidence(), but then 0183 // the ETMCalendar received the monitor notification and tried to delete it again. 0184 if (incidence) { 0185 q->Calendar::notifyIncidenceAboutToBeDeleted(incidence); 0186 0187 mItemById.remove(item.id()); 0188 // qCDebug(AKONADICALENDAR_LOG) << "Deleting incidence from calendar .id=" << item.id() << "uid=" << incidence->uid(); 0189 mItemIdByUid.remove(incidence->instanceIdentifier()); 0190 0191 mItemsByCollection.remove(item.storageCollectionId(), item); 0192 0193 if (!incidence->hasRecurrenceId()) { 0194 const QString uid = incidence->uid(); 0195 const QString parentUid = incidence->relatedTo(); 0196 mParentUidToChildrenUid.remove(uid); 0197 if (!parentUid.isEmpty()) { 0198 mParentUidToChildrenUid[parentUid].removeAll(uid); 0199 mUidToParent.remove(uid); 0200 } 0201 } 0202 0203 q->Calendar::setObserversEnabled(false); 0204 // Must be the last one due to re-entrancy 0205 const bool result = q->MemoryCalendar::deleteIncidence(incidence); 0206 q->Calendar::setObserversEnabled(true); 0207 q->Calendar::notifyIncidenceDeleted(incidence); 0208 if (!result) { 0209 qCritical() << "Error removing incidence " << itemToString(item); 0210 Q_ASSERT(false); 0211 } 0212 } else { 0213 qCWarning(AKONADICALENDAR_LOG) << "CalendarBase::internalRemove2: incidence is null, item.id=" << itemToString(item); 0214 } 0215 } 0216 0217 void CalendarBasePrivate::slotDeleteFinished(int changeId, 0218 const QList<Akonadi::Item::Id> &itemIds, 0219 IncidenceChanger::ResultCode resultCode, 0220 const QString &errorMessage) 0221 { 0222 Q_UNUSED(changeId) 0223 if (resultCode == IncidenceChanger::ResultCodeSuccess) { 0224 for (const Akonadi::Item::Id &id : itemIds) { 0225 if (mItemById.contains(id)) { 0226 internalRemove(mItemById.value(id)); 0227 } 0228 } 0229 } 0230 0231 Q_EMIT q->deleteFinished(resultCode == IncidenceChanger::ResultCodeSuccess, errorMessage); 0232 } 0233 0234 void CalendarBasePrivate::slotCreateFinished(int changeId, const Akonadi::Item &item, IncidenceChanger::ResultCode resultCode, const QString &errorMessage) 0235 { 0236 Q_UNUSED(changeId) 0237 Q_UNUSED(item) 0238 if (resultCode == IncidenceChanger::ResultCodeSuccess && !mListensForNewItems) { 0239 Q_ASSERT(item.isValid()); 0240 Q_ASSERT(item.hasPayload<KCalendarCore::Incidence::Ptr>()); 0241 internalInsert(item); 0242 } 0243 0244 mLastCreationCancelled = (resultCode == IncidenceChanger::ResultCodeUserCanceled); 0245 0246 Q_EMIT q->createFinished(resultCode == IncidenceChanger::ResultCodeSuccess, errorMessage); 0247 } 0248 0249 void CalendarBasePrivate::slotModifyFinished(int changeId, const Akonadi::Item &item, IncidenceChanger::ResultCode resultCode, const QString &errorMessage) 0250 { 0251 Q_UNUSED(changeId) 0252 Q_UNUSED(item) 0253 QString message = errorMessage; 0254 if (resultCode == IncidenceChanger::ResultCodeSuccess) { 0255 KCalendarCore::Incidence::Ptr incidence = CalendarUtils::incidence(item); 0256 Q_ASSERT(incidence); 0257 KCalendarCore::Incidence::Ptr localIncidence = q->incidence(incidence->instanceIdentifier()); 0258 0259 if (localIncidence) { 0260 // update our local one 0261 *(static_cast<KCalendarCore::IncidenceBase *>(localIncidence.data())) = *(incidence.data()); 0262 } else { 0263 // This shouldn't happen, unless the incidence gets deleted between event loops 0264 qCWarning(AKONADICALENDAR_LOG) << "CalendarBasePrivate::slotModifyFinished() Incidence was deleted already probably? id=" << item.id(); 0265 message = i18n("Could not find incidence to update, it probably was deleted recently."); 0266 resultCode = IncidenceChanger::ResultCodeAlreadyDeleted; 0267 } 0268 } 0269 Q_EMIT q->modifyFinished(resultCode == IncidenceChanger::ResultCodeSuccess, message); 0270 } 0271 0272 void CalendarBasePrivate::handleUidChange(const Akonadi::Item &oldItem, const Akonadi::Item &newItem, const QString &newIdentifier) 0273 { 0274 Q_ASSERT(oldItem.isValid()); 0275 Incidence::Ptr newIncidence = CalendarUtils::incidence(newItem); 0276 Q_ASSERT(newIncidence); 0277 Incidence::Ptr oldIncidence = CalendarUtils::incidence(oldItem); 0278 Q_ASSERT(oldIncidence); 0279 0280 const QString newUid = newIncidence->uid(); 0281 if (mItemIdByUid.contains(newIdentifier)) { 0282 Incidence::Ptr oldIncidence = CalendarUtils::incidence(oldItem); 0283 #if 0 0284 qCWarning(AKONADICALENDAR_LOG) << "New uid shouldn't be known: " << newIdentifier << "; id=" 0285 << newItem.id() << "; oldItem.id=" << mItemIdByUid[newIdentifier] 0286 << "; new summary= " << newIncidence->summary() 0287 << "; new recurrenceId=" << newIncidence->recurrenceId() 0288 << "; oldIncidence" << oldIncidence; 0289 #endif 0290 if (oldIncidence) { 0291 #if 0 0292 qCWarning(AKONADICALENDAR_LOG) << "; oldIncidence uid=" << oldIncidence->uid() 0293 << "; oldIncidence recurrenceId = " << oldIncidence->recurrenceId() 0294 << "; oldIncidence summary = " << oldIncidence->summary(); 0295 #endif 0296 } 0297 Q_ASSERT(false); 0298 return; 0299 } 0300 0301 mItemIdByUid[newIdentifier] = newItem.id(); 0302 0303 // Get the real pointer 0304 oldIncidence = q->MemoryCalendar::incidence(oldIncidence->uid()); 0305 0306 if (!oldIncidence) { 0307 // How can this happen ? 0308 qCWarning(AKONADICALENDAR_LOG) << "Couldn't find old incidence"; 0309 Q_ASSERT(false); 0310 return; 0311 } 0312 0313 if (newIncidence->instanceIdentifier() == oldIncidence->instanceIdentifier()) { 0314 #if 0 0315 qCWarning(AKONADICALENDAR_LOG) << "New uid=" << newIncidence->uid() << "; old uid=" << oldIncidence->uid() 0316 << "; new recurrenceId=" 0317 << newIncidence->recurrenceId() 0318 << "; old recurrenceId=" << oldIncidence->recurrenceId() 0319 << "; new summary = " << newIncidence->summary() 0320 << "; old summary = " << oldIncidence->summary() 0321 << "; id = " << newItem.id(); 0322 #endif 0323 Q_ASSERT(false); // The reason we're here in the first place 0324 return; 0325 } 0326 0327 mItemIdByUid.remove(oldIncidence->instanceIdentifier()); 0328 const QString oldUid = oldIncidence->uid(); 0329 0330 if (mParentUidToChildrenUid.contains(oldUid)) { 0331 Q_ASSERT(!mParentUidToChildrenUid.contains(newIdentifier)); 0332 QStringList children = mParentUidToChildrenUid.value(oldUid); 0333 mParentUidToChildrenUid.insert(newIdentifier, children); 0334 mParentUidToChildrenUid.remove(oldUid); 0335 } 0336 0337 // Update internal maps of the base class, MemoryCalendar 0338 q->setObserversEnabled(false); 0339 q->MemoryCalendar::deleteIncidence(oldIncidence); 0340 q->MemoryCalendar::addIncidence(newIncidence); 0341 0342 newIncidence->setUid(oldUid); // We set and unset just to notify observers of a change. 0343 q->setObserversEnabled(true); 0344 newIncidence->setUid(newUid); 0345 } 0346 0347 void CalendarBasePrivate::handleParentChanged(const KCalendarCore::Incidence::Ptr &newIncidence) 0348 { 0349 Q_ASSERT(newIncidence); 0350 0351 if (newIncidence->hasRecurrenceId()) { // These ones don't/shouldn't have a parent 0352 return; 0353 } 0354 0355 const QString originalParentUid = mUidToParent.value(newIncidence->uid()); 0356 const QString newParentUid = newIncidence->relatedTo(); 0357 0358 if (originalParentUid == newParentUid) { 0359 return; // nothing changed 0360 } 0361 0362 if (!originalParentUid.isEmpty()) { 0363 // Remove this child from it's old parent: 0364 Q_ASSERT(mParentUidToChildrenUid.contains(originalParentUid)); 0365 mParentUidToChildrenUid[originalParentUid].removeAll(newIncidence->uid()); 0366 } 0367 0368 mUidToParent.remove(newIncidence->uid()); 0369 0370 if (!newParentUid.isEmpty()) { 0371 // Deliver this child to it's new parent: 0372 Q_ASSERT(!mParentUidToChildrenUid[newParentUid].contains(newIncidence->uid())); 0373 mParentUidToChildrenUid[newParentUid].append(newIncidence->uid()); 0374 mUidToParent.insert(newIncidence->uid(), newParentUid); 0375 } 0376 } 0377 0378 CalendarBase::CalendarBase(QObject *parent) 0379 : MemoryCalendar(QTimeZone::systemTimeZone()) 0380 , d_ptr(new CalendarBasePrivate(this)) 0381 { 0382 setParent(parent); 0383 } 0384 0385 CalendarBase::CalendarBase(CalendarBasePrivate *const dd, QObject *parent) 0386 : MemoryCalendar(QTimeZone::systemTimeZone()) 0387 , d_ptr(dd) 0388 { 0389 setParent(parent); 0390 } 0391 0392 CalendarBase::~CalendarBase() = default; 0393 0394 Akonadi::Item CalendarBase::item(Akonadi::Item::Id id) const 0395 { 0396 Q_D(const CalendarBase); 0397 Akonadi::Item i; 0398 auto it = d->mItemById.constFind(id); 0399 if (it != d->mItemById.cend()) { 0400 i = *it; 0401 } else { 0402 qCDebug(AKONADICALENDAR_LOG) << "Can't find any item with id " << id; 0403 } 0404 return i; 0405 } 0406 0407 Akonadi::Item CalendarBase::item(const QString &uid) const 0408 { 0409 Q_D(const CalendarBase); 0410 Akonadi::Item i; 0411 0412 if (uid.isEmpty()) { 0413 return i; 0414 } 0415 0416 auto it = d->mItemIdByUid.constFind(uid); 0417 if (it != d->mItemIdByUid.cend()) { 0418 const Akonadi::Item::Id id = *it; 0419 auto it2 = d->mItemById.constFind(id); 0420 if (it2 == d->mItemById.cend()) { 0421 qCritical() << "Item with id " << id << "(uid=" << uid << ") not found, but in uid map"; 0422 Q_ASSERT_X(false, "CalendarBase::item", "not in mItemById"); 0423 } else { 0424 i = *it2; 0425 } 0426 } else { 0427 qCDebug(AKONADICALENDAR_LOG) << "Can't find any incidence with uid " << uid; 0428 } 0429 return i; 0430 } 0431 0432 Item CalendarBase::item(const Incidence::Ptr &incidence) const 0433 { 0434 return incidence ? item(incidence->instanceIdentifier()) : Item(); 0435 } 0436 0437 Akonadi::Item::List CalendarBase::items(Akonadi::Collection::Id id) const 0438 { 0439 Q_D(const CalendarBase); 0440 0441 Akonadi::Item::List result; 0442 if (id == -1) { 0443 result.reserve(d->mItemsByCollection.size()); 0444 } 0445 0446 auto it = id == -1 ? d->mItemsByCollection.cbegin() : d->mItemsByCollection.constFind(id); 0447 while (it != d->mItemsByCollection.cend() && (id == -1 || it.key() == id)) { 0448 result.push_back(*it); 0449 ++it; 0450 } 0451 0452 return result; 0453 } 0454 0455 Akonadi::Item::List CalendarBase::itemList(const KCalendarCore::Incidence::List &incidences) const 0456 { 0457 Akonadi::Item::List items; 0458 items.reserve(incidences.size()); 0459 0460 for (const KCalendarCore::Incidence::Ptr &incidence : incidences) { 0461 if (incidence) { 0462 items << item(incidence->instanceIdentifier()); 0463 } else { 0464 items << Akonadi::Item(); 0465 } 0466 } 0467 0468 return items; 0469 } 0470 0471 KCalendarCore::Incidence::List CalendarBase::childIncidences(Akonadi::Item::Id parentId) const 0472 { 0473 Q_D(const CalendarBase); 0474 KCalendarCore::Incidence::List children; 0475 0476 if (d->mItemById.contains(parentId)) { 0477 const Akonadi::Item item = d->mItemById.value(parentId); 0478 Q_ASSERT(item.isValid()); 0479 KCalendarCore::Incidence::Ptr parent = CalendarUtils::incidence(item); 0480 0481 if (parent) { 0482 children = childIncidences(parent->uid()); 0483 } else { 0484 Q_ASSERT(false); 0485 } 0486 } 0487 0488 return children; 0489 } 0490 0491 KCalendarCore::Incidence::List CalendarBase::childIncidences(const QString &parentUid) const 0492 { 0493 Q_D(const CalendarBase); 0494 KCalendarCore::Incidence::List children; 0495 const QStringList uids = d->mParentUidToChildrenUid.value(parentUid); 0496 for (const QString &uid : uids) { 0497 Incidence::Ptr child = incidence(uid); 0498 if (child) { 0499 children.append(child); 0500 } else { 0501 qCWarning(AKONADICALENDAR_LOG) << "Invalid child with uid " << uid; 0502 } 0503 } 0504 return children; 0505 } 0506 0507 Akonadi::Item::List CalendarBase::childItems(Akonadi::Item::Id parentId) const 0508 { 0509 Q_D(const CalendarBase); 0510 Akonadi::Item::List children; 0511 0512 if (d->mItemById.contains(parentId)) { 0513 const Akonadi::Item item = d->mItemById.value(parentId); 0514 Q_ASSERT(item.isValid()); 0515 KCalendarCore::Incidence::Ptr parent = CalendarUtils::incidence(item); 0516 0517 if (parent) { 0518 children = childItems(parent->uid()); 0519 } else { 0520 Q_ASSERT(false); 0521 } 0522 } 0523 0524 return children; 0525 } 0526 0527 Akonadi::Item::List CalendarBase::childItems(const QString &parentUid) const 0528 { 0529 Q_D(const CalendarBase); 0530 Akonadi::Item::List children; 0531 const QStringList uids = d->mParentUidToChildrenUid.value(parentUid); 0532 for (const QString &uid : uids) { 0533 Akonadi::Item child = item(uid); 0534 if (child.isValid() && child.hasPayload<KCalendarCore::Incidence::Ptr>()) { 0535 children.append(child); 0536 } else { 0537 qCWarning(AKONADICALENDAR_LOG) << "Invalid child with uid " << uid; 0538 } 0539 } 0540 return children; 0541 } 0542 0543 bool CalendarBase::addEvent(const KCalendarCore::Event::Ptr &event) 0544 { 0545 return addIncidence(event); 0546 } 0547 0548 bool CalendarBase::deleteEvent(const KCalendarCore::Event::Ptr &event) 0549 { 0550 return deleteIncidence(event); 0551 } 0552 0553 bool CalendarBase::addTodo(const KCalendarCore::Todo::Ptr &todo) 0554 { 0555 return addIncidence(todo); 0556 } 0557 0558 bool CalendarBase::deleteTodo(const KCalendarCore::Todo::Ptr &todo) 0559 { 0560 return deleteIncidence(todo); 0561 } 0562 0563 bool CalendarBase::addJournal(const KCalendarCore::Journal::Ptr &journal) 0564 { 0565 return addIncidence(journal); 0566 } 0567 0568 bool CalendarBase::deleteJournal(const KCalendarCore::Journal::Ptr &journal) 0569 { 0570 return deleteIncidence(journal); 0571 } 0572 0573 bool CalendarBase::addIncidence(const KCalendarCore::Incidence::Ptr &incidence) 0574 { 0575 // TODO: Parent for dialogs 0576 Q_D(CalendarBase); 0577 0578 // User canceled on the collection selection dialog 0579 if (batchAdding() && d->mBatchInsertionCancelled) { 0580 return false; 0581 } 0582 0583 d->mLastCreationCancelled = false; 0584 0585 Akonadi::Collection collection; 0586 0587 if (batchAdding() && d->mCollectionForBatchInsertion.isValid()) { 0588 collection = d->mCollectionForBatchInsertion; 0589 } 0590 0591 if (incidence->hasRecurrenceId() && !collection.isValid()) { 0592 // We are creating an exception, reuse the same collection that the main incidence uses 0593 Item mainItem = item(incidence->uid()); 0594 if (mainItem.isValid()) { 0595 collection = Collection(mainItem.storageCollectionId()); 0596 } 0597 } 0598 0599 const int changeId = d->mIncidenceChanger->createIncidence(incidence, collection); 0600 0601 if (batchAdding()) { 0602 const Akonadi::Collection lastCollection = d->mIncidenceChanger->lastCollectionUsed(); 0603 if (changeId != -1 && !lastCollection.isValid()) { 0604 d->mBatchInsertionCancelled = true; 0605 } else if (lastCollection.isValid() && !d->mCollectionForBatchInsertion.isValid()) { 0606 d->mCollectionForBatchInsertion = d->mIncidenceChanger->lastCollectionUsed(); 0607 } 0608 } 0609 0610 return changeId != -1; 0611 } 0612 0613 bool CalendarBase::deleteIncidence(const KCalendarCore::Incidence::Ptr &incidence) 0614 { 0615 Q_D(CalendarBase); 0616 Q_ASSERT(incidence); 0617 if (!incidence->hasRecurrenceId() && incidence->recurs()) { 0618 deleteIncidenceInstances(incidence); 0619 } 0620 Akonadi::Item item_ = item(incidence->instanceIdentifier()); 0621 return -1 != d->mIncidenceChanger->deleteIncidence(item_); 0622 } 0623 0624 bool CalendarBase::modifyIncidence(const KCalendarCore::Incidence::Ptr &newIncidence) 0625 { 0626 Q_D(CalendarBase); 0627 Q_ASSERT(newIncidence); 0628 Akonadi::Item item_ = item(newIncidence->instanceIdentifier()); 0629 item_.setPayload<KCalendarCore::Incidence::Ptr>(newIncidence); 0630 return -1 != d->mIncidenceChanger->modifyIncidence(item_); 0631 } 0632 0633 IncidenceChanger *CalendarBase::incidenceChanger() const 0634 { 0635 Q_D(const CalendarBase); 0636 return d->mIncidenceChanger; 0637 } 0638 0639 void CalendarBase::startBatchAdding() 0640 { 0641 KCalendarCore::MemoryCalendar::startBatchAdding(); 0642 } 0643 0644 void CalendarBase::endBatchAdding() 0645 { 0646 Q_D(CalendarBase); 0647 d->mCollectionForBatchInsertion = Akonadi::Collection(); 0648 d->mBatchInsertionCancelled = false; 0649 KCalendarCore::MemoryCalendar::endBatchAdding(); 0650 } 0651 0652 #include "moc_calendarbase.cpp" 0653 #include "moc_calendarbase_p.cpp"