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

KDE's Doxygen guidelines are available online.