Akonadi Calendar

etmcalendar.cpp
1/*
2 SPDX-FileCopyrightText: 2011-2013 Sérgio Martins <iamsergio@gmail.com>
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.h"
12#include "calfilterproxymodel.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
30using namespace Akonadi;
31using namespace KCalendarCore;
32
33// TODO: implement batchAdding
34
35ETMCalendarPrivate::ETMCalendarPrivate(ETMCalendar *qq)
36 : CalendarBasePrivate(qq)
37 , mETM(nullptr)
38 , q(qq)
39{
40 mListensForNewItems = true;
41}
42
43void 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
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
99void 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
118void 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
177ETMCalendarPrivate::~ETMCalendarPrivate() = default;
178
179void ETMCalendarPrivate::loadFromETM()
180{
181 itemsAdded(itemsFromModel(mFilteredETM));
182}
183
184void 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
210Akonadi::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;
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
232Akonadi::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) {
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
253Akonadi::Item ETMCalendarPrivate::itemFromIndex(const QModelIndex &idx)
254{
257 return item;
258}
259
260void 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
276void 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
284void 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
297void ETMCalendarPrivate::onCollectionPopulated(Akonadi::Collection::Id id)
298{
299 mPopulatedCollectionIds.insert(id);
300 Q_EMIT q->calendarChanged();
301 updateLoadingState();
302}
303
304void 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
316void 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
330void 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
340void ETMCalendarPrivate::onLayoutChangedInFilteredModel()
341{
342 clear();
343 loadFromETM();
344}
345
346void ETMCalendarPrivate::onModelResetInFilteredModel()
347{
348 clear();
349 loadFromETM();
350}
351
352void 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
371void 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
403void ETMCalendarPrivate::onRowsInsertedInFilteredModel(const QModelIndex &index, int start, int end)
404{
405 itemsAdded(itemsFromModel(mFilteredETM, index, start, end));
406}
407
408void ETMCalendarPrivate::onRowsAboutToBeRemovedInFilteredModel(const QModelIndex &index, int start, int end)
409{
410 itemsRemoved(itemsFromModel(mFilteredETM, index, start, end));
411}
412
413void ETMCalendarPrivate::onFilterChanged()
414{
415 mCalFilterProxyModel->setFilter(q->filter());
416}
417
419 : CalendarBase(new ETMCalendarPrivate(this), parent)
420{
422 d->init();
423}
424
426 : CalendarBase(new ETMCalendarPrivate(this), parent)
427{
429 d->mMimeTypes = mimeTypes;
430 d->init();
431}
432
434 : CalendarBase(new ETMCalendarPrivate(this), parent)
435{
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
447 : CalendarBase(new ETMCalendarPrivate(this), parent)
448{
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
464ETMCalendar::~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
499KCalendarCore::Alarm::List ETMCalendar::alarms(const QDateTime &from, const QDateTime &to, bool excludeBlockedAlarms) const
500{
501 Q_D(const ETMCalendar);
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{
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
580void 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"
An Attribute that marks that alarms from a calendar collection are blocked.
bool isEverythingBlocked() const
Returns whether all alarms are blocked or not.
The base class for all akonadi aware calendars.
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...
bool isValid() const
static Collection root()
const T * attribute() const
Rights rights() const
bool hasAttribute() const
A KCalendarCore::Calendar that uses an EntityTreeModel to populate itself.
Definition etmcalendar.h:41
Akonadi::EntityTreeModel * entityTreeModel() const
Returns the underlying EntityTreeModel.
void setCollectionFilteringEnabled(bool enable)
Enable or disable collection filtering.
ETMCalendar(QObject *parent=nullptr)
Constructs a new ETMCalendar.
Akonadi::Collection collection(Akonadi::Collection::Id) const
Returns the collection having id.
KCheckableProxyModel * checkableProxyModel() const
Returns the KCheckableProxyModel used to select from which collections should the calendar be populat...
~ETMCalendar() override
Destroys this ETMCalendar.
bool hasRight(const Akonadi::Item &item, Akonadi::Collection::Right right) const
Returns true if the collection owning incidence has righ right.
QAbstractItemModel * model() const
Convenience method to access the contents of this KCalendarCore::Calendar through a QAIM interface.
KCalendarCore::Alarm::List alarms(const QDateTime &from, const QDateTime &to, bool excludeBlockedAlarms=false) const override
Returns all alarms occurring in a specified time interval.
bool collectionFilteringEnabled() const
Returns whether collection filtering is enabled.
void collectionPopulated(Akonadi::Collection::Id collectionId)
void fetchFullPayload(bool fetch=true)
void setParentCollection(const Collection &parent)
void setPayload(const T &p)
bool hasPayload() const
Id id() const
T payload() const
Collection::Id storageCollectionId() const
bool isValid() const
void collectionChanged(const Akonadi::Collection &collection)
void appendAlarms(Alarm::List &alarms, const Incidence::Ptr &incidence, const QDateTime &from, const QDateTime &to) const
Incidence::Ptr incidence(const QString &uid, const QDateTime &recurrenceId={}) const
void appendRecurringAlarms(Alarm::List &alarms, const Incidence::Ptr &incidence, const QDateTime &from, const QDateTime &to) const
static QLatin1String eventMimeType()
static QLatin1String journalMimeType()
static QLatin1String todoMimeType()
Q_SCRIPTABLE Q_NOREPLY void start()
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.
AKONADICORE_EXPORT Collection fromIndex(const QModelIndex &index)
FreeBusyManager::Singleton.
KGuiItem clear()
const QList< QKeySequence > & end()
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
void layoutChanged(const QList< QPersistentModelIndex > &parents, QAbstractItemModel::LayoutChangeHint hint)
virtual int rowCount(const QModelIndex &parent) const const=0
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
void rowsInserted(const QModelIndex &parent, int first, int last)
void rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
void rowsRemoved(const QModelIndex &parent, int first, int last)
bool hasNext() const const
iterator begin()
iterator end()
iterator erase(const_iterator begin, const_iterator end)
T & first()
bool isEmpty() const const
void push_back(parameter_type value)
void reserve(qsizetype size)
int column() const const
QVariant data(int role) const const
bool isValid() const const
int row() const const
QModelIndex sibling(int row, int column) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool contains(const QSet< T > &other) const const
T * data() const const
QSharedPointer< X > staticCast() const const
QString number(double n, char format, int precision)
CaseInsensitive
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
virtual void setModel(QAbstractItemModel *model) override
T value() const const
void show()
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:17:16 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.