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

KDE's Doxygen guidelines are available online.