Eventviews

agendaitem.cpp
1/*
2 SPDX-FileCopyrightText: 2000, 2001, 2003 Cornelius Schumacher <schumacher@kde.org>
3 SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
4
5 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
6*/
7#include "agendaitem.h"
8#include "eventview.h"
9#include "helper.h"
10
11#include "prefs.h"
12#include "prefs_base.h" // for enums
13
14#include <CalendarSupport/KCalPrefs>
15#include <CalendarSupport/Utils>
16
17#include <Akonadi/TagCache>
18
19#include <KContacts/VCardDrag>
20
21#include <KCalUtils/ICalDrag>
22#include <KCalUtils/IncidenceFormatter>
23#include <KCalUtils/VCalDrag>
24
25#include <KEmailAddress>
26
27#include <KLocalizedString>
28#include <KMessageBox>
29#include <KWordWrap>
30
31#include <QDragEnterEvent>
32#include <QLocale>
33#include <QMimeData>
34#include <QPainter>
35#include <QPainterPath>
36#include <QPixmapCache>
37#include <QToolTip>
38
39using namespace KCalendarCore;
40using namespace EventViews;
41
42//-----------------------------------------------------------------------------
43
44QPixmap *AgendaItem::alarmPxmp = nullptr;
45QPixmap *AgendaItem::recurPxmp = nullptr;
46QPixmap *AgendaItem::readonlyPxmp = nullptr;
47QPixmap *AgendaItem::replyPxmp = nullptr;
48QPixmap *AgendaItem::groupPxmp = nullptr;
49QPixmap *AgendaItem::groupPxmpTent = nullptr;
50QPixmap *AgendaItem::organizerPxmp = nullptr;
51QPixmap *AgendaItem::eventPxmp = nullptr;
52
53//-----------------------------------------------------------------------------
54
55AgendaItem::AgendaItem(EventView *eventView,
56 const MultiViewCalendar::Ptr &calendar,
58 int itemPos,
59 int itemCount,
60 const QDateTime &qd,
61 bool isSelected,
62 QWidget *parent)
63 : QWidget(parent)
64 , mEventView(eventView)
65 , mCalendar(calendar)
66 , mIncidence(item)
67 , mOccurrenceDateTime(qd)
68 , mSelected(isSelected)
69 , mSpecialEvent(false)
70{
71 if (!mIncidence) {
72 mValid = false;
73 return;
74 }
75
76 mIncidence = Incidence::Ptr(mIncidence->clone());
77 if (mIncidence->customProperty("KABC", "BIRTHDAY") == QLatin1StringView("YES")
78 || mIncidence->customProperty("KABC", "ANNIVERSARY") == QLatin1StringView("YES")) {
79 const int years = EventViews::yearDiff(mIncidence->dtStart().date(), qd.toLocalTime().date());
80 if (years > 0) {
81 mIncidence->setReadOnly(false);
82 mIncidence->setSummary(i18np("%2 (1 year)", "%2 (%1 years)", years, mIncidence->summary()));
83 mIncidence->setReadOnly(true);
84 mCloned = true;
85 }
86 }
87
88 mLabelText = mIncidence->summary();
89 mIconAlarm = false;
90 mIconRecur = false;
91 mIconReadonly = false;
92 mIconReply = false;
93 mIconGroup = false;
94 mIconGroupTent = false;
95 mIconOrganizer = false;
96 mMultiItemInfo = nullptr;
97 mStartMoveInfo = nullptr;
98
99 mItemPos = itemPos;
100 mItemCount = itemCount;
101
102 QPalette pal = palette();
104 setPalette(pal);
105
106 setCellXY(0, 0, 1);
107 setCellXRight(0);
108 setMouseTracking(true);
109 mResourceColor = QColor();
110 updateIcons();
111
112 setAcceptDrops(true);
113}
114
115AgendaItem::~AgendaItem() = default;
116
117void AgendaItem::updateIcons()
118{
119 if (!mValid) {
120 return;
121 }
122 mIconReadonly = mIncidence->isReadOnly();
123 mIconRecur = mIncidence->recurs() || mIncidence->hasRecurrenceId();
124 mIconAlarm = mIncidence->hasEnabledAlarms();
125 if (mIncidence->attendeeCount() > 1) {
126 if (mEventView->kcalPreferences()->thatIsMe(mIncidence->organizer().email())) {
127 mIconReply = false;
128 mIconGroup = false;
129 mIconGroupTent = false;
130 mIconOrganizer = true;
131 } else {
132 KCalendarCore::Attendee me = mIncidence->attendeeByMails(mEventView->kcalPreferences()->allEmails());
133
134 if (!me.isNull()) {
136 mIconReply = true;
137 mIconGroup = false;
138 mIconGroupTent = false;
139 mIconOrganizer = false;
140 } else if (me.status() == KCalendarCore::Attendee::Tentative) {
141 mIconReply = false;
142 mIconGroup = false;
143 mIconGroupTent = true;
144 mIconOrganizer = false;
145 } else {
146 mIconReply = false;
147 mIconGroup = true;
148 mIconGroupTent = false;
149 mIconOrganizer = false;
150 }
151 } else {
152 mIconReply = false;
153 mIconGroup = true;
154 mIconGroupTent = false;
155 mIconOrganizer = false;
156 }
157 }
158 }
159 update();
160}
161
162void AgendaItem::select(bool selected)
163{
164 if (mSelected != selected) {
165 mSelected = selected;
166 update();
167 }
168}
169
170bool AgendaItem::dissociateFromMultiItem()
171{
172 if (!isMultiItem()) {
173 return false;
174 }
175
176 AgendaItem::QPtr firstItem = firstMultiItem();
177 if (firstItem == this) {
178 firstItem = nextMultiItem();
179 }
180
181 AgendaItem::QPtr lastItem = lastMultiItem();
182 if (lastItem == this) {
183 lastItem = prevMultiItem();
184 }
185
186 AgendaItem::QPtr prevItem = prevMultiItem();
187 AgendaItem::QPtr nextItem = nextMultiItem();
188
189 if (prevItem) {
190 prevItem->setMultiItem(firstItem, prevItem->prevMultiItem(), nextItem, lastItem);
191 }
192 if (nextItem) {
193 nextItem->setMultiItem(firstItem, prevItem, nextItem->prevMultiItem(), lastItem);
194 }
195 delete mMultiItemInfo;
196 mMultiItemInfo = nullptr;
197 return true;
198}
199
200void AgendaItem::setIncidence(const KCalendarCore::Incidence::Ptr &incidence)
201{
202 mValid = false;
203 if (incidence) {
204 mValid = true;
205 mIncidence = incidence;
206 mLabelText = mIncidence->summary();
207 updateIcons();
208 }
209}
210
211/*
212 Return height of item in units of agenda cells
213*/
214int AgendaItem::cellHeight() const
215{
216 return mCellYBottom - mCellYTop + 1;
217}
218
219/*
220 Return height of item in units of agenda cells
221*/
222int AgendaItem::cellWidth() const
223{
224 return mCellXRight - mCellXLeft + 1;
225}
226
227void AgendaItem::setOccurrenceDateTime(const QDateTime &qd)
228{
229 mOccurrenceDateTime = qd;
230}
231
232QDate AgendaItem::occurrenceDate() const
233{
234 return mOccurrenceDateTime.toLocalTime().date();
235}
236
237void AgendaItem::setCellXY(int X, int YTop, int YBottom)
238{
239 mCellXLeft = X;
240 mCellYTop = YTop;
241 mCellYBottom = YBottom;
242}
243
244void AgendaItem::setCellXRight(int XRight)
245{
246 mCellXRight = XRight;
247}
248
249void AgendaItem::setCellX(int XLeft, int XRight)
250{
251 mCellXLeft = XLeft;
252 mCellXRight = XRight;
253}
254
255void AgendaItem::setCellY(int YTop, int YBottom)
256{
257 mCellYTop = YTop;
258 mCellYBottom = YBottom;
259}
260
261void AgendaItem::setMultiItem(const AgendaItem::QPtr &first, const AgendaItem::QPtr &prev, const AgendaItem::QPtr &next, const AgendaItem::QPtr &last)
262{
263 if (!mMultiItemInfo) {
264 mMultiItemInfo = new MultiItemInfo;
265 }
266 mMultiItemInfo->mFirstMultiItem = first;
267 mMultiItemInfo->mPrevMultiItem = prev;
268 mMultiItemInfo->mNextMultiItem = next;
269 mMultiItemInfo->mLastMultiItem = last;
270}
271
272bool AgendaItem::isMultiItem() const
273{
274 return mMultiItemInfo;
275}
276
277AgendaItem::QPtr AgendaItem::prependMoveItem(const AgendaItem::QPtr &e)
278{
279 if (!e) {
280 return nullptr;
281 }
282
283 AgendaItem::QPtr first = nullptr;
284 AgendaItem::QPtr last = nullptr;
285 if (isMultiItem()) {
286 first = mMultiItemInfo->mFirstMultiItem;
287 last = mMultiItemInfo->mLastMultiItem;
288 }
289 if (!first) {
290 first = this;
291 }
292 if (!last) {
293 last = this;
294 }
295
296 e->setMultiItem(nullptr, nullptr, first, last);
297 first->setMultiItem(e, e, first->nextMultiItem(), first->lastMultiItem());
298
299 AgendaItem::QPtr tmp = first->nextMultiItem();
300 while (tmp) {
301 tmp->setMultiItem(e, tmp->prevMultiItem(), tmp->nextMultiItem(), tmp->lastMultiItem());
302 tmp = tmp->nextMultiItem();
303 }
304
305 if (mStartMoveInfo && !e->moveInfo()) {
306 e->mStartMoveInfo = new MultiItemInfo(*mStartMoveInfo);
307 // e->moveInfo()->mFirstMultiItem = moveInfo()->mFirstMultiItem;
308 // e->moveInfo()->mLastMultiItem = moveInfo()->mLastMultiItem;
309 e->moveInfo()->mPrevMultiItem = nullptr;
310 e->moveInfo()->mNextMultiItem = first;
311 }
312
313 if (first && first->moveInfo()) {
314 first->moveInfo()->mPrevMultiItem = e;
315 }
316 return e;
317}
318
319AgendaItem::QPtr AgendaItem::appendMoveItem(const AgendaItem::QPtr &e)
320{
321 if (!e) {
322 return nullptr;
323 }
324
325 AgendaItem::QPtr first = nullptr;
326 AgendaItem::QPtr last = nullptr;
327 if (isMultiItem()) {
328 first = mMultiItemInfo->mFirstMultiItem;
329 last = mMultiItemInfo->mLastMultiItem;
330 }
331 if (!first) {
332 first = this;
333 }
334 if (!last) {
335 last = this;
336 }
337
338 e->setMultiItem(first, last, nullptr, nullptr);
339 AgendaItem::QPtr tmp = first;
340
341 while (tmp) {
342 tmp->setMultiItem(tmp->firstMultiItem(), tmp->prevMultiItem(), tmp->nextMultiItem(), e);
343 tmp = tmp->nextMultiItem();
344 }
345 last->setMultiItem(last->firstMultiItem(), last->prevMultiItem(), e, e);
346
347 if (mStartMoveInfo && !e->moveInfo()) {
348 e->mStartMoveInfo = new MultiItemInfo(*mStartMoveInfo);
349 // e->moveInfo()->mFirstMultiItem = moveInfo()->mFirstMultiItem;
350 // e->moveInfo()->mLastMultiItem = moveInfo()->mLastMultiItem;
351 e->moveInfo()->mPrevMultiItem = last;
352 e->moveInfo()->mNextMultiItem = nullptr;
353 }
354 if (last && last->moveInfo()) {
355 last->moveInfo()->mNextMultiItem = e;
356 }
357 return e;
358}
359
360AgendaItem::QPtr AgendaItem::removeMoveItem(const AgendaItem::QPtr &e)
361{
362 if (isMultiItem()) {
363 AgendaItem::QPtr first = mMultiItemInfo->mFirstMultiItem;
365 AgendaItem::QPtr prev;
366 AgendaItem::QPtr last = mMultiItemInfo->mLastMultiItem;
367 if (!first) {
368 first = this;
369 }
370 if (!last) {
371 last = this;
372 }
373 if (first == e) {
374 first = first->nextMultiItem();
375 first->setMultiItem(nullptr, nullptr, first->nextMultiItem(), first->lastMultiItem());
376 }
377 if (last == e) {
378 last = last->prevMultiItem();
379 last->setMultiItem(last->firstMultiItem(), last->prevMultiItem(), nullptr, nullptr);
380 }
381
382 AgendaItem::QPtr tmp = first;
383 if (first == last) {
384 delete mMultiItemInfo;
385 tmp = nullptr;
386 mMultiItemInfo = nullptr;
387 }
388 while (tmp) {
389 next = tmp->nextMultiItem();
390 prev = tmp->prevMultiItem();
391 if (e == next) {
392 next = next->nextMultiItem();
393 }
394 if (e == prev) {
395 prev = prev->prevMultiItem();
396 }
397 tmp->setMultiItem((tmp == first) ? nullptr : first, (tmp == prev) ? nullptr : prev, (tmp == next) ? nullptr : next, (tmp == last) ? nullptr : last);
398 tmp = tmp->nextMultiItem();
399 }
400 }
401
402 return e;
403}
404
406{
407 AgendaItem::QPtr first = this;
408 if (isMultiItem() && mMultiItemInfo->mFirstMultiItem) {
409 first = mMultiItemInfo->mFirstMultiItem;
410 }
411 first->startMovePrivate();
412}
413
415{
416 mStartMoveInfo = new MultiItemInfo;
417 mStartMoveInfo->mStartCellXLeft = mCellXLeft;
418 mStartMoveInfo->mStartCellXRight = mCellXRight;
419 mStartMoveInfo->mStartCellYTop = mCellYTop;
420 mStartMoveInfo->mStartCellYBottom = mCellYBottom;
421 if (mMultiItemInfo) {
422 mStartMoveInfo->mFirstMultiItem = mMultiItemInfo->mFirstMultiItem;
423 mStartMoveInfo->mLastMultiItem = mMultiItemInfo->mLastMultiItem;
424 mStartMoveInfo->mPrevMultiItem = mMultiItemInfo->mPrevMultiItem;
425 mStartMoveInfo->mNextMultiItem = mMultiItemInfo->mNextMultiItem;
426 } else {
427 mStartMoveInfo->mFirstMultiItem = nullptr;
428 mStartMoveInfo->mLastMultiItem = nullptr;
429 mStartMoveInfo->mPrevMultiItem = nullptr;
430 mStartMoveInfo->mNextMultiItem = nullptr;
431 }
432 if (isMultiItem() && mMultiItemInfo->mNextMultiItem) {
433 mMultiItemInfo->mNextMultiItem->startMovePrivate();
434 }
435}
436
438{
439 if (mStartMoveInfo) {
440 if (mStartMoveInfo->mFirstMultiItem) {
441 mStartMoveInfo->mFirstMultiItem->resetMovePrivate();
442 } else {
443 resetMovePrivate();
444 }
445 }
446}
447
448void AgendaItem::resetMovePrivate()
449{
450 if (mStartMoveInfo) {
451 mCellXLeft = mStartMoveInfo->mStartCellXLeft;
452 mCellXRight = mStartMoveInfo->mStartCellXRight;
453 mCellYTop = mStartMoveInfo->mStartCellYTop;
454 mCellYBottom = mStartMoveInfo->mStartCellYBottom;
455
456 // if we don't have mMultiItemInfo, the item didn't span two days before,
457 // and wasn't moved over midnight, either, so we don't have to reset
458 // anything. Otherwise, restore from mMoveItemInfo
459 if (mMultiItemInfo) {
460 // It was already a multi-day info
461 mMultiItemInfo->mFirstMultiItem = mStartMoveInfo->mFirstMultiItem;
462 mMultiItemInfo->mPrevMultiItem = mStartMoveInfo->mPrevMultiItem;
463 mMultiItemInfo->mNextMultiItem = mStartMoveInfo->mNextMultiItem;
464 mMultiItemInfo->mLastMultiItem = mStartMoveInfo->mLastMultiItem;
465
466 if (!mStartMoveInfo->mFirstMultiItem) {
467 // This was the first multi-item when the move started, delete all previous
468 AgendaItem::QPtr toDel = mStartMoveInfo->mPrevMultiItem;
469 AgendaItem::QPtr nowDel = nullptr;
470 while (toDel) {
471 nowDel = toDel;
472 if (nowDel->moveInfo()) {
473 toDel = nowDel->moveInfo()->mPrevMultiItem;
474 }
475 Q_EMIT removeAgendaItem(nowDel);
476 }
477 mMultiItemInfo->mFirstMultiItem = nullptr;
478 mMultiItemInfo->mPrevMultiItem = nullptr;
479 }
480 if (!mStartMoveInfo->mLastMultiItem) {
481 // This was the last multi-item when the move started, delete all next
482 AgendaItem::QPtr toDel = mStartMoveInfo->mNextMultiItem;
483 AgendaItem::QPtr nowDel = nullptr;
484 while (toDel) {
485 nowDel = toDel;
486 if (nowDel->moveInfo()) {
487 toDel = nowDel->moveInfo()->mNextMultiItem;
488 }
489 Q_EMIT removeAgendaItem(nowDel);
490 }
491 mMultiItemInfo->mLastMultiItem = nullptr;
492 mMultiItemInfo->mNextMultiItem = nullptr;
493 }
494
495 if (mStartMoveInfo->mFirstMultiItem == nullptr && mStartMoveInfo->mLastMultiItem == nullptr) {
496 // it was a single-day event before we started the move.
497 delete mMultiItemInfo;
498 mMultiItemInfo = nullptr;
499 }
500 }
501 delete mStartMoveInfo;
502 mStartMoveInfo = nullptr;
503 }
504 Q_EMIT showAgendaItem(this);
505 if (nextMultiItem()) {
506 nextMultiItem()->resetMovePrivate();
507 }
508}
509
511{
512 AgendaItem::QPtr first = firstMultiItem();
513 if (!first) {
514 first = this;
515 }
516 first->endMovePrivate();
517}
518
519void AgendaItem::endMovePrivate()
520{
521 if (mStartMoveInfo) {
522 // if first, delete all previous
523 if (!firstMultiItem() || firstMultiItem() == this) {
524 AgendaItem::QPtr toDel = mStartMoveInfo->mPrevMultiItem;
525 AgendaItem::QPtr nowDel = nullptr;
526 while (toDel) {
527 nowDel = toDel;
528 if (nowDel->moveInfo()) {
529 toDel = nowDel->moveInfo()->mPrevMultiItem;
530 }
531 Q_EMIT removeAgendaItem(nowDel);
532 }
533 }
534 // if last, delete all next
535 if (!lastMultiItem() || lastMultiItem() == this) {
536 AgendaItem::QPtr toDel = mStartMoveInfo->mNextMultiItem;
537 AgendaItem::QPtr nowDel = nullptr;
538 while (toDel) {
539 nowDel = toDel;
540 if (nowDel->moveInfo()) {
541 toDel = nowDel->moveInfo()->mNextMultiItem;
542 }
543 Q_EMIT removeAgendaItem(nowDel);
544 }
545 }
546 // also delete the moving info
547 delete mStartMoveInfo;
548 mStartMoveInfo = nullptr;
549 if (nextMultiItem()) {
550 nextMultiItem()->endMovePrivate();
551 }
552 }
553}
554
555void AgendaItem::moveRelative(int dx, int dy)
556{
557 int newXLeft = cellXLeft() + dx;
558 int newXRight = cellXRight() + dx;
559 int newYTop = cellYTop() + dy;
560 int newYBottom = cellYBottom() + dy;
561 setCellXY(newXLeft, newYTop, newYBottom);
562 setCellXRight(newXRight);
563}
564
565void AgendaItem::expandTop(int dy, const bool allowOverLimit)
566{
567 int newYTop = cellYTop() + dy;
568 int newYBottom = cellYBottom();
569 if (newYTop > newYBottom && !allowOverLimit) {
570 newYTop = newYBottom;
571 }
572 setCellY(newYTop, newYBottom);
573}
574
575void AgendaItem::expandBottom(int dy)
576{
577 int newYTop = cellYTop();
578 int newYBottom = cellYBottom() + dy;
579 if (newYBottom < newYTop) {
580 newYBottom = newYTop;
581 }
582 setCellY(newYTop, newYBottom);
583}
584
585void AgendaItem::expandLeft(int dx)
586{
587 int newXLeft = cellXLeft() + dx;
588 int newXRight = cellXRight();
589 if (newXLeft > newXRight) {
590 newXLeft = newXRight;
591 }
592 setCellX(newXLeft, newXRight);
593}
594
595void AgendaItem::expandRight(int dx)
596{
597 int newXLeft = cellXLeft();
598 int newXRight = cellXRight() + dx;
599 if (newXRight < newXLeft) {
600 newXRight = newXLeft;
601 }
602 setCellX(newXLeft, newXRight);
603}
604
605void AgendaItem::dragEnterEvent(QDragEnterEvent *e)
606{
607 const QMimeData *md = e->mimeData();
609 // TODO: Allow dragging events/todos onto other events to create a relation
610 e->ignore();
611 return;
612 }
613 if (KContacts::VCardDrag::canDecode(md) || md->hasText()) {
614 e->accept();
615 } else {
616 e->ignore();
617 }
618}
619
620void AgendaItem::addAttendee(const QString &newAttendee)
621{
622 if (!mValid) {
623 return;
624 }
625
627 QString email;
628 KEmailAddress::extractEmailAddressAndName(newAttendee, email, name);
629 if (!(name.isEmpty() && email.isEmpty())) {
630 mIncidence->addAttendee(KCalendarCore::Attendee(name, email));
632 i18n("Attendee \"%1\" added to the calendar item \"%2\"", KEmailAddress::normalizedAddress(name, email, QString()), text()),
633 i18nc("@title:window", "Attendee added"),
634 QStringLiteral("AttendeeDroppedAdded"));
635 }
636}
637
638void AgendaItem::dropEvent(QDropEvent *e)
639{
640 // TODO: Organize this better: First check for attachment
641 // (not only file, also any other url!), then if it's a vcard,
642 // otherwise check for attendees, then if the data is binary,
643 // add a binary attachment.
644 if (!mValid) {
645 return;
646 }
647
648 const QMimeData *md = e->mimeData();
649
650 bool decoded = md->hasText();
651 QString text = md->text();
652 if (decoded && text.startsWith(QLatin1StringView("file:"))) {
653 mIncidence->addAttachment(KCalendarCore::Attachment(text));
654 return;
655 }
656
658
660 for (const KContacts::Addressee &addressee : std::as_const(list)) {
661 QString em(addressee.fullEmail());
662 if (em.isEmpty()) {
663 em = addressee.realName();
664 }
665 addAttendee(em);
666 }
667 }
668}
669
670QList<AgendaItem::QPtr> &AgendaItem::conflictItems()
671{
672 return mConflictItems;
673}
674
675void AgendaItem::setConflictItems(const QList<AgendaItem::QPtr> &ci)
676{
677 mConflictItems = ci;
678 for (QList<AgendaItem::QPtr>::iterator it = mConflictItems.begin(), end(mConflictItems.end()); it != end; ++it) {
679 (*it)->addConflictItem(this);
680 }
681}
682
683void AgendaItem::addConflictItem(const AgendaItem::QPtr &ci)
684{
685 if (!mConflictItems.contains(ci)) {
686 mConflictItems.append(ci);
687 }
688}
689
690QString AgendaItem::label() const
691{
692 return mLabelText;
693}
694
695bool AgendaItem::overlaps(CellItem *o) const
696{
697 AgendaItem::QPtr other = static_cast<AgendaItem *>(o);
698
699 if (cellXLeft() <= other->cellXRight() && cellXRight() >= other->cellXLeft()) {
700 if ((cellYTop() <= other->cellYBottom()) && (cellYBottom() >= other->cellYTop())) {
701 return true;
702 }
703 }
704
705 return false;
706}
707
708static void conditionalPaint(QPainter *p, bool condition, int &x, int y, int ft, const QPixmap &pxmp)
709{
710 if (condition) {
711 p->drawPixmap(x, y, pxmp);
712 x += pxmp.width() + ft;
713 }
714}
715
716void AgendaItem::paintIcon(QPainter *p, int &x, int y, int ft)
717{
718 QString iconName;
719 if (mIncidence->customProperty("KABC", "ANNIVERSARY") == QLatin1StringView("YES")) {
720 mSpecialEvent = true;
721 iconName = QStringLiteral("view-calendar-wedding-anniversary");
722 } else if (mIncidence->customProperty("KABC", "BIRTHDAY") == QLatin1StringView("YES")) {
723 mSpecialEvent = true;
724 // We don't draw icon. The icon is drawn already, because it's the Akonadi::Collection's icon
725 }
726
727 conditionalPaint(p, !iconName.isEmpty(), x, y, ft, cachedSmallIcon(iconName));
728}
729
730void AgendaItem::paintIcons(QPainter *p, int &x, int y, int ft)
731{
732 if (!mEventView->preferences()->enableAgendaItemIcons()) {
733 return;
734 }
735
736 paintIcon(p, x, y, ft);
737
738 QSet<EventView::ItemIcon> icons = mEventView->preferences()->agendaViewIcons();
739
740 if (icons.contains(EventViews::EventView::CalendarCustomIcon)) {
741 const QString iconName = mCalendar->iconForIncidence(mIncidence);
742 if (!iconName.isEmpty() && iconName != QLatin1StringView("view-calendar") && iconName != QLatin1StringView("office-calendar")) {
743 conditionalPaint(p, true, x, y, ft, QIcon::fromTheme(iconName).pixmap(16, 16));
744 }
745 }
746
747 const bool isTodo = mIncidence && mIncidence->type() == Incidence::TypeTodo;
748
749 if (isTodo && icons.contains(EventViews::EventView::TaskIcon)) {
750 const QString iconName = mIncidence->iconName(mOccurrenceDateTime.toLocalTime());
751 conditionalPaint(p, !mSpecialEvent, x, y, ft, QIcon::fromTheme(iconName).pixmap(16, 16));
752 }
753
754 if (icons.contains(EventView::RecurringIcon)) {
755 conditionalPaint(p, mIconRecur && !mSpecialEvent, x, y, ft, *recurPxmp);
756 }
757
758 if (icons.contains(EventView::ReminderIcon)) {
759 conditionalPaint(p, mIconAlarm && !mSpecialEvent, x, y, ft, *alarmPxmp);
760 }
761
762 if (icons.contains(EventView::ReadOnlyIcon)) {
763 conditionalPaint(p, mIconReadonly && !mSpecialEvent, x, y, ft, *readonlyPxmp);
764 }
765
766 if (icons.contains(EventView::ReplyIcon)) {
767 conditionalPaint(p, mIconReply, x, y, ft, *replyPxmp);
768 }
769
770 if (icons.contains(EventView::AttendingIcon)) {
771 conditionalPaint(p, mIconGroup, x, y, ft, *groupPxmp);
772 }
773
774 if (icons.contains(EventView::TentativeIcon)) {
775 conditionalPaint(p, mIconGroupTent, x, y, ft, *groupPxmpTent);
776 }
777
778 if (icons.contains(EventView::OrganizerIcon)) {
779 conditionalPaint(p, mIconOrganizer, x, y, ft, *organizerPxmp);
780 }
781}
782
783void AgendaItem::paintEvent(QPaintEvent *ev)
784{
785 if (!mValid) {
786 return;
787 }
788
789 QRect visRect = visibleRegion().boundingRect();
790 // when scrolling horizontally in the side-by-side view, the repainted area is clipped
791 // to the newly visible area, which is a problem since the content changes when visRect
792 // changes, so repaint the full item in that case
793 if (ev->rect() != visRect && visRect.isValid() && ev->rect().isValid()) {
794 update(visRect);
795 return;
796 }
797
798 QPainter p(this);
800 const int fmargin = 0; // frame margin
801 const int ft = 1; // frame thickness for layout, see drawRoundedRect(),
802 // keep multiple of 2
803 const int margin = 5 + ft + fmargin; // frame + space between frame and content
804
805 // General idea is to always show the icons (even in the all-day events).
806 // This creates a consistent feeling for the user when the view mode
807 // changes and therefore the available width changes.
808 // Also look at #17984
809
810 if (!alarmPxmp) {
811 alarmPxmp = new QPixmap(QIcon::fromTheme(QStringLiteral("task-reminder")).pixmap(16, 16));
812 recurPxmp = new QPixmap(QIcon::fromTheme(QStringLiteral("appointment-recurring")).pixmap(16, 16));
813 readonlyPxmp = new QPixmap(QIcon::fromTheme(QStringLiteral("object-locked")).pixmap(16, 16));
814 replyPxmp = new QPixmap(QIcon::fromTheme(QStringLiteral("mail-reply-sender")).pixmap(16, 16));
815 groupPxmp = new QPixmap(QIcon::fromTheme(QStringLiteral("meeting-attending")).pixmap(16, 16));
816 groupPxmpTent = new QPixmap(QIcon::fromTheme(QStringLiteral("meeting-attending-tentative")).pixmap(16, 16));
817 organizerPxmp = new QPixmap(QIcon::fromTheme(QStringLiteral("meeting-organizer")).pixmap(16, 16));
818 }
819
820 const auto categoryColor = getCategoryColor();
821 const auto resourceColor = mResourceColor.isValid() ? mResourceColor : categoryColor;
822 const auto frameColor = getFrameColor(resourceColor, categoryColor);
823 const auto bgBaseColor = getBackgroundColor(resourceColor, categoryColor);
824 const auto bgColor = mSelected ? bgBaseColor.lighter(EventView::BRIGHTNESS_FACTOR) : bgBaseColor;
825 const auto textColor = EventViews::getTextColor(bgColor);
826
827 p.setPen(textColor);
828
829 p.setFont(mEventView->preferences()->agendaViewFont());
830 QFontMetrics fm = p.fontMetrics();
831
832 const int singleLineHeight = fm.boundingRect(mLabelText).height();
833
834 const bool roundTop = !prevMultiItem();
835 const bool roundBottom = !nextMultiItem();
836
837 drawRoundedRect(&p,
838 QRect(fmargin, fmargin, width() - fmargin * 2, height() - fmargin * 2),
839 mSelected,
840 bgColor,
841 frameColor,
842 true,
843 ft,
844 roundTop,
845 roundBottom);
846
847 // calculate the height of the full version (case 4) to test whether it is
848 // possible
849
850 QString shortH;
851 QString longH;
852 if (!isMultiItem()) {
853 shortH = QLocale().toString(mIncidence->dateTime(KCalendarCore::Incidence::RoleDisplayStart).toLocalTime().time(), QLocale::ShortFormat);
854
855 if (CalendarSupport::hasEvent(mIncidence)) {
856 longH =
857 i18n("%1 - %2", shortH, QLocale().toString(mIncidence->dateTime(KCalendarCore::Incidence::RoleEnd).toLocalTime().time(), QLocale::ShortFormat));
858 } else {
859 longH = shortH;
860 }
861 } else if (!mMultiItemInfo->mFirstMultiItem) {
862 shortH = QLocale().toString(mIncidence->dtStart().toLocalTime().time(), QLocale::ShortFormat);
863 longH = shortH;
864 } else {
865 shortH = QLocale().toString(mIncidence->dateTime(KCalendarCore::Incidence::RoleEnd).toLocalTime().time(), QLocale::ShortFormat);
866 longH = i18n("- %1", shortH);
867 }
868
869 KWordWrap ww = KWordWrap::formatText(fm, QRect(0, 0, width() - (2 * margin), -1), 0, mLabelText);
870 int th = ww.boundingRect().height();
871
872 int hlHeight =
873 qMax(fm.boundingRect(longH).height(),
874 qMax(alarmPxmp->height(),
875 qMax(recurPxmp->height(), qMax(readonlyPxmp->height(), qMax(replyPxmp->height(), qMax(groupPxmp->height(), organizerPxmp->height()))))));
876
877 const bool completelyRenderable = th < (height() - 2 * ft - 2 - hlHeight);
878
879 // case 1: do not draw text when not even a single line fits
880 // Don't do this any more, always try to print out the text.
881 // Even if it's just a few pixel, one can still guess the whole
882 // text from just four pixels' height!
883 if ( //( singleLineHeight > height() - 4 ) ||
884 (width() < 16)) {
885 int x = qRound((width() - 16) / 2.0);
886 paintIcon(&p, x /*by-ref*/, margin, ft);
887 return;
888 }
889
890 // case 2: draw a single line when no more space
891 if ((2 * singleLineHeight) > (height() - 2 * margin)) {
892 int x = margin;
893 int txtWidth;
894
895 if (mIncidence->allDay()) {
896 x += visRect.left();
897 const int y = qRound((height() - 16) / 2.0);
898 paintIcons(&p, x, y, ft);
899 txtWidth = visRect.right() - margin - x;
900 } else {
901 const int y = qRound((height() - 16) / 2.0);
902 paintIcons(&p, x, y, ft);
903 txtWidth = width() - margin - x;
904 }
905
906 const int y = ((height() - singleLineHeight) / 2) + fm.ascent();
907 KWordWrap::drawFadeoutText(&p, x, y, txtWidth, mLabelText);
908 return;
909 }
910
911 // case 3: enough for 2-5 lines, but not for the header.
912 // Also used for the middle days in multi-events
913 if (((!completelyRenderable) && ((height() - (2 * margin)) <= (5 * singleLineHeight)))
914 || (isMultiItem() && mMultiItemInfo->mNextMultiItem && mMultiItemInfo->mFirstMultiItem)) {
915 int x = margin;
916 int txtWidth;
917
918 if (mIncidence->allDay()) {
919 x += visRect.left();
920 paintIcons(&p, x, margin, ft);
921 txtWidth = visRect.right() - margin - x;
922 } else {
923 paintIcons(&p, x, margin, ft);
924 txtWidth = width() - margin - x;
925 }
926
927 ww = KWordWrap::formatText(fm, QRect(0, 0, txtWidth, (height() - (2 * margin))), 0, mLabelText);
928
929 ww.drawText(&p, x, margin, Qt::AlignHCenter | KWordWrap::FadeOut);
930 return;
931 }
932
933 // case 4: paint everything, with header:
934 // consists of (vertically) ft + headline&icons + ft + text + margin
935 int y = 2 * ft + hlHeight;
936 if (completelyRenderable) {
937 y += (height() - (2 * ft) - margin - hlHeight - th) / 2;
938 }
939
940 int x = margin;
941 int txtWidth;
942 int hTxtWidth;
943 int eventX;
944
945 if (mIncidence->allDay()) {
946 shortH.clear();
947 longH.clear();
948
949 if (const KCalendarCore::Event::Ptr event = CalendarSupport::event(mIncidence)) {
950 if (event->isMultiDay(QTimeZone::systemTimeZone())) {
951 // multi-day, all-day event
952 shortH = i18n("%1 - %2",
953 QLocale().toString(mIncidence->dtStart().toLocalTime().date()),
954 QLocale().toString(mIncidence->dateTime(KCalendarCore::Incidence::RoleEnd).toLocalTime().date()));
955 longH = shortH;
956
957 // paint headline
958 drawRoundedRect(&p,
959 QRect(fmargin, fmargin, width() - fmargin * 2, -fmargin * 2 + margin + hlHeight),
960 mSelected,
961 frameColor,
962 frameColor,
963 false,
964 ft,
965 roundTop,
966 false);
967 } else {
968 // single-day, all-day event
969
970 // paint headline
971 drawRoundedRect(&p,
972 QRect(fmargin, fmargin, width() - fmargin * 2, -fmargin * 2 + margin + hlHeight),
973 mSelected,
974 frameColor,
975 frameColor,
976 false,
977 ft,
978 roundTop,
979 false);
980 }
981 } else {
982 // to-do
983
984 // paint headline
985 drawRoundedRect(&p,
986 QRect(fmargin, fmargin, width() - fmargin * 2, -fmargin * 2 + margin + hlHeight),
987 mSelected,
988 frameColor,
989 frameColor,
990 false,
991 ft,
992 roundTop,
993 false);
994 }
995
996 x += visRect.left();
997 eventX = x;
998 txtWidth = visRect.right() - margin - x;
999 paintIcons(&p, x, margin / 2, ft);
1000 hTxtWidth = visRect.right() - margin - x;
1001 } else {
1002 // paint headline
1003 drawRoundedRect(&p,
1004 QRect(fmargin, fmargin, width() - fmargin * 2, -fmargin * 2 + margin + hlHeight),
1005 mSelected,
1006 frameColor,
1007 frameColor,
1008 false,
1009 ft,
1010 roundTop,
1011 false);
1012
1013 txtWidth = width() - margin - x;
1014 eventX = x;
1015 paintIcons(&p, x, margin / 2, ft);
1016 hTxtWidth = width() - margin - x;
1017 }
1018
1019 QString headline;
1020 int hw = fm.boundingRect(longH).width();
1021 if (hw > hTxtWidth) {
1022 headline = shortH;
1023 hw = fm.boundingRect(shortH).width();
1024 if (hw < txtWidth) {
1025 x += (hTxtWidth - hw) / 2;
1026 }
1027 } else {
1028 headline = longH;
1029 x += (hTxtWidth - hw) / 2;
1030 }
1031 p.setBackground(QBrush(frameColor));
1032 p.setPen(EventViews::getTextColor(frameColor));
1033 KWordWrap::drawFadeoutText(&p, x, (margin + hlHeight + fm.ascent()) / 2 - 2, hTxtWidth, headline);
1034
1035 // draw event text
1036 ww = KWordWrap::formatText(fm, QRect(0, 0, txtWidth, height() - margin - y), 0, mLabelText);
1037
1038 p.setBackground(QBrush(bgColor));
1039 p.setPen(textColor);
1040 QString ws = ww.wrappedString();
1041 if (QStringView(ws).left(ws.length() - 1).indexOf(QLatin1Char('\n')) >= 0) {
1042 ww.drawText(&p, eventX, y, Qt::AlignLeft | KWordWrap::FadeOut);
1043 } else {
1044 ww.drawText(&p, eventX + (txtWidth - ww.boundingRect().width() - 2 * margin) / 2, y, Qt::AlignHCenter | KWordWrap::FadeOut);
1045 }
1046}
1047
1048void AgendaItem::drawRoundedRect(QPainter *p,
1049 QRect rect,
1050 bool selected,
1051 const QColor &bgColor,
1052 const QColor &frameColor,
1053 bool frame,
1054 int ft,
1055 bool roundTop,
1056 bool roundBottom)
1057{
1058 Q_UNUSED(ft)
1059 if (!mValid) {
1060 return;
1061 }
1062
1064
1065 const int RECT_MARGIN = 2;
1066 const int RADIUS = 2; // absolute radius
1067
1068 const QRect rectWithMargin(rect.x() + RECT_MARGIN, rect.y() + RECT_MARGIN, rect.width() - 2 * RECT_MARGIN, rect.height() - 2 * RECT_MARGIN);
1069
1070 const QPoint pointLeftTop(rectWithMargin.x(), rectWithMargin.y());
1071 const QPoint pointRightTop(rectWithMargin.x() + rectWithMargin.width(), rectWithMargin.y());
1072 const QPoint pointLeftBottom(rectWithMargin.x(), rectWithMargin.y() + rectWithMargin.height());
1073 const QPoint pointRightBottom(rectWithMargin.x() + rectWithMargin.width(), rectWithMargin.y() + rectWithMargin.height());
1074
1075 if (!roundTop && !roundBottom) {
1076 path.addRect(rectWithMargin);
1077 } else if (roundTop && roundBottom) {
1078 path.addRoundedRect(rectWithMargin, RADIUS, RADIUS, Qt::AbsoluteSize);
1079 } else if (roundTop) {
1080 path.moveTo(pointRightBottom);
1081 path.lineTo(pointLeftBottom);
1082 path.lineTo(QPoint(pointLeftTop.x(), pointLeftTop.y() + RADIUS));
1083 path.quadTo(pointLeftTop, QPoint(pointLeftTop.x() + RADIUS, pointLeftTop.y()));
1084 path.lineTo(QPoint(pointRightTop.x() - RADIUS, pointRightTop.y()));
1085 path.quadTo(pointRightTop, QPoint(pointRightTop.x(), pointRightTop.y() + RADIUS));
1086 path.lineTo(pointRightBottom);
1087 } else if (roundBottom) {
1088 path.moveTo(pointRightTop);
1089 path.lineTo(QPoint(pointRightBottom.x(), pointRightBottom.y() - RADIUS));
1090 path.quadTo(pointRightBottom, QPoint(pointRightBottom.x() - RADIUS, pointRightBottom.y()));
1091 path.lineTo(QPoint(pointLeftBottom.x() + RADIUS, pointLeftBottom.y()));
1092 path.quadTo(pointLeftBottom, QPoint(pointLeftBottom.x(), pointLeftBottom.y() - RADIUS));
1093 path.lineTo(pointLeftTop);
1094 path.lineTo(pointRightTop);
1095 }
1096
1097 path.closeSubpath();
1098 p->save();
1100 const QPen border(frameColor, 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
1101 p->setPen(border);
1102
1103 // header
1104 if (!frame) {
1105 QBrush brushSolid(Qt::SolidPattern);
1106
1107 QColor top = bgColor.darker(250);
1108 top.setAlpha(selected ? 40 : 60);
1109 brushSolid.setColor(top);
1110
1111 p->setBrush(bgColor);
1112 p->drawPath(path);
1113
1114 p->setBrush(brushSolid);
1115 p->drawPath(path);
1116 p->restore();
1117
1118 return;
1119 }
1120
1121 p->setBrush(bgColor);
1122 p->drawPath(path);
1123 p->restore();
1124}
1125
1126QColor AgendaItem::getCategoryColor() const
1127{
1128 const QStringList &categories = mIncidence->categories();
1129 if (categories.isEmpty() || !Akonadi::TagCache::instance()->tagColor(categories.first()).isValid()) {
1130 const auto colorPreference = mEventView->preferences()->agendaViewColors();
1131 if (colorPreference == PrefsBase::CategoryOnly || !mResourceColor.isValid()) {
1132 return CalendarSupport::KCalPrefs::instance()->unsetCategoryColor();
1133 }
1134 return mResourceColor;
1135 }
1136 return Akonadi::TagCache::instance()->tagColor(categories.first());
1137}
1138
1139QColor AgendaItem::getFrameColor(const QColor &resourceColor, const QColor &categoryColor) const
1140{
1141 const auto colorPreference = mEventView->preferences()->agendaViewColors();
1142 const bool frameDisplaysCategory = (colorPreference == PrefsBase::CategoryOnly || colorPreference == PrefsBase::ResourceInsideCategoryOutside);
1143 return frameDisplaysCategory ? categoryColor : resourceColor;
1144}
1145
1146QColor AgendaItem::getBackgroundColor(const QColor &resourceColor, const QColor &categoryColor) const
1147{
1148 if (CalendarSupport::hasTodo(mIncidence) && !mEventView->preferences()->todosUseCategoryColors()) {
1149 Todo::Ptr todo = CalendarSupport::todo(mIncidence);
1150 Q_ASSERT(todo);
1151 const QDate dueDate = todo->dtDue().toLocalTime().date();
1152 const QDate today = QDate::currentDate();
1153 const QDate occurrenceDate = this->occurrenceDate();
1154 if (todo->isOverdue() && today >= occurrenceDate) {
1155 return mEventView->preferences()->todoOverdueColor();
1156 } else if (dueDate == today && dueDate == occurrenceDate && !todo->isCompleted()) {
1157 return mEventView->preferences()->todoDueTodayColor();
1158 }
1159 }
1160 const auto colorPreference = mEventView->preferences()->agendaViewColors();
1161 const bool bgDisplaysCategory = (colorPreference == PrefsBase::CategoryOnly || colorPreference == PrefsBase::CategoryInsideResourceOutside);
1162 return bgDisplaysCategory ? categoryColor : resourceColor;
1163}
1164
1165bool AgendaItem::eventFilter(QObject *obj, QEvent *event)
1166{
1167 if (event->type() == QEvent::Paint) {
1168 return mValid;
1169 } else {
1170 // standard event processing
1171 return QObject::eventFilter(obj, event);
1172 }
1173}
1174
1175bool AgendaItem::event(QEvent *event)
1176{
1177 if (event->type() == QEvent::ToolTip) {
1178 if (!mEventView->preferences()->enableToolTips()) {
1179 return true;
1180 } else if (mValid) {
1181 auto helpEvent = static_cast<QHelpEvent *>(event);
1182 QToolTip::showText(helpEvent->globalPos(),
1183 KCalUtils::IncidenceFormatter::toolTipStr(mCalendar->displayName(mIncidence), mIncidence, occurrenceDate(), true),
1184 this);
1185 }
1186 }
1187 return QWidget::event(event);
1188}
1189
1190#include "moc_agendaitem.cpp"
QColor tagColor(const QString &tagName) const
static TagCache * instance()
This class describes the widgets that represent the various calendar items in the agenda view.
Definition agendaitem.h:61
bool overlaps(CellItem *o) const override
Tells whether this item overlaps item o.
void endMove()
End the movement (i.e.
void expandTop(int dy, const bool allowOverLimit=false)
Expands the item's top.
void startMovePrivate()
private movement functions.
void resetMove()
Reset to original values.
void startMove()
Start movement.
EventView is the abstract base class from which all other calendar views for event data are derived.
Definition eventview.h:67
PartStat status() const
QSharedPointer< Incidence > Ptr
AddresseeList List
QRect boundingRect() const
static KWordWrap formatText(QFontMetrics &fm, const QRect &r, int flags, const QString &str, int len=-1)
static void drawFadeoutText(QPainter *p, int x, int y, int maxW, const QString &t)
void drawText(QPainter *painter, int x, int y, int flags=Qt::AlignLeft) const
QString wrappedString() const
KCODECS_EXPORT QString normalizedAddress(const QString &displayName, const QString &addrSpec, const QString &comment=QString())
KCODECS_EXPORT bool extractEmailAddressAndName(const QString &aStr, QString &mail, QString &name)
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
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)
AKONADI_CALENDAR_EXPORT KCalendarCore::Todo::Ptr todo(const Akonadi::Item &item)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
char * toString(const EngineQuery &query)
Namespace EventViews provides facilities for displaying incidences, including events,...
Definition agenda.h:33
EVENTVIEWS_EXPORT QColor resourceColor(const Akonadi::Collection &collection, const PrefsPtr &preferences)
This method returns the proper resource / subresource color for the view.
Definition helper.cpp:56
QPixmap cachedSmallIcon(const QString &name)
Equivalent to SmallIcon( name ), but uses QPixmapCache.
Definition helper.cpp:83
int yearDiff(QDate start, QDate end)
Returns the number of years between the start QDate and the end QDate (i.e.
Definition helper.cpp:78
QColor getTextColor(const QColor &c)
Returns a nice QColor for text, give the input color &c.
Definition helper.cpp:26
KCALUTILS_EXPORT bool canDecode(const QMimeData *)
KCALUTILS_EXPORT QString toolTipStr(const QString &sourceName, const KCalendarCore::IncidenceBase::Ptr &incidence, QDate date=QDate(), bool richText=true)
KCALUTILS_EXPORT bool canDecode(const QMimeData *)
KCONTACTS_EXPORT bool canDecode(const QMimeData *md)
KCONTACTS_EXPORT bool fromMimeData(const QMimeData *md, KContacts::Addressee::List &contacts)
QString path(const QString &relativePath)
void information(QWidget *parent, const QString &text, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
const QList< QKeySequence > & next()
const QList< QKeySequence > & end()
QString name(StandardShortcut id)
QColor darker(int factor) const const
bool isValid() const const
void setAlpha(int alpha)
QDate currentDate()
QDate date() const const
QDateTime toLocalTime() const const
const QMimeData * mimeData() const const
int ascent() const const
QRect boundingRect(QChar ch) const const
QIcon fromTheme(const QString &name)
T & first()
bool isEmpty() const const
QString toString(QDate date, FormatType format) const const
bool hasText() const const
QString text() const const
Q_EMITQ_EMIT
virtual bool eventFilter(QObject *watched, QEvent *event)
void drawPath(const QPainterPath &path)
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
QFontMetrics fontMetrics() const const
void restore()
void save()
void setBackground(const QBrush &brush)
void setBrush(Qt::BrushStyle style)
void setFont(const QFont &font)
void setPen(Qt::PenStyle style)
void setRenderHint(RenderHint hint, bool on)
const QRect & rect() const const
void setColor(ColorGroup group, ColorRole role, const QColor &color)
int height() const const
int width() const const
int height() const const
bool isValid() const const
int left() const const
int right() const const
int width() const const
QRect boundingRect() const const
bool contains(const QSet< T > &other) const const
void clear()
bool isEmpty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
AlignHCenter
SolidPattern
transparent
RoundCap
RoundJoin
SolidLine
AbsoluteSize
QTextStream & left(QTextStream &stream)
QTextStream & ws(QTextStream &stream)
QTimeZone systemTimeZone()
void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)
virtual bool event(QEvent *event) override
void update()
QRegion visibleRegion() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:12:29 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.