Akonadi Calendar

todomodel.cpp
1/*
2 SPDX-FileCopyrightText: 2008 Thomas Thrainer <tom_t@gmx.at>
3 SPDX-FileCopyrightText: 2012 Sérgio Martins <iamsergio@gmail.com>
4
5 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
6*/
7
8#include "todomodel.h"
9using namespace Qt::Literals::StringLiterals;
10
11#include <KCalendarCore/Attachment>
12#include <KCalendarCore/Event>
13#include <KEmailAddress>
14#include <KLocalizedString>
15
16#include <Akonadi/CalendarUtils>
17#include <Akonadi/IncidenceTreeModel>
18#include <Akonadi/TagCache>
19
20#include <KCalUtils/DndFactory>
21#include <KCalUtils/ICalDrag>
22#include <KCalUtils/IncidenceFormatter>
23#include <KCalUtils/VCalDrag>
24
25#include "akonadicalendar_debug.h"
26
27#include <QIcon>
28#include <QMimeData>
29
30namespace Akonadi
31{
32class TodoModelPrivate
33{
34public:
35 TodoModelPrivate(TodoModel *qq);
36
38 {
39 if (!mEtm) {
40 auto *model = q->sourceModel();
41 while (model) {
42 if (auto *proxy = qobject_cast<QAbstractProxyModel *>(model); proxy) {
43 model = proxy->sourceModel();
44 } else if (auto *etm = qobject_cast<Akonadi::EntityTreeModel *>(model); etm) {
45 mEtm = etm;
46 break;
47 } else {
48 return nullptr;
49 }
50 }
51 }
52
53 return mEtm;
54 }
55
56 // TODO: O(N) complexity, see if the profiler complains about this
57 Akonadi::Item findItemByUid(const QString &uid, const QModelIndex &parent) const;
58
59 Akonadi::IncidenceChanger *m_changer = nullptr;
60
61 void onDataChanged(const QModelIndex &begin, const QModelIndex &end);
62
63 TodoModel *const q;
64 Akonadi::EntityTreeModel *mEtm = nullptr;
65};
66}
67
68using namespace Akonadi;
69
70TodoModelPrivate::TodoModelPrivate(TodoModel *qq)
71 : q(qq)
72{
73}
74
75Akonadi::Item TodoModelPrivate::findItemByUid(const QString &uid, const QModelIndex &parent) const
76{
77 Q_ASSERT(!uid.isEmpty());
78 auto treeModel = qobject_cast<Akonadi::IncidenceTreeModel *>(q->sourceModel());
79 if (treeModel) { // O(1) Shortcut
80 return treeModel->item(uid);
81 }
82
83 Akonadi::Item item;
84 const int count = q->rowCount(parent);
85 for (int i = 0; i < count; ++i) {
86 const QModelIndex currentIndex = q->index(i, 0, parent);
87 Q_ASSERT(currentIndex.isValid());
88 item = q->data(currentIndex, Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
89 if (item.isValid()) {
90 return item;
91 } else {
92 item = findItemByUid(uid, currentIndex);
93 if (item.isValid()) {
94 return item;
95 }
96 }
97 }
98
99 return item;
100}
101
102void TodoModelPrivate::onDataChanged(const QModelIndex &begin, const QModelIndex &end)
103{
104 Q_ASSERT(begin.isValid());
105 Q_ASSERT(end.isValid());
106 const QModelIndex proxyBegin = q->mapFromSource(begin);
107 Q_ASSERT(proxyBegin.column() == 0);
108 const QModelIndex proxyEnd = q->mapFromSource(end);
109 Q_EMIT q->dataChanged(proxyBegin, proxyEnd.sibling(proxyEnd.row(), TodoModel::ColumnCount - 1));
110}
111
112TodoModel::TodoModel(QObject *parent)
114 , d(new TodoModelPrivate(this))
115{
116 setObjectName("TodoModel"_L1);
117}
118
119TodoModel::~TodoModel() = default;
120
121QVariant TodoModel::data(const QModelIndex &index, int role) const
122{
123 Q_ASSERT(index.isValid());
124 if (!index.isValid()) {
125 return {};
126 }
127
128 const QModelIndex sourceIndex = mapToSource(index.sibling(index.row(), 0));
129 if (!sourceIndex.isValid()) {
130 return {};
131 }
132 Q_ASSERT(sourceIndex.isValid());
133 const auto item = sourceIndex.data(Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
134 if (!item.isValid()) {
135 qCWarning(AKONADICALENDAR_LOG) << "Invalid index: " << sourceIndex;
136 // Q_ASSERT( false );
137 return {};
138 }
140 if (!todo) {
141 qCCritical(AKONADICALENDAR_LOG) << "item.hasPayload()" << item.hasPayload();
144 if (incidence) {
145 qCCritical(AKONADICALENDAR_LOG) << "It's actually " << incidence->type();
146 }
147 }
148
149 Q_ASSERT(!"There's no to-do.");
150 return {};
151 }
152
153 switch (role) {
154 case SummaryRole:
155 return todo->summary();
156 case RecurRole:
157 if (todo->recurs()) {
158 if (todo->hasRecurrenceId()) {
159 return i18nc("yes, an exception to a recurring to-do", "Exception");
160 } else {
161 return i18nc("yes, recurring to-do", "Yes");
162 }
163 } else {
164 return i18nc("no, not a recurring to-do", "No");
165 }
166 case PriorityRole:
167 if (todo->priority() == 0) {
168 return QStringLiteral("--");
169 }
170 return todo->priority();
171 case PercentRole:
172 return todo->percentComplete();
173 case StartDateRole:
174 return todo->hasStartDate() ? QLocale().toString(todo->dtStart().toLocalTime().date(), QLocale::ShortFormat) : QString();
175 case DueDateRole:
176 return todo->hasDueDate() ? QLocale().toString(todo->dtDue().toLocalTime().date(), QLocale::ShortFormat) : QString();
177 case CategoriesRole:
178 return todo->categories().join(i18nc("delimiter for joining category/tag names", ","));
179 case DescriptionRole:
180 return todo->description();
181 case CalendarRole:
183 default:
184 break; // column based model handling
185 }
186
187 if (role == Qt::DisplayRole) {
188 switch (index.column()) {
189 case SummaryColumn:
190 return QVariant(todo->summary());
191 case RecurColumn:
192 if (todo->recurs()) {
193 if (todo->hasRecurrenceId()) {
194 return i18nc("yes, an exception to a recurring to-do", "Exception");
195 } else {
196 return i18nc("yes, recurring to-do", "Yes");
197 }
198 } else {
199 return i18nc("no, not a recurring to-do", "No");
200 }
201 case PriorityColumn:
202 if (todo->priority() == 0) {
203 return QVariant(QStringLiteral("--"));
204 }
205 return {todo->priority()};
206 case PercentColumn:
207 return {todo->percentComplete()};
208 case StartDateColumn:
209 return todo->hasStartDate() ? QLocale().toString(todo->dtStart().toLocalTime().date(), QLocale::ShortFormat) : QVariant(QString());
210 case DueDateColumn:
211 return todo->hasDueDate() ? QLocale().toString(todo->dtDue().toLocalTime().date(), QLocale::ShortFormat) : QVariant(QString());
212 case CompletedDateColumn:
213 return todo->hasCompletedDate() ? QLocale().toString(todo->completed().toLocalTime().date(), QLocale::ShortFormat) : QVariant(QString());
214 case CategoriesColumn: {
215 QString categories = todo->categories().join(i18nc("delimiter for joining category/tag names", ","));
216 return QVariant(categories);
217 }
218 case DescriptionColumn:
219 return QVariant(todo->description());
220 case CalendarColumn:
222 }
223 return {};
224 }
225
226 if (role == Qt::EditRole) {
227 switch (index.column()) {
228 case SummaryColumn:
229 return QVariant(todo->summary());
230 case RecurColumn:
231 return {todo->recurs()};
232 case PriorityColumn:
233 return {todo->priority()};
234 case PercentColumn:
235 return {todo->percentComplete()};
236 case StartDateColumn:
237 return QVariant(todo->dtStart().date());
238 case DueDateColumn:
239 return QVariant(todo->dtDue().date());
240 case CompletedDateColumn:
241 return QVariant(todo->completed().date());
242 case CategoriesColumn:
243 return QVariant(todo->categories());
244 case DescriptionColumn:
245 return QVariant(todo->description());
246 case CalendarColumn:
248 }
249 return {};
250 }
251
252 // indicate if a row is checked (=completed) only in the first column
253 if (role == Qt::CheckStateRole && index.column() == 0) {
254 if (hasChildren(index) && !index.parent().isValid()) {
255 return {};
256 }
257
258 if (todo->isCompleted()) {
259 return {Qt::Checked};
260 } else {
261 return {Qt::Unchecked};
262 }
263 }
264
265 // icon for recurring todos
266 // It's in the summary column so you don't accidentally click
267 // the checkbox ( which increments the next occurrence date ).
268 // category colour
269 if (role == Qt::DecorationRole && index.column() == SummaryColumn) {
270 if (todo->recurs()) {
271 return QVariant(QIcon::fromTheme(QStringLiteral("task-recurring")));
272 }
273 const QStringList categories = todo->categories();
274 return categories.isEmpty() ? QVariant() : QVariant(Akonadi::TagCache::instance()->tagColor(categories.first()));
275 } else if (role == Qt::DecorationRole) {
276 return {};
277 }
278
279 if (role == TodoRole) {
280 return QVariant::fromValue(item);
281 }
282
283 if (role == TodoPtrRole) {
284 return QVariant::fromValue(todo);
285 }
286
287 if (role == IsRichTextRole) {
288 if (index.column() == SummaryColumn) {
289 return {todo->summaryIsRich()};
290 } else if (index.column() == DescriptionColumn) {
291 return {todo->descriptionIsRich()};
292 } else {
293 return {};
294 }
295 }
296
297 if (role == Qt::TextAlignmentRole) {
298 switch (index.column()) {
299 // If you change this, change headerData() too.
300 case RecurColumn:
301 case PriorityColumn:
302 case PercentColumn:
303 case StartDateColumn:
304 case DueDateColumn:
305 case CategoriesColumn:
306 case CalendarColumn:
308 }
310 }
311
312 if (sourceModel()) {
313 return sourceModel()->data(mapToSource(index.sibling(index.row(), 0)), role);
314 }
315
316 return {};
317}
318
319QVariant TodoModel::extraColumnData(const QModelIndex &parent, int row, int extraColumn, int role) const
320{
321 // we customize all columns, not just the extra ones, and thus do all that in ::data()
322 Q_UNUSED(parent);
323 Q_UNUSED(row);
324 Q_UNUSED(extraColumn);
325 Q_UNUSED(role);
326 return {};
327}
328
329bool TodoModel::setData(const QModelIndex &index, const QVariant &value, int role)
330{
331 Q_ASSERT(index.isValid());
332 if (!d->m_changer) {
333 return false;
334 }
335 const QVariant oldValue = data(index, role);
336
337 if (oldValue == value) {
338 // Nothing changed, the user used one of the QStyledDelegate's editors but seted the old value
339 // Lets just skip this then and avoid a roundtrip to akonadi, and avoid sending invitations
340 return true;
341 }
342
345
346 if (!item.isValid() || !todo) {
347 qCWarning(AKONADICALENDAR_LOG) << "TodoModel::setData() called, bug item is invalid or doesn't have payload";
348 Q_ASSERT(false);
349 return false;
350 }
351
352 const auto parentCol = Akonadi::EntityTreeModel::updatedCollection(d->etm(), item.parentCollection());
353 if (parentCol.rights() & Akonadi::Collection::CanChangeItem) {
354 KCalendarCore::Todo::Ptr oldTodo(todo->clone());
355 if (role == Qt::CheckStateRole && index.column() == 0) {
356 const bool checked = static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked;
357 if (checked) {
358 todo->setCompleted(QDateTime::currentDateTimeUtc()); // Because it calls Todo::recurTodo()
359 } else {
360 todo->setCompleted(false);
361 }
362 }
363
364 if (role == Qt::EditRole) {
365 switch (index.column()) {
366 case SummaryColumn:
367 if (!value.toString().isEmpty()) {
368 todo->setSummary(value.toString());
369 }
370 break;
371 case PriorityColumn:
372 todo->setPriority(value.toInt());
373 break;
374 case PercentColumn:
375 todo->setPercentComplete(value.toInt());
376 break;
377 case StartDateColumn: {
378 QDateTime tmp = todo->dtStart();
379 tmp.setDate(value.toDate());
380 todo->setDtStart(tmp);
381 break;
382 }
383 case DueDateColumn: {
384 QDateTime tmp = todo->dtDue();
385 tmp.setDate(value.toDate());
386 todo->setDtDue(tmp);
387 break;
388 }
389 case CategoriesColumn:
390 todo->setCategories(value.toStringList());
391 break;
392 case DescriptionColumn:
393 todo->setDescription(value.toString());
394 break;
395 }
396 }
397
398 if (!todo->dirtyFields().isEmpty()) {
399 d->m_changer->modifyIncidence(item, oldTodo);
400 // modifyIncidence will eventually call the view's
401 // changeIncidenceDisplay method, which in turn
402 // will call processChange. processChange will then emit
403 // dataChanged to the view, so we don't have to
404 // do it here
405 }
406
407 return true;
408 } else {
409 if (!(role == Qt::CheckStateRole && index.column() == 0)) {
410 // KOHelper::showSaveIncidenceErrorMsg( 0, todo ); //TODO pass parent
411 qCCritical(AKONADICALENDAR_LOG) << "Unable to modify incidence";
412 }
413 return false;
414 }
415}
416
417int TodoModel::columnCount(const QModelIndex &) const
418{
419 return ColumnCount;
420}
421
422void TodoModel::setSourceModel(QAbstractItemModel *model)
423{
424 if (model == sourceModel()) {
425 return;
426 }
427
429
430 if (sourceModel()) {
432 }
433
435
436 if (sourceModel()) {
437 connect(sourceModel(), &QAbstractItemModel::dataChanged, this, [this](const auto &begin, const auto &end) {
438 d->onDataChanged(begin, end);
439 });
440 }
441
443}
444
445void TodoModel::setIncidenceChanger(Akonadi::IncidenceChanger *changer)
446{
447 d->m_changer = changer;
448}
449
450QVariant TodoModel::headerData(int column, Qt::Orientation orientation, int role) const
451{
452 if (orientation != Qt::Horizontal) {
453 return {};
454 }
455
456 if (role == Qt::DisplayRole) {
457 switch (column) {
458 case SummaryColumn:
459 return QVariant(i18n("Summary"));
460 case RecurColumn:
461 return QVariant(i18n("Recurs"));
462 case PriorityColumn:
463 return QVariant(i18n("Priority"));
464 case PercentColumn:
465 return QVariant(i18nc("@title:column percent complete", "Complete"));
466 case StartDateColumn:
467 return QVariant(i18n("Start Date"));
468 case DueDateColumn:
469 return QVariant(i18n("Due Date"));
470 case CompletedDateColumn:
471 return QVariant(i18nc("@title:column date completed", "Completed"));
472 case CategoriesColumn:
473 return QVariant(i18n("Tags"));
474 case DescriptionColumn:
475 return QVariant(i18n("Description"));
476 case CalendarColumn:
477 return QVariant(i18n("Calendar"));
478 }
479 }
480
481 if (role == Qt::TextAlignmentRole) {
482 switch (column) {
483 // If you change this, change data() too.
484 case RecurColumn:
485 case PriorityColumn:
486 case PercentColumn:
487 case StartDateColumn:
488 case DueDateColumn:
489 case CategoriesColumn:
490 case CalendarColumn:
491 return {Qt::AlignHCenter};
492 }
493 return {};
494 }
495 return {};
496}
497
498void TodoModel::setCalendar(const Akonadi::ETMCalendar::Ptr &calendar)
499{
500 Q_UNUSED(calendar);
501 // Deprecated, no longer does anything
502}
503
504Qt::DropActions TodoModel::supportedDropActions() const
505{
506 // Qt::CopyAction not supported yet
507 return Qt::MoveAction;
508}
509
510QStringList TodoModel::mimeTypes() const
511{
512 static QStringList list;
513 if (list.isEmpty()) {
515 }
516 return list;
517}
518
519QMimeData *TodoModel::mimeData(const QModelIndexList &indexes) const
520{
522 for (const QModelIndex &index : indexes) {
523 const auto item = this->data(index, Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
524 if (item.isValid() && !items.contains(item)) {
525 items.push_back(item);
526 }
527 }
529}
530
531bool TodoModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
532{
533 Q_UNUSED(row)
534 Q_UNUSED(column)
535
536 if (action != Qt::MoveAction) {
537 qCWarning(AKONADICALENDAR_LOG) << "No action other than MoveAction currently supported!"; // TODO
538 return false;
539 }
540
541 if (d->m_changer && (KCalUtils::ICalDrag::canDecode(data) || KCalUtils::VCalDrag::canDecode(data))) {
542 // DndFactory only needs a valid calendar for drag event, not for drop event.
544 KCalendarCore::Todo::Ptr t = dndFactory.createDropTodo(data);
545 KCalendarCore::Event::Ptr e = dndFactory.createDropEvent(data);
546
547 if (t) {
548 // we don't want to change the created todo, but the one which is already
549 // stored in our calendar / tree
550 const Akonadi::Item item = d->findItemByUid(t->uid(), QModelIndex());
553 if (parent.isValid()) {
554 const auto parentItem = this->data(parent, Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
555 if (parentItem.isValid()) {
556 destTodo = Akonadi::CalendarUtils::todo(parentItem);
557 }
558
559 auto tmpParent = parent;
560 while (tmpParent.isValid()) {
561 const auto parentItem = this->data(parent, Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
562 if (!parentItem.isValid()) {
563 break;
564 }
565 const auto parentTodo = Akonadi::CalendarUtils::todo(parentItem);
566 if (!parentTodo) {
567 break;
568 }
569
570 if (parentTodo->uid() == todo->uid()) { // correct, don't use instanceIdentifier() here
572 return false;
573 }
574
575 tmpParent = tmpParent.parent();
576 }
577 }
578
579 if (!destTodo || !destTodo->hasRecurrenceId()) {
581 // destTodo is empty when we drag a to-do out of a relationship
582 todo->setRelatedTo(destTodo ? destTodo->uid() : QString());
583 d->m_changer->modifyIncidence(item, oldTodo);
584
585 // again, no need to Q_EMIT dataChanged, that's done by processChange
586 return true;
587 } else {
588 qCDebug(AKONADICALENDAR_LOG) << "Todo's with recurring id can't have child todos yet.";
589 return false;
590 }
591 } else if (e) {
592 // TODO: Implement dropping an event onto a to-do: Generate a relationship to the event!
593 } else {
594 if (!parent.isValid()) {
595 // TODO we should create a new todo with the data in the drop object
596 qCDebug(AKONADICALENDAR_LOG) << "TODO: Create a new todo with the given data";
597 return false;
598 }
599
600 const auto parentItem = this->data(parent, Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
602
603 if (data->hasText()) {
604 QString text = data->text();
605
606 KCalendarCore::Todo::Ptr oldTodo = KCalendarCore::Todo::Ptr(destTodo->clone());
607
608 if (text.startsWith("file:"_L1)) {
609 destTodo->addAttachment(KCalendarCore::Attachment(text));
610 } else {
612 for (QStringList::ConstIterator it = emails.constBegin(); it != emails.constEnd(); ++it) {
614 QString email;
615 QString comment;
616 if (KEmailAddress::splitAddress(*it, name, email, comment) == KEmailAddress::AddressOk) {
617 destTodo->addAttendee(KCalendarCore::Attendee(name, email));
618 }
619 }
620 }
621 d->m_changer->modifyIncidence(parentItem, oldTodo);
622 return true;
623 }
624 }
625 }
626
627 return false;
628}
629
630Qt::ItemFlags TodoModel::flags(const QModelIndex &index) const
631{
632 if (!index.isValid()) {
633 return Qt::NoItemFlags;
634 }
635
637
638 const auto item = data(index, Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
639
640 if (!item.isValid()) {
641 Q_ASSERT(mapToSource(index).isValid());
642 qCWarning(AKONADICALENDAR_LOG) << "Item is invalid " << index;
643 Q_ASSERT(false);
644 return Qt::NoItemFlags;
645 }
646
648
650
651 const auto parentCol = Akonadi::EntityTreeModel::updatedCollection(d->etm(), item.parentCollection());
652 if (parentCol.rights() & Akonadi::Collection::CanChangeItem) {
653 // the following columns are editable:
654 switch (index.column()) {
655 case SummaryColumn:
656 case PriorityColumn:
657 case PercentColumn:
658 case StartDateColumn:
659 case DueDateColumn:
660 case CategoriesColumn:
661 ret |= Qt::ItemIsEditable;
662 break;
663 case DescriptionColumn:
664 if (!todo->descriptionIsRich()) {
665 ret |= Qt::ItemIsEditable;
666 }
667 break;
668 }
669 }
670
671 if (index.column() == 0) {
672 // whole rows should have checkboxes, so append the flag for the
673 // first item of every row only. Also, only the first item of every
674 // row should be used as a target for a drag and drop operation.
676 }
677 return ret;
678}
679
680QHash<int, QByteArray> TodoModel::roleNames() const
681{
682 return {
683 {SummaryRole, QByteArrayLiteral("summary")},
684 {RecurRole, QByteArrayLiteral("recur")},
685 {PriorityRole, QByteArrayLiteral("priority")},
686 {PercentRole, QByteArrayLiteral("percent")},
687 {StartDateRole, QByteArrayLiteral("startDate")},
688 {DueDateRole, QByteArrayLiteral("dueDate")},
689 {CategoriesRole, QByteArrayLiteral("categories")},
690 {DescriptionRole, QByteArrayLiteral("description")},
691 {CalendarRole, QByteArrayLiteral("calendar")},
692 {Qt::CheckStateRole, QByteArrayLiteral("checked")},
693 };
694}
695
696#include "moc_todomodel.cpp"
static Collection updatedCollection(const QAbstractItemModel *model, qint64 collectionId)
Collection & parentCollection()
bool hasPayload() const
T payload() const
bool isValid() const
Expands an IncidenceTreeModel by additional columns for showing todos.
Definition todomodel.h:31
void dropOnSelfRejected()
Emitted when dropMimeData() rejected a drop on the same item or any of its children.
QSharedPointer< Todo > Ptr
void setSourceModel(QAbstractItemModel *model) override
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
bool hasChildren(const QModelIndex &index) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
KCODECS_EXPORT QStringList splitAddressList(const QString &aStr)
KCODECS_EXPORT EmailParseResult splitAddress(const QByteArray &address, QByteArray &displayName, QByteArray &addrSpec, QByteArray &comment)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
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.
AKONADI_CALENDAR_EXPORT KCalendarCore::Todo::Ptr todo(const Akonadi::Item &item)
Returns the todo from an Akonadi item, or a null pointer if the item has no such payload.
AKONADI_CALENDAR_EXPORT QString displayName(Akonadi::ETMCalendar *calendar, const Akonadi::Collection &collection)
Returns a suitable display name for the calendar (or calendar folder) collection.
AKONADI_CALENDAR_EXPORT QMimeData * createMimeData(const Akonadi::Item::List &items)
Creates a MIME data object for dragging Akonadi items containing calendar incidences.
FreeBusyManager::Singleton.
KCALUTILS_EXPORT QString mimeType()
KCALUTILS_EXPORT bool canDecode(const QMimeData *)
KCALUTILS_EXPORT QString mimeType()
KCALUTILS_EXPORT bool canDecode(const QMimeData *)
QString name(GameStandardAction id)
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
bool isValid(QStringView ifopt)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
const QList< QKeySequence > & begin()
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
QDateTime currentDateTimeUtc()
void setDate(QDate date)
QIcon fromTheme(const QString &name)
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const const override
virtual int rowCount(const QModelIndex &parent) const const override
const_iterator constBegin() const const
const_iterator constEnd() const const
bool contains(const AT &value) const const
bool isEmpty() const const
void push_back(parameter_type value)
QString toString(QDate date, FormatType format) const const
bool hasText() const const
QString text() const const
int column() const const
QVariant data(int role) const const
bool isValid() const const
QModelIndex parent() const const
int row() const const
QModelIndex sibling(int row, int column) const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QObject * parent() const const
bool isEmpty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
AlignHCenter
typedef DropActions
DisplayRole
typedef ItemFlags
Orientation
QVariant fromValue(T &&value)
QDate toDate() const const
int toInt(bool *ok) const const
QString toString() const const
QStringList toStringList() const const
T value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:37:41 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.