File indexing completed on 2024-05-12 05:13:27

0001 /*
0002   SPDX-FileCopyrightText: 2000, 2001 Cornelius Schumacher <schumacher@kde.org>
0003   SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
0004   SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
0005   SPDX-FileContributor: Kevin Krammer <krake@kdab.com>
0006   SPDX-FileContributor: Sergio Martins <sergio@kdab.com>
0007 
0008   SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0009 */
0010 
0011 #include "eventview_p.h"
0012 #include "prefs.h"
0013 
0014 #include <CalendarSupport/CollectionSelection>
0015 #include <CalendarSupport/KCalPrefs>
0016 
0017 #include <Akonadi/CalendarUtils>
0018 #include <Akonadi/ETMViewStateSaver>
0019 #include <Akonadi/EntityDisplayAttribute>
0020 #include <Akonadi/EntityTreeModel>
0021 
0022 #include <KCalendarCore/CalFilter>
0023 
0024 #include <KCalUtils/RecurrenceActions>
0025 
0026 #include <KHolidays/HolidayRegion>
0027 
0028 #include "calendarview_debug.h"
0029 #include <KCheckableProxyModel>
0030 #include <KGuiItem>
0031 #include <KLocalizedString>
0032 #include <KRandom>
0033 #include <KRearrangeColumnsProxyModel>
0034 #include <KViewStateMaintainer>
0035 
0036 #include <QApplication>
0037 #include <QKeyEvent>
0038 #include <QSortFilterProxyModel>
0039 
0040 using namespace KCalendarCore;
0041 using namespace EventViews;
0042 using namespace Akonadi;
0043 
0044 CalendarSupport::CollectionSelection *EventViewPrivate::sGlobalCollectionSelection = nullptr;
0045 
0046 /* static */
0047 void EventView::setGlobalCollectionSelection(CalendarSupport::CollectionSelection *s)
0048 {
0049     EventViewPrivate::sGlobalCollectionSelection = s;
0050 }
0051 
0052 EventView::EventView(QWidget *parent)
0053     : QWidget(parent)
0054     , d_ptr(new EventViewPrivate(this))
0055 {
0056     QByteArray cname = metaObject()->className();
0057     cname.replace(':', '_');
0058     d_ptr->identifier = cname + '_' + KRandom::randomString(8).toLatin1();
0059 
0060     // AKONADI_PORT review: the FocusLineEdit in the editor emits focusReceivedSignal(),
0061     // which triggered finishTypeAhead.  But the global focus widget in QApplication is
0062     // changed later, thus subsequent keyevents still went to this view, triggering another
0063     // editor, for each keypress.
0064     // Thus, listen to the global focusChanged() signal (seen in Qt 4.6-stable-patched 20091112 -Frank)
0065     connect(qobject_cast<QApplication *>(QApplication::instance()), &QApplication::focusChanged, this, &EventView::focusChanged);
0066 
0067     d_ptr->setUpModels();
0068 }
0069 
0070 EventView::~EventView() = default;
0071 
0072 void EventView::defaultAction(const Akonadi::Item &aitem)
0073 {
0074     qCDebug(CALENDARVIEW_LOG);
0075     const Incidence::Ptr incidence = Akonadi::CalendarUtils::incidence(aitem);
0076     if (!incidence) {
0077         return;
0078     }
0079 
0080     qCDebug(CALENDARVIEW_LOG) << "  type:" << int(incidence->type());
0081 
0082     if (incidence->isReadOnly()) {
0083         Q_EMIT showIncidenceSignal(aitem);
0084     } else {
0085         Q_EMIT editIncidenceSignal(aitem);
0086     }
0087 }
0088 
0089 void EventView::setHolidayRegions(const QStringList &regions)
0090 {
0091     Q_D(EventView);
0092     d->mHolidayRegions.clear();
0093     for (const QString &regionStr : regions) {
0094         auto region = std::make_unique<KHolidays::HolidayRegion>(regionStr);
0095         if (region->isValid()) {
0096             d->mHolidayRegions.push_back(std::move(region));
0097         }
0098     }
0099 }
0100 
0101 int EventView::showMoveRecurDialog(const Incidence::Ptr &inc, QDate date)
0102 {
0103     QDateTime dateTime(date, {}, Qt::LocalTime);
0104 
0105     int availableOccurrences = KCalUtils::RecurrenceActions::availableOccurrences(inc, dateTime);
0106 
0107     const QString caption = i18nc("@title:window", "Changing Recurring Item");
0108     KGuiItem itemFuture(i18n("Also &Future Items"));
0109     KGuiItem itemSelected(i18n("Only &This Item"));
0110     KGuiItem itemAll(i18n("&All Occurrences"));
0111 
0112     switch (availableOccurrences) {
0113     case KCalUtils::RecurrenceActions::NoOccurrence:
0114         return KCalUtils::RecurrenceActions::NoOccurrence;
0115 
0116     case KCalUtils::RecurrenceActions::SelectedOccurrence:
0117         return KCalUtils::RecurrenceActions::SelectedOccurrence;
0118 
0119     case KCalUtils::RecurrenceActions::AllOccurrences:
0120         Q_ASSERT(availableOccurrences & KCalUtils::RecurrenceActions::SelectedOccurrence);
0121 
0122         // if there are all kinds of ooccurrences (i.e. past present and future) the user might
0123         // want the option only apply to current and future occurrences, leaving the past ones
0124         // provide a third choice for that ("Also future")
0125         if (availableOccurrences == KCalUtils::RecurrenceActions::AllOccurrences) {
0126             const QString message = i18n(
0127                 "The item you are trying to change is a recurring item. "
0128                 "Should the changes be applied only to this single occurrence, "
0129                 "also to future items, or to all items in the recurrence?");
0130             return KCalUtils::RecurrenceActions::questionSelectedFutureAllCancel(message, caption, itemSelected, itemFuture, itemAll, this);
0131         }
0132         [[fallthrough]];
0133 
0134     default:
0135         Q_ASSERT(availableOccurrences & KCalUtils::RecurrenceActions::SelectedOccurrence);
0136         // selected occurrence and either past or future occurrences
0137         const QString message = i18n(
0138             "The item you are trying to change is a recurring item. "
0139             "Should the changes be applied only to this single occurrence "
0140             "or to all items in the recurrence?");
0141         return KCalUtils::RecurrenceActions::questionSelectedAllCancel(message, caption, itemSelected, itemAll, this);
0142         break;
0143     }
0144 
0145     return KCalUtils::RecurrenceActions::NoOccurrence;
0146 }
0147 
0148 void EventView::addCalendar(const Akonadi::CollectionCalendar::Ptr &calendar)
0149 {
0150     Q_D(EventView);
0151     d->mCalendars.push_back(calendar);
0152 }
0153 
0154 void EventView::removeCalendar(const Akonadi::CollectionCalendar::Ptr &calendar)
0155 {
0156     Q_D(EventView);
0157     d->mCalendars.removeOne(calendar);
0158 }
0159 
0160 void EventView::setModel(QAbstractItemModel *model)
0161 {
0162     Q_D(EventView);
0163     if (d->model != model) {
0164         d->model = model;
0165         if (d->model) {
0166             if (d->collectionSelectionModel) {
0167                 d->collectionSelectionModel->setSourceModel(d->model);
0168             }
0169 
0170             d->setEtm(d->model);
0171             d->setUpModels();
0172 
0173             connect(d->model, &QAbstractItemModel::dataChanged, this, [this](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
0174                 Q_D(EventView);
0175 
0176                 for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
0177                     const auto index = topLeft.siblingAtRow(i);
0178                     const auto col = d->model->data(index, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0179                     if (col.isValid()) {
0180                         // TODO: we have no way of knowing what has actually changed in the model :(
0181                         onCollectionChanged(col, {"AccessRights"});
0182                     }
0183                 }
0184             });
0185         }
0186     }
0187 }
0188 
0189 QAbstractItemModel *EventView::model() const
0190 {
0191     Q_D(const EventView);
0192     return d->model;
0193 }
0194 
0195 Akonadi::EntityTreeModel *EventView::entityTreeModel() const
0196 {
0197     Q_D(const EventView);
0198     return d->etm;
0199 }
0200 
0201 void EventView::setPreferences(const PrefsPtr &preferences)
0202 {
0203     Q_D(EventView);
0204     if (d->mPrefs != preferences) {
0205         if (preferences) {
0206             d->mPrefs = preferences;
0207         } else {
0208             d->mPrefs = PrefsPtr(new Prefs());
0209         }
0210         updateConfig();
0211     }
0212 }
0213 
0214 void EventView::setKCalPreferences(const KCalPrefsPtr &preferences)
0215 {
0216     Q_D(EventView);
0217     if (d->mKCalPrefs != preferences) {
0218         if (preferences) {
0219             d->mKCalPrefs = preferences;
0220         } else {
0221             d->mKCalPrefs = KCalPrefsPtr(new CalendarSupport::KCalPrefs());
0222         }
0223         updateConfig();
0224     }
0225 }
0226 
0227 PrefsPtr EventView::preferences() const
0228 {
0229     Q_D(const EventView);
0230     return d->mPrefs;
0231 }
0232 
0233 KCalPrefsPtr EventView::kcalPreferences() const
0234 {
0235     Q_D(const EventView);
0236     return d->mKCalPrefs;
0237 }
0238 
0239 void EventView::dayPassed(const QDate &)
0240 {
0241     updateView();
0242 }
0243 
0244 void EventView::setIncidenceChanger(Akonadi::IncidenceChanger *changer)
0245 {
0246     Q_D(EventView);
0247     d->mChanger = changer;
0248 }
0249 
0250 void EventView::flushView()
0251 {
0252 }
0253 
0254 EventView *EventView::viewAt(const QPoint &)
0255 {
0256     return this;
0257 }
0258 
0259 void EventView::updateConfig()
0260 {
0261 }
0262 
0263 QDateTime EventView::selectionStart() const
0264 {
0265     return {};
0266 }
0267 
0268 QDateTime EventView::selectionEnd() const
0269 {
0270     return {};
0271 }
0272 
0273 bool EventView::dateRangeSelectionEnabled() const
0274 {
0275     Q_D(const EventView);
0276     return d->mDateRangeSelectionEnabled;
0277 }
0278 
0279 void EventView::setDateRangeSelectionEnabled(bool enable)
0280 {
0281     Q_D(EventView);
0282     d->mDateRangeSelectionEnabled = enable;
0283 }
0284 
0285 bool EventView::supportsZoom() const
0286 {
0287     return false;
0288 }
0289 
0290 bool EventView::hasConfigurationDialog() const
0291 {
0292     return false;
0293 }
0294 
0295 void EventView::setDateRange(const QDateTime &start, const QDateTime &end, const QDate &preferredMonth)
0296 {
0297     Q_D(EventView);
0298 
0299     d->startDateTime = start;
0300     d->endDateTime = end;
0301     showDates(start.date(), end.date(), preferredMonth);
0302     const QPair<QDateTime, QDateTime> adjusted = actualDateRange(start, end, preferredMonth);
0303     d->actualStartDateTime = adjusted.first;
0304     d->actualEndDateTime = adjusted.second;
0305 }
0306 
0307 QDateTime EventView::startDateTime() const
0308 {
0309     Q_D(const EventView);
0310     return d->startDateTime;
0311 }
0312 
0313 QDateTime EventView::endDateTime() const
0314 {
0315     Q_D(const EventView);
0316     return d->endDateTime;
0317 }
0318 
0319 QDateTime EventView::actualStartDateTime() const
0320 {
0321     Q_D(const EventView);
0322     return d->actualStartDateTime;
0323 }
0324 
0325 QDateTime EventView::actualEndDateTime() const
0326 {
0327     Q_D(const EventView);
0328     return d->actualEndDateTime;
0329 }
0330 
0331 void EventView::showConfigurationDialog(QWidget *)
0332 {
0333 }
0334 
0335 bool EventView::processKeyEvent(QKeyEvent *ke)
0336 {
0337     Q_D(EventView);
0338     // If Return is pressed bring up an editor for the current selected time span.
0339     if (ke->key() == Qt::Key_Return) {
0340         if (ke->type() == QEvent::KeyPress) {
0341             d->mReturnPressed = true;
0342         } else if (ke->type() == QEvent::KeyRelease) {
0343             if (d->mReturnPressed) {
0344                 Q_EMIT newEventSignal();
0345                 d->mReturnPressed = false;
0346                 return true;
0347             } else {
0348                 d->mReturnPressed = false;
0349             }
0350         }
0351     }
0352 
0353     // Ignore all input that does not produce any output
0354     if (ke->text().isEmpty() || (ke->modifiers() & Qt::ControlModifier)) {
0355         return false;
0356     }
0357 
0358     if (ke->type() == QEvent::KeyPress) {
0359         switch (ke->key()) {
0360         case Qt::Key_Escape:
0361         case Qt::Key_Return:
0362         case Qt::Key_Enter:
0363         case Qt::Key_Tab:
0364         case Qt::Key_Backtab:
0365         case Qt::Key_Left:
0366         case Qt::Key_Right:
0367         case Qt::Key_Up:
0368         case Qt::Key_Down:
0369         case Qt::Key_Backspace:
0370         case Qt::Key_Delete:
0371         case Qt::Key_PageUp:
0372         case Qt::Key_PageDown:
0373         case Qt::Key_Home:
0374         case Qt::Key_End:
0375         case Qt::Key_Control:
0376         case Qt::Key_Meta:
0377         case Qt::Key_Alt:
0378             break;
0379         default:
0380             d->mTypeAheadEvents.append(new QKeyEvent(ke->type(), ke->key(), ke->modifiers(), ke->text(), ke->isAutoRepeat(), static_cast<ushort>(ke->count())));
0381             if (!d->mTypeAhead) {
0382                 d->mTypeAhead = true;
0383                 Q_EMIT newEventSignal();
0384             }
0385             return true;
0386         }
0387     }
0388     return false;
0389 }
0390 
0391 void EventView::setTypeAheadReceiver(QObject *o)
0392 {
0393     Q_D(EventView);
0394     d->mTypeAheadReceiver = o;
0395 }
0396 
0397 void EventView::focusChanged(QWidget *, QWidget *now)
0398 {
0399     Q_D(EventView);
0400     if (d->mTypeAhead && now && now == d->mTypeAheadReceiver) {
0401         d->finishTypeAhead();
0402     }
0403 }
0404 
0405 CalendarSupport::CollectionSelection *EventView::collectionSelection() const
0406 {
0407     Q_D(const EventView);
0408     return d->customCollectionSelection ? d->customCollectionSelection.get() : globalCollectionSelection();
0409 }
0410 
0411 void EventView::setCustomCollectionSelectionProxyModel(KCheckableProxyModel *model)
0412 {
0413     Q_D(EventView);
0414     if (d->collectionSelectionModel == model) {
0415         return;
0416     }
0417 
0418     delete d->collectionSelectionModel;
0419     d->collectionSelectionModel = model;
0420     d->setUpModels();
0421 }
0422 
0423 KCheckableProxyModel *EventView::customCollectionSelectionProxyModel() const
0424 {
0425     Q_D(const EventView);
0426     return d->collectionSelectionModel;
0427 }
0428 
0429 KCheckableProxyModel *EventView::takeCustomCollectionSelectionProxyModel()
0430 {
0431     Q_D(EventView);
0432     KCheckableProxyModel *m = d->collectionSelectionModel;
0433     d->collectionSelectionModel = nullptr;
0434     d->setUpModels();
0435     return m;
0436 }
0437 
0438 CalendarSupport::CollectionSelection *EventView::customCollectionSelection() const
0439 {
0440     Q_D(const EventView);
0441     return d->customCollectionSelection.get();
0442 }
0443 
0444 void EventView::clearSelection()
0445 {
0446 }
0447 
0448 bool EventView::eventDurationHint(QDateTime &startDt, QDateTime &endDt, bool &allDay) const
0449 {
0450     Q_UNUSED(startDt)
0451     Q_UNUSED(endDt)
0452     Q_UNUSED(allDay)
0453     return false;
0454 }
0455 
0456 Akonadi::IncidenceChanger *EventView::changer() const
0457 {
0458     Q_D(const EventView);
0459     return d->mChanger;
0460 }
0461 
0462 void EventView::doRestoreConfig(const KConfigGroup &)
0463 {
0464 }
0465 
0466 void EventView::doSaveConfig(KConfigGroup &)
0467 {
0468 }
0469 
0470 QPair<QDateTime, QDateTime> EventView::actualDateRange(const QDateTime &start, const QDateTime &end, const QDate &preferredMonth) const
0471 {
0472     Q_UNUSED(preferredMonth)
0473     return qMakePair(start, end);
0474 }
0475 
0476 /*
0477 void EventView::incidencesAdded( const Akonadi::Item::List & )
0478 {
0479 }
0480 
0481 void EventView::incidencesAboutToBeRemoved( const Akonadi::Item::List & )
0482 {
0483 }
0484 
0485 void EventView::incidencesChanged( const Akonadi::Item::List & )
0486 {
0487 }
0488 */
0489 
0490 void EventView::handleBackendError(const QString &errorString)
0491 {
0492     qCCritical(CALENDARVIEW_LOG) << errorString;
0493 }
0494 
0495 void EventView::calendarReset()
0496 {
0497 }
0498 
0499 CalendarSupport::CollectionSelection *EventView::globalCollectionSelection()
0500 {
0501     return EventViewPrivate::sGlobalCollectionSelection;
0502 }
0503 
0504 QByteArray EventView::identifier() const
0505 {
0506     Q_D(const EventView);
0507     return d->identifier;
0508 }
0509 
0510 void EventView::setIdentifier(const QByteArray &identifier)
0511 {
0512     Q_D(EventView);
0513     d->identifier = identifier;
0514 }
0515 
0516 void EventView::setChanges(Changes changes)
0517 {
0518     Q_D(EventView);
0519     if (d->mChanges == NothingChanged) {
0520         QMetaObject::invokeMethod(this, &EventView::updateView, Qt::QueuedConnection);
0521     }
0522 
0523     d->mChanges = changes;
0524 }
0525 
0526 EventView::Changes EventView::changes() const
0527 {
0528     Q_D(const EventView);
0529     return d->mChanges;
0530 }
0531 
0532 void EventView::restoreConfig(const KConfigGroup &configGroup)
0533 {
0534     Q_D(EventView);
0535     const bool useCustom = configGroup.readEntry("UseCustomCollectionSelection", false);
0536     if (!d->collectionSelectionModel && !useCustom) {
0537         delete d->collectionSelectionModel;
0538         d->collectionSelectionModel = nullptr;
0539         d->setUpModels();
0540     } else if (useCustom) {
0541         if (!d->collectionSelectionModel) {
0542             // Sort the calendar model on calendar name
0543             auto sortProxy = new QSortFilterProxyModel(this);
0544             sortProxy->setDynamicSortFilter(true);
0545             sortProxy->setSortCaseSensitivity(Qt::CaseInsensitive);
0546             sortProxy->setSourceModel(d->model);
0547 
0548             // Only show the first column.
0549             auto columnFilterProxy = new KRearrangeColumnsProxyModel(this);
0550             columnFilterProxy->setSourceColumns(QList<int>() << 0);
0551             columnFilterProxy->setSourceModel(sortProxy);
0552 
0553             // Make the calendar model checkable.
0554             d->collectionSelectionModel = new KCheckableProxyModel(this);
0555             d->collectionSelectionModel->setSourceModel(columnFilterProxy);
0556 
0557             d->setUpModels();
0558         }
0559         const KConfigGroup selectionGroup = configGroup.config()->group(configGroup.name() + QLatin1StringView("_selectionSetup"));
0560 
0561         KViewStateMaintainer<ETMViewStateSaver> maintainer(selectionGroup);
0562         maintainer.setSelectionModel(d->collectionSelectionModel->selectionModel());
0563         maintainer.restoreState();
0564     }
0565 
0566     doRestoreConfig(configGroup);
0567 }
0568 
0569 void EventView::saveConfig(KConfigGroup &configGroup)
0570 {
0571     Q_D(EventView);
0572     configGroup.writeEntry("UseCustomCollectionSelection", d->collectionSelectionModel != nullptr);
0573 
0574     if (d->collectionSelectionModel) {
0575         KConfigGroup selectionGroup = configGroup.config()->group(configGroup.name() + QLatin1StringView("_selectionSetup"));
0576 
0577         KViewStateMaintainer<ETMViewStateSaver> maintainer(selectionGroup);
0578         maintainer.setSelectionModel(d->collectionSelectionModel->selectionModel());
0579         maintainer.saveState();
0580     }
0581 
0582     doSaveConfig(configGroup);
0583 }
0584 
0585 bool EventView::makesWholeDayBusy(const KCalendarCore::Incidence::Ptr &incidence) const
0586 {
0587     // Must be event
0588     // Must be all day
0589     // Must be marked busy (TRANSP: OPAQUE)
0590     // You must be attendee or organizer
0591 
0592     if (incidence->type() != KCalendarCore::Incidence::TypeEvent || !incidence->allDay()) {
0593         return false;
0594     }
0595 
0596     KCalendarCore::Event::Ptr ev = incidence.staticCast<KCalendarCore::Event>();
0597 
0598     if (ev->transparency() != KCalendarCore::Event::Opaque) {
0599         return false;
0600     }
0601 
0602     // Last check: must be organizer or attendee:
0603 
0604     if (kcalPreferences()->thatIsMe(ev->organizer().email())) {
0605         return true;
0606     }
0607 
0608     KCalendarCore::Attendee::List attendees = ev->attendees();
0609     KCalendarCore::Attendee::List::ConstIterator it;
0610     for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
0611         if (kcalPreferences()->thatIsMe((*it).email())) {
0612             return true;
0613         }
0614     }
0615 
0616     return false;
0617 }
0618 
0619 /*static*/
0620 QColor EventView::itemFrameColor(const QColor &color, bool selected)
0621 {
0622     if (color.isValid()) {
0623         return selected ? QColor(85 + color.red() * 2.0 / 3, 85 + color.green() * 2.0 / 3, 85 + color.blue() * 2.0 / 3) : color.darker(115);
0624     } else {
0625         return Qt::black;
0626     }
0627 }
0628 
0629 QString EventView::iconForItem(const Akonadi::Item &item)
0630 {
0631     Q_D(EventView);
0632     QString iconName;
0633     Akonadi::Collection collection = item.parentCollection();
0634     while (collection.parentCollection().isValid() && collection.parentCollection() != Akonadi::Collection::root()) {
0635         collection = Akonadi::EntityTreeModel::updatedCollection(d->model, collection.parentCollection());
0636     }
0637 
0638     if (collection.isValid() && collection.hasAttribute<Akonadi::EntityDisplayAttribute>()) {
0639         iconName = collection.attribute<Akonadi::EntityDisplayAttribute>()->iconName();
0640     }
0641 
0642     return iconName;
0643 }
0644 
0645 void EventView::onCollectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &changedAttributes)
0646 {
0647     Q_UNUSED(collection)
0648     if (changedAttributes.contains("AccessRights")) {
0649         setChanges(changes() | EventViews::EventView::ResourcesChanged);
0650         updateView();
0651     }
0652 }
0653 
0654 QList<Akonadi::CollectionCalendar::Ptr> EventView::calendars() const
0655 {
0656     Q_D(const EventView);
0657     return d->mCalendars;
0658 }
0659 
0660 Akonadi::CollectionCalendar::Ptr EventView::calendar3(const Akonadi::Item &item) const
0661 {
0662     Q_D(const EventView);
0663     return calendarForCollection(item.storageCollectionId());
0664 }
0665 
0666 Akonadi::CollectionCalendar::Ptr EventView::calendar3(const KCalendarCore::Incidence::Ptr &incidence) const
0667 {
0668     Q_D(const EventView);
0669     const auto collectionId = incidence->customProperty("VOLATILE", "COLLECTION-ID").toLongLong();
0670     return calendarForCollection(collectionId);
0671 }
0672 
0673 Akonadi::CollectionCalendar::Ptr EventView::calendarForCollection(Akonadi::Collection::Id collectionId) const
0674 {
0675     const auto hasCollectionId = [collectionId](const Akonadi::CollectionCalendar::Ptr &calendar) {
0676         return calendar->collection().id() == collectionId;
0677     };
0678 
0679     Q_D(const EventView);
0680     const auto cal = std::find_if(d->mCalendars.cbegin(), d->mCalendars.cend(), hasCollectionId);
0681     return cal != d->mCalendars.cend() ? *cal : Akonadi::CollectionCalendar::Ptr{};
0682 }
0683 
0684 Akonadi::CollectionCalendar::Ptr EventView::calendarForCollection(const Akonadi::Collection &collection) const
0685 {
0686     return calendarForCollection(collection.id());
0687 }
0688 
0689 #include "moc_eventview.cpp"