CalendarSupport

calprintpluginbase.cpp
1/*
2 SPDX-FileCopyrightText: 1998 Preston Brown <pbrown@kde.org>
3 SPDX-FileCopyrightText: 2003 Reinhold Kainhofer <reinhold@kainhofer.com>
4 SPDX-FileCopyrightText: 2008 Ron Goodheart <rong.dev@gmail.com>
5 SPDX-FileCopyrightText: 2012-2013 Allen Winter <winter@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
8*/
9
10#include "calprintpluginbase.h"
11#include "cellitem.h"
12#include "kcalprefs.h"
13#include "utils.h"
14
15#include <Akonadi/Item>
16#include <Akonadi/TagCache>
17
18#include "calendarsupport_debug.h"
19#include <KConfig>
20#include <KConfigGroup>
21#include <KWordWrap>
22
23#include <KLocalizedString>
24#include <QAbstractTextDocumentLayout>
25#include <QFrame>
26#include <QLabel>
27#include <QLocale>
28#include <QTextCursor>
29#include <QTextDocument>
30#include <QTextDocumentFragment>
31#include <QTimeZone>
32#include <QVBoxLayout>
33#include <qmath.h> // qCeil krazy:exclude=camelcase since no QMath
34
35using namespace CalendarSupport;
36
37static QString cleanStr(const QString &instr)
38{
39 QString ret = instr;
40 return ret.replace(QLatin1Char('\n'), QLatin1Char(' '));
41}
42
43const QColor CalPrintPluginBase::sHolidayBackground = QColor(244, 244, 244);
44
45/******************************************************************
46 ** The Todo positioning structure **
47 ******************************************************************/
48class CalPrintPluginBase::TodoParentStart
49{
50public:
51 TodoParentStart(QRect pt = QRect(), bool hasLine = false, bool page = true)
52 : mRect(pt)
53 , mHasLine(hasLine)
54 , mSamePage(page)
55 {
56 }
57
58 QRect mRect;
59 bool mHasLine;
60 bool mSamePage;
61};
62
63/******************************************************************
64 ** The Print item **
65 ******************************************************************/
66
67class PrintCellItem : public CellItem
68{
69public:
70 PrintCellItem(const KCalendarCore::Event::Ptr &event, const QDateTime &start, const QDateTime &end)
71 : mEvent(event)
72 , mStart(start)
73 , mEnd(end)
74 {
75 }
76
77 [[nodiscard]] KCalendarCore::Event::Ptr event() const
78 {
79 return mEvent;
80 }
81
82 [[nodiscard]] QString label() const override
83 {
84 return mEvent->summary();
85 }
86
87 [[nodiscard]] QDateTime start() const
88 {
89 return mStart;
90 }
91
92 [[nodiscard]] QDateTime end() const
93 {
94 return mEnd;
95 }
96
97 /** Calculate the start and end date/time of the recurrence that
98 happens on the given day */
99 bool overlaps(CellItem *o) const override
100 {
101 auto other = static_cast<PrintCellItem *>(o);
102 return !(other->start() >= end() || other->end() <= start());
103 }
104
105private:
107 QDateTime mStart, mEnd;
108};
109
110/******************************************************************
111 ** The Print plugin **
112 ******************************************************************/
113
115 : PrintPlugin()
116 , mUseColors(true)
117 , mPrintFooter(true)
118 , mHeaderHeight(-1)
119 , mSubHeaderHeight(SUBHEADER_HEIGHT)
120 , mFooterHeight(-1)
121 , mMargin(MARGIN_SIZE)
122 , mPadding(PADDING_SIZE)
123{
124}
125
126CalPrintPluginBase::~CalPrintPluginBase() = default;
127
129{
130 auto wdg = new QFrame(w);
131 auto layout = new QVBoxLayout(wdg);
132
133 auto title = new QLabel(description(), wdg);
134 QFont titleFont(title->font());
135 titleFont.setPointSize(20);
136 titleFont.setBold(true);
137 title->setFont(titleFont);
138
139 layout->addWidget(title);
140 layout->addWidget(new QLabel(info(), wdg));
141 layout->addSpacing(20);
142 layout->addWidget(new QLabel(i18n("This printing style does not have any configuration options."), wdg));
143 layout->addStretch();
144 return wdg;
145}
146
148{
149 if (!printer) {
150 return;
151 }
152 mPrinter = printer;
153 QPainter p;
154
156
157 p.begin(mPrinter);
158 // TODO: Fix the margins!!!
159 // the painter initially begins at 72 dpi per the Qt docs.
160 // we want half-inch margins.
161 int margins = margin();
162 p.setViewport(margins, margins, p.viewport().width() - 2 * margins, p.viewport().height() - 2 * margins);
163 // QRect vp( p.viewport() );
164 // vp.setRight( vp.right()*2 );
165 // vp.setBottom( vp.bottom()*2 );
166 // p.setWindow( vp );
167 int pageWidth = p.window().width();
168 int pageHeight = p.window().height();
169 // int pageWidth = p.viewport().width();
170 // int pageHeight = p.viewport().height();
171
172 print(p, pageWidth, pageHeight);
173
174 p.end();
175 mPrinter = nullptr;
176}
177
179{
180 if (mConfig) {
181 KConfigGroup group(mConfig, groupName());
182 mConfig->sync();
184 mFromDate = group.readEntry("FromDate", dt).date();
185 mToDate = group.readEntry("ToDate", dt).date();
186 mUseColors = group.readEntry("UseColors", true);
187 mPrintFooter = group.readEntry("PrintFooter", true);
188 mShowNoteLines = group.readEntry("Note Lines", false);
189 mExcludeConfidential = group.readEntry("Exclude confidential", true);
190 mExcludePrivate = group.readEntry("Exclude private", true);
191 } else {
192 qCDebug(CALENDARSUPPORT_LOG) << "No config available in loadConfig!!!!";
193 }
194}
195
197{
198 if (mConfig) {
199 KConfigGroup group(mConfig, groupName());
200 QDateTime dt = QDateTime::currentDateTime(); // any valid QDateTime will do
201 dt.setDate(mFromDate);
202 group.writeEntry("FromDate", dt);
203 dt.setDate(mToDate);
204 group.writeEntry("ToDate", dt);
205 group.writeEntry("UseColors", mUseColors);
206 group.writeEntry("PrintFooter", mPrintFooter);
207 group.writeEntry("Note Lines", mShowNoteLines);
208 group.writeEntry("Exclude confidential", mExcludeConfidential);
209 group.writeEntry("Exclude private", mExcludePrivate);
210 mConfig->sync();
211 } else {
212 qCDebug(CALENDARSUPPORT_LOG) << "No config available in saveConfig!!!!";
213 }
214}
215
217{
218 return mUseColors;
219}
220
221void CalPrintPluginBase::setUseColors(bool useColors)
222{
224}
225
226bool CalPrintPluginBase::printFooter() const
227{
228 return mPrintFooter;
229}
230
231void CalPrintPluginBase::setPrintFooter(bool printFooter)
232{
233 mPrintFooter = printFooter;
234}
235
236QPageLayout::Orientation CalPrintPluginBase::orientation() const
237{
239}
240
241QColor CalPrintPluginBase::getTextColor(const QColor &c) const
242{
243 double luminance = (c.red() * 0.299) + (c.green() * 0.587) + (c.blue() * 0.114);
244 return (luminance > 128.0) ? QColor(0, 0, 0) : QColor(255, 255, 255);
245}
246
247QTime CalPrintPluginBase::dayStart() const
248{
249 QTime start(8, 0, 0);
250 QDateTime dayBegins = KCalPrefs::instance()->dayBegins();
251 if (dayBegins.isValid()) {
252 start = dayBegins.time();
253 }
254 return start;
255}
256
257void CalPrintPluginBase::setColorsByIncidenceCategory(QPainter &p, const KCalendarCore::Incidence::Ptr &incidence) const
258{
259 QColor bgColor = categoryBgColor(incidence);
260 if (bgColor.isValid()) {
261 p.setBrush(bgColor);
262 }
263 QColor tColor(getTextColor(bgColor));
264 if (tColor.isValid()) {
265 p.setPen(tColor);
266 }
267}
268
269QColor CalPrintPluginBase::categoryColor(const QStringList &categories) const
270{
271 // FIXME: Correctly treat events with multiple categories
272 QColor bgColor;
273 if (!categories.isEmpty()) {
274 bgColor = Akonadi::TagCache::instance()->tagColor(categories.at(0));
275 }
276
277 return bgColor.isValid() ? bgColor : KCalPrefs::instance()->unsetCategoryColor();
278}
279
280QColor CalPrintPluginBase::categoryBgColor(const KCalendarCore::Incidence::Ptr &incidence) const
281{
282 if (incidence) {
283 QColor backColor = categoryColor(incidence->categories());
285 if ((incidence.staticCast<KCalendarCore::Todo>())->isOverdue()) {
286 backColor = QColor(255, 100, 100); // was KOPrefs::instance()->todoOverdueColor();
287 }
288 }
289 return backColor;
290 } else {
291 return {};
292 }
293}
294
295QString CalPrintPluginBase::holidayString(QDate date) const
296{
297 const QStringList lst = holiday(date);
298 return lst.join(i18nc("@item:intext delimiter for joining holiday names", ","));
299}
300
301KCalendarCore::Event::Ptr CalPrintPluginBase::holidayEvent(QDate date) const
302{
303 QString hstring(holidayString(date));
304 if (hstring.isEmpty()) {
305 return {};
306 }
307
309 holiday->setSummary(hstring);
310 holiday->setCategories(i18n("Holiday"));
311
312 QDateTime kdt(date, QTime(0, 0), QTimeZone::LocalTime);
313 holiday->setDtStart(kdt);
314 holiday->setDtEnd(kdt);
315 holiday->setAllDay(true);
316
317 return holiday;
318}
319
321{
322 if (mHeaderHeight >= 0) {
323 return mHeaderHeight;
324 } else if (orientation() == QPageLayout::Portrait) {
325 return PORTRAIT_HEADER_HEIGHT;
326 } else {
327 return LANDSCAPE_HEADER_HEIGHT;
328 }
329}
330
331void CalPrintPluginBase::setHeaderHeight(const int height)
332{
333 mHeaderHeight = height;
334}
335
336int CalPrintPluginBase::subHeaderHeight() const
337{
338 return mSubHeaderHeight;
339}
340
341void CalPrintPluginBase::setSubHeaderHeight(const int height)
342{
343 mSubHeaderHeight = height;
344}
345
347{
348 if (!mPrintFooter) {
349 return 0;
350 }
351
352 if (mFooterHeight >= 0) {
353 return mFooterHeight;
354 } else if (orientation() == QPageLayout::Portrait) {
355 return PORTRAIT_FOOTER_HEIGHT;
356 } else {
357 return LANDSCAPE_FOOTER_HEIGHT;
358 }
359}
360
361void CalPrintPluginBase::setFooterHeight(const int height)
362{
363 mFooterHeight = height;
364}
365
366int CalPrintPluginBase::margin() const
367{
368 return mMargin;
369}
370
371void CalPrintPluginBase::setMargin(const int margin)
372{
373 mMargin = margin;
374}
375
376int CalPrintPluginBase::padding() const
377{
378 return mPadding;
379}
380
381void CalPrintPluginBase::setPadding(const int padding)
382{
383 mPadding = padding;
384}
385
386int CalPrintPluginBase::borderWidth() const
387{
388 return mBorder;
389}
390
391void CalPrintPluginBase::setBorderWidth(const int borderwidth)
392{
393 mBorder = borderwidth;
394}
395
396void CalPrintPluginBase::drawBox(QPainter &p, int linewidth, QRect rect)
397{
398 QPen pen(p.pen());
399 QPen oldpen(pen);
400 // no border
401 if (linewidth >= 0) {
402 pen.setWidth(linewidth);
403 p.setPen(pen);
404 } else {
405 p.setPen(Qt::NoPen);
406 }
407 p.drawRect(rect);
408 p.setPen(oldpen);
409}
410
411void CalPrintPluginBase::drawShadedBox(QPainter &p, int linewidth, const QBrush &brush, QRect rect)
412{
413 QBrush oldbrush(p.brush());
414 p.setBrush(brush);
415 drawBox(p, linewidth, rect);
416 p.setBrush(oldbrush);
417}
418
419void CalPrintPluginBase::printEventString(QPainter &p, QRect box, const QString &str, int flags)
420{
421 QRect newbox(box);
422 newbox.adjust(3, 1, -1, -1);
423 p.drawText(newbox, (flags == -1) ? (Qt::AlignTop | Qt::AlignLeft | Qt::TextWordWrap) : flags, str);
424}
425
426void CalPrintPluginBase::showEventBox(QPainter &p, int linewidth, QRect box, const KCalendarCore::Incidence::Ptr &incidence, const QString &str, int flags)
427{
428 QPen oldpen(p.pen());
429 QBrush oldbrush(p.brush());
430 QColor bgColor(categoryBgColor(incidence));
431 if (mUseColors && bgColor.isValid()) {
432 p.setBrush(bgColor);
433 } else {
434 p.setBrush(QColor(232, 232, 232));
435 }
436 drawBox(p, (linewidth > 0) ? linewidth : EVENT_BORDER_WIDTH, box);
437 if (mUseColors && bgColor.isValid()) {
438 p.setPen(getTextColor(bgColor));
439 }
440 printEventString(p, box, str, flags);
441 p.setPen(oldpen);
442 p.setBrush(oldbrush);
443}
444
446{
447 drawShadedBox(p, BOX_BORDER_WIDTH, QColor(232, 232, 232), box);
448 QFont oldfont(p.font());
449 p.setFont(QFont(QStringLiteral("sans-serif"), 10, QFont::Bold));
451 p.setFont(oldfont);
452}
453
454void CalPrintPluginBase::drawVerticalBox(QPainter &p, int linewidth, QRect box, const QString &str, int flags)
455{
456 p.save();
457 p.rotate(-90);
458 QRect rotatedBox(-box.top() - box.height(), box.left(), box.height(), box.width());
459 showEventBox(p, linewidth, rotatedBox, KCalendarCore::Incidence::Ptr(), str, (flags == -1) ? Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine : flags);
460
461 p.restore();
462}
463
464/*
465 * Return value: If expand, bottom of the printed box, otherwise vertical end
466 * of the printed contents inside the box.
467 */
469 QRect allbox,
470 const QString &caption,
471 const QString &contents,
472 bool sameLine,
473 bool expand,
474 const QFont &captionFont,
475 const QFont &textFont,
476 bool richContents)
477{
478 QFont oldFont(p.font());
479 // QFont captionFont( "sans-serif", 11, QFont::Bold );
480 // QFont textFont( "sans-serif", 11, QFont::Normal );
481 // QFont captionFont( "Tahoma", 11, QFont::Bold );
482 // QFont textFont( "Tahoma", 11, QFont::Normal );
483
484 QRect box(allbox);
485
486 // Bounding rectangle for caption, single-line, clip on the right
487 QRect captionBox(box.left() + padding(), box.top() + padding(), 0, 0);
488 p.setFont(captionFont);
489 captionBox = p.boundingRect(captionBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, caption);
490 p.setFont(oldFont);
491 if (captionBox.right() > box.right()) {
492 captionBox.setRight(box.right());
493 }
494 if (expand && captionBox.bottom() + padding() > box.bottom()) {
495 box.setBottom(captionBox.bottom() + padding());
496 }
497
498 // Bounding rectangle for the contents (if any), word break, clip on the bottom
499 QRect textBox(captionBox);
500 if (!contents.isEmpty()) {
501 if (sameLine) {
502 textBox.setLeft(captionBox.right() + padding());
503 } else {
504 textBox.setTop(captionBox.bottom() + padding());
505 }
506 textBox.setRight(box.right());
507 }
508 drawBox(p, BOX_BORDER_WIDTH, box);
509 p.setFont(captionFont);
510 p.drawText(captionBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, caption);
511
512 if (!contents.isEmpty()) {
513 if (sameLine) {
514 QString contentText = toPlainText(contents);
515 p.setFont(textFont);
516 p.drawText(textBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, contentText);
517 } else {
518 QTextDocument rtb;
519 int borderWidth = 2 * BOX_BORDER_WIDTH;
520 if (richContents) {
521 rtb.setHtml(contents);
522 } else {
523 rtb.setPlainText(contents);
524 }
525 int boxHeight = allbox.height();
526 if (!sameLine) {
527 boxHeight -= captionBox.height();
528 }
529 rtb.setPageSize(QSize(textBox.width(), boxHeight));
530 rtb.setDefaultFont(textFont);
531 p.save();
532 p.translate(textBox.x() - borderWidth, textBox.y());
533 QRect clipBox(0, 0, box.width(), boxHeight);
535 ctx.palette.setColor(QPalette::Text, p.pen().color());
536 p.setClipRect(clipBox);
537 ctx.clip = clipBox;
538 rtb.documentLayout()->draw(&p, ctx);
539 p.restore();
540 textBox.setBottom(textBox.y() + rtb.documentLayout()->documentSize().height());
541 }
542 }
543 p.setFont(oldFont);
544
545 if (expand) {
546 return box.bottom();
547 } else {
548 return textBox.bottom();
549 }
550}
551
552int CalPrintPluginBase::drawHeader(QPainter &p, const QString &title, QDate month1, QDate month2, QRect allbox, bool expand, QColor backColor)
553{
554 // print previous month for month view, print current for to-do, day and week
555 int smallMonthWidth = (allbox.width() / 4) - 10;
556 if (smallMonthWidth > 100) {
557 smallMonthWidth = 100;
558 }
559
560 QRect box(allbox);
561 QRect textRect(allbox);
562
563 QFont oldFont(p.font());
564 QFont newFont(QStringLiteral("sans-serif"), (textRect.height() < 60) ? 16 : 18, QFont::Bold);
565 if (expand) {
566 p.setFont(newFont);
567 QRect boundingR = p.boundingRect(textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextWordWrap, title);
568 p.setFont(oldFont);
569 int h = boundingR.height();
570 if (h > allbox.height()) {
571 box.setHeight(h);
572 textRect.setHeight(h);
573 }
574 }
575
576 if (!backColor.isValid()) {
577 backColor = QColor(232, 232, 232);
578 }
579
580 drawShadedBox(p, BOX_BORDER_WIDTH, backColor, box);
581
582 const auto oldPen{p.pen()};
583 p.setPen(getTextColor(backColor));
584
585 // prev month left, current month centered, next month right
586 QRect monthbox2(box.right() - 10 - smallMonthWidth, box.top(), smallMonthWidth, box.height());
587 if (month2.isValid()) {
588 drawSmallMonth(p, QDate(month2.year(), month2.month(), 1), monthbox2);
589 textRect.setRight(monthbox2.left());
590 }
591 QRect monthbox1(box.left() + 10, box.top(), smallMonthWidth, box.height());
592 if (month1.isValid()) {
593 drawSmallMonth(p, QDate(month1.year(), month1.month(), 1), monthbox1);
594 textRect.setLeft(monthbox1.right());
595 }
596
597 // Set the margins
598 p.setFont(newFont);
600
601 p.setPen(oldPen);
602 p.setFont(oldFont);
603
604 return textRect.bottom();
605}
606
608{
609 QFont oldfont(p.font());
610 p.setFont(QFont(QStringLiteral("sans-serif"), 6));
612 p.drawText(footbox, Qt::AlignCenter | Qt::AlignVCenter | Qt::TextSingleLine, i18nc("print date: formatted-datetime", "printed: %1", dateStr));
613 p.setFont(oldfont);
614
615 return footbox.bottom();
616}
617
619{
620 int weekdayCol = weekdayColumn(qd.dayOfWeek());
621 int month = qd.month();
622 QDate monthDate(QDate(qd.year(), qd.month(), 1));
623 // correct begin of week
624 QDate monthDate2(monthDate.addDays(-weekdayCol));
625
626 double cellWidth = double(box.width()) / double(7);
627 int rownr = 3 + (qd.daysInMonth() + weekdayCol - 1) / 7;
628 // 3 Pixel after month name, 2 after day names, 1 after the calendar
629 double cellHeight = (box.height() - 5) / rownr;
630 QFont oldFont(p.font());
631 auto newFont = QFont(QStringLiteral("sans-serif"));
632 newFont.setPixelSize(cellHeight);
633 p.setFont(newFont);
634
635 const QLocale locale;
636
637 // draw the title
638 QRect titleBox(box);
639 titleBox.setHeight(p.fontMetrics().height());
640 p.drawText(titleBox, Qt::AlignTop | Qt::AlignHCenter, locale.standaloneMonthName(month));
641
642 // draw days of week
643 QRect wdayBox(box);
644 wdayBox.setTop(int(box.top() + 3 + cellHeight));
645 wdayBox.setHeight(int(2 * cellHeight) - int(cellHeight));
646
647 for (int col = 0; col < 7; ++col) {
648 const auto dayLetter = locale.standaloneDayName(monthDate2.dayOfWeek(), QLocale::ShortFormat)[0].toUpper();
649 wdayBox.setLeft(int(box.left() + col * cellWidth));
650 wdayBox.setRight(int(box.left() + (col + 1) * cellWidth));
651 p.drawText(wdayBox, Qt::AlignCenter, dayLetter);
652 monthDate2 = monthDate2.addDays(1);
653 }
654
655 // draw separator line
656 int calStartY = wdayBox.bottom() + 2;
657 p.drawLine(box.left(), calStartY, box.right(), calStartY);
658 monthDate = monthDate.addDays(-weekdayCol);
659
660 for (int row = 0; row < (rownr - 2); row++) {
661 for (int col = 0; col < 7; col++) {
662 if (monthDate.month() == month) {
663 QRect dayRect(int(box.left() + col * cellWidth), int(calStartY + row * cellHeight), 0, 0);
664 dayRect.setRight(int(box.left() + (col + 1) * cellWidth));
665 dayRect.setBottom(int(calStartY + (row + 1) * cellHeight));
666 p.drawText(dayRect, Qt::AlignCenter, QString::number(monthDate.day()));
667 }
668 monthDate = monthDate.addDays(1);
669 }
670 }
671 p.setFont(oldFont);
672}
673
674/*
675 * This routine draws a header box over the main part of the calendar
676 * containing the days of the week.
677 */
679{
680 double cellWidth = double(box.width() - 1) / double(fromDate.daysTo(toDate) + 1);
681 QDate cellDate(fromDate);
682 QRect dateBox(box);
683 int i = 0;
684
685 while (cellDate <= toDate) {
686 dateBox.setLeft(box.left() + int(i * cellWidth));
687 dateBox.setRight(box.left() + int((i + 1) * cellWidth));
688 drawDaysOfWeekBox(p, cellDate, dateBox);
689 cellDate = cellDate.addDays(1);
690 ++i;
691 }
692}
693
698
700{
701 drawBox(p, BOX_BORDER_WIDTH, box);
702
703 int totalsecs = fromTime.secsTo(toTime);
704 float minlen = (float)box.height() * 60. / (float)totalsecs;
705 float cellHeight = (60. * (float)minlen);
706 float currY = box.top();
707 // TODO: Don't use half of the width, but less, for the minutes!
708 int xcenter = box.left() + box.width() / 2;
709
710 QTime curTime(fromTime);
711 QTime endTime(toTime);
712 if (fromTime.minute() > 30) {
713 curTime = QTime(fromTime.hour() + 1, 0, 0);
714 } else if (fromTime.minute() > 0) {
715 curTime = QTime(fromTime.hour(), 30, 0);
716 float yy = currY + minlen * (float)fromTime.secsTo(curTime) / 60.;
717 p.drawLine(xcenter, (int)yy, box.right(), (int)yy);
718 curTime = QTime(fromTime.hour() + 1, 0, 0);
719 }
720 currY += (float(fromTime.secsTo(curTime) * minlen) / 60.);
721
722 while (curTime < endTime) {
723 p.drawLine(box.left(), (int)currY, box.right(), (int)currY);
724 int newY = (int)(currY + cellHeight / 2.);
725 QString numStr;
726 if (newY < box.bottom()) {
727 QFont oldFont(p.font());
728 // draw the time:
729 if (!QLocale().timeFormat().contains(QLatin1StringView("AP"))) { // 12h clock
730 p.drawLine(xcenter, (int)newY, box.right(), (int)newY);
731 numStr.setNum(curTime.hour());
732 if (cellHeight > 30) {
733 p.setFont(QFont(QStringLiteral("sans-serif"), 14, QFont::Bold));
734 } else {
735 p.setFont(QFont(QStringLiteral("sans-serif"), 12, QFont::Bold));
736 }
737 p.drawText(box.left() + 4, (int)currY + 2, box.width() / 2 - 2, (int)cellHeight, Qt::AlignTop | Qt::AlignRight, numStr);
738 p.setFont(QFont(QStringLiteral("helvetica"), 10, QFont::Normal));
739 p.drawText(xcenter + 4, (int)currY + 2, box.width() / 2 + 2, (int)(cellHeight / 2) - 3, Qt::AlignTop | Qt::AlignLeft, QStringLiteral("00"));
740 } else {
741 p.drawLine(box.left(), (int)newY, box.right(), (int)newY);
742 QTime time(curTime.hour(), 0);
744 if (box.width() < 60) {
745 p.setFont(QFont(QStringLiteral("sans-serif"), 7, QFont::Bold)); // for weekprint
746 } else {
747 p.setFont(QFont(QStringLiteral("sans-serif"), 12, QFont::Bold)); // for dayprint
748 }
749 p.drawText(box.left() + 2, (int)currY + 2, box.width() - 4, (int)cellHeight / 2 - 3, Qt::AlignTop | Qt::AlignLeft, numStr);
750 }
751 currY += cellHeight;
752 p.setFont(oldFont);
753 } // enough space for half-hour line and time
754 if (curTime.secsTo(endTime) > 3600) {
755 curTime = curTime.addSecs(3600);
756 } else {
757 curTime = endTime;
758 }
759 }
760}
761
763 const KCalendarCore::Event::List &events,
764 QDate qd,
765 bool expandable,
766 QTime fromTime,
767 QTime toTime,
768 QRect oldbox,
769 bool includeDescription,
770 bool includeCategories,
771 bool excludeTime,
772 const QList<QDate> &workDays)
773{
774 QTime myFromTime;
775 QTime myToTime;
776 if (fromTime.isValid()) {
777 myFromTime = fromTime;
778 } else {
779 myFromTime = QTime(0, 0, 0);
780 }
781 if (toTime.isValid()) {
782 myToTime = toTime;
783 } else {
784 myToTime = QTime(23, 59, 59);
785 }
786
787 if (!workDays.contains(qd)) {
788 drawShadedBox(p, BOX_BORDER_WIDTH, sHolidayBackground, oldbox);
789 } else {
790 drawBox(p, BOX_BORDER_WIDTH, oldbox);
791 }
792 QRect box(oldbox);
793 // Account for the border with and cut away that margin from the interior
794 // box.setRight( box.right()-BOX_BORDER_WIDTH );
795
796 if (expandable) {
797 // Adapt start/end times to include complete events
798 for (const KCalendarCore::Event::Ptr &event : std::as_const(events)) {
799 Q_ASSERT(event);
800 if (!event || (mExcludeConfidential && event->secrecy() == KCalendarCore::Incidence::SecrecyConfidential)
801 || (mExcludePrivate && event->secrecy() == KCalendarCore::Incidence::SecrecyPrivate)) {
802 continue;
803 }
804 // skip items without times so that we do not adjust for all day items
805 if (event->allDay()) {
806 continue;
807 }
808 if (event->dtStart().time() < myFromTime) {
809 myFromTime = event->dtStart().time();
810 }
811 if (event->dtEnd().time() > myToTime) {
812 myToTime = event->dtEnd().time();
813 }
814 }
815 }
816
817 // calculate the height of a cell and of a minute
818 int totalsecs = myFromTime.secsTo(myToTime);
819 float minlen = box.height() * 60. / totalsecs;
820 float cellHeight = 60. * minlen;
821 float currY = box.top();
822
823 // print grid:
824 QTime curTime(QTime(myFromTime.hour(), 0, 0));
825 currY += myFromTime.secsTo(curTime) * minlen / 60;
826
827 while (curTime < myToTime && curTime.isValid()) {
828 if (currY > box.top()) {
829 p.drawLine(box.left(), int(currY), box.right(), int(currY));
830 }
831 currY += cellHeight / 2;
832 if ((currY > box.top()) && (currY < box.bottom())) {
833 // enough space for half-hour line
834 QPen oldPen(p.pen());
835 p.setPen(QColor(192, 192, 192));
836 p.drawLine(box.left(), int(currY), box.right(), int(currY));
837 p.setPen(oldPen);
838 }
839 if (curTime.secsTo(myToTime) > 3600) {
840 curTime = curTime.addSecs(3600);
841 } else {
842 curTime = myToTime;
843 }
844 currY += cellHeight / 2;
845 }
846
847 QDateTime startPrintDate = QDateTime(qd, myFromTime);
848 QDateTime endPrintDate = QDateTime(qd, myToTime);
849
850 // Calculate horizontal positions and widths of events taking into account
851 // overlapping events
852
853 QList<CellItem *> cells;
854
855 for (const KCalendarCore::Event::Ptr &event : std::as_const(events)) {
856 if (!event || (mExcludeConfidential && event->secrecy() == KCalendarCore::Incidence::SecrecyConfidential)
857 || (mExcludePrivate && event->secrecy() == KCalendarCore::Incidence::SecrecyPrivate)) {
858 continue;
859 }
860 if (event->allDay()) {
861 continue;
862 }
863 QList<QDateTime> times = event->startDateTimesForDate(qd, QTimeZone::systemTimeZone());
864 cells.reserve(times.count());
865 for (auto it = times.constBegin(); it != times.constEnd(); ++it) {
866 cells.append(new PrintCellItem(event, (*it).toLocalTime(), event->endDateForStart(*it).toLocalTime()));
867 }
868 }
869
870 QListIterator<CellItem *> it1(cells);
871 while (it1.hasNext()) {
872 CellItem *placeItem = it1.next();
873 CellItem::placeItem(cells, placeItem);
874 }
875
876 QListIterator<CellItem *> it2(cells);
877 while (it2.hasNext()) {
878 auto placeItem = static_cast<PrintCellItem *>(it2.next());
879 drawAgendaItem(placeItem, p, startPrintDate, endPrintDate, minlen, box, includeDescription, includeCategories, excludeTime);
880 }
881}
882
883void CalPrintPluginBase::drawAgendaItem(PrintCellItem *item,
884 QPainter &p,
885 const QDateTime &startPrintDate,
886 const QDateTime &endPrintDate,
887 float minlen,
888 QRect box,
889 bool includeDescription,
890 bool includeCategories,
891 bool excludeTime)
892{
893 KCalendarCore::Event::Ptr event = item->event();
894
895 // start/end of print area for event
896 QDateTime startTime = item->start();
897 QDateTime endTime = item->end();
898 if ((startTime < endPrintDate && endTime > startPrintDate) || (endTime > startPrintDate && startTime < endPrintDate)) {
899 if (startTime < startPrintDate) {
900 startTime = startPrintDate;
901 }
902 if (endTime > endPrintDate) {
903 endTime = endPrintDate;
904 }
905 int currentWidth = box.width() / item->subCells();
906 int currentX = box.left() + item->subCell() * currentWidth;
907 int currentYPos = int(box.top() + startPrintDate.secsTo(startTime) * minlen / 60.);
908 int currentHeight = int(box.top() + startPrintDate.secsTo(endTime) * minlen / 60.) - currentYPos;
909
910 QRect eventBox(currentX, currentYPos, currentWidth, currentHeight);
911 QString str;
912 if (excludeTime) {
913 if (event->location().isEmpty()) {
914 str = cleanStr(event->summary());
915 } else {
916 str = i18nc("summary, location", "%1, %2", cleanStr(event->summary()), cleanStr(event->location()));
917 }
918 } else {
919 if (event->location().isEmpty()) {
920 str = i18nc("starttime - endtime summary",
921 "%1-%2 %3",
924 cleanStr(event->summary()));
925 } else {
926 str = i18nc("starttime - endtime summary, location",
927 "%1-%2 %3, %4",
930 cleanStr(event->summary()),
931 cleanStr(event->location()));
932 }
933 }
934 if (includeCategories && !event->categoriesStr().isEmpty()) {
935 str = i18nc("summary, categories", "%1, %2", str, event->categoriesStr());
936 }
937 if (includeDescription && !event->description().isEmpty()) {
938 str += QLatin1Char('\n');
939 if (event->descriptionIsRich()) {
940 str += toPlainText(event->description());
941 } else {
942 str += event->description();
943 }
944 }
945 QFont oldFont(p.font());
946 if (eventBox.height() < 24) {
947 if (eventBox.height() < 12) {
948 if (eventBox.height() < 8) {
949 p.setFont(QFont(QStringLiteral("sans-serif"), 4));
950 } else {
951 p.setFont(QFont(QStringLiteral("sans-serif"), 5));
952 }
953 } else {
954 p.setFont(QFont(QStringLiteral("sans-serif"), 6));
955 }
956 } else {
957 p.setFont(QFont(QStringLiteral("sans-serif"), 8));
958 }
959 showEventBox(p, EVENT_BORDER_WIDTH, eventBox, event, str);
960 p.setFont(oldFont);
961 }
962}
963
965 QDate qd,
966 QTime fromTime,
967 QTime toTime,
968 QRect box,
969 bool fullDate,
970 bool printRecurDaily,
971 bool printRecurWeekly,
972 bool singleLineLimit,
973 bool includeDescription,
974 bool includeCategories)
975{
976 QString dayNumStr;
977 const auto local = QLocale::system();
978
979 QTime myFromTime;
980 QTime myToTime;
981 if (fromTime.isValid()) {
982 myFromTime = fromTime;
983 } else {
984 myFromTime = QTime(0, 0, 0);
985 }
986 if (toTime.isValid()) {
987 myToTime = toTime;
988 } else {
989 myToTime = QTime(23, 59, 59);
990 }
991
992 if (fullDate) {
993 dayNumStr = i18nc("weekday, shortmonthname daynumber",
994 "%1, %2 %3",
995 QLocale::system().dayName(qd.dayOfWeek()),
997 QString::number(qd.day()));
998 } else {
999 dayNumStr = QString::number(qd.day());
1000 }
1001
1002 QRect subHeaderBox(box);
1003 subHeaderBox.setHeight(mSubHeaderHeight);
1004 drawShadedBox(p, BOX_BORDER_WIDTH, p.background(), box);
1005 drawShadedBox(p, 0, QColor(232, 232, 232), subHeaderBox);
1006 drawBox(p, BOX_BORDER_WIDTH, box);
1007 QString hstring(holidayString(qd));
1008 const QFont oldFont(p.font());
1009
1010 QRect headerTextBox(subHeaderBox.adjusted(5, 0, -5, 0));
1011 p.setFont(QFont(QStringLiteral("sans-serif"), 10, QFont::Bold));
1012 QRect dayNumRect;
1013 p.drawText(headerTextBox, Qt::AlignRight | Qt::AlignVCenter, dayNumStr, &dayNumRect);
1014 if (!hstring.isEmpty()) {
1015 p.setFont(QFont(QStringLiteral("sans-serif"), 8, QFont::Bold, true));
1016 QFontMetrics fm(p.font());
1017 hstring = fm.elidedText(hstring, Qt::ElideRight, headerTextBox.width() - dayNumRect.width() - 5);
1018 p.drawText(headerTextBox, Qt::AlignLeft | Qt::AlignVCenter, hstring);
1019 p.setFont(QFont(QStringLiteral("sans-serif"), 10, QFont::Bold));
1020 }
1021
1022 const KCalendarCore::Event::List eventList =
1024
1025 QString timeText;
1026 p.setFont(QFont(QStringLiteral("sans-serif"), 7));
1027
1028 int textY = mSubHeaderHeight; // gives the relative y-coord of the next printed entry
1029 unsigned int visibleEventsCounter = 0;
1030 for (const KCalendarCore::Event::Ptr &currEvent : std::as_const(eventList)) {
1031 Q_ASSERT(currEvent);
1032 if (!currEvent->allDay()) {
1033 if (currEvent->dtEnd().toLocalTime().time() <= myFromTime || currEvent->dtStart().toLocalTime().time() > myToTime) {
1034 continue;
1035 }
1036 }
1037 if ((!printRecurDaily && currEvent->recurrenceType() == KCalendarCore::Recurrence::rDaily)
1038 || (!printRecurWeekly && currEvent->recurrenceType() == KCalendarCore::Recurrence::rWeekly)) {
1039 continue;
1040 }
1042 || (mExcludePrivate && currEvent->secrecy() == KCalendarCore::Incidence::SecrecyPrivate)) {
1043 continue;
1044 }
1045 if (currEvent->allDay() || currEvent->isMultiDay()) {
1046 timeText.clear();
1047 } else {
1048 timeText = local.toString(currEvent->dtStart().toLocalTime().time(), QLocale::ShortFormat) + QLatin1Char(' ');
1049 }
1050 p.save();
1051 if (mUseColors) {
1052 setColorsByIncidenceCategory(p, currEvent);
1053 }
1054 QString summaryStr = currEvent->summary();
1055 if (!currEvent->location().isEmpty()) {
1056 summaryStr = i18nc("summary, location", "%1, %2", summaryStr, currEvent->location());
1057 }
1058 if (includeCategories && !currEvent->categoriesStr().isEmpty()) {
1059 summaryStr = i18nc("summary, categories", "%1, %2", summaryStr, currEvent->categoriesStr());
1060 }
1061 drawIncidence(p, box, timeText, summaryStr, currEvent->description(), textY, singleLineLimit, includeDescription, currEvent->descriptionIsRich());
1062 p.restore();
1063 visibleEventsCounter++;
1064
1065 if (textY >= box.height()) {
1066 const QChar downArrow(0x21e3);
1067
1068 const unsigned int invisibleIncidences = (eventList.count() - visibleEventsCounter) + mCalendar->todos(qd).count();
1069 if (invisibleIncidences > 0) {
1070 const QString warningMsg = QStringLiteral("%1 (%2)").arg(downArrow).arg(invisibleIncidences);
1071
1072 QFontMetrics fm(p.font());
1073 QRect msgRect = fm.boundingRect(warningMsg);
1074 msgRect.setRect(box.right() - msgRect.width() - 2, box.bottom() - msgRect.height() - 2, msgRect.width(), msgRect.height());
1075
1076 p.save();
1077 p.setPen(Qt::red); // krazy:exclude=qenums we don't allow custom print colors
1078 p.drawText(msgRect, Qt::AlignLeft, warningMsg);
1079 p.restore();
1080 }
1081 break;
1082 }
1083 }
1084
1085 if (textY < box.height()) {
1086 KCalendarCore::Todo::List todos = mCalendar->todos(qd);
1087 for (const KCalendarCore::Todo::Ptr &todo : std::as_const(todos)) {
1088 if (!todo->allDay()) {
1089 if ((todo->hasDueDate() && todo->dtDue().toLocalTime().time() <= myFromTime)
1090 || (todo->hasStartDate() && todo->dtStart().toLocalTime().time() > myToTime)) {
1091 continue;
1092 }
1093 }
1094 if ((!printRecurDaily && todo->recurrenceType() == KCalendarCore::Recurrence::rDaily)
1095 || (!printRecurWeekly && todo->recurrenceType() == KCalendarCore::Recurrence::rWeekly)) {
1096 continue;
1097 }
1099 || (mExcludePrivate && todo->secrecy() == KCalendarCore::Incidence::SecrecyPrivate)) {
1100 continue;
1101 }
1102 if (todo->hasStartDate() && !todo->allDay()) {
1103 timeText = QLocale().toString(todo->dtStart().toLocalTime().time(), QLocale::ShortFormat) + QLatin1Char(' ');
1104 } else {
1105 timeText.clear();
1106 }
1107 p.save();
1108 if (mUseColors) {
1109 setColorsByIncidenceCategory(p, todo);
1110 }
1111 QString summaryStr = todo->summary();
1112 if (!todo->location().isEmpty()) {
1113 summaryStr = i18nc("summary, location", "%1, %2", summaryStr, todo->location());
1114 }
1115
1116 QString str;
1117 if (todo->hasDueDate()) {
1118 if (!todo->allDay()) {
1119 str = i18nc("to-do summary (Due: datetime)",
1120 "%1 (Due: %2)",
1121 summaryStr,
1122 QLocale().toString(todo->dtDue().toLocalTime(), QLocale::ShortFormat));
1123 } else {
1124 str = i18nc("to-do summary (Due: date)",
1125 "%1 (Due: %2)",
1126 summaryStr,
1127 QLocale().toString(todo->dtDue().toLocalTime().date(), QLocale::ShortFormat));
1128 }
1129 } else {
1130 str = summaryStr;
1131 }
1132 drawIncidence(p, box, timeText, i18n("To-do: %1", str), todo->description(), textY, singleLineLimit, includeDescription, todo->descriptionIsRich());
1133 p.restore();
1134 }
1135 }
1136 if (mShowNoteLines) {
1137 drawNoteLines(p, box, box.y() + textY);
1138 }
1139
1140 p.setFont(oldFont);
1141}
1142
1143void CalPrintPluginBase::drawIncidence(QPainter &p,
1144 QRect dayBox,
1145 const QString &time,
1146 const QString &summary,
1147 const QString &description,
1148 int &textY,
1149 bool singleLineLimit,
1150 bool includeDescription,
1151 bool richDescription)
1152{
1153 qCDebug(CALENDARSUPPORT_LOG) << "summary =" << summary << ", singleLineLimit=" << singleLineLimit;
1154
1155 int flags = Qt::AlignLeft | Qt::OpaqueMode;
1156 QFontMetrics fm = p.fontMetrics();
1157 const int borderWidth = p.pen().width() + 1;
1158
1159 QString firstLine{time};
1160 if (!firstLine.isEmpty()) {
1161 firstLine += QStringLiteral(" ");
1162 }
1163 firstLine += summary;
1164
1165 if (singleLineLimit) {
1166 if (includeDescription && !description.isEmpty()) {
1167 firstLine += QStringLiteral(". ") + toPlainText(description);
1168 }
1169
1170 int totalHeight = fm.height() + borderWidth;
1171 int textBoxHeight = (totalHeight > (dayBox.height() - textY)) ? dayBox.height() - textY : totalHeight;
1172 QRect boxRect(dayBox.x() + p.pen().width(), dayBox.y() + textY, dayBox.width(), textBoxHeight);
1173 drawBox(p, 1, boxRect);
1174 p.drawText(boxRect.adjusted(3, 0, -3, 0), flags, firstLine);
1175 textY += textBoxHeight;
1176 } else {
1177 QTextDocument textDoc;
1178 QTextCursor textCursor(&textDoc);
1179 textCursor.insertText(firstLine);
1180 if (includeDescription && !description.isEmpty()) {
1181 textCursor.insertText(QStringLiteral("\n"));
1182 if (richDescription) {
1183 textCursor.insertHtml(description);
1184 } else {
1185 textCursor.insertText(toPlainText(description));
1186 }
1187 }
1188
1189 QRect textBox = QRect(dayBox.x(), dayBox.y() + textY + 1, dayBox.width(), dayBox.height() - textY);
1190 textDoc.setPageSize(QSize(textBox.width(), textBox.height()));
1191
1192 textBox.setHeight(textDoc.documentLayout()->documentSize().height());
1193 if (textBox.bottom() > dayBox.bottom()) {
1194 textBox.setBottom(dayBox.bottom());
1195 }
1196
1197 QRect boxRext(dayBox.x() + p.pen().width(), dayBox.y() + textY, dayBox.width(), textBox.height());
1198 drawBox(p, 1, boxRext);
1199
1200 QRect clipRect(0, 0, textBox.width(), textBox.height());
1202 ctx.palette.setColor(QPalette::Text, p.pen().color());
1203 ctx.clip = clipRect;
1204 p.save();
1205 p.translate(textBox.x(), textBox.y());
1206 p.setClipRect(clipRect);
1207 textDoc.documentLayout()->draw(&p, ctx);
1208 p.restore();
1209
1210 textY += textBox.height();
1211
1212 if (textDoc.pageCount() > 1) {
1213 // show that we have overflowed the box
1214 QPolygon poly(3);
1215 int x = dayBox.x() + dayBox.width();
1216 int y = dayBox.y() + dayBox.height();
1217 poly.setPoint(0, x - 10, y);
1218 poly.setPoint(1, x, y - 10);
1219 poly.setPoint(2, x, y);
1220 QBrush oldBrush(p.brush());
1222 p.drawPolygon(poly);
1223 p.setBrush(oldBrush);
1224 textY = dayBox.height();
1225 }
1226 }
1227}
1228
1229class MonthEventStruct
1230{
1231public:
1232 MonthEventStruct()
1233 : event(nullptr)
1234 {
1235 }
1236
1237 MonthEventStruct(const QDateTime &s, const QDateTime &e, const KCalendarCore::Event::Ptr &ev)
1238 : start(s)
1239 , end(e)
1240 , event(ev)
1241 {
1242 if (event->allDay()) {
1243 start = QDateTime(start.date(), QTime(0, 0, 0));
1244 end = QDateTime(end.date().addDays(1), QTime(0, 0, 0)).addSecs(-1);
1245 }
1246 }
1247
1248 bool operator<(const MonthEventStruct &mes)
1249 {
1250 return start < mes.start;
1251 }
1252
1254 QDateTime end;
1256};
1257
1258void CalPrintPluginBase::drawMonth(QPainter &p, QDate dt, QRect box, int maxdays, int subDailyFlags, int holidaysFlags)
1259{
1260 p.save();
1261 QRect subheaderBox(box);
1262 subheaderBox.setHeight(subHeaderHeight());
1263 QRect borderBox(box);
1264 borderBox.setTop(subheaderBox.bottom() + 1);
1265 drawSubHeaderBox(p, QLocale().standaloneMonthName(dt.month()), subheaderBox);
1266 // correct for half the border width
1267 int correction = (BOX_BORDER_WIDTH /*-1*/) / 2;
1268 QRect daysBox(borderBox);
1269 daysBox.adjust(correction, correction, -correction, -correction);
1270
1271 int daysinmonth = dt.daysInMonth();
1272 if (maxdays <= 0) {
1273 maxdays = daysinmonth;
1274 }
1275
1276 float dayheight = float(daysBox.height()) / float(maxdays);
1277
1278 QColor holidayColor(240, 240, 240);
1279 QColor workdayColor(255, 255, 255);
1280 int dayNrWidth = p.fontMetrics().boundingRect(QStringLiteral("99")).width();
1281
1282 // Fill the remaining space (if a month has less days than others) with a crossed-out pattern
1283 if (daysinmonth < maxdays) {
1284 QRect dayBox(box.left(), daysBox.top() + qRound(dayheight * daysinmonth), box.width(), 0);
1285 dayBox.setBottom(daysBox.bottom());
1286 p.fillRect(dayBox, Qt::DiagCrossPattern);
1287 }
1288 // Backgrounded boxes for each day, plus day numbers
1289 QBrush oldbrush(p.brush());
1290
1291 QList<QDate> workDays;
1292
1293 {
1294 QDate startDate(dt.year(), dt.month(), 1);
1295 QDate endDate(dt.year(), dt.month(), daysinmonth);
1296
1297 workDays = CalendarSupport::workDays(startDate, endDate);
1298 }
1299
1300 for (int d = 0; d < daysinmonth; ++d) {
1301 QDate day(dt.year(), dt.month(), d + 1);
1302 QRect dayBox(daysBox.left() /*+rand()%50*/, daysBox.top() + qRound(dayheight * d), daysBox.width() /*-rand()%50*/, 0);
1303 // FIXME: When using a border width of 0 for event boxes,
1304 // don't let the rectangles overlap, i.e. subtract 1 from the top or bottom!
1305 dayBox.setBottom(daysBox.top() + qRound(dayheight * (d + 1)) - 1);
1306
1307 p.setBrush(workDays.contains(day) ? workdayColor : holidayColor);
1308 p.drawRect(dayBox);
1309 QRect dateBox(dayBox);
1310 dateBox.setWidth(dayNrWidth + 3);
1312 }
1313 p.setBrush(oldbrush);
1314 int xstartcont = box.left() + dayNrWidth + 5;
1315
1316 QDate start(dt.year(), dt.month(), 1);
1317 QDate end = start.addMonths(1);
1318 end = end.addDays(-1);
1319
1320 const KCalendarCore::Event::List events = mCalendar->events(start, end);
1321 QMap<int, QStringList> textEvents;
1322 QList<CellItem *> timeboxItems;
1323
1324 // 1) For multi-day events, show boxes spanning several cells, use CellItem
1325 // print the summary vertically
1326 // 2) For sub-day events, print the concated summaries into the remaining
1327 // space of the box (optional, depending on the given flags)
1328 // 3) Draw some kind of timeline showing free and busy times
1329
1330 // Holidays
1331 // QList<KCalendarCore::Event::Ptr> holidays;
1332 for (QDate d(start); d <= end; d = d.addDays(1)) {
1333 KCalendarCore::Event::Ptr e = holidayEvent(d);
1334 if (e) {
1335 // holidays.append(e);
1336 if (holidaysFlags & TimeBoxes) {
1337 timeboxItems.append(new PrintCellItem(e, QDateTime(d, QTime(0, 0, 0)), QDateTime(d.addDays(1), QTime(0, 0, 0))));
1338 }
1339 if (holidaysFlags & Text) {
1340 textEvents[d.day()] << e->summary();
1341 }
1342 }
1343 }
1344
1345 QList<MonthEventStruct> monthentries;
1346
1347 for (const KCalendarCore::Event::Ptr &e : std::as_const(events)) {
1350 continue;
1351 }
1352 if (e->recurs()) {
1353 if (e->recursOn(start, QTimeZone::systemTimeZone())) {
1354 // This occurrence has possibly started before the beginning of the
1355 // month, so obtain the start date before the beginning of the month
1356 QList<QDateTime> starttimes = e->startDateTimesForDate(start, QTimeZone::systemTimeZone());
1357 for (auto it = starttimes.constBegin(); it != starttimes.constEnd(); ++it) {
1358 monthentries.append(MonthEventStruct((*it).toLocalTime(), e->endDateForStart(*it).toLocalTime(), e));
1359 }
1360 }
1361 // Loop through all remaining days of the month and check if the event
1362 // begins on that day (don't use Event::recursOn, as that will
1363 // also return events that have started earlier. These start dates
1364 // however, have already been treated!
1365 KCalendarCore::Recurrence *recur = e->recurrence();
1366 QDate d1(start.addDays(1));
1367 while (d1 <= end) {
1368 if (recur->recursOn(d1, QTimeZone::systemTimeZone())) {
1369 KCalendarCore::TimeList times(recur->recurTimesOn(d1, QTimeZone::systemTimeZone()));
1370 for (KCalendarCore::TimeList::ConstIterator it = times.constBegin(); it != times.constEnd(); ++it) {
1371 QDateTime d1start(d1, *it, QTimeZone::LocalTime);
1372 monthentries.append(MonthEventStruct(d1start, e->endDateForStart(d1start).toLocalTime(), e));
1373 }
1374 }
1375 d1 = d1.addDays(1);
1376 }
1377 } else {
1378 monthentries.append(MonthEventStruct(e->dtStart().toLocalTime(), e->dtEnd().toLocalTime(), e));
1379 }
1380 }
1381
1382 // TODO: to port the month entries sorting
1383
1384 // qSort( monthentries.begin(), monthentries.end() );
1385
1387 QDateTime endofmonth(end, QTime(0, 0, 0));
1388 endofmonth = endofmonth.addDays(1);
1389 for (; mit != monthentries.constEnd(); ++mit) {
1390 if ((*mit).start.date() == (*mit).end.date()) {
1391 // Show also single-day events as time line boxes
1392 if (subDailyFlags & TimeBoxes) {
1393 timeboxItems.append(new PrintCellItem((*mit).event, (*mit).start, (*mit).end));
1394 }
1395 // Show as text in the box
1396 if (subDailyFlags & Text) {
1397 textEvents[(*mit).start.date().day()] << (*mit).event->summary();
1398 }
1399 } else {
1400 // Multi-day events are always shown as time line boxes
1401 QDateTime thisstart((*mit).start);
1402 QDateTime thisend((*mit).end);
1403 if (thisstart.date() < start) {
1404 thisstart.setDate(start);
1405 }
1406 if (thisend > endofmonth) {
1407 thisend = endofmonth;
1408 }
1409 timeboxItems.append(new PrintCellItem((*mit).event, thisstart, thisend));
1410 }
1411 }
1412
1413 // For Multi-day events, line them up nicely so that the boxes don't overlap
1414 QListIterator<CellItem *> it1(timeboxItems);
1415 while (it1.hasNext()) {
1416 CellItem *placeItem = it1.next();
1417 CellItem::placeItem(timeboxItems, placeItem);
1418 }
1419 QDateTime starttime(start, QTime(0, 0, 0));
1420 int newxstartcont = xstartcont;
1421
1422 QFont oldfont(p.font());
1423 p.setFont(QFont(QStringLiteral("sans-serif"), 7));
1424 while (it1.hasNext()) {
1425 auto placeItem = static_cast<PrintCellItem *>(it1.next());
1426 int minsToStart = starttime.secsTo(placeItem->start()) / 60;
1427 int minsToEnd = starttime.secsTo(placeItem->end()) / 60;
1428
1429 QRect eventBox(xstartcont + placeItem->subCell() * 17,
1430 daysBox.top() + qRound(double(minsToStart * daysBox.height()) / double(maxdays * 24 * 60)),
1431 14,
1432 0);
1433 eventBox.setBottom(daysBox.top() + qRound(double(minsToEnd * daysBox.height()) / double(maxdays * 24 * 60)));
1434 drawVerticalBox(p, 0, eventBox, placeItem->event()->summary());
1435 newxstartcont = qMax(newxstartcont, eventBox.right());
1436 }
1437 xstartcont = newxstartcont;
1438
1439 // For Single-day events, simply print their summaries into the remaining
1440 // space of the day's cell
1441 for (int d = 0; d < daysinmonth; ++d) {
1442 QStringList dayEvents(textEvents[d + 1]);
1443 QString txt = dayEvents.join(QLatin1StringView(", "));
1444 QRect dayBox(xstartcont, daysBox.top() + qRound(dayheight * d), 0, 0);
1445 dayBox.setRight(box.right());
1446 dayBox.setBottom(daysBox.top() + qRound(dayheight * (d + 1)));
1448 }
1449 p.setFont(oldfont);
1450 drawBox(p, BOX_BORDER_WIDTH, borderBox);
1451 p.restore();
1452}
1453
1455 QDate qd,
1456 QTime fromTime,
1457 QTime toTime,
1458 bool weeknumbers,
1459 bool recurDaily,
1460 bool recurWeekly,
1461 bool singleLineLimit,
1462 bool includeDescription,
1463 bool includeCategories,
1464 QRect box)
1465{
1466 int yoffset = mSubHeaderHeight;
1467 int xoffset = 0;
1468 QDate monthDate(QDate(qd.year(), qd.month(), 1));
1469 QDate monthFirst(monthDate);
1470 QDate monthLast(monthDate.addMonths(1).addDays(-1));
1471
1472 int weekdayCol = weekdayColumn(monthDate.dayOfWeek());
1473 monthDate = monthDate.addDays(-weekdayCol);
1474
1475 if (weeknumbers) {
1476 xoffset += 14;
1477 }
1478
1479 int rows = (weekdayCol + qd.daysInMonth() - 1) / 7 + 1;
1480 double cellHeight = (box.height() - yoffset) / (1. * rows);
1481 double cellWidth = (box.width() - xoffset) / 7.;
1482
1483 // Precalculate the grid...
1484 // rows is at most 6, so using 8 entries in the array is fine, too!
1485 int coledges[8];
1486 int rowedges[8];
1487 for (int i = 0; i <= 7; ++i) {
1488 rowedges[i] = int(box.top() + yoffset + i * cellHeight);
1489 coledges[i] = int(box.left() + xoffset + i * cellWidth);
1490 }
1491
1492 if (weeknumbers) {
1493 QFont oldFont(p.font());
1494 QFont newFont(p.font());
1495 newFont.setPointSize(6);
1496 p.setFont(newFont);
1497 QDate weekDate(monthDate);
1498 for (int row = 0; row < rows; ++row) {
1499 int calWeek = weekDate.weekNumber();
1500 QRect rc(box.left(), rowedges[row], coledges[0] - 3 - box.left(), rowedges[row + 1] - rowedges[row]);
1502 weekDate = weekDate.addDays(7);
1503 }
1504 p.setFont(oldFont);
1505 }
1506
1507 QRect daysOfWeekBox(box);
1508 daysOfWeekBox.setHeight(mSubHeaderHeight);
1509 daysOfWeekBox.setLeft(box.left() + xoffset);
1510 drawDaysOfWeek(p, monthDate, monthDate.addDays(6), daysOfWeekBox);
1511
1512 QColor back = p.background().color();
1513 bool darkbg = false;
1514 for (int row = 0; row < rows; ++row) {
1515 for (int col = 0; col < 7; ++col) {
1516 // show days from previous/next month with a grayed background
1517 if ((monthDate < monthFirst) || (monthDate > monthLast)) {
1518 p.setBackground(back.darker(120));
1519 darkbg = true;
1520 }
1521 QRect dayBox(coledges[col], rowedges[row], coledges[col + 1] - coledges[col], rowedges[row + 1] - rowedges[row]);
1522 drawDayBox(p, monthDate, fromTime, toTime, dayBox, false, recurDaily, recurWeekly, singleLineLimit, includeDescription, includeCategories);
1523 if (darkbg) {
1524 p.setBackground(back);
1525 darkbg = false;
1526 }
1527 monthDate = monthDate.addDays(1);
1528 }
1529 }
1530}
1531
1532void CalPrintPluginBase::drawTodoLines(QPainter &p,
1533 const QString &entry,
1534 int x,
1535 int &y,
1536 int width,
1537 int pageHeight,
1538 bool richTextEntry,
1539 QList<TodoParentStart *> &startPoints,
1540 bool connectSubTodos)
1541{
1542 QString plainEntry = (richTextEntry) ? toPlainText(entry) : entry;
1543
1544 QRect textrect(0, 0, width, -1);
1545 int flags = Qt::AlignLeft;
1546 QFontMetrics fm = p.fontMetrics();
1547
1548 QStringList lines = plainEntry.split(QLatin1Char('\n'));
1549 for (int currentLine = 0; currentLine < lines.count(); currentLine++) {
1550 // split paragraphs into lines
1551 KWordWrap ww = KWordWrap::formatText(fm, textrect, flags, lines[currentLine]);
1552 QStringList textLine = ww.wrappedString().split(QLatin1Char('\n'));
1553
1554 // print each individual line
1555 for (int lineCount = 0; lineCount < textLine.count(); lineCount++) {
1556 if (y >= pageHeight) {
1557 if (connectSubTodos) {
1558 for (int i = 0; i < startPoints.size(); ++i) {
1559 TodoParentStart *rct;
1560 rct = startPoints.at(i);
1561 int start = rct->mRect.bottom() + 1;
1562 int center = rct->mRect.left() + (rct->mRect.width() / 2);
1563 int to = y;
1564 if (!rct->mSamePage) {
1565 start = 0;
1566 }
1567 if (rct->mHasLine) {
1568 p.drawLine(center, start, center, to);
1569 }
1570 rct->mSamePage = false;
1571 }
1572 }
1573 y = 0;
1574 mPrinter->newPage();
1575 }
1576 y += fm.height();
1577 p.drawText(x, y, textLine[lineCount]);
1578 }
1579 }
1580}
1581
1583 const KCalendarCore::Todo::Ptr &todo,
1584 QPainter &p,
1587 bool connectSubTodos,
1588 bool strikeoutCompleted,
1589 bool desc,
1590 int posPriority,
1591 int posSummary,
1592 int posCategories,
1593 int posStartDt,
1594 int posDueDt,
1595 int posPercentComplete,
1596 int level,
1597 int x,
1598 int &y,
1599 int width,
1600 int pageHeight,
1601 const KCalendarCore::Todo::List &todoList,
1602 TodoParentStart *r)
1603{
1604 QString outStr;
1605 const auto locale = QLocale::system();
1606 QRect rect;
1607 TodoParentStart startpt;
1608 // This list keeps all starting points of the parent to-dos so the connection
1609 // lines of the tree can easily be drawn (needed if a new page is started)
1610 static QList<TodoParentStart *> startPoints;
1611 if (level < 1) {
1612 startPoints.clear();
1613 }
1614
1615 // Don't print confidential or private items if so configured (sub-items are also ignored!)
1617 || (mExcludePrivate && todo->secrecy() == KCalendarCore::Incidence::SecrecyPrivate)) {
1618 return;
1619 }
1620
1621 QFontMetrics fm = p.fontMetrics();
1622 y += 10;
1623 // Start a new page if the item does not fit on the page any more (only
1624 // first line is checked! Word-wrapped summaries might still overflow!)
1625 if (y + fm.height() >= pageHeight) {
1626 y = 0;
1627 mPrinter->newPage();
1628 // reset the parent start points to indicate not on same page
1629 for (int i = 0; i < startPoints.size(); ++i) {
1630 TodoParentStart *rct;
1631 rct = startPoints.at(i);
1632 rct->mSamePage = false;
1633 }
1634 }
1635
1636 int left = posSummary + (level * 10);
1637
1638 // If this is a sub-to-do, r will not be 0, and we want the LH side
1639 // of the priority line up to the RH side of the parent to-do's priority
1640 int lhs = posPriority;
1641 if (r) {
1642 lhs = r->mRect.right() + 1;
1643 }
1644
1645 outStr.setNum(todo->priority());
1646 rect = p.boundingRect(lhs, y + 10, 5, -1, Qt::AlignCenter, outStr);
1647 // Make it a more reasonable size
1648 rect.setWidth(18);
1649 rect.setHeight(18);
1650 const int top = rect.top();
1651
1652 // Draw a checkbox
1654 p.drawRect(rect);
1655 if (todo->isCompleted()) {
1656 // cross out the rectangle for completed to-dos
1657 p.drawLine(rect.topLeft(), rect.bottomRight());
1658 p.drawLine(rect.topRight(), rect.bottomLeft());
1659 }
1660 lhs = rect.right() + 5;
1661
1662 // Priority
1663 if (posPriority >= 0 && todo->priority() > 0) {
1664 p.drawText(rect, Qt::AlignCenter, outStr);
1665 }
1666 startpt.mRect = rect; // save for later
1667
1668 // Connect the dots
1669 if (r && level > 0 && connectSubTodos) {
1670 int bottom;
1671 int center(r->mRect.left() + (r->mRect.width() / 2));
1672 int to(rect.top() + (rect.height() / 2));
1673 int endx(rect.left());
1674 p.drawLine(center, to, endx, to); // side connector
1675 if (r->mSamePage) {
1676 bottom = r->mRect.bottom() + 1;
1677 } else {
1678 bottom = 0;
1679 }
1680 p.drawLine(center, bottom, center, to);
1681 }
1682
1683 int posSoFar = width; // Position of leftmost optional field.
1684
1685 // due date
1686 if (posDueDt >= 0 && todo->hasDueDate()) {
1687 outStr = locale.toString(todo->dtDue().toLocalTime().date(), QLocale::ShortFormat);
1688 rect = p.boundingRect(posDueDt, top, x + width, -1, Qt::AlignTop | Qt::AlignLeft, outStr);
1689 p.drawText(rect, Qt::AlignTop | Qt::AlignLeft, outStr);
1690 posSoFar = posDueDt;
1691 }
1692
1693 // start date
1694 if (posStartDt >= 0 && todo->hasStartDate()) {
1695 outStr = locale.toString(todo->dtStart().toLocalTime().date(), QLocale::ShortFormat);
1696 rect = p.boundingRect(posStartDt, top, x + width, -1, Qt::AlignTop | Qt::AlignLeft, outStr);
1697 p.drawText(rect, Qt::AlignTop | Qt::AlignLeft, outStr);
1698 posSoFar = posStartDt;
1699 }
1700
1701 // percentage completed
1702 if (posPercentComplete >= 0) {
1703 int lwidth = 24;
1704 int lheight = p.fontMetrics().ascent();
1705 // first, draw the progress bar
1706 int progress = static_cast<int>(((lwidth * todo->percentComplete()) / 100.0 + 0.5));
1707
1709 p.drawRect(posPercentComplete, top, lwidth, lheight);
1710 if (progress > 0) {
1711 p.setBrush(QColor(128, 128, 128));
1712 p.drawRect(posPercentComplete, top, progress, lheight);
1713 }
1714
1715 // now, write the percentage
1716 outStr = i18n("%1%", todo->percentComplete());
1717 rect = p.boundingRect(posPercentComplete + lwidth + 3, top, x + width, -1, Qt::AlignTop | Qt::AlignLeft, outStr);
1718 p.drawText(rect, Qt::AlignTop | Qt::AlignLeft, outStr);
1719 posSoFar = posPercentComplete;
1720 }
1721
1722 // categories
1723 QRect categoriesRect{0, 0, 0, 0};
1724 if (posCategories >= 0) {
1725 outStr = todo->categoriesStr();
1726 outStr.replace(QLatin1Char(','), QLatin1Char('\n'));
1727 rect = p.boundingRect(posCategories, top, posSoFar - posCategories, -1, Qt::TextWordWrap, outStr);
1728 p.drawText(rect, Qt::TextWordWrap, outStr, &categoriesRect);
1729 posSoFar = posCategories;
1730 }
1731
1732 // summary
1733 outStr = todo->summary();
1734 rect = p.boundingRect(lhs, top, posSoFar - lhs - 5, -1, Qt::TextWordWrap, outStr);
1735 QFont oldFont(p.font());
1736 if (strikeoutCompleted && todo->isCompleted()) {
1737 QFont newFont(p.font());
1738 newFont.setStrikeOut(true);
1739 p.setFont(newFont);
1740 }
1741 QRect summaryRect;
1742 p.drawText(rect, Qt::TextWordWrap, outStr, &summaryRect);
1743 p.setFont(oldFont);
1744
1745 y = std::max(categoriesRect.bottom(), summaryRect.bottom());
1746
1747 // description
1748 if (desc && !todo->description().isEmpty()) {
1749 drawTodoLines(p, todo->description(), left, y, width - (left + 10 - x), pageHeight, todo->descriptionIsRich(), startPoints, connectSubTodos);
1750 }
1751
1752 // Make a list of all the sub-to-dos related to this to-do.
1754 for (const KCalendarCore::Incidence::Ptr &incidence : mCalendar->incidences()) {
1755 // In the future, to-dos might also be related to events
1756 // Manually check if the sub-to-do is in the list of to-dos to print
1757 // The problem is that relations() does not apply filters, so
1758 // we need to compare manually with the complete filtered list!
1760 if (!subtodo) {
1761 continue;
1762 }
1763
1764 if (subtodo->relatedTo() != todo->uid()) {
1765 continue;
1766 }
1767
1768#ifdef AKONADI_PORT_DISABLED
1769 if (subtodo && todoList.contains(subtodo)) {
1770#else
1771 bool subtodoOk = false;
1772 if (subtodo) {
1773 for (const KCalendarCore::Todo::Ptr &tt : std::as_const(todoList)) {
1774 if (tt == subtodo) {
1775 subtodoOk = true;
1776 break;
1777 }
1778 }
1779 }
1780 if (subtodoOk) {
1781#endif
1782 t.append(subtodo);
1783 }
1784 }
1785
1786 // has sub-todos?
1787 startpt.mHasLine = (t.size() > 0);
1788 startPoints.append(&startpt);
1789
1790 // Sort the sub-to-dos and print them
1791#ifdef AKONADI_PORT_DISABLED
1792 KCalendarCore::Todo::List sl = mCalendar->sortTodos(&t, sortField, sortDir);
1793#else
1795 tl.reserve(t.count());
1796 for (const KCalendarCore::Todo::Ptr &todo : std::as_const(t)) {
1797 tl.append(todo);
1798 }
1799 KCalendarCore::Todo::List sl = mCalendar->sortTodos(std::move(tl), sortField, sortDir);
1800#endif
1801
1802 int subcount = 0;
1803 for (const KCalendarCore::Todo::Ptr &isl : std::as_const(sl)) {
1804 count++;
1805 if (++subcount == sl.size()) {
1806 startpt.mHasLine = false;
1807 }
1808 drawTodo(count,
1809 isl,
1810 p,
1811 sortField,
1812 sortDir,
1813 connectSubTodos,
1814 strikeoutCompleted,
1815 desc,
1816 posPriority,
1817 posSummary,
1818 posCategories,
1819 posStartDt,
1820 posDueDt,
1821 posPercentComplete,
1822 level + 1,
1823 x,
1824 y,
1825 width,
1826 pageHeight,
1827 todoList,
1828 &startpt);
1829 }
1830 startPoints.removeAll(&startpt);
1831}
1832
1834{
1835 int w = weekday + 7 - QLocale().firstDayOfWeek();
1836 return w % 7;
1837}
1838
1839void CalPrintPluginBase::drawTextLines(QPainter &p, const QString &entry, int x, int &y, int width, int pageHeight, bool richTextEntry)
1840{
1841 QString plainEntry = (richTextEntry) ? toPlainText(entry) : entry;
1842
1843 QRect textrect(0, 0, width, -1);
1844 int flags = Qt::AlignLeft;
1845 QFontMetrics fm = p.fontMetrics();
1846
1847 QStringList lines = plainEntry.split(QLatin1Char('\n'));
1848 for (int currentLine = 0; currentLine < lines.count(); currentLine++) {
1849 // split paragraphs into lines
1850 KWordWrap ww = KWordWrap::formatText(fm, textrect, flags, lines[currentLine]);
1851 QStringList textLine = ww.wrappedString().split(QLatin1Char('\n'));
1852 // print each individual line
1853 for (int lineCount = 0; lineCount < textLine.count(); lineCount++) {
1854 y += fm.height();
1855 if (y >= pageHeight) {
1856 if (mPrintFooter) {
1857 drawFooter(p, {0, pageHeight, width, footerHeight()});
1858 }
1859 y = fm.height();
1860 mPrinter->newPage();
1861 }
1862 p.drawText(x, y, textLine[lineCount]);
1863 }
1864 }
1865}
1866
1867void CalPrintPluginBase::drawSplitHeaderRight(QPainter &p, QDate fd, QDate td, QDate, int width, int height)
1868{
1869 QFont oldFont(p.font());
1870
1871 QPen oldPen(p.pen());
1872 QPen pen(Qt::black, 4);
1873
1874 QString title;
1875 QLocale locale;
1876 if (fd.month() == td.month()) {
1877 title = i18nc("Date range: Month dayStart - dayEnd",
1878 "%1 %2\u2013%3",
1879 locale.monthName(fd.month(), QLocale::LongFormat),
1880 locale.toString(fd, QStringLiteral("dd")),
1881 locale.toString(td, QStringLiteral("dd")));
1882 } else {
1883 title = i18nc("Date range: monthStart dayStart - monthEnd dayEnd",
1884 "%1 %2\u2013%3 %4",
1885 locale.monthName(fd.month(), QLocale::LongFormat),
1886 locale.toString(fd, QStringLiteral("dd")),
1887 locale.monthName(td.month(), QLocale::LongFormat),
1888 locale.toString(td, QStringLiteral("dd")));
1889 }
1890
1891 if (height < 60) {
1892 p.setFont(QFont(QStringLiteral("Times"), 22));
1893 } else {
1894 p.setFont(QFont(QStringLiteral("Times"), 28));
1895 }
1896
1897 int lineSpacing = p.fontMetrics().lineSpacing();
1898 p.drawText(0, 0, width, lineSpacing, Qt::AlignRight | Qt::AlignTop, title);
1899
1900 title.truncate(0);
1901
1902 p.setPen(pen);
1903 p.drawLine(300, lineSpacing, width, lineSpacing);
1904 p.setPen(oldPen);
1905
1906 if (height < 60) {
1907 p.setFont(QFont(QStringLiteral("Times"), 14, QFont::Bold, true));
1908 } else {
1909 p.setFont(QFont(QStringLiteral("Times"), 18, QFont::Bold, true));
1910 }
1911
1912 title += QString::number(fd.year());
1913 p.drawText(0, lineSpacing + padding(), width, lineSpacing, Qt::AlignRight | Qt::AlignTop, title);
1914
1915 p.setFont(oldFont);
1916}
1917
1919{
1920 int lineHeight = int(p.fontMetrics().lineSpacing() * 1.5);
1921 int linePos = box.y();
1922 int startPos = startY;
1923 // adjust line to start at multiple from top of box for alignment
1924 while (linePos < startPos) {
1925 linePos += lineHeight;
1926 }
1927 QPen oldPen(p.pen());
1929 while (linePos < box.bottom()) {
1930 p.drawLine(box.left() + padding(), linePos, box.right() - padding(), linePos);
1931 linePos += lineHeight;
1932 }
1933 p.setPen(oldPen);
1934}
1935
1936QString CalPrintPluginBase::toPlainText(const QString &htmlText)
1937{
1938 // this converts possible rich text to plain text
1940}
QColor tagColor(const QString &tagName) const
static TagCache * instance()
int drawHeader(QPainter &p, const QString &title, QDate month1, QDate month2, QRect box, bool expand=false, QColor backColor=QColor())
Draw the gray header bar of the printout to the QPainter.
int drawBoxWithCaption(QPainter &p, QRect box, const QString &caption, const QString &contents, bool sameLine, bool expand, const QFont &captionFont, const QFont &textFont, bool richContents=false)
Draw a component box with a heading (printed in bold).
int footerHeight() const
Returns the height of the page footer.
static void drawShadedBox(QPainter &p, int linewidth, const QBrush &brush, QRect rect)
Draw a shaded box with given width at the given coordinates.
bool mExcludePrivate
Whether or not to print incidences with secrecy "private".
void drawAgendaDayBox(QPainter &p, const KCalendarCore::Event::List &eventList, QDate qd, bool expandable, QTime fromTime, QTime toTime, QRect box, bool includeDescription, bool includeCategories, bool excludeTime, const QList< QDate > &workDays)
Draw the agenda box for the day print style (the box showing all events of that day).
void drawTodo(int &count, const KCalendarCore::Todo::Ptr &todo, QPainter &p, KCalendarCore::TodoSortField sortField, KCalendarCore::SortDirection sortDir, bool connectSubTodos, bool strikeoutCompleted, bool desc, int posPriority, int posSummary, int posCategories, int posStartDt, int posDueDt, int posPercentComplete, int level, int x, int &y, int width, int pageHeight, const KCalendarCore::Todo::List &todoList, TodoParentStart *r)
Draws single to-do and its (indented) sub-to-dos, optionally connects them by a tree-like line,...
bool mShowNoteLines
Whether or not to print horizontal lines in note areas.
virtual void print(QPainter &p, int width, int height)=0
Actually do the printing.
void drawVerticalBox(QPainter &p, int linewidth, QRect box, const QString &str, int flags=-1)
Draw an event box with vertical text.
static void drawBox(QPainter &p, int linewidth, QRect rect)
Draw a box with given width at the given coordinates.
void drawDaysOfWeekBox(QPainter &p, QDate qd, QRect box)
Draw a single weekday name in a box inside the given area of the painter.
void showEventBox(QPainter &p, int linewidth, QRect box, const KCalendarCore::Incidence::Ptr &incidence, const QString &str, int flags=-1)
Print the box for the given event with the given string.
void drawTextLines(QPainter &p, const QString &entry, int x, int &y, int width, int pageHeight, bool richTextEntry)
Draws text lines splitting on page boundaries.
int headerHeight() const
Returns the height of the page header.
void drawSmallMonth(QPainter &p, QDate qd, QRect box)
Draw a small calendar with the days of a month into the given area.
void drawMonth(QPainter &p, QDate dt, QRect box, int maxdays=-1, int subDailyFlags=TimeBoxes, int holidaysFlags=Text)
Draw a vertical representation of the month containing the date dt.
void drawSubHeaderBox(QPainter &p, const QString &str, QRect box)
Draw a subheader box with a shaded background and the given string.
void printEventString(QPainter &p, QRect box, const QString &str, int flags=-1)
Print the given string (event summary) in the given rectangle.
int drawFooter(QPainter &p, QRect box)
Draw a page footer containing the printing date and possibly other things, like a page number.
bool mExcludeConfidential
Whether or not to print incidences with secrecy "confidential".
void doSaveConfig() override
Save complete configuration.
void doPrint(QPrinter *printer) override
Start printing.
void doLoadConfig() override
Load complete configuration.
void drawDayBox(QPainter &p, QDate qd, QTime fromTime, QTime toTime, QRect box, bool fullDate=false, bool printRecurDaily=true, bool printRecurWeekly=true, bool singleLineLimit=true, bool includeDescription=false, bool includeCategories=false)
Draw the box containing a list of all events of the given day (with their times, of course).
void drawMonthTable(QPainter &p, QDate qd, QTime fromTime, QTime toTime, bool weeknumbers, bool recurDaily, bool recurWeekly, bool singleLineLimit, bool includeDescription, bool includeCategories, QRect box)
Draw the month table of the month containing the date qd.
void drawDaysOfWeek(QPainter &p, QDate fromDate, QDate toDate, QRect box)
Draw a horizontal bar with the weekday names of the given date range in the given area of the painter...
static int weekdayColumn(int weekday)
Determines the column of the given weekday ( 1=Monday, 7=Sunday ), taking the start of the week setti...
bool mPrintFooter
Whether or not to print a footer at the bottoms of pages.
bool useColors() const
HELPER FUNCTIONS.
void drawNoteLines(QPainter &p, QRect box, int startY)
Draws dotted lines for notes in a box.
void drawTimeLine(QPainter &p, QTime fromTime, QTime toTime, QRect box)
Draw a (vertical) time scale from time fromTime to toTime inside the given area of the painter.
bool mUseColors
Whether or not to use event category colors to draw the events.
QWidget * createConfigWidget(QWidget *) override
Returns widget for configuring the print format.
Base class for Calendar printing classes.
Definition printplugin.h:33
virtual QString info() const =0
Returns long description of print format.
virtual QString description() const =0
Returns short description of print format.
virtual QString groupName() const =0
Returns KConfig group name where store settings.
QPrinter * mPrinter
The printer object.
bool recursOn(const QDate &date, const QTimeZone &timeZone) const
TimeList recurTimesOn(const QDate &date, const QTimeZone &timeZone) const
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
QString readEntry(const char *key, const char *aDefault=nullptr) const
bool sync() override
static KWordWrap formatText(QFontMetrics &fm, const QRect &r, int flags, const QString &str, int len=-1)
QString wrappedString() const
Q_SCRIPTABLE Q_NOREPLY void start()
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::Event::Ptr event(const Akonadi::Item &item)
char * toString(const EngineQuery &query)
const QList< QKeySequence > & end()
virtual QSizeF documentSize() const const=0
virtual void draw(QPainter *painter, const PaintContext &context)=0
const QColor & color() const const
int blue() const const
int green() const const
bool isValid() const const
int red() const const
QDate addDays(qint64 ndays) const const
QDate addMonths(int nmonths) const const
int day() const const
int dayOfWeek() const const
int daysInMonth() const const
qint64 daysTo(QDate d) const const
bool isValid(int year, int month, int day)
int month() const const
int weekNumber(int *yearNumber) const const
int year() const const
QDateTime addDays(qint64 ndays) const const
QDateTime addSecs(qint64 s) const const
QDateTime currentDateTime()
QDate date() const const
bool isValid() const const
qint64 secsTo(const QDateTime &other) const const
void setDate(QDate date)
QTime time() const const
QDateTime toLocalTime() const const
void setBold(bool enable)
void setPointSize(int pointSize)
void setStrikeOut(bool enable)
int ascent() const const
QRect boundingRect(QChar ch) const const
QString elidedText(const QString &text, Qt::TextElideMode mode, int width, int flags) const const
int height() const const
int lineSpacing() const const
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
void clear()
const_iterator constBegin() const const
const_iterator constEnd() const const
bool contains(const AT &value) const const
qsizetype count() const const
bool isEmpty() const const
qsizetype removeAll(const AT &t)
void reserve(qsizetype size)
qsizetype size() const const
bool hasNext() const const
const T & next()
Qt::DayOfWeek firstDayOfWeek() const const
QString monthName(int month, FormatType type) const const
QString standaloneDayName(int day, FormatType type) const const
QString standaloneMonthName(int month, FormatType type) const const
QLocale system()
QString toString(QDate date, FormatType format) const const
QPageLayout pageLayout() const const
Orientation orientation() const const
const QBrush & background() const const
bool begin(QPaintDevice *device)
QRect boundingRect(const QRect &rectangle, int flags, const QString &text)
const QBrush & brush() const const
void drawLine(const QLine &line)
void drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule)
void drawRect(const QRect &rectangle)
void drawText(const QPoint &position, const QString &text)
bool end()
void fillRect(const QRect &rectangle, QGradient::Preset preset)
const QFont & font() const const
QFontMetrics fontMetrics() const const
const QPen & pen() const const
void restore()
void rotate(qreal angle)
void save()
void setBackground(const QBrush &brush)
void setBrush(Qt::BrushStyle style)
void setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
void setFont(const QFont &font)
void setPen(Qt::PenStyle style)
void setViewport(const QRect &rectangle)
void translate(const QPoint &offset)
QRect viewport() const const
QRect window() const const
QColor color() const const
void setWidth(int width)
int width() const const
virtual bool newPage() override
void setColorMode(ColorMode newColorMode)
void adjust(int dx1, int dy1, int dx2, int dy2)
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
int bottom() const const
QPoint bottomLeft() const const
QPoint bottomRight() const const
int height() const const
int left() const const
int right() const const
void setBottom(int y)
void setHeight(int height)
void setLeft(int x)
void setRect(int x, int y, int width, int height)
void setRight(int x)
void setTop(int y)
void setWidth(int width)
int top() const const
QPoint topLeft() const const
QPoint topRight() const const
int width() const const
int x() const const
int y() const const
QSharedPointer< X > dynamicCast() const const
QSharedPointer< X > staticCast() const const
qreal height() const const
QString arg(Args &&... args) const const
void clear()
bool isEmpty() const const
QString number(double n, char format, int precision)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString & setNum(double n, char format, int precision)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString toUpper() const const
void truncate(qsizetype position)
QString join(QChar separator) const const
AlignTop
OpaqueMode
DiagCrossPattern
ElideRight
TextWordWrap
QAbstractTextDocumentLayout * documentLayout() const const
int pageCount() const const
void setPageSize(const QSizeF &size)
void setDefaultFont(const QFont &font)
void setHtml(const QString &html)
void setPlainText(const QString &text)
QTextDocumentFragment fromHtml(const QString &text, const QTextDocument *resourceProvider)
QString toPlainText() const const
QTime addSecs(int s) const const
int hour() const const
bool isValid(int h, int m, int s, int ms)
int minute() const const
int secsTo(QTime t) const const
QTimeZone systemTimeZone()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:16:32 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.