Akonadi Calendar

etmcalendar.cpp
1 /*
2  SPDX-FileCopyrightText: 2011-2013 Sérgio Martins <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "etmcalendar.h"
8 #include "etmcalendar_p.h"
9 #include "blockalarmsattribute.h"
10 #include "calendarmodel_p.h"
11 #include "kcolumnfilterproxymodel_p.h"
12 #include "calfilterproxymodel_p.h"
13 #include "calfilterpartstatusproxymodel_p.h"
14 #include "utils_p.h"
15 #include "akonadicalendar_debug.h"
16 #include <item.h>
17 #include <session.h>
18 #include <collection.h>
19 #include <monitor.h>
20 #include <itemfetchscope.h>
21 #include <entitydisplayattribute.h>
22 #include <entitymimetypefiltermodel.h>
23 #include <collectionfilterproxymodel.h>
24 #include <KSelectionProxyModel>
25 #include <KDescendantsProxyModel>
26 
27 #include <QItemSelectionModel>
28 #include <QTreeView>
29 
30 using namespace Akonadi;
31 using namespace KCalendarCore;
32 
33 //TODO: implement batchAdding
34 
35 ETMCalendarPrivate::ETMCalendarPrivate(ETMCalendar *qq)
36  : CalendarBasePrivate(qq)
37  , mETM(nullptr)
38  , q(qq)
39 {
40  mListensForNewItems = true;
41 }
42 
43 void ETMCalendarPrivate::init()
44 {
45  if (!mETM) {
46  Akonadi::Session *session = new Akonadi::Session("ETMCalendar", q);
47  Akonadi::Monitor *monitor = new Akonadi::Monitor(q);
48  monitor->setObjectName(QStringLiteral("ETMCalendarMonitor"));
49  connect(monitor, QOverload<const Akonadi::Collection &, const QSet<QByteArray> &>::of(&Monitor::collectionChanged), this, [this](const Akonadi::Collection &cols, const QSet<QByteArray> &set)
50  {
51  onCollectionChanged(cols, set);
52  });
53 
55  scope.fetchFullPayload(true);
56  scope.fetchAttribute<Akonadi::EntityDisplayAttribute>();
57 
58  monitor->setSession(session);
60  monitor->fetchCollection(true);
61  monitor->setItemFetchScope(scope);
62  monitor->setAllMonitored(true);
63 
65 
66  for (const QString &mimetype : allMimeTypes) {
67  monitor->setMimeTypeMonitored(mimetype, mMimeTypes.isEmpty() || mMimeTypes.contains(mimetype));
68  }
69 
70  mETM = CalendarModel::create(monitor);
71  mETM->setObjectName(QStringLiteral("ETM"));
72  mETM->setListFilter(Akonadi::CollectionFetchScope::Display);
73  }
74 
75  setupFilteredETM();
76 
77  connect(q, &Calendar::filterChanged, this, &ETMCalendarPrivate::onFilterChanged);
78 
80  this, &ETMCalendarPrivate::onCollectionPopulated);
82  this, &ETMCalendarPrivate::onRowsInserted);
84  this, &ETMCalendarPrivate::onDataChanged);
86  this, &ETMCalendarPrivate::onRowsMoved);
88  this, &ETMCalendarPrivate::onRowsRemoved);
89 
91  this, &ETMCalendarPrivate::onDataChangedInFilteredModel);
93  this, &ETMCalendarPrivate::onLayoutChangedInFilteredModel);
95  this, &ETMCalendarPrivate::onModelResetInFilteredModel);
97  this, &ETMCalendarPrivate::onRowsInsertedInFilteredModel);
99  this, &ETMCalendarPrivate::onRowsAboutToBeRemovedInFilteredModel);
100 
101  loadFromETM();
102 }
103 
104 void ETMCalendarPrivate::onCollectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &attributeNames)
105 {
106  Q_ASSERT(collection.isValid());
107  // Is the collection changed to read-only, we update all Incidences
108  if (attributeNames.contains("AccessRights")) {
109  const Akonadi::Item::List items = q->items();
110  for (const Akonadi::Item &item : items) {
111  if (item.storageCollectionId() == collection.id()) {
112  KCalendarCore::Incidence::Ptr incidence = CalendarUtils::incidence(item);
113  if (incidence) {
114  incidence->setReadOnly(!(collection.rights() & Akonadi::Collection::CanChangeItem));
115  }
116  }
117  }
118  }
119 
120  Q_EMIT q->collectionChanged(collection, attributeNames);
121 }
122 
123 void ETMCalendarPrivate::setupFilteredETM()
124 {
125  // We're only interested in the CollectionTitle column
126  KColumnFilterProxyModel *columnFilterProxy = new KColumnFilterProxyModel(this);
127  columnFilterProxy->setSourceModel(mETM.data());
128  columnFilterProxy->setVisibleColumn(CalendarModel::CollectionTitle);
129  columnFilterProxy->setObjectName(QStringLiteral("Remove columns"));
130 
131  mCollectionProxyModel = new Akonadi::CollectionFilterProxyModel(this);
132  mCollectionProxyModel->setObjectName(QStringLiteral("Only show collections"));
133  mCollectionProxyModel->setDynamicSortFilter(true);
134  mCollectionProxyModel->addMimeTypeFilter(QStringLiteral("text/calendar"));
135  mCollectionProxyModel->setExcludeVirtualCollections(false);
136  mCollectionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
137  mCollectionProxyModel->setSourceModel(columnFilterProxy);
138 
139  // Keep track of selected items.
140  QItemSelectionModel *selectionModel = new QItemSelectionModel(mCollectionProxyModel);
141  selectionModel->setObjectName(QStringLiteral("Calendar Selection Model"));
142 
143  // Make item selection work by means of checkboxes.
144  mCheckableProxyModel = new CheckableProxyModel(this);
145  mCheckableProxyModel->setSelectionModel(selectionModel);
146  mCheckableProxyModel->setSourceModel(mCollectionProxyModel);
147  mCheckableProxyModel->setObjectName(QStringLiteral("Add checkboxes"));
148 
149  mSelectionProxy = new KSelectionProxyModel(selectionModel, this);
150  mSelectionProxy->setObjectName(QStringLiteral("Only show items of selected collection"));
151  mSelectionProxy->setFilterBehavior(KSelectionProxyModel::ChildrenOfExactSelection);
152  mSelectionProxy->setSourceModel(mETM.data());
153 
154  mCalFilterProxyModel = new CalFilterProxyModel(this);
155  mCalFilterProxyModel->setFilter(q->filter());
156  mCalFilterProxyModel->setSourceModel(mSelectionProxy);
157  mCalFilterProxyModel->setObjectName(QStringLiteral("KCalendarCore::CalFilter filtering"));
158 
159  mCalFilterPartStatusProxyModel = new CalFilterPartStatusProxyModel(this);
160  mCalFilterPartStatusProxyModel->setFilterVirtual(false);
162  blockedStatusList << KCalendarCore::Attendee::NeedsAction;
163  blockedStatusList << KCalendarCore::Attendee::Declined;
164  mCalFilterPartStatusProxyModel->setDynamicSortFilter(true);
165  mCalFilterPartStatusProxyModel->setBlockedStatusList(blockedStatusList);
166  mCalFilterPartStatusProxyModel->setSourceModel(mCalFilterProxyModel);
167  mCalFilterPartStatusProxyModel->setObjectName(QStringLiteral("PartStatus filtering"));
168 
169  mFilteredETM = new Akonadi::EntityMimeTypeFilterModel(this);
170  mFilteredETM->setSourceModel(mCalFilterPartStatusProxyModel);
171  mFilteredETM->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders);
172  mFilteredETM->setSortRole(CalendarModel::SortRole);
173  mFilteredETM->setObjectName(QStringLiteral("Show headers"));
174 
175 #ifdef AKONADI_CALENDAR_DEBUG_MODEL
176  QTreeView *view = new QTreeView;
177  view->setModel(mFilteredETM);
178  view->show();
179 #endif
180 }
181 
182 ETMCalendarPrivate::~ETMCalendarPrivate()
183 {
184 }
185 
186 void ETMCalendarPrivate::loadFromETM()
187 {
188  itemsAdded(itemsFromModel(mFilteredETM));
189 }
190 
191 void ETMCalendarPrivate::clear()
192 {
193  mCollectionMap.clear();
194  mItemsByCollection.clear();
195 
196  Akonadi::Item::List removedItems;
197  removedItems.reserve(mItemById.size());
198  for (auto it = mItemById.cbegin(), end = mItemById.cend(); it != end; ++it) {
199  removedItems.push_back(it.value());
200  }
201 
202  itemsRemoved(removedItems);
203 
204  if (!mItemById.isEmpty()) {
205  mItemById.clear();
206  //Q_ASSERT(false); // TODO: discover why this happens
207  }
208 
209  if (!mItemIdByUid.isEmpty()) {
210  mItemIdByUid.clear();
211  //Q_ASSERT(false);
212  }
213  mParentUidToChildrenUid.clear();
214  //m_virtualItems.clear();
215 }
216 
217 Akonadi::Item::List ETMCalendarPrivate::itemsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex, int start, int end)
218 {
219  const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1;
220  Akonadi::Item::List items;
221  int row = start;
222  QModelIndex i = model->index(row, 0, parentIndex);
223  while (row <= endRow) {
224  const Akonadi::Item item = itemFromIndex(i);
225  if (item.hasPayload<KCalendarCore::Incidence::Ptr>()) {
226  items << item;
227  } else {
228  const QModelIndex childIndex = model->index(0, 0, i);
229  if (childIndex.isValid()) {
230  items << itemsFromModel(model, i);
231  }
232  }
233  ++row;
234  i = i.sibling(row, 0);
235  }
236  return items;
237 }
238 
239 Akonadi::Collection::List ETMCalendarPrivate::collectionsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex, int start, int end)
240 {
241  const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1;
242  Akonadi::Collection::List collections;
243  int row = start;
244  QModelIndex i = model->index(row, 0, parentIndex);
245  while (row <= endRow) {
246  const Akonadi::Collection collection = collectionFromIndex(i);
247  if (collection.isValid()) {
248  collections << collection;
249  QModelIndex childIndex = model->index(0, 0, i);
250  if (childIndex.isValid()) {
251  collections << collectionsFromModel(model, i);
252  }
253  }
254  ++row;
255  i = i.sibling(row, 0);
256  }
257  return collections;
258 }
259 
260 Akonadi::Item ETMCalendarPrivate::itemFromIndex(const QModelIndex &idx)
261 {
262  Akonadi::Item item = idx.data(Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
263  item.setParentCollection(
265  return item;
266 }
267 
268 void ETMCalendarPrivate::itemsAdded(const Akonadi::Item::List &items)
269 {
270  if (!items.isEmpty()) {
271  for (const Akonadi::Item &item : items) {
272  internalInsert(item);
273  }
274 
275  Akonadi::Collection::Id id = items.first().storageCollectionId();
276  if (mPopulatedCollectionIds.contains(id)) {
277  // If the collection isn't populated yet, it will be sent later
278  // Saves some cpu cycles
279  Q_EMIT q->calendarChanged();
280  }
281  }
282 }
283 
284 void ETMCalendarPrivate::itemsRemoved(const Akonadi::Item::List &items)
285 {
286  for (const Akonadi::Item &item : items) {
287  internalRemove(item);
288  }
289  Q_EMIT q->calendarChanged();
290 }
291 
292 Akonadi::Collection ETMCalendarPrivate::collectionFromIndex(const QModelIndex &index)
293 {
295 }
296 
297 void ETMCalendarPrivate::onRowsInserted(const QModelIndex &index, int start, int end)
298 {
299  const Akonadi::Collection::List collections = collectionsFromModel(mETM.data(), index,
300  start, end);
301 
302  for (const Akonadi::Collection &collection : collections) {
303  mCollectionMap[collection.id()] = collection;
304  }
305 
306  if (!collections.isEmpty()) {
307  Q_EMIT q->collectionsAdded(collections);
308  }
309 }
310 
311 void ETMCalendarPrivate::onCollectionPopulated(Akonadi::Collection::Id id)
312 {
313  mPopulatedCollectionIds.insert(id);
314  Q_EMIT q->calendarChanged();
315 }
316 
317 void ETMCalendarPrivate::onRowsRemoved(const QModelIndex &index, int start, int end)
318 {
319  const Akonadi::Collection::List collections = collectionsFromModel(mETM.data(), index, start, end);
320  for (const Akonadi::Collection &collection : collections) {
321  mCollectionMap.remove(collection.id());
322  }
323 
324  if (!collections.isEmpty()) {
325  Q_EMIT q->collectionsRemoved(collections);
326  }
327 }
328 
329 void ETMCalendarPrivate::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
330 {
331  // We only update collections, because items are handled in the filtered model
332  Q_ASSERT(topLeft.row() <= bottomRight.row());
333  const int endRow = bottomRight.row();
334  for (int row = topLeft.row(); row <= endRow; ++row) {
335  const Akonadi::Collection col = collectionFromIndex(topLeft.sibling(row, 0));
336  if (col.isValid()) {
337  // Attributes might have changed, store the new collection and discard the old one
338  mCollectionMap.insert(col.id(), col);
339  }
340  }
341 }
342 
343 void ETMCalendarPrivate::onRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
344 {
345  //TODO
346  Q_UNUSED(sourceParent);
347  Q_UNUSED(sourceStart);
348  Q_UNUSED(sourceEnd);
349  Q_UNUSED(destinationParent);
350  Q_UNUSED(destinationRow);
351 }
352 
353 void ETMCalendarPrivate::onLayoutChangedInFilteredModel()
354 {
355  clear();
356  loadFromETM();
357 }
358 
359 void ETMCalendarPrivate::onModelResetInFilteredModel()
360 {
361  clear();
362  loadFromETM();
363 }
364 
365 void ETMCalendarPrivate::onDataChangedInFilteredModel(const QModelIndex &topLeft, const QModelIndex &bottomRight)
366 {
367  Q_ASSERT(topLeft.row() <= bottomRight.row());
368  const int endRow = bottomRight.row();
369  QModelIndex i(topLeft);
370  int row = i.row();
371  while (row <= endRow) {
372  const Akonadi::Item item = itemFromIndex(i);
373  if (item.isValid() && item.hasPayload<KCalendarCore::Incidence::Ptr>()) {
374  updateItem(item);
375  }
376 
377  ++row;
378  i = i.sibling(row, topLeft.column());
379  }
380 
381  Q_EMIT q->calendarChanged();
382 }
383 
384 void ETMCalendarPrivate::updateItem(const Akonadi::Item &item)
385 {
386  Incidence::Ptr newIncidence = CalendarUtils::incidence(item);
387  Q_ASSERT(newIncidence);
388  Q_ASSERT(!newIncidence->uid().isEmpty());
389  newIncidence->setCustomProperty("VOLATILE", "AKONADI-ID", QString::number(item.id()));
390  IncidenceBase::Ptr existingIncidence = q->incidence(newIncidence->uid(), newIncidence->recurrenceId());
391 
392  if (!existingIncidence && !mItemById.contains(item.id())) {
393  // We don't know about this one because it was discarded, for example because of not having DTSTART
394  return;
395  }
396 
397  mItemsByCollection.insert(item.storageCollectionId(), item);
398  Akonadi::Item oldItem = mItemById.value(item.id());
399 
400  if (existingIncidence) {
401  // We set the payload so that the internal incidence pointer and the one in mItemById stay the same
402  Akonadi::Item updatedItem = item;
403  updatedItem.setPayload<KCalendarCore::Incidence::Ptr>(existingIncidence.staticCast<KCalendarCore::Incidence>());
404  mItemById.insert(item.id(), updatedItem); // The item needs updating too, revision changed.
405 
406  // Check if RELATED-TO changed, updating parenting information
407  handleParentChanged(newIncidence);
408  *(existingIncidence.data()) = *(newIncidence.data());
409  } else {
410  mItemById.insert(item.id(), item); // The item needs updating too, revision changed.
411  // The item changed it's UID, update our maps, the Google resource changes the UID when we create incidences.
412  handleUidChange(oldItem, item, newIncidence->instanceIdentifier());
413  }
414 }
415 
416 void ETMCalendarPrivate::onRowsInsertedInFilteredModel(const QModelIndex &index, int start, int end)
417 {
418  itemsAdded(itemsFromModel(mFilteredETM, index, start, end));
419 }
420 
421 void ETMCalendarPrivate::onRowsAboutToBeRemovedInFilteredModel(const QModelIndex &index, int start, int end)
422 {
423  itemsRemoved(itemsFromModel(mFilteredETM, index, start, end));
424 }
425 
426 void ETMCalendarPrivate::onFilterChanged()
427 {
428  mCalFilterProxyModel->setFilter(q->filter());
429 }
430 
432  : CalendarBase(new ETMCalendarPrivate(this), parent)
433 {
434  Q_D(ETMCalendar);
435  d->init();
436 }
437 
439  : CalendarBase(new ETMCalendarPrivate(this), parent)
440 {
441  Q_D(ETMCalendar);
442  d->mMimeTypes = mimeTypes;
443  d->init();
444 }
445 
447  : CalendarBase(new ETMCalendarPrivate(this), parent)
448 {
449  Q_D(ETMCalendar);
450 
451  CalendarModel *model = qobject_cast<Akonadi::CalendarModel *>(other->entityTreeModel());
452  if (model) {
453  d->mETM = model->weakPointer().toStrongRef();
454  }
455 
456  d->init();
457 }
458 
460  : CalendarBase(new ETMCalendarPrivate(this), parent)
461 {
462  Q_D(ETMCalendar);
463 
464  if (monitor) {
465  QObject::connect(monitor, QOverload<const Akonadi::Collection &, const QSet<QByteArray> &>::of(&Akonadi::Monitor::collectionChanged), d, &ETMCalendarPrivate::onCollectionChanged);
466  d->mETM = CalendarModel::create(monitor);
467  d->mETM->setObjectName(QStringLiteral("ETM"));
468  d->mETM->setListFilter(Akonadi::CollectionFetchScope::Display);
469  }
470 
471  d->init();
472 }
473 
475 {
476 }
477 
478 //TODO: move this up?
480 {
481  Q_D(const ETMCalendar);
482  return d->mCollectionMap.value(id);
483 }
484 
486 {
487  return hasRight(item(uid), right);
488 }
489 
490 bool ETMCalendar::hasRight(const Akonadi::Item &item, Akonadi::Collection::Right right) const
491 {
492  // if the users changes the rights, item.parentCollection()
493  // can still have the old rights, so we use call collection()
494  // which returns the updated one
495  const Akonadi::Collection col = collection(item.storageCollectionId());
496  return col.rights() & right;
497 }
498 
500 {
501  Q_D(const ETMCalendar);
502  return d->mFilteredETM;
503 }
504 
506 {
507  Q_D(const ETMCalendar);
508  return d->mCheckableProxyModel;
509 }
510 
511 KCalendarCore::Alarm::List ETMCalendar::alarms(const QDateTime &from, const QDateTime &to, bool excludeBlockedAlarms) const
512 {
513  Q_D(const ETMCalendar);
514  KCalendarCore::Alarm::List alarmList;
516  while (i.hasNext()) {
517  const Akonadi::Item item = i.next().value();
518 
519  Akonadi::Collection parentCollection; // must have same lifetime as blockedAttr
520  BlockAlarmsAttribute *blockedAttr = nullptr;
521 
522  if (excludeBlockedAlarms) {
523  // take the collection from m_collectionMap, because we need the up-to-date collection attrs
524  parentCollection = d->mCollectionMap.value(item.storageCollectionId());
525  if (parentCollection.isValid() && parentCollection.hasAttribute<BlockAlarmsAttribute>()) {
526  blockedAttr = parentCollection.attribute<BlockAlarmsAttribute>();
527  if (blockedAttr->isEverythingBlocked()) {
528  continue;
529  }
530  }
531  }
532 
534  if (item.isValid() && item.hasPayload<KCalendarCore::Incidence::Ptr>()) {
535  incidence = KCalendarCore::Incidence::Ptr(item.payload<KCalendarCore::Incidence::Ptr>()->clone());
536  } else {
537  continue;
538  }
539 
540  if (!incidence) {
541  continue;
542  }
543 
544  if (blockedAttr) {
545  // Remove all blocked types of alarms
546  const auto alarmsLst = incidence->alarms();
547  for (const KCalendarCore::Alarm::Ptr &alarm : alarmsLst) {
548  if (blockedAttr->isAlarmTypeBlocked(alarm->type())) {
549  incidence->removeAlarm(alarm);
550  }
551  }
552  }
553 
554  if (incidence->alarms().isEmpty()) {
555  continue;
556  }
557 
558  Alarm::List tmpList;
559  if (incidence->recurs()) {
560  appendRecurringAlarms(tmpList, incidence, from, to);
561  } else {
562  appendAlarms(tmpList, incidence, from, to);
563  }
564 
565  // We need to tag them with the incidence uid in case
566  // the caller will need it, because when we get out of
567  // this scope the incidence will be destroyed.
568  QVectorIterator<Alarm::Ptr> a(tmpList);
569  while (a.hasNext()) {
570  a.next()->setCustomProperty("ETMCalendar", "parentUid", incidence->uid());
571  }
572  alarmList += tmpList;
573  }
574  return alarmList;
575 }
576 
578 {
579  Q_D(const ETMCalendar);
580  return d->mETM.data();
581 }
582 
584 {
585  Q_D(ETMCalendar);
586  if (d->mCollectionFilteringEnabled != enable) {
587  d->mCollectionFilteringEnabled = enable;
588  if (enable) {
589  d->mSelectionProxy->setSourceModel(d->mETM.data());
590  QAbstractItemModel *oldModel = d->mCalFilterProxyModel->sourceModel();
591  d->mCalFilterProxyModel->setSourceModel(d->mSelectionProxy);
592  delete qobject_cast<KDescendantsProxyModel *>(oldModel);
593  } else {
594  KDescendantsProxyModel *flatner = new KDescendantsProxyModel(this);
595  flatner->setSourceModel(d->mETM.data());
596  d->mCalFilterProxyModel->setSourceModel(flatner);
597  }
598  }
599 }
600 
602 {
603  Q_D(const ETMCalendar);
604  return d->mCollectionFilteringEnabled;
605 }
606 
608 {
609  Q_D(const ETMCalendar);
610 
611  if (!entityTreeModel()->isCollectionTreeFetched()) {
612  return false;
613  }
614 
615  for (const Akonadi::Collection &collection : qAsConst(d->mCollectionMap)) {
616  if (!entityTreeModel()->isCollectionPopulated(collection.id())) {
617  return false;
618  }
619  }
620 
621  return true;
622 }
623 
624 #include "moc_etmcalendar.cpp"
625 #include "moc_etmcalendar_p.cpp"
void setAllMonitored(bool monitored=true)
virtual int rowCount(const QModelIndex &parent) const const =0
void appendAlarms(Alarm::List &alarms, const Incidence::Ptr &incidence, const QDateTime &from, const QDateTime &to) const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const =0
bool isValid() const
void layoutChanged(const QList< QPersistentModelIndex > &parents, QAbstractItemModel::LayoutChangeHint hint)
KCalendarCore::Alarm::List alarms(const QDateTime &from, const QDateTime &to, bool excludeBlockedAlarms=false) const override
Returns all alarms occurring in a specified time interval.
void setSession(Akonadi::Session *session)
void setMimeTypeMonitored(const QString &mimetype, bool monitored=true)
void setCollectionMonitored(const Collection &collection, bool monitored=true)
Akonadi::EntityTreeModel * entityTreeModel() const
Returns the underlying EntityTreeModel.
bool isLoaded() const override
Returns if the calendar already finished loading.
bool hasNext() const const
void setItemFetchScope(const ItemFetchScope &fetchScope)
QSharedPointer< Incidence > Ptr
Akonadi::Item item(const QString &uid) const
Returns the Item containing the incidence with uid uid or an invalid Item if the incidence isn&#39;t foun...
T value() const const
static QLatin1String eventMimeType()
static QLatin1String journalMimeType()
void appendRecurringAlarms(Alarm::List &alarms, const Incidence::Ptr &incidence, const QDateTime &from, const QDateTime &to) const
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
bool isEverythingBlocked() const
Returns whether all alarms are blocked or not.
T * data() const const
void fetchFullPayload(bool fetch=true)
bool isValid() const const
QString number(int n, int base)
void rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles)
~ETMCalendar() override
Destroys this ETMCalendar.
bool collectionFilteringEnabled() const
Returns whether collection filtering is enabled.
QAbstractItemModel * model() const
Convenience method to access the contents of this KCalendarCore::Calendar through a QAIM interface...
KCheckableProxyModel * checkableProxyModel() const
Returns the KCheckableProxyModel used to select from which collections should the calendar be populat...
CaseInsensitive
void setObjectName(const QString &name)
void remove(int i)
int row() const const
static Collection root()
bool isAlarmTypeBlocked(KCalendarCore::Alarm::Type type) const
Returns whether given alarm type is blocked or not.
void rowsRemoved(const QModelIndex &parent, int first, int last)
bool hasNext() const const
void fetchCollection(bool enable)
Attribute * attribute(const QByteArray &name)
Rights rights() const
static QLatin1String todoMimeType()
QHashIterator::Item next()
bool contains(const T &value) const const
bool hasAttribute(const QByteArray &name) const
Akonadi::Collection collection(Akonadi::Collection::Id) const
Returns the collection having id.
const QList< QKeySequence > & end()
QVariant data(int role) const const
void setSourceModel(QAbstractItemModel *model) override
QModelIndex sibling(int row, int column) const const
FreeBusyManager::Singleton.
virtual void setModel(QAbstractItemModel *model) override
Incidence::Ptr incidence(const QString &uid, const QDateTime &recurrenceId={}) const
void collectionChanged(const Akonadi::Collection &collection)
int column() const const
void show()
The base class for all akonadi aware calendars.
Definition: calendarbase.h:35
CalendarBase(QObject *parent=nullptr)
Constructs a CalendarBase object.
void rowsInserted(const QModelIndex &parent, int first, int last)
void collectionPopulated(Akonadi::Collection::Id collectionId)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
T qobject_cast(QObject *object)
QObject * parent() const const
QSharedPointer< X > staticCast() const const
const T & next()
A KCalendarCore::Calendar that uses an EntityTreeModel to populate itself.
Definition: etmcalendar.h:40
bool hasRight(const Akonadi::Item &item, Akonadi::Collection::Right right) const
Returns true if the collection owning incidence has righ right.
ETMCalendar(QObject *parent=nullptr)
Constructs a new ETMCalendar.
Q_EMITQ_EMIT
void setCollectionFilteringEnabled(bool enable)
Enable or disable collection filtering.
An Attribute that marks that alarms from a calendar collection are blocked.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Sep 19 2020 23:10:30 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.