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 "blockalarmsattribute.h"
9 #include "calendarmodel_p.h"
10 #include "calendarutils.h"
11 #include "calfilterpartstatusproxymodel_p.h"
12 #include "calfilterproxymodel_p.h"
13 #include "etmcalendar_p.h"
14 #include "kcolumnfilterproxymodel_p.h"
15 
16 #include <Akonadi/CollectionFilterProxyModel>
17 #include <Akonadi/CollectionUtils>
18 #include <Akonadi/EntityDisplayAttribute>
19 #include <Akonadi/EntityMimeTypeFilterModel>
20 #include <Akonadi/Item>
21 #include <Akonadi/ItemFetchScope>
22 #include <Akonadi/Monitor>
23 #include <Akonadi/Session>
24 #include <KDescendantsProxyModel>
25 #include <KSelectionProxyModel>
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  auto session = new Akonadi::Session("ETMCalendar", q);
47  auto monitor = new Akonadi::Monitor(q);
48  monitor->setObjectName(QLatin1StringView("ETMCalendarMonitor"));
49  connect(monitor,
51  this,
52  [this](const Akonadi::Collection &cols, const QSet<QByteArray> &set) {
53  onCollectionChanged(cols, set);
54  });
55 
57  scope.fetchFullPayload(true);
58  scope.fetchAttribute<Akonadi::EntityDisplayAttribute>();
59 
60  monitor->setSession(session);
61  monitor->setCollectionMonitored(Akonadi::Collection::root());
62  monitor->fetchCollection(true);
63  monitor->setItemFetchScope(scope);
64  monitor->setAllMonitored(true);
65 
66  const QStringList allMimeTypes = {KCalendarCore::Event::eventMimeType(),
69 
70  for (const QString &mimetype : allMimeTypes) {
71  monitor->setMimeTypeMonitored(mimetype, mMimeTypes.isEmpty() || mMimeTypes.contains(mimetype));
72  }
73 
74  mETM = CalendarModel::create(monitor);
75  mETM->setObjectName(QLatin1StringView("ETM"));
76  mETM->setListFilter(Akonadi::CollectionFetchScope::Display);
77  }
78 
79  setupFilteredETM();
80 
81  connect(q, &Calendar::filterChanged, this, &ETMCalendarPrivate::onFilterChanged);
82 
83  connect(mETM.data(), &EntityTreeModel::collectionPopulated, this, &ETMCalendarPrivate::onCollectionPopulated);
84  connect(mETM.data(), &QAbstractItemModel::rowsInserted, this, &ETMCalendarPrivate::onRowsInserted);
85  connect(mETM.data(), &QAbstractItemModel::dataChanged, this, &ETMCalendarPrivate::onDataChanged);
86  connect(mETM.data(), &QAbstractItemModel::rowsMoved, this, &ETMCalendarPrivate::onRowsMoved);
87  connect(mETM.data(), &QAbstractItemModel::rowsRemoved, this, &ETMCalendarPrivate::onRowsRemoved);
88 
89  connect(mFilteredETM, &QAbstractItemModel::dataChanged, this, &ETMCalendarPrivate::onDataChangedInFilteredModel);
90  connect(mFilteredETM, &QAbstractItemModel::layoutChanged, this, &ETMCalendarPrivate::onLayoutChangedInFilteredModel);
91  connect(mFilteredETM, &QAbstractItemModel::modelReset, this, &ETMCalendarPrivate::onModelResetInFilteredModel);
92  connect(mFilteredETM, &QAbstractItemModel::rowsInserted, this, &ETMCalendarPrivate::onRowsInsertedInFilteredModel);
93  connect(mFilteredETM, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ETMCalendarPrivate::onRowsAboutToBeRemovedInFilteredModel);
94 
95  loadFromETM();
96  updateLoadingState();
97 }
98 
99 void ETMCalendarPrivate::onCollectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &attributeNames)
100 {
101  Q_ASSERT(collection.isValid());
102  // Is the collection changed to read-only, we update all Incidences
103  if (attributeNames.contains("AccessRights")) {
104  const Akonadi::Item::List items = q->items();
105  for (const Akonadi::Item &item : items) {
106  if (item.storageCollectionId() == collection.id()) {
108  if (incidence) {
109  incidence->setReadOnly(!(collection.rights() & Akonadi::Collection::CanChangeItem));
110  }
111  }
112  }
113  }
114 
115  Q_EMIT q->collectionChanged(collection, attributeNames);
116 }
117 
118 void ETMCalendarPrivate::setupFilteredETM()
119 {
120  // We're only interested in the CollectionTitle column
121  auto columnFilterProxy = new KColumnFilterProxyModel(this);
122  columnFilterProxy->setSourceModel(mETM.data());
123  columnFilterProxy->setVisibleColumn(CalendarModel::CollectionTitle);
124  columnFilterProxy->setObjectName(QLatin1StringView("Remove columns"));
125 
126  mCollectionProxyModel = new Akonadi::CollectionFilterProxyModel(this);
127  mCollectionProxyModel->setObjectName(QLatin1StringView("Only show collections"));
128  mCollectionProxyModel->setDynamicSortFilter(true);
129  mCollectionProxyModel->addMimeTypeFilter(QStringLiteral("text/calendar"));
130  mCollectionProxyModel->setExcludeVirtualCollections(false);
131  mCollectionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
132  mCollectionProxyModel->setSourceModel(columnFilterProxy);
133 
134  // Keep track of selected items.
135  auto selectionModel = new QItemSelectionModel(mCollectionProxyModel);
136  selectionModel->setObjectName(QLatin1StringView("Calendar Selection Model"));
137 
138  // Make item selection work by means of checkboxes.
139  mCheckableProxyModel = new CheckableProxyModel(this);
140  mCheckableProxyModel->setSelectionModel(selectionModel);
141  mCheckableProxyModel->setSourceModel(mCollectionProxyModel);
142  mCheckableProxyModel->setObjectName(QLatin1StringView("Add checkboxes"));
143 
144  mSelectionProxy = new KSelectionProxyModel(selectionModel, /**parent=*/this);
145  mSelectionProxy->setObjectName(QLatin1StringView("Only show items of selected collection"));
146  mSelectionProxy->setFilterBehavior(KSelectionProxyModel::ChildrenOfExactSelection);
147  mSelectionProxy->setSourceModel(mETM.data());
148 
149  mCalFilterProxyModel = new CalFilterProxyModel(this);
150  mCalFilterProxyModel->setFilter(q->filter());
151  mCalFilterProxyModel->setSourceModel(mSelectionProxy);
152  mCalFilterProxyModel->setObjectName(QLatin1StringView("KCalendarCore::CalFilter filtering"));
153 
154  mCalFilterPartStatusProxyModel = new CalFilterPartStatusProxyModel(this);
155  mCalFilterPartStatusProxyModel->setFilterVirtual(false);
157  blockedStatusList << KCalendarCore::Attendee::NeedsAction;
158  blockedStatusList << KCalendarCore::Attendee::Declined;
159  mCalFilterPartStatusProxyModel->setDynamicSortFilter(true);
160  mCalFilterPartStatusProxyModel->setBlockedStatusList(blockedStatusList);
161  mCalFilterPartStatusProxyModel->setSourceModel(mCalFilterProxyModel);
162  mCalFilterPartStatusProxyModel->setObjectName(QLatin1StringView("PartStatus filtering"));
163 
164  mFilteredETM = new Akonadi::EntityMimeTypeFilterModel(this);
165  mFilteredETM->setSourceModel(mCalFilterPartStatusProxyModel);
166  mFilteredETM->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders);
167  mFilteredETM->setSortRole(CalendarModel::SortRole);
168  mFilteredETM->setObjectName(QLatin1StringView("Show headers"));
169 
170 #ifdef AKONADI_CALENDAR_DEBUG_MODEL
171  QTreeView *view = new QTreeView;
172  view->setModel(mFilteredETM);
173  view->show();
174 #endif
175 }
176 
177 ETMCalendarPrivate::~ETMCalendarPrivate() = default;
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 = CollectionUtils::fromIndex(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 void ETMCalendarPrivate::onRowsInserted(const QModelIndex &index, int start, int end)
285 {
286  const Akonadi::Collection::List collections = collectionsFromModel(mETM.data(), index, start, end);
287 
288  for (const Akonadi::Collection &collection : collections) {
289  mCollectionMap[collection.id()] = collection;
290  }
291 
292  if (!collections.isEmpty()) {
293  Q_EMIT q->collectionsAdded(collections);
294  }
295 }
296 
297 void ETMCalendarPrivate::onCollectionPopulated(Akonadi::Collection::Id id)
298 {
299  mPopulatedCollectionIds.insert(id);
300  Q_EMIT q->calendarChanged();
301  updateLoadingState();
302 }
303 
304 void ETMCalendarPrivate::onRowsRemoved(const QModelIndex &index, int start, int end)
305 {
306  const Akonadi::Collection::List collections = collectionsFromModel(mETM.data(), index, start, end);
307  for (const Akonadi::Collection &collection : collections) {
308  mCollectionMap.remove(collection.id());
309  }
310 
311  if (!collections.isEmpty()) {
312  Q_EMIT q->collectionsRemoved(collections);
313  }
314 }
315 
316 void ETMCalendarPrivate::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
317 {
318  // We only update collections, because items are handled in the filtered model
319  Q_ASSERT(topLeft.row() <= bottomRight.row());
320  const int endRow = bottomRight.row();
321  for (int row = topLeft.row(); row <= endRow; ++row) {
322  const Akonadi::Collection col = CollectionUtils::fromIndex(topLeft.sibling(row, 0));
323  if (col.isValid()) {
324  // Attributes might have changed, store the new collection and discard the old one
325  mCollectionMap.insert(col.id(), col);
326  }
327  }
328 }
329 
330 void ETMCalendarPrivate::onRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
331 {
332  // TODO
333  Q_UNUSED(sourceParent)
334  Q_UNUSED(sourceStart)
335  Q_UNUSED(sourceEnd)
336  Q_UNUSED(destinationParent)
337  Q_UNUSED(destinationRow)
338 }
339 
340 void ETMCalendarPrivate::onLayoutChangedInFilteredModel()
341 {
342  clear();
343  loadFromETM();
344 }
345 
346 void ETMCalendarPrivate::onModelResetInFilteredModel()
347 {
348  clear();
349  loadFromETM();
350 }
351 
352 void ETMCalendarPrivate::onDataChangedInFilteredModel(const QModelIndex &topLeft, const QModelIndex &bottomRight)
353 {
354  Q_ASSERT(topLeft.row() <= bottomRight.row());
355  const int endRow = bottomRight.row();
356  QModelIndex i(topLeft);
357  int row = i.row();
358  while (row <= endRow) {
359  const Akonadi::Item item = itemFromIndex(i);
360  if (item.isValid() && item.hasPayload<KCalendarCore::Incidence::Ptr>()) {
361  updateItem(item);
362  }
363 
364  ++row;
365  i = i.sibling(row, topLeft.column());
366  }
367 
368  Q_EMIT q->calendarChanged();
369 }
370 
371 void ETMCalendarPrivate::updateItem(const Akonadi::Item &item)
372 {
373  Incidence::Ptr newIncidence = CalendarUtils::incidence(item);
374  Q_ASSERT(newIncidence);
375  Q_ASSERT(!newIncidence->uid().isEmpty());
376  newIncidence->setCustomProperty("VOLATILE", "AKONADI-ID", QString::number(item.id()));
377  IncidenceBase::Ptr existingIncidence = q->incidence(newIncidence->uid(), newIncidence->recurrenceId());
378 
379  if (!existingIncidence && !mItemById.contains(item.id())) {
380  // We don't know about this one because it was discarded, for example because of not having DTSTART
381  return;
382  }
383 
384  mItemsByCollection.insert(item.storageCollectionId(), item);
385  Akonadi::Item oldItem = mItemById.value(item.id());
386 
387  if (existingIncidence) {
388  // We set the payload so that the internal incidence pointer and the one in mItemById stay the same
389  Akonadi::Item updatedItem = item;
391  mItemById.insert(item.id(), updatedItem); // The item needs updating too, revision changed.
392 
393  // Check if RELATED-TO changed, updating parenting information
394  handleParentChanged(newIncidence);
395  *(existingIncidence.data()) = *(newIncidence.data());
396  } else {
397  mItemById.insert(item.id(), item); // The item needs updating too, revision changed.
398  // The item changed it's UID, update our maps, the Google resource changes the UID when we create incidences.
399  handleUidChange(oldItem, item, newIncidence->instanceIdentifier());
400  }
401 }
402 
403 void ETMCalendarPrivate::onRowsInsertedInFilteredModel(const QModelIndex &index, int start, int end)
404 {
405  itemsAdded(itemsFromModel(mFilteredETM, index, start, end));
406 }
407 
408 void ETMCalendarPrivate::onRowsAboutToBeRemovedInFilteredModel(const QModelIndex &index, int start, int end)
409 {
410  itemsRemoved(itemsFromModel(mFilteredETM, index, start, end));
411 }
412 
413 void ETMCalendarPrivate::onFilterChanged()
414 {
415  mCalFilterProxyModel->setFilter(q->filter());
416 }
417 
419  : CalendarBase(new ETMCalendarPrivate(this), parent)
420 {
421  Q_D(ETMCalendar);
422  d->init();
423 }
424 
425 ETMCalendar::ETMCalendar(const QStringList &mimeTypes, QObject *parent)
426  : CalendarBase(new ETMCalendarPrivate(this), parent)
427 {
428  Q_D(ETMCalendar);
429  d->mMimeTypes = mimeTypes;
430  d->init();
431 }
432 
434  : CalendarBase(new ETMCalendarPrivate(this), parent)
435 {
436  Q_D(ETMCalendar);
437 
438  auto model = qobject_cast<Akonadi::CalendarModel *>(other->entityTreeModel());
439  if (model) {
440  d->mETM = model->weakPointer().toStrongRef();
441  }
442 
443  d->init();
444 }
445 
446 ETMCalendar::ETMCalendar(Monitor *monitor, QObject *parent)
447  : CalendarBase(new ETMCalendarPrivate(this), parent)
448 {
449  Q_D(ETMCalendar);
450 
451  if (monitor) {
452  QObject::connect(monitor,
454  d,
455  &ETMCalendarPrivate::onCollectionChanged);
456  d->mETM = CalendarModel::create(monitor);
457  d->mETM->setObjectName(QLatin1StringView("ETM"));
458  d->mETM->setListFilter(Akonadi::CollectionFetchScope::Display);
459  }
460 
461  d->init();
462 }
463 
464 ETMCalendar::~ETMCalendar() = default;
465 
466 // TODO: move this up?
468 {
469  Q_D(const ETMCalendar);
470  return d->mCollectionMap.value(id);
471 }
472 
474 {
475  return hasRight(item(uid), right);
476 }
477 
479 {
480  // if the users changes the rights, item.parentCollection()
481  // can still have the old rights, so we use call collection()
482  // which returns the updated one
484  return col.rights() & right;
485 }
486 
488 {
489  Q_D(const ETMCalendar);
490  return d->mFilteredETM;
491 }
492 
494 {
495  Q_D(const ETMCalendar);
496  return d->mCheckableProxyModel;
497 }
498 
499 KCalendarCore::Alarm::List ETMCalendar::alarms(const QDateTime &from, const QDateTime &to, bool excludeBlockedAlarms) const
500 {
501  Q_D(const ETMCalendar);
502  KCalendarCore::Alarm::List alarmList;
504  while (i.hasNext()) {
505  const Akonadi::Item item = i.next().value();
506 
507  Akonadi::Collection parentCollection; // must have same lifetime as blockedAttr
508  BlockAlarmsAttribute *blockedAttr = nullptr;
509 
510  if (excludeBlockedAlarms) {
511  // take the collection from m_collectionMap, because we need the up-to-date collection attrs
512  parentCollection = d->mCollectionMap.value(item.storageCollectionId());
513  if (parentCollection.isValid() && parentCollection.hasAttribute<BlockAlarmsAttribute>()) {
514  blockedAttr = parentCollection.attribute<BlockAlarmsAttribute>();
515  if (blockedAttr->isEverythingBlocked()) {
516  continue;
517  }
518  }
519  }
520 
524  }
525  if (!incidence || incidence->alarms().isEmpty()) {
526  continue;
527  }
528 
529  Alarm::List tmpList;
530  if (incidence->recurs()) {
531  appendRecurringAlarms(tmpList, incidence, from, to);
532  } else {
533  appendAlarms(tmpList, incidence, from, to);
534  }
535 
536  if (blockedAttr) {
537  tmpList.erase(std::remove_if(tmpList.begin(),
538  tmpList.end(),
539  [blockedAttr](const auto &alarm) {
540  return blockedAttr->isAlarmTypeBlocked(alarm->type());
541  }),
542  tmpList.end());
543  }
544 
545  alarmList += tmpList;
546  }
547  return alarmList;
548 }
549 
551 {
552  Q_D(const ETMCalendar);
553  return d->mETM.data();
554 }
555 
557 {
558  Q_D(ETMCalendar);
559  if (d->mCollectionFilteringEnabled != enable) {
560  d->mCollectionFilteringEnabled = enable;
561  if (enable) {
562  d->mSelectionProxy->setSourceModel(d->mETM.data());
563  QAbstractItemModel *oldModel = d->mCalFilterProxyModel->sourceModel();
564  d->mCalFilterProxyModel->setSourceModel(d->mSelectionProxy);
565  delete qobject_cast<KDescendantsProxyModel *>(oldModel);
566  } else {
567  auto flatner = new KDescendantsProxyModel(this);
568  flatner->setSourceModel(d->mETM.data());
569  d->mCalFilterProxyModel->setSourceModel(flatner);
570  }
571  }
572 }
573 
575 {
576  Q_D(const ETMCalendar);
577  return d->mCollectionFilteringEnabled;
578 }
579 
580 void ETMCalendarPrivate::updateLoadingState()
581 {
582  if (!q->entityTreeModel()->isCollectionTreeFetched()) {
583  return q->setIsLoading(true);
584  }
585 
586  for (const Akonadi::Collection &collection : std::as_const(mCollectionMap)) {
587  if (!q->entityTreeModel()->isCollectionPopulated(collection.id())) {
588  return q->setIsLoading(true);
589  }
590  }
591 
592  q->setIsLoading(false);
593 }
594 
595 #include "moc_etmcalendar.cpp"
596 #include "moc_etmcalendar_p.cpp"
bool isValid() const
Incidence::Ptr incidence(const QString &uid, const QDateTime &recurrenceId={}) const
void appendAlarms(Alarm::List &alarms, const Incidence::Ptr &incidence, const QDateTime &from, const QDateTime &to) const
T * data() const const
bool collectionFilteringEnabled() const
Returns whether collection filtering is enabled.
bool isEverythingBlocked() const
Returns whether all alarms are blocked or not.
QString number(int n, int base)
AKONADICORE_EXPORT Collection fromIndex(const QModelIndex &index)
virtual int rowCount(const QModelIndex &parent) const const=0
CaseInsensitive
QModelIndex sibling(int row, int column) const const
void collectionChanged(const Akonadi::Collection &collection)
virtual void setModel(QAbstractItemModel *model) override
QVector::iterator begin()
static QLatin1String todoMimeType()
int column() const const
T value() const const
void layoutChanged(const QList< QPersistentModelIndex > &parents, QAbstractItemModel::LayoutChangeHint hint)
Q_SCRIPTABLE Q_NOREPLY void start()
KCheckableProxyModel * checkableProxyModel() const
Returns the KCheckableProxyModel used to select from which collections should the calendar be populat...
void setParentCollection(const Collection &parent)
void push_back(const T &value)
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 fetchFullPayload(bool fetch=true)
AKONADI_CALENDAR_EXPORT KCalendarCore::Incidence::Ptr incidence(const Akonadi::Item &item)
Returns the incidence from an Akonadi item, or a null pointer if the item has no such payload.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool hasPayload() const
bool hasAttribute() const
void collectionPopulated(Akonadi::Collection::Id collectionId)
void reserve(int alloc)
void rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
QVariant data(int role) const const
Collection::Id storageCollectionId() const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles)
QHashIterator::Item next()
static QLatin1String eventMimeType()
ETMCalendar(QObject *parent=nullptr)
Constructs a new ETMCalendar.
A KCalendarCore::Calendar that uses an EntityTreeModel to populate itself.
Definition: etmcalendar.h:40
const T * attribute() const
void appendRecurringAlarms(Alarm::List &alarms, const Incidence::Ptr &incidence, const QDateTime &from, const QDateTime &to) const
void setCollectionFilteringEnabled(bool enable)
Enable or disable collection filtering.
bool isEmpty() const const
Akonadi::Collection collection(Akonadi::Collection::Id) const
Returns the collection having id.
Rights rights() const
bool isValid() const const
static Collection root()
bool contains(const T &value) const const
void show()
bool hasNext() const const
int row() const const
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
QVector::iterator end()
static QLatin1String journalMimeType()
QAction * clear(const QObject *recvr, const char *slot, QObject *parent)
Id id() const
void rowsInserted(const QModelIndex &parent, int first, int last)
void rowsRemoved(const QModelIndex &parent, int first, int last)
Akonadi::EntityTreeModel * entityTreeModel() const
Returns the underlying EntityTreeModel.
bool hasRight(const Akonadi::Item &item, Akonadi::Collection::Right right) const
Returns true if the collection owning incidence has righ right.
QVector::iterator erase(QVector::iterator begin, QVector::iterator end)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
QAbstractItemModel * model() const
Convenience method to access the contents of this KCalendarCore::Calendar through a QAIM interface.
bool isValid() const
void setPayload(const T &p)
QSharedPointer< X > staticCast() const const
An Attribute that marks that alarms from a calendar collection are blocked.
T payload() const
Akonadi::Item item(const QString &uid) const
Returns the Item containing the incidence with uid uid or an invalid Item if the incidence isn't foun...
The base class for all akonadi aware calendars.
Definition: calendarbase.h:37
const QList< QKeySequence > & end()
Q_D(Todo)
~ETMCalendar() override
Destroys this ETMCalendar.
FreeBusyManager::Singleton.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Dec 11 2023 03:52:57 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.