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"
8using namespace Qt::Literals::StringLiterals;
9
10#include "blockalarmsattribute.h"
11#include "calendarmodel_p.h"
12#include "calendarutils.h"
13#include "calfilterpartstatusproxymodel.h"
14#include "calfilterproxymodel.h"
15#include "etmcalendar_p.h"
16#include "kcolumnfilterproxymodel_p.h"
17
18#include <Akonadi/CollectionFilterProxyModel>
19#include <Akonadi/CollectionUtils>
20#include <Akonadi/EntityDisplayAttribute>
21#include <Akonadi/EntityMimeTypeFilterModel>
22#include <Akonadi/Item>
23#include <Akonadi/ItemFetchScope>
24#include <Akonadi/Monitor>
25#include <Akonadi/Session>
26#include <KDescendantsProxyModel>
27#include <KSelectionProxyModel>
28
29#include <QItemSelectionModel>
30#include <QTreeView>
31
32using namespace Akonadi;
33using namespace KCalendarCore;
34
35// TODO: implement batchAdding
36
37ETMCalendarPrivate::ETMCalendarPrivate(ETMCalendar *qq)
38 : CalendarBasePrivate(qq)
39 , mETM(nullptr)
40 , q(qq)
41{
42 mListensForNewItems = true;
43}
44
45void ETMCalendarPrivate::init()
46{
47 if (!mETM) {
48 auto session = new Akonadi::Session("ETMCalendar", q);
49 auto monitor = new Akonadi::Monitor(q);
50 monitor->setObjectName("ETMCalendarMonitor"_L1);
51 connect(monitor,
53 this,
54 [this](const Akonadi::Collection &cols, const QSet<QByteArray> &set) {
55 onCollectionChanged(cols, set);
56 });
57
59 scope.fetchFullPayload(true);
60 scope.fetchAttribute<Akonadi::EntityDisplayAttribute>();
61
62 monitor->setSession(session);
63 monitor->setCollectionMonitored(Akonadi::Collection::root());
64 monitor->fetchCollection(true);
65 monitor->setItemFetchScope(scope);
66 monitor->setAllMonitored(true);
67
71
72 for (const QString &mimetype : allMimeTypes) {
73 monitor->setMimeTypeMonitored(mimetype, mMimeTypes.isEmpty() || mMimeTypes.contains(mimetype));
74 }
75
76 mETM = CalendarModel::create(monitor);
77 mETM->setObjectName("ETM"_L1);
78 mETM->setListFilter(Akonadi::CollectionFetchScope::Display);
79 }
80
81 setupFilteredETM();
82
83 connect(q, &Calendar::filterChanged, this, &ETMCalendarPrivate::onFilterChanged);
84
85 connect(mETM.data(), &EntityTreeModel::collectionPopulated, this, &ETMCalendarPrivate::onCollectionPopulated);
86 connect(mETM.data(), &QAbstractItemModel::rowsInserted, this, &ETMCalendarPrivate::onRowsInserted);
87 connect(mETM.data(), &QAbstractItemModel::dataChanged, this, &ETMCalendarPrivate::onDataChanged);
88 connect(mETM.data(), &QAbstractItemModel::rowsMoved, this, &ETMCalendarPrivate::onRowsMoved);
89 connect(mETM.data(), &QAbstractItemModel::rowsRemoved, this, &ETMCalendarPrivate::onRowsRemoved);
90
91 connect(mFilteredETM, &QAbstractItemModel::dataChanged, this, &ETMCalendarPrivate::onDataChangedInFilteredModel);
92 connect(mFilteredETM, &QAbstractItemModel::layoutChanged, this, &ETMCalendarPrivate::onLayoutChangedInFilteredModel);
93 connect(mFilteredETM, &QAbstractItemModel::modelReset, this, &ETMCalendarPrivate::onModelResetInFilteredModel);
94 connect(mFilteredETM, &QAbstractItemModel::rowsInserted, this, &ETMCalendarPrivate::onRowsInsertedInFilteredModel);
95 connect(mFilteredETM, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ETMCalendarPrivate::onRowsAboutToBeRemovedInFilteredModel);
96
97 loadFromETM();
98 updateLoadingState();
99}
100
101void ETMCalendarPrivate::onCollectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &attributeNames)
102{
103 Q_ASSERT(collection.isValid());
104 // Is the collection changed to read-only, we update all Incidences
105 if (attributeNames.contains("AccessRights")) {
106 const Akonadi::Item::List items = q->items();
107 for (const Akonadi::Item &item : items) {
108 if (item.storageCollectionId() == collection.id()) {
110 if (incidence) {
111 incidence->setReadOnly(!(collection.rights() & Akonadi::Collection::CanChangeItem));
112 }
113 }
114 }
115 }
116
117 Q_EMIT q->collectionChanged(collection, attributeNames);
118}
119
120void ETMCalendarPrivate::setupFilteredETM()
121{
122 // We're only interested in the CollectionTitle column
123 auto columnFilterProxy = new KColumnFilterProxyModel(this);
124 columnFilterProxy->setSourceModel(mETM.data());
125 columnFilterProxy->setVisibleColumn(CalendarModel::CollectionTitle);
126 columnFilterProxy->setObjectName("Remove columns"_L1);
127
128 mCollectionProxyModel = new Akonadi::CollectionFilterProxyModel(this);
129 mCollectionProxyModel->setObjectName("Only show collections"_L1);
130 mCollectionProxyModel->setDynamicSortFilter(true);
131 mCollectionProxyModel->addMimeTypeFilter(QStringLiteral("text/calendar"));
132 mCollectionProxyModel->setExcludeVirtualCollections(false);
133 mCollectionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
134 mCollectionProxyModel->setSourceModel(columnFilterProxy);
135
136 // Keep track of selected items.
137 auto selectionModel = new QItemSelectionModel(mCollectionProxyModel);
138 selectionModel->setObjectName("Calendar Selection Model"_L1);
139
140 // Make item selection work by means of checkboxes.
141 mCheckableProxyModel = new CheckableProxyModel(this);
142 mCheckableProxyModel->setSelectionModel(selectionModel);
143 mCheckableProxyModel->setSourceModel(mCollectionProxyModel);
144 mCheckableProxyModel->setObjectName("Add checkboxes"_L1);
145
146 connect(mCheckableProxyModel, &CheckableProxyModel::checkedByUser, q, &ETMCalendar::calendarSelectionEdited);
147
148 mSelectionProxy = new KSelectionProxyModel(selectionModel, /**parent=*/this);
149 mSelectionProxy->setObjectName("Only show items of selected collection"_L1);
150 mSelectionProxy->setFilterBehavior(KSelectionProxyModel::ChildrenOfExactSelection);
151 mSelectionProxy->setSourceModel(mETM.data());
152
153 mCalFilterProxyModel = new CalFilterProxyModel(this);
154 mCalFilterProxyModel->setFilter(q->filter());
155 mCalFilterProxyModel->setSourceModel(mSelectionProxy);
156 mCalFilterProxyModel->setObjectName("KCalendarCore::CalFilter filtering"_L1);
157
158 mCalFilterPartStatusProxyModel = new CalFilterPartStatusProxyModel(this);
159 mCalFilterPartStatusProxyModel->setFilterVirtual(false);
161 blockedStatusList << KCalendarCore::Attendee::NeedsAction;
162 blockedStatusList << KCalendarCore::Attendee::Declined;
163 mCalFilterPartStatusProxyModel->setDynamicSortFilter(true);
164 mCalFilterPartStatusProxyModel->setBlockedStatusList(blockedStatusList);
165 mCalFilterPartStatusProxyModel->setSourceModel(mCalFilterProxyModel);
166 mCalFilterPartStatusProxyModel->setObjectName("PartStatus filtering"_L1);
167
168 mFilteredETM = new Akonadi::EntityMimeTypeFilterModel(this);
169 mFilteredETM->setSourceModel(mCalFilterPartStatusProxyModel);
170 mFilteredETM->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders);
171 mFilteredETM->setSortRole(CalendarModel::SortRole);
172 mFilteredETM->setObjectName("Show headers"_L1);
173
174#ifdef AKONADI_CALENDAR_DEBUG_MODEL
175 QTreeView *view = new QTreeView;
176 view->setModel(mFilteredETM);
177 view->show();
178#endif
179}
180
181ETMCalendarPrivate::~ETMCalendarPrivate() = default;
182
183void ETMCalendarPrivate::loadFromETM()
184{
185 itemsAdded(itemsFromModel(mFilteredETM));
186}
187
188void ETMCalendarPrivate::clear()
189{
190 mCollectionMap.clear();
191 mItemsByCollection.clear();
192
193 Akonadi::Item::List removedItems;
194 removedItems.reserve(mItemById.size());
195 for (auto it = mItemById.cbegin(), end = mItemById.cend(); it != end; ++it) {
196 removedItems.push_back(it.value());
197 }
198
199 itemsRemoved(removedItems);
200
201 if (!mItemById.isEmpty()) {
202 mItemById.clear();
203 // Q_ASSERT(false); // TODO: discover why this happens
204 }
205
206 if (!mItemIdByUid.isEmpty()) {
207 mItemIdByUid.clear();
208 // Q_ASSERT(false);
209 }
210 mParentUidToChildrenUid.clear();
211 // m_virtualItems.clear();
212}
213
214Akonadi::Item::List ETMCalendarPrivate::itemsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex, int start, int end)
215{
216 const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1;
218 int row = start;
219 QModelIndex i = model->index(row, 0, parentIndex);
220 while (row <= endRow) {
221 const Akonadi::Item item = itemFromIndex(i);
223 items << item;
224 } else {
225 const QModelIndex childIndex = model->index(0, 0, i);
226 if (childIndex.isValid()) {
227 items << itemsFromModel(model, i);
228 }
229 }
230 ++row;
231 i = i.sibling(row, 0);
232 }
233 return items;
234}
235
236Akonadi::Collection::List ETMCalendarPrivate::collectionsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex, int start, int end)
237{
238 const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1;
239 Akonadi::Collection::List collections;
240 int row = start;
241 QModelIndex i = model->index(row, 0, parentIndex);
242 while (row <= endRow) {
244 if (collection.isValid()) {
245 collections << collection;
246 QModelIndex childIndex = model->index(0, 0, i);
247 if (childIndex.isValid()) {
248 collections << collectionsFromModel(model, i);
249 }
250 }
251 ++row;
252 i = i.sibling(row, 0);
253 }
254 return collections;
255}
256
257Akonadi::Item ETMCalendarPrivate::itemFromIndex(const QModelIndex &idx)
258{
261 return item;
262}
263
264void ETMCalendarPrivate::itemsAdded(const Akonadi::Item::List &items)
265{
266 if (!items.isEmpty()) {
267 for (const Akonadi::Item &item : items) {
268 internalInsert(item);
269 }
270
271 Akonadi::Collection::Id id = items.first().storageCollectionId();
272 if (mPopulatedCollectionIds.contains(id)) {
273 // If the collection isn't populated yet, it will be sent later
274 // Saves some cpu cycles
275 Q_EMIT q->calendarChanged();
276 }
277 }
278}
279
280void ETMCalendarPrivate::itemsRemoved(const Akonadi::Item::List &items)
281{
282 for (const Akonadi::Item &item : items) {
283 internalRemove(item);
284 }
285 Q_EMIT q->calendarChanged();
286}
287
288void ETMCalendarPrivate::onRowsInserted(const QModelIndex &index, int start, int end)
289{
290 const Akonadi::Collection::List collections = collectionsFromModel(mETM.data(), index, start, end);
291
292 for (const Akonadi::Collection &collection : collections) {
293 mCollectionMap[collection.id()] = collection;
294 }
295
296 if (!collections.isEmpty()) {
297 Q_EMIT q->collectionsAdded(collections);
298 }
299}
300
301void ETMCalendarPrivate::onCollectionPopulated(Akonadi::Collection::Id id)
302{
303 mPopulatedCollectionIds.insert(id);
304 Q_EMIT q->calendarChanged();
305 updateLoadingState();
306}
307
308void 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
320void 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 = CollectionUtils::fromIndex(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
334void 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
344void ETMCalendarPrivate::onLayoutChangedInFilteredModel()
345{
346 clear();
347 loadFromETM();
348}
349
350void ETMCalendarPrivate::onModelResetInFilteredModel()
351{
352 clear();
353 loadFromETM();
354}
355
356void 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
375void 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
407void ETMCalendarPrivate::onRowsInsertedInFilteredModel(const QModelIndex &index, int start, int end)
408{
409 itemsAdded(itemsFromModel(mFilteredETM, index, start, end));
410}
411
412void ETMCalendarPrivate::onRowsAboutToBeRemovedInFilteredModel(const QModelIndex &index, int start, int end)
413{
414 itemsRemoved(itemsFromModel(mFilteredETM, index, start, end));
415}
416
417void ETMCalendarPrivate::onFilterChanged()
418{
419 mCalFilterProxyModel->setFilter(q->filter());
420}
421
423 : CalendarBase(new ETMCalendarPrivate(this), parent)
424{
426 d->init();
427}
428
430 : CalendarBase(new ETMCalendarPrivate(this), parent)
431{
433 d->mMimeTypes = mimeTypes;
434 d->init();
435}
436
438 : CalendarBase(new ETMCalendarPrivate(this), parent)
439{
441
443 if (model) {
444 d->mETM = model->weakPointer().toStrongRef();
445 }
446
447 d->init();
448}
449
451 : CalendarBase(new ETMCalendarPrivate(this), parent)
452{
454
455 if (monitor) {
456 QObject::connect(monitor,
458 d,
459 &ETMCalendarPrivate::onCollectionChanged);
460 d->mETM = CalendarModel::create(monitor);
461 d->mETM->setObjectName("ETM"_L1);
462 d->mETM->setListFilter(Akonadi::CollectionFetchScope::Display);
463 }
464
465 d->init();
466}
467
468ETMCalendar::~ETMCalendar() = default;
469
470// TODO: move this up?
472{
473 Q_D(const ETMCalendar);
474 return d->mCollectionMap.value(id);
475}
476
478{
479 return hasRight(item(uid), right);
480}
481
483{
484 // if the users changes the rights, item.parentCollection()
485 // can still have the old rights, so we use call collection()
486 // which returns the updated one
488 return col.rights() & right;
489}
490
492{
493 Q_D(const ETMCalendar);
494 return d->mFilteredETM;
495}
496
498{
499 Q_D(const ETMCalendar);
500 return d->mCheckableProxyModel;
501}
502
503KCalendarCore::Alarm::List ETMCalendar::alarms(const QDateTime &from, const QDateTime &to, bool excludeBlockedAlarms) const
504{
505 Q_D(const ETMCalendar);
508 while (i.hasNext()) {
509 const Akonadi::Item item = i.next().value();
510
511 Akonadi::Collection parentCollection; // must have same lifetime as blockedAttr
512 BlockAlarmsAttribute *blockedAttr = nullptr;
513
514 if (excludeBlockedAlarms) {
515 // take the collection from m_collectionMap, because we need the up-to-date collection attrs
516 parentCollection = d->mCollectionMap.value(item.storageCollectionId());
517 if (parentCollection.isValid() && parentCollection.hasAttribute<BlockAlarmsAttribute>()) {
518 blockedAttr = parentCollection.attribute<BlockAlarmsAttribute>();
519 if (blockedAttr->isEverythingBlocked()) {
520 continue;
521 }
522 }
523 }
524
528 }
529 if (!incidence || incidence->alarms().isEmpty()) {
530 continue;
531 }
532
533 Alarm::List tmpList;
534 if (incidence->recurs()) {
535 appendRecurringAlarms(tmpList, incidence, from, to);
536 } else {
537 appendAlarms(tmpList, incidence, from, to);
538 }
539
540 if (blockedAttr) {
541 tmpList.erase(std::remove_if(tmpList.begin(),
542 tmpList.end(),
543 [blockedAttr](const auto &alarm) {
544 return blockedAttr->isAlarmTypeBlocked(alarm->type());
545 }),
546 tmpList.end());
547 }
548
549 alarmList += tmpList;
550 }
551 return alarmList;
552}
553
555{
556 Q_D(const ETMCalendar);
557 return d->mETM.data();
558}
559
561{
563 if (d->mCollectionFilteringEnabled != enable) {
564 d->mCollectionFilteringEnabled = enable;
565 if (enable) {
566 d->mSelectionProxy->setSourceModel(d->mETM.data());
567 QAbstractItemModel *oldModel = d->mCalFilterProxyModel->sourceModel();
568 d->mCalFilterProxyModel->setSourceModel(d->mSelectionProxy);
570 } else {
571 auto flatner = new KDescendantsProxyModel(this);
572 flatner->setSourceModel(d->mETM.data());
573 d->mCalFilterProxyModel->setSourceModel(flatner);
574 }
575 }
576}
577
579{
580 Q_D(const ETMCalendar);
581 return d->mCollectionFilteringEnabled;
582}
583
584void ETMCalendarPrivate::updateLoadingState()
585{
586 if (!q->entityTreeModel()->isCollectionTreeFetched()) {
587 return q->setIsLoading(true);
588 }
589
590 for (const Akonadi::Collection &collection : std::as_const(mCollectionMap)) {
591 if (!q->entityTreeModel()->isCollectionPopulated(collection.id())) {
592 return q->setIsLoading(true);
593 }
594 }
595
596 q->setIsLoading(false);
597}
598
599#include "moc_etmcalendar.cpp"
600#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.
void calendarSelectionEdited()
Emitted whenever the set selected (checked) calendars was modified by the user.
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)
T qobject_cast(QObject *object)
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 Fri Jul 12 2024 11:56:25 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.