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->addMimeTypeFilter(QStringLiteral("text/calendar"));
131 mCollectionProxyModel->setExcludeVirtualCollections(false);
132 mCollectionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
133 mCollectionProxyModel->setSourceModel(columnFilterProxy);
134
135 // Keep track of selected items.
136 auto selectionModel = new QItemSelectionModel(mCollectionProxyModel);
137 selectionModel->setObjectName("Calendar Selection Model"_L1);
138
139 // Make item selection work by means of checkboxes.
140 mCheckableProxyModel = new CheckableProxyModel(this);
141 mCheckableProxyModel->setSelectionModel(selectionModel);
142 mCheckableProxyModel->setSourceModel(mCollectionProxyModel);
143 mCheckableProxyModel->setObjectName("Add checkboxes"_L1);
144
145 connect(mCheckableProxyModel, &CheckableProxyModel::checkedByUser, q, &ETMCalendar::calendarSelectionEdited);
146
147 mSelectionProxy = new KSelectionProxyModel(selectionModel, /**parent=*/this);
148 mSelectionProxy->setObjectName("Only show items of selected collection"_L1);
149 mSelectionProxy->setFilterBehavior(KSelectionProxyModel::ChildrenOfExactSelection);
150 mSelectionProxy->setSourceModel(mETM.data());
151
152 mCalFilterProxyModel = new CalFilterProxyModel(this);
153 mCalFilterProxyModel->setFilter(q->filter());
154 mCalFilterProxyModel->setSourceModel(mSelectionProxy);
155 mCalFilterProxyModel->setObjectName("KCalendarCore::CalFilter filtering"_L1);
156
157 mCalFilterPartStatusProxyModel = new CalFilterPartStatusProxyModel(this);
158 mCalFilterPartStatusProxyModel->setFilterVirtual(false);
160 blockedStatusList << KCalendarCore::Attendee::NeedsAction;
161 blockedStatusList << KCalendarCore::Attendee::Declined;
162 mCalFilterPartStatusProxyModel->setBlockedStatusList(blockedStatusList);
163 mCalFilterPartStatusProxyModel->setSourceModel(mCalFilterProxyModel);
164 mCalFilterPartStatusProxyModel->setObjectName("PartStatus filtering"_L1);
165
166 mFilteredETM = new Akonadi::EntityMimeTypeFilterModel(this);
167 mFilteredETM->setSourceModel(mCalFilterPartStatusProxyModel);
168 mFilteredETM->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders);
169 mFilteredETM->setSortRole(CalendarModel::SortRole);
170 mFilteredETM->setObjectName("Show headers"_L1);
171
172#ifdef AKONADI_CALENDAR_DEBUG_MODEL
173 QTreeView *view = new QTreeView;
174 view->setModel(mFilteredETM);
175 view->show();
176#endif
177}
178
179ETMCalendarPrivate::~ETMCalendarPrivate() = default;
180
181void ETMCalendarPrivate::loadFromETM()
182{
183 itemsAdded(itemsFromModel(mFilteredETM));
184}
185
186void ETMCalendarPrivate::clear()
187{
188 mCollectionMap.clear();
189 mItemsByCollection.clear();
190
191 Akonadi::Item::List removedItems;
192 removedItems.reserve(mItemById.size());
193 for (auto it = mItemById.cbegin(), end = mItemById.cend(); it != end; ++it) {
194 removedItems.push_back(it.value());
195 }
196
197 itemsRemoved(removedItems);
198
199 if (!mItemById.isEmpty()) {
200 mItemById.clear();
201 // Q_ASSERT(false); // TODO: discover why this happens
202 }
203
204 if (!mItemIdByUid.isEmpty()) {
205 mItemIdByUid.clear();
206 // Q_ASSERT(false);
207 }
208 mParentUidToChildrenUid.clear();
209 // m_virtualItems.clear();
210}
211
212Akonadi::Item::List ETMCalendarPrivate::itemsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex, int start, int end)
213{
214 const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1;
216 int row = start;
217 QModelIndex i = model->index(row, 0, parentIndex);
218 while (row <= endRow) {
219 const Akonadi::Item item = itemFromIndex(i);
221 items << item;
222 } else {
223 const QModelIndex childIndex = model->index(0, 0, i);
224 if (childIndex.isValid()) {
225 items << itemsFromModel(model, i);
226 }
227 }
228 ++row;
229 i = i.sibling(row, 0);
230 }
231 return items;
232}
233
234Akonadi::Collection::List ETMCalendarPrivate::collectionsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex, int start, int end)
235{
236 const int endRow = end >= 0 ? end : model->rowCount(parentIndex) - 1;
237 Akonadi::Collection::List collections;
238 int row = start;
239 QModelIndex i = model->index(row, 0, parentIndex);
240 while (row <= endRow) {
242 if (collection.isValid()) {
243 collections << collection;
244 QModelIndex childIndex = model->index(0, 0, i);
245 if (childIndex.isValid()) {
246 collections << collectionsFromModel(model, i);
247 }
248 }
249 ++row;
250 i = i.sibling(row, 0);
251 }
252 return collections;
253}
254
255Akonadi::Item ETMCalendarPrivate::itemFromIndex(const QModelIndex &idx)
256{
259 return item;
260}
261
262void ETMCalendarPrivate::itemsAdded(const Akonadi::Item::List &items)
263{
264 if (!items.isEmpty()) {
265 for (const Akonadi::Item &item : items) {
266 internalInsert(item);
267 }
268
269 Akonadi::Collection::Id id = items.first().storageCollectionId();
270 if (mPopulatedCollectionIds.contains(id)) {
271 // If the collection isn't populated yet, it will be sent later
272 // Saves some cpu cycles
273 Q_EMIT q->calendarChanged();
274 }
275 }
276}
277
278void ETMCalendarPrivate::itemsRemoved(const Akonadi::Item::List &items)
279{
280 for (const Akonadi::Item &item : items) {
281 internalRemove(item);
282 }
283 Q_EMIT q->calendarChanged();
284}
285
286void ETMCalendarPrivate::onRowsInserted(const QModelIndex &index, int start, int end)
287{
288 const Akonadi::Collection::List collections = collectionsFromModel(mETM.data(), index, start, end);
289
290 for (const Akonadi::Collection &collection : collections) {
291 mCollectionMap[collection.id()] = collection;
292 }
293
294 if (!collections.isEmpty()) {
295 Q_EMIT q->collectionsAdded(collections);
296 }
297}
298
299void ETMCalendarPrivate::onCollectionPopulated(Akonadi::Collection::Id id)
300{
301 mPopulatedCollectionIds.insert(id);
302 Q_EMIT q->calendarChanged();
303 updateLoadingState();
304}
305
306void ETMCalendarPrivate::onRowsRemoved(const QModelIndex &index, int start, int end)
307{
308 const Akonadi::Collection::List collections = collectionsFromModel(mETM.data(), index, start, end);
309 for (const Akonadi::Collection &collection : collections) {
310 mCollectionMap.remove(collection.id());
311 }
312
313 if (!collections.isEmpty()) {
314 Q_EMIT q->collectionsRemoved(collections);
315 }
316}
317
318void ETMCalendarPrivate::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
319{
320 // We only update collections, because items are handled in the filtered model
321 Q_ASSERT(topLeft.row() <= bottomRight.row());
322 const int endRow = bottomRight.row();
323 for (int row = topLeft.row(); row <= endRow; ++row) {
324 const Akonadi::Collection col = CollectionUtils::fromIndex(topLeft.sibling(row, 0));
325 if (col.isValid()) {
326 // Attributes might have changed, store the new collection and discard the old one
327 mCollectionMap.insert(col.id(), col);
328 }
329 }
330}
331
332void ETMCalendarPrivate::onRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
333{
334 // TODO
335 Q_UNUSED(sourceParent)
336 Q_UNUSED(sourceStart)
337 Q_UNUSED(sourceEnd)
338 Q_UNUSED(destinationParent)
339 Q_UNUSED(destinationRow)
340}
341
342void ETMCalendarPrivate::onLayoutChangedInFilteredModel()
343{
344 clear();
345 loadFromETM();
346}
347
348void ETMCalendarPrivate::onModelResetInFilteredModel()
349{
350 clear();
351 loadFromETM();
352}
353
354void ETMCalendarPrivate::onDataChangedInFilteredModel(const QModelIndex &topLeft, const QModelIndex &bottomRight)
355{
356 Q_ASSERT(topLeft.row() <= bottomRight.row());
357 const int endRow = bottomRight.row();
358 QModelIndex i(topLeft);
359 int row = i.row();
360 while (row <= endRow) {
361 const Akonadi::Item item = itemFromIndex(i);
362 if (item.isValid() && item.hasPayload<KCalendarCore::Incidence::Ptr>()) {
363 updateItem(item);
364 }
365
366 ++row;
367 i = i.sibling(row, topLeft.column());
368 }
369
370 Q_EMIT q->calendarChanged();
371}
372
373void ETMCalendarPrivate::updateItem(const Akonadi::Item &item)
374{
375 Incidence::Ptr newIncidence = CalendarUtils::incidence(item);
376 Q_ASSERT(newIncidence);
377 Q_ASSERT(!newIncidence->uid().isEmpty());
378 newIncidence->setCustomProperty("VOLATILE", "AKONADI-ID", QString::number(item.id()));
379 IncidenceBase::Ptr existingIncidence = q->incidence(newIncidence->uid(), newIncidence->recurrenceId());
380
381 if (!existingIncidence && !mItemById.contains(item.id())) {
382 // We don't know about this one because it was discarded, for example because of not having DTSTART
383 return;
384 }
385
386 mItemsByCollection.insert(item.storageCollectionId(), item);
387 Akonadi::Item oldItem = mItemById.value(item.id());
388
389 if (existingIncidence) {
390 // We set the payload so that the internal incidence pointer and the one in mItemById stay the same
391 Akonadi::Item updatedItem = item;
393 mItemById.insert(item.id(), updatedItem); // The item needs updating too, revision changed.
394
395 // Check if RELATED-TO changed, updating parenting information
396 handleParentChanged(newIncidence);
397 *(existingIncidence.data()) = *(newIncidence.data());
398 } else {
399 mItemById.insert(item.id(), item); // The item needs updating too, revision changed.
400 // The item changed it's UID, update our maps, the Google resource changes the UID when we create incidences.
401 handleUidChange(oldItem, item, newIncidence->instanceIdentifier());
402 }
403}
404
405void ETMCalendarPrivate::onRowsInsertedInFilteredModel(const QModelIndex &index, int start, int end)
406{
407 itemsAdded(itemsFromModel(mFilteredETM, index, start, end));
408}
409
410void ETMCalendarPrivate::onRowsAboutToBeRemovedInFilteredModel(const QModelIndex &index, int start, int end)
411{
412 itemsRemoved(itemsFromModel(mFilteredETM, index, start, end));
413}
414
415void ETMCalendarPrivate::onFilterChanged()
416{
417 mCalFilterProxyModel->setFilter(q->filter());
418}
419
421 : CalendarBase(new ETMCalendarPrivate(this), parent)
422{
424 d->init();
425}
426
428 : CalendarBase(new ETMCalendarPrivate(this), parent)
429{
431 d->mMimeTypes = mimeTypes;
432 d->init();
433}
434
436 : CalendarBase(new ETMCalendarPrivate(this), parent)
437{
439
441 if (model) {
442 d->mETM = model->weakPointer().toStrongRef();
443 }
444
445 d->init();
446}
447
449 : CalendarBase(new ETMCalendarPrivate(this), parent)
450{
452
453 if (monitor) {
454 QObject::connect(monitor,
456 d,
457 &ETMCalendarPrivate::onCollectionChanged);
458 d->mETM = CalendarModel::create(monitor);
459 d->mETM->setObjectName("ETM"_L1);
460 d->mETM->setListFilter(Akonadi::CollectionFetchScope::Display);
461 }
462
463 d->init();
464}
465
466ETMCalendar::~ETMCalendar() = default;
467
468// TODO: move this up?
470{
471 Q_D(const ETMCalendar);
472 return d->mCollectionMap.value(id);
473}
474
476{
477 return hasRight(item(uid), right);
478}
479
481{
482 // if the users changes the rights, item.parentCollection()
483 // can still have the old rights, so we use call collection()
484 // which returns the updated one
486 return col.rights() & right;
487}
488
490{
491 Q_D(const ETMCalendar);
492 return d->mFilteredETM;
493}
494
496{
497 Q_D(const ETMCalendar);
498 return d->mCheckableProxyModel;
499}
500
501KCalendarCore::Alarm::List ETMCalendar::alarms(const QDateTime &from, const QDateTime &to, bool excludeBlockedAlarms) const
502{
503 Q_D(const ETMCalendar);
506 while (i.hasNext()) {
507 const Akonadi::Item item = i.next().value();
508
509 Akonadi::Collection parentCollection; // must have same lifetime as blockedAttr
510 BlockAlarmsAttribute *blockedAttr = nullptr;
511
512 if (excludeBlockedAlarms) {
513 // take the collection from m_collectionMap, because we need the up-to-date collection attrs
514 parentCollection = d->mCollectionMap.value(item.storageCollectionId());
515 if (parentCollection.isValid() && parentCollection.hasAttribute<BlockAlarmsAttribute>()) {
516 blockedAttr = parentCollection.attribute<BlockAlarmsAttribute>();
517 if (blockedAttr->isEverythingBlocked()) {
518 continue;
519 }
520 }
521 }
522
526 }
527 if (!incidence || incidence->alarms().isEmpty()) {
528 continue;
529 }
530
531 Alarm::List tmpList;
532 if (incidence->recurs()) {
533 appendRecurringAlarms(tmpList, incidence, from, to);
534 } else {
535 appendAlarms(tmpList, incidence, from, to);
536 }
537
538 if (blockedAttr) {
539 tmpList.erase(std::remove_if(tmpList.begin(),
540 tmpList.end(),
541 [blockedAttr](const auto &alarm) {
542 return blockedAttr->isAlarmTypeBlocked(alarm->type());
543 }),
544 tmpList.end());
545 }
546
547 alarmList += tmpList;
548 }
549 return alarmList;
550}
551
553{
554 Q_D(const ETMCalendar);
555 return d->mETM.data();
556}
557
559{
561 if (d->mCollectionFilteringEnabled != enable) {
562 d->mCollectionFilteringEnabled = enable;
563 if (enable) {
564 d->mSelectionProxy->setSourceModel(d->mETM.data());
565 QAbstractItemModel *oldModel = d->mCalFilterProxyModel->sourceModel();
566 d->mCalFilterProxyModel->setSourceModel(d->mSelectionProxy);
568 } else {
569 auto flatner = new KDescendantsProxyModel(this);
570 flatner->setSourceModel(d->mETM.data());
571 d->mCalFilterProxyModel->setSourceModel(flatner);
572 }
573 }
574}
575
577{
578 Q_D(const ETMCalendar);
579 return d->mCollectionFilteringEnabled;
580}
581
582void ETMCalendarPrivate::updateLoadingState()
583{
584 if (!q->entityTreeModel()->isCollectionTreeFetched()) {
585 return q->setIsLoading(true);
586 }
587
588 for (const Akonadi::Collection &collection : std::as_const(mCollectionMap)) {
589 if (!q->entityTreeModel()->isCollectionPopulated(collection.id())) {
590 return q->setIsLoading(true);
591 }
592 }
593
594 q->setIsLoading(false);
595}
596
597#include "moc_etmcalendar.cpp"
598#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)
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 Oct 11 2024 12:15:47 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.