CalendarSupport

calprintdefaultplugins.cpp
1/*
2 SPDX-FileCopyrightText: 1998 Preston Brown <pbrown@kde.org>
3 SPDX-FileCopyrightText: 2003 Reinhold Kainhofer <reinhold@kainhofer.com>
4 SPDX-FileCopyrightText: 2003 Cornelius Schumacher <schumacher@kde.org>
5 SPDX-FileCopyrightText: 2008 Ron Goodheart <rong.dev@gmail.com>
6 SPDX-FileCopyrightText: 2010-2024 Laurent Montel <montel@kde.org>
7 SPDX-FileCopyrightText: 2012-2013 Allen Winter <winter@kde.org>
8
9 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
10*/
11
12#include "calprintdefaultplugins.h"
13#include "kcalprefs.h"
14#include "utils.h"
15
16#include <cmath>
17
18#include <Akonadi/CalendarUtils>
19#include <Akonadi/Item>
20
21#include <KCalendarCore/Visitor>
22
23#include <KCalUtils/IncidenceFormatter>
24#include <KCalUtils/Stringify>
25
26#include <KConfigGroup>
27
28#include <QPainter>
29
30using namespace CalendarSupport;
31
32/**************************************************************
33 * Print Incidence
34 **************************************************************/
35
36CalPrintIncidence::CalPrintIncidence()
38{
39}
40
41CalPrintIncidence::~CalPrintIncidence() = default;
42
43QWidget *CalPrintIncidence::createConfigWidget(QWidget *w)
44{
45 return new CalPrintIncidenceConfig(w);
46}
47
48void CalPrintIncidence::readSettingsWidget()
49{
50 auto cfg = dynamic_cast<CalPrintIncidenceConfig *>((QWidget *)mConfigWidget);
51 if (cfg) {
52 mUseColors = cfg->mColors->isChecked();
53 mPrintFooter = cfg->mPrintFooter->isChecked();
54 mShowOptions = cfg->mShowDetails->isChecked();
55 mShowSubitemsNotes = cfg->mShowSubitemsNotes->isChecked();
56 mShowAttendees = cfg->mShowAttendees->isChecked();
57 mShowAttachments = cfg->mShowAttachments->isChecked();
58 mShowNoteLines = cfg->mShowNoteLines->isChecked();
59 }
60}
61
62void CalPrintIncidence::setSettingsWidget()
63{
64 auto cfg = dynamic_cast<CalPrintIncidenceConfig *>((QWidget *)mConfigWidget);
65 if (cfg) {
66 cfg->mColors->setChecked(mUseColors);
67 cfg->mPrintFooter->setChecked(mPrintFooter);
68 cfg->mShowDetails->setChecked(mShowOptions);
69 cfg->mShowSubitemsNotes->setChecked(mShowSubitemsNotes);
70 cfg->mShowAttendees->setChecked(mShowAttendees);
71 cfg->mShowAttachments->setChecked(mShowAttachments);
72 cfg->mShowNoteLines->setChecked(mShowNoteLines);
73 }
74}
75
76void CalPrintIncidence::doLoadConfig()
77{
79 if (mConfig) {
80 KConfigGroup grp(mConfig, groupName());
81 mShowOptions = grp.readEntry("Show Options", false);
82 mShowSubitemsNotes = grp.readEntry("Show Subitems and Notes", false);
83 mShowAttendees = grp.readEntry("Use Attendees", false);
84 mShowAttachments = grp.readEntry("Use Attachments", false);
85 }
86 setSettingsWidget();
87}
88
89void CalPrintIncidence::doSaveConfig()
90{
91 readSettingsWidget();
92 if (mConfig) {
93 KConfigGroup grp(mConfig, groupName());
94 grp.writeEntry("Show Options", mShowOptions);
95 grp.writeEntry("Show Subitems and Notes", mShowSubitemsNotes);
96 grp.writeEntry("Use Attendees", mShowAttendees);
97 grp.writeEntry("Use Attachments", mShowAttachments);
98 }
100}
101
102class TimePrintStringsVisitor : public KCalendarCore::Visitor
103{
104public:
105 TimePrintStringsVisitor() = default;
106
107 bool act(KCalendarCore::IncidenceBase::Ptr incidence)
108 {
109 return incidence->accept(*this, incidence);
110 }
111
112 QString mStartCaption, mStartString;
113 QString mEndCaption, mEndString;
114 QString mDurationCaption, mDurationString;
115
116protected:
117 bool visit(const KCalendarCore::Event::Ptr &event) override
118 {
119 if (event->dtStart().isValid()) {
120 mStartCaption = i18n("Start date: ");
121 mStartString = KCalUtils::IncidenceFormatter::dateTimeToString(event->dtStart(), event->allDay(), false);
122 } else {
123 mStartCaption = i18n("No start date");
124 mStartString.clear();
125 }
126
127 if (event->hasEndDate()) {
128 mEndCaption = i18n("End date: ");
129 mEndString = KCalUtils::IncidenceFormatter::dateTimeToString(event->dtEnd(), event->allDay(), false);
130 } else if (event->hasDuration()) {
131 mEndCaption = i18n("Duration: ");
132 int mins = event->duration().asSeconds() / 60;
133 if (mins >= 60) {
134 mEndString += i18np("1 hour ", "%1 hours ", mins / 60);
135 }
136 if (mins % 60 > 0) {
137 mEndString += i18np("1 minute ", "%1 minutes ", mins % 60);
138 }
139 } else {
140 mEndCaption = i18n("No end date");
141 mEndString.clear();
142 }
143 return true;
144 }
145
146 bool visit(const KCalendarCore::Todo::Ptr &todo) override
147 {
148 if (todo->hasStartDate()) {
149 mStartCaption = i18n("Start date: ");
150 mStartString = KCalUtils::IncidenceFormatter::dateTimeToString(todo->dtStart(), todo->allDay(), false);
151 } else {
152 mStartCaption = i18n("No start date");
153 mStartString.clear();
154 }
155
156 if (todo->hasDueDate()) {
157 mEndCaption = i18n("Due date: ");
158 mEndString = KCalUtils::IncidenceFormatter::dateTimeToString(todo->dtDue(), todo->allDay(), false);
159 } else {
160 mEndCaption = i18n("No due date");
161 mEndString.clear();
162 }
163 return true;
164 }
165
166 bool visit(const KCalendarCore::Journal::Ptr &journal) override
167 {
168 mStartCaption = i18n("Start date: ");
169 mStartString = KCalUtils::IncidenceFormatter::dateTimeToString(journal->dtStart(), journal->allDay(), false);
170 mEndCaption.clear();
171 mEndString.clear();
172 return true;
173 }
174
175 bool visit(const KCalendarCore::FreeBusy::Ptr &fb) override
176 {
177 Q_UNUSED(fb)
178 return true;
179 }
180};
181
182int CalPrintIncidence::printCaptionAndText(QPainter &p, QRect box, const QString &caption, const QString &text, const QFont &captionFont, const QFont &textFont)
183{
184 QFontMetrics captionFM(captionFont);
185 int textWd = captionFM.horizontalAdvance(caption);
186 QRect textRect(box);
187
188 QFont oldFont(p.font());
189 p.setFont(captionFont);
191
192 if (!text.isEmpty()) {
193 textRect.setLeft(textRect.left() + textWd);
194 p.setFont(textFont);
196 }
197 p.setFont(oldFont);
198 return textRect.bottom();
199}
200
201void CalPrintIncidence::print(QPainter &p, int width, int height)
202{
203 QFont oldFont(p.font());
204 QFont textFont(QStringLiteral("sans-serif"), 11, QFont::Normal);
205 QFont captionFont(QStringLiteral("sans-serif"), 11, QFont::Bold);
206 p.setFont(textFont);
207 int lineHeight = p.fontMetrics().lineSpacing();
208 QString cap;
209 QString txt;
210
212 for (it = mSelectedIncidences.constBegin(); it != mSelectedIncidences.constEnd(); ++it) {
213 // don't do anything on a 0-pointer!
214 if (!(*it)) {
215 continue;
216 }
217 if (it != mSelectedIncidences.constBegin()) {
218 mPrinter->newPage();
219 }
220
221 const bool isJournal = ((*it)->type() == KCalendarCore::Incidence::TypeJournal);
222
223 // PAGE Layout (same for landscape and portrait! astonishingly, it looks good with both!):
224 // +-----------------------------------+
225 // | Header: Summary |
226 // +===================================+
227 // | start: ______ end: _________ |
228 // | repeats: ___________________ |
229 // | reminder: __________________ |
230 // +-----------------------------------+
231 // | Location: ______________________ |
232 // +------------------------+----------+
233 // | Description: | Notes or |
234 // | | Subitems |
235 // | | |
236 // | | |
237 // | | |
238 // | | |
239 // | | |
240 // | | |
241 // | | |
242 // | | |
243 // +------------------------+----------+
244 // | Attachments: | Settings |
245 // | | |
246 // +------------------------+----------+
247 // | Attendees: |
248 // | |
249 // +-----------------------------------+
250 // | Categories: _____________________ |
251 // +-----------------------------------+
252
253 QRect box(0, 0, width, height);
254 QRect titleBox(box);
255 titleBox.setHeight(headerHeight());
256 QColor headerColor = mUseColors ? categoryBgColor(*it) : QColor();
257 // Draw summary as header, no small calendars in title bar, expand height if needed
258 int titleBottom = drawHeader(p, (*it)->summary(), QDate(), QDate(), titleBox, true, headerColor);
259 titleBox.setBottom(titleBottom);
260
261 QRect timesBox(titleBox);
262 timesBox.setTop(titleBox.bottom() + padding());
263 timesBox.setHeight(height / 8);
264
265 TimePrintStringsVisitor stringVis;
266 int h = timesBox.top();
267 if (stringVis.act(*it)) {
268 QRect textRect(timesBox.left() + padding(), timesBox.top() + padding(), 0, lineHeight);
269 textRect.setRight(timesBox.center().x());
270 h = printCaptionAndText(p, textRect, stringVis.mStartCaption, stringVis.mStartString, captionFont, textFont);
271
272 textRect.setLeft(textRect.right());
273 textRect.setRight(timesBox.right() - padding());
274 h = qMax(printCaptionAndText(p, textRect, stringVis.mEndCaption, stringVis.mEndString, captionFont, textFont), h);
275 }
276
277 // Recurrence Printing
278 if ((*it)->recurs()) {
279 QRect recurBox(timesBox.left() + padding(), h + padding(), timesBox.right() - padding(), lineHeight);
280 KCalendarCore::Recurrence *recurs = (*it)->recurrence();
282 // exception dates
283 QString exceptString;
284 if (!recurs->exDates().isEmpty()) {
285 exceptString = i18nc("except for listed dates", " except");
286 for (int i = 0; i < recurs->exDates().size(); ++i) {
287 exceptString.append(QLatin1Char(' '));
288 exceptString.append(QLocale::system().toString(recurs->exDates().at(i), QLocale::ShortFormat));
289 }
290 }
291 displayString.append(exceptString);
292 h = qMax(printCaptionAndText(p, recurBox, i18n("Repeats: "), displayString, captionFont, textFont), h);
293 }
294
295 if (!isJournal) {
296 // Alarms Printing
297 QRect alarmBox(timesBox.left() + padding(), h + padding(), timesBox.right() - padding(), lineHeight);
298 KCalendarCore::Alarm::List alarms = (*it)->alarms();
299 if (alarms.isEmpty()) {
300 cap = i18n("No reminders");
301 txt.clear();
302 } else {
303 cap = i18np("Reminder: ", "%1 reminders: ", alarms.count());
304
305 QStringList alarmStrings;
307 alarmStrings.reserve(alarms.count());
308 for (it = alarms.constBegin(); it != alarms.constEnd(); ++it) {
309 KCalendarCore::Alarm::Ptr alarm = *it;
310
311 // Alarm offset, copied from koeditoralarms.cpp:
312 KLocalizedString offsetstr;
313 int offset = 0;
314 if (alarm->hasStartOffset()) {
315 offset = alarm->startOffset().asSeconds();
316 if (offset < 0) {
317 offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 before the start");
318 offset = -offset;
319 } else {
320 offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 after the start");
321 }
322 } else if (alarm->hasEndOffset()) {
323 offset = alarm->endOffset().asSeconds();
324 if (offset < 0) {
325 offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 before the end");
326 offset = -offset;
327 } else {
328 offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 after the end");
329 }
330 }
331
332 offset = offset / 60; // make minutes
333 int useoffset = 0;
334
335 if (offset % (24 * 60) == 0 && offset > 0) { // divides evenly into days?
336 useoffset = offset / (24 * 60);
337 offsetstr = offsetstr.subs(i18np("1 day", "%1 days", useoffset));
338 } else if (offset % 60 == 0 && offset > 0) { // divides evenly into hours?
339 useoffset = offset / 60;
340 offsetstr = offsetstr.subs(i18np("1 hour", "%1 hours", useoffset));
341 } else {
342 useoffset = offset;
343 offsetstr = offsetstr.subs(i18np("1 minute", "%1 minutes", useoffset));
344 }
345 alarmStrings << offsetstr.toString();
346 }
347 txt = alarmStrings.join(i18nc("Spacer for the joined list of categories/tags", ", "));
348 }
349 h = qMax(printCaptionAndText(p, alarmBox, cap, txt, captionFont, textFont), h);
350 }
351 QRect organizerBox(timesBox.left() + padding(), h + padding(), timesBox.right() - padding(), lineHeight);
352 h = qMax(printCaptionAndText(p, organizerBox, i18n("Organizer: "), (*it)->organizer().fullName(), captionFont, textFont), h);
353
354 // Finally, draw the frame around the time information...
355 timesBox.setBottom(qMax(timesBox.bottom(), h + padding()));
356 drawBox(p, BOX_BORDER_WIDTH, timesBox);
357
358 QRect locationBox(timesBox);
359 locationBox.setTop(timesBox.bottom() + padding());
360 locationBox.setHeight(0);
361 int locationBottom = 0;
362 if (!isJournal) {
363 locationBottom = drawBoxWithCaption(p,
364 locationBox,
365 i18n("Location: "),
366 (*it)->location(),
367 /*sameLine=*/true,
368 /*expand=*/true,
369 captionFont,
370 textFont);
371 }
372 locationBox.setBottom(locationBottom);
373
374 // Now start constructing the boxes from the bottom:
375 QRect footerBox(locationBox);
376 footerBox.setBottom(box.bottom());
377 footerBox.setTop(footerBox.bottom() - lineHeight - 2 * padding());
378
379 QRect categoriesBox(footerBox);
380 categoriesBox.setBottom(footerBox.top());
381 categoriesBox.setTop(categoriesBox.bottom() - lineHeight - 2 * padding());
382 QRect attendeesBox(box.left(), categoriesBox.top() - padding() - box.height() / 9, box.width(), box.height() / 9);
383 QRect attachmentsBox(box.left(), attendeesBox.top() - padding() - box.height() / 9, box.width() * 3 / 4 - padding(), box.height() / 9);
384 QRect optionsBox(isJournal ? box.left() : attachmentsBox.right() + padding(), attachmentsBox.top(), 0, 0);
385 optionsBox.setRight(box.right());
386 optionsBox.setBottom(attachmentsBox.bottom());
387 QRect notesBox(optionsBox.left(), isJournal ? (timesBox.bottom() + padding()) : (locationBox.bottom() + padding()), optionsBox.width(), 0);
388 notesBox.setBottom(optionsBox.top() - padding());
389 QRect descriptionBox(notesBox);
390 descriptionBox.setLeft(box.left());
391 descriptionBox.setRight(attachmentsBox.right());
392
393 // Adjust boxes depending on the show options...
394 if (!mShowSubitemsNotes || isJournal) {
395 descriptionBox.setRight(box.right());
396 }
397 if (!mShowAttachments || !mShowAttendees) {
398 descriptionBox.setBottom(attachmentsBox.bottom());
399 optionsBox.setTop(attendeesBox.top());
400 optionsBox.setBottom(attendeesBox.bottom());
401 notesBox.setBottom(attachmentsBox.bottom());
402 if (mShowOptions) {
403 attendeesBox.setRight(attachmentsBox.right());
404 }
405 if (!mShowAttachments && !mShowAttendees) {
406 if (mShowSubitemsNotes) {
407 descriptionBox.setBottom(attendeesBox.bottom());
408 }
409 if (!mShowOptions) {
410 descriptionBox.setBottom(attendeesBox.bottom());
411 notesBox.setBottom(attendeesBox.bottom());
412 }
413 }
414 }
415 if (mShowAttachments && !isJournal) {
416 if (!mShowOptions) {
417 attachmentsBox.setRight(box.right());
418 attachmentsBox.setRight(box.right());
419 }
420 if (!mShowAttendees) {
421 attachmentsBox.setTop(attendeesBox.top());
422 attachmentsBox.setBottom(attendeesBox.bottom());
423 }
424 }
425 int newBottom = drawBoxWithCaption(p,
426 descriptionBox,
427 i18n("Description:"),
428 (*it)->description(),
429 /*sameLine=*/false,
430 /*expand=*/false,
431 captionFont,
432 textFont,
433 (*it)->descriptionIsRich());
434 if (mShowNoteLines) {
435 drawNoteLines(p, descriptionBox, newBottom);
436 }
437
438 if (mShowSubitemsNotes && !isJournal) {
440 for (const auto &incidence : mCalendar->incidences()) {
442 if (!todo) {
443 continue;
444 }
445 if (todo->relatedTo() != (*it)->uid()) {
446 continue;
447 }
448 relations.push_back(todo);
449 }
450
451 if (relations.isEmpty() || (*it)->type() != KCalendarCore::Incidence::TypeTodo) {
452 int notesPosition = drawBoxWithCaption(p,
453 notesBox,
454 i18n("Notes:"),
455 QString(),
456 /*sameLine=*/false,
457 /*expand=*/false,
458 captionFont,
459 textFont);
460 if (mShowNoteLines) {
461 drawNoteLines(p, notesBox, notesPosition);
462 }
463 } else {
464 QString subitemCaption;
465 if (relations.isEmpty()) {
466 subitemCaption = i18n("No Subitems");
467 txt.clear();
468 } else {
469 subitemCaption = i18np("1 Subitem:", "%1 Subitems:", relations.count());
470 }
471
472 QString subitemString;
473 QString statusString;
474 QString datesString;
475 int count = 0;
476 for (const auto &todo : std::as_const(relations)) {
477 ++count;
478 if (!todo) { // defensive, skip any zero pointers
479 continue;
480 }
481 // format the status
482 statusString = KCalUtils::Stringify::incidenceStatus(todo->status());
483 if (statusString.isEmpty()) {
485 statusString = i18nc("no status", "none");
486 } else {
487 statusString = i18nc("unknown status", "unknown");
488 }
489 }
490 // format the dates if provided
491 datesString.clear();
492 if (todo->dtStart().isValid()) {
493 datesString +=
494 i18nc("subitem start date", "Start Date: %1\n", QLocale().toString(todo->dtStart().toLocalTime().date(), QLocale::ShortFormat));
495 if (!todo->allDay()) {
496 datesString +=
497 i18nc("subitem start time", "Start Time: %1\n", QLocale().toString(todo->dtStart().toLocalTime().time(), QLocale::ShortFormat));
498 }
499 }
500 if (todo->dateTime(KCalendarCore::Incidence::RoleEnd).isValid()) {
501 subitemString +=
502 i18nc("subitem due date",
503 "Due Date: %1\n",
504 QLocale().toString(todo->dateTime(KCalendarCore::Incidence ::RoleEnd).toLocalTime().date(), QLocale::ShortFormat));
505
506 if (!todo->allDay()) {
507 subitemString +=
508 i18nc("subitem due time",
509 "Due Time: %1\n",
511 }
512 }
513 subitemString += i18nc("subitem counter", "%1: ", count);
514 subitemString += todo->summary();
515 subitemString += QLatin1Char('\n');
516 if (!datesString.isEmpty()) {
517 subitemString += datesString;
518 subitemString += QLatin1Char('\n');
519 }
520 subitemString += i18nc("subitem Status: statusString", "Status: %1\n", statusString);
522 subitemString += i18nc("subitem Priority: N", "Priority: %1\n", QString::number(todo->priority()));
523 subitemString += i18nc("subitem Secrecy: secrecyString", "Secrecy: %1\n", KCalUtils::Stringify::incidenceSecrecy(todo->secrecy()));
524 subitemString += QLatin1Char('\n');
525 }
527 notesBox,
528 subitemCaption,
529 subitemString,
530 /*sameLine=*/false,
531 /*expand=*/false,
532 captionFont,
533 textFont);
534 }
535 }
536
537 if (mShowAttachments && !isJournal) {
538 const KCalendarCore::Attachment::List attachments = (*it)->attachments();
539 QString attachmentCaption;
540 if (attachments.isEmpty()) {
541 attachmentCaption = i18n("No Attachments");
542 txt.clear();
543 } else {
544 attachmentCaption = i18np("1 Attachment:", "%1 Attachments:", attachments.count());
545 }
546 QString attachmentString;
548 for (; ait != attachments.constEnd(); ++ait) {
549 if (!attachmentString.isEmpty()) {
550 attachmentString += i18nc("Spacer for list of attachments", " ");
551 }
552 attachmentString.append((*ait).label());
553 }
555 attachmentsBox,
556 attachmentCaption,
557 attachmentString,
558 /*sameLine=*/false,
559 /*expand=*/false,
560 captionFont,
561 textFont);
562 }
563 if (mShowAttendees) {
564 const KCalendarCore::Attendee::List attendees = (*it)->attendees();
565 QString attendeeCaption;
566 if (attendees.isEmpty()) {
567 attendeeCaption = i18n("No Attendees");
568 } else {
569 attendeeCaption = i18np("1 Attendee:", "%1 Attendees:", attendees.count());
570 }
571 QString attendeeString;
573 for (; ait != attendees.constEnd(); ++ait) {
574 if (!attendeeString.isEmpty()) {
575 attendeeString += QLatin1Char('\n');
576 }
577 attendeeString += i18nc(
578 "Formatting of an attendee: "
579 "'Name (Role): Status', e.g. 'Reinhold Kainhofer "
580 "<reinhold@kainhofer.com> (Participant): Awaiting Response'",
581 "%1 (%2): %3",
582 (*ait).fullName(),
583 KCalUtils::Stringify::attendeeRole((*ait).role()),
584 KCalUtils::Stringify::attendeeStatus((*ait).status()));
585 }
587 attendeesBox,
588 attendeeCaption,
589 attendeeString,
590 /*sameLine=*/false,
591 /*expand=*/false,
592 captionFont,
593 textFont);
594 }
595
596 if (mShowOptions) {
597 QString optionsString;
598 if (!KCalUtils::Stringify::incidenceStatus((*it)->status()).isEmpty()) {
599 optionsString += i18n("Status: %1", KCalUtils::Stringify::incidenceStatus((*it)->status()));
600 optionsString += QLatin1Char('\n');
601 }
602 if (!KCalUtils::Stringify::incidenceSecrecy((*it)->secrecy()).isEmpty()) {
603 optionsString += i18n("Secrecy: %1", KCalUtils::Stringify::incidenceSecrecy((*it)->secrecy()));
604 optionsString += QLatin1Char('\n');
605 }
606 if ((*it)->type() == KCalendarCore::Incidence::TypeEvent) {
608 if (e->transparency() == KCalendarCore::Event::Opaque) {
609 optionsString += i18n("Show as: Busy");
610 } else {
611 optionsString += i18n("Show as: Free");
612 }
613 optionsString += QLatin1Char('\n');
614 } else if ((*it)->type() == KCalendarCore::Incidence::TypeTodo) {
616 if (t->isOverdue()) {
617 optionsString += i18n("This task is overdue!");
618 optionsString += QLatin1Char('\n');
619 }
620 } else if ((*it)->type() == KCalendarCore::Incidence::TypeJournal) {
621 // TODO: Anything Journal-specific?
622 }
623 drawBoxWithCaption(p, optionsBox, i18n("Settings: "), optionsString, /*sameLine=*/false, /*expand=*/false, captionFont, textFont);
624 }
625
627 categoriesBox,
628 i18n("Tags: "),
629 (*it)->categories().join(i18nc("Spacer for the joined list of categories/tags", ", ")),
630 /*sameLine=*/true,
631 /*expand=*/false,
632 captionFont,
633 textFont);
634
635 if (mPrintFooter) {
636 drawFooter(p, footerBox);
637 }
638 }
639 p.setFont(oldFont);
640}
641
642/**************************************************************
643 * Print Timetables
644 **************************************************************/
645
646CalPrintTimetable::CalPrintTimetable()
648{
649}
650
651CalPrintTimetable::~CalPrintTimetable() = default;
652
653void CalPrintTimetable::doLoadConfig()
654{
656 if (mConfig) {
657 KConfigGroup grp(mConfig, groupName());
658 QDate dt = QDate::currentDate(); // any valid QDate will do
659 QTime tm1(dayStart());
660 QDateTime startTm(dt, tm1);
661 QDateTime endTm(dt, tm1.addSecs(12 * 60 * 60));
662 mStartTime = grp.readEntry("Start time", startTm).time();
663 mEndTime = grp.readEntry("End time", endTm).time();
664 mIncludeDescription = grp.readEntry("Include description", false);
665 mIncludeCategories = grp.readEntry("Include categories", false);
666 mIncludeTodos = grp.readEntry("Include todos", false);
667 mIncludeAllEvents = grp.readEntry("Include all events", false);
668 mSingleLineLimit = grp.readEntry("Single line limit", false);
669 mExcludeTime = grp.readEntry("Exclude time", false);
670 }
671}
672
673void CalPrintTimetable::doSaveConfig()
674{
675 if (mConfig) {
676 KConfigGroup grp(mConfig, groupName());
677 QDateTime dt = QDateTime::currentDateTime(); // any valid QDateTime will do
678 dt.setTime(mStartTime);
679 grp.writeEntry("Start time", dt);
680 dt.setTime(mEndTime);
681 grp.writeEntry("End time", dt);
682 grp.writeEntry("Include description", mIncludeDescription);
683 grp.writeEntry("Include categories", mIncludeCategories);
684 grp.writeEntry("Include todos", mIncludeTodos);
685 grp.writeEntry("Include all events", mIncludeAllEvents);
686 grp.writeEntry("Single line limit", mSingleLineLimit);
687 grp.writeEntry("Exclude time", mExcludeTime);
688 }
690}
691
692static QString cleanString(const QString &instr)
693{
694 QString ret = instr;
695 return ret.replace(QLatin1Char('\n'), QLatin1Char(' '));
696}
697
698void CalPrintTimetable::drawAllDayBox(QPainter &p, const KCalendarCore::Event::List &eventList, QDate qd, QRect box, const QList<QDate> &workDays)
699{
700 int lineSpacing = p.fontMetrics().lineSpacing();
701
702 if (!workDays.contains(qd)) {
703 drawShadedBox(p, BOX_BORDER_WIDTH, sHolidayBackground, box);
704 } else {
705 drawBox(p, BOX_BORDER_WIDTH, box);
706 }
707
708 QRect eventBox(box);
709 eventBox.setTop(box.top() + padding());
710 eventBox.setBottom(eventBox.top() + lineSpacing);
711
712 for (const KCalendarCore::Event::Ptr &currEvent : std::as_const(eventList)) {
713 if (!currEvent || !currEvent->allDay() || (mExcludeConfidential && currEvent->secrecy() == KCalendarCore::Incidence::SecrecyConfidential)
714 || (mExcludePrivate && currEvent->secrecy() == KCalendarCore::Incidence::SecrecyPrivate)) {
715 continue;
716 }
717 QString str;
718 if (currEvent->location().isEmpty()) {
719 str = cleanString(currEvent->summary());
720 } else {
721 str = i18nc("summary, location", "%1, %2", cleanString(currEvent->summary()), cleanString(currEvent->location()));
722 }
723 if (mIncludeCategories && !currEvent->categoriesStr().isEmpty()) {
724 str = i18nc("summary, categories", "%1, %2", str, currEvent->categoriesStr());
725 }
726 printEventString(p, eventBox, str);
727 eventBox.setTop(eventBox.bottom());
728 eventBox.setBottom(eventBox.top() + lineSpacing);
729 }
730}
731
732void CalPrintTimetable::drawTimeTable(QPainter &p, QDate fromDate, QDate toDate, QRect box)
733{
734 QTime myFromTime = mStartTime;
735 QTime myToTime = mEndTime;
736 int maxAllDayEvents = 0;
737 QDate curDate(fromDate);
738 while (curDate <= toDate) {
739 KCalendarCore::Event::List eventList = mCalendar->events(curDate, QTimeZone::systemTimeZone());
740 int allDayEvents = holiday(curDate).isEmpty() ? 0 : 1;
741 for (const KCalendarCore::Event::Ptr &event : std::as_const(eventList)) {
742 Q_ASSERT(event);
745 continue;
746 }
747 if (event->allDay()) {
748 allDayEvents += 1;
749 } else if (mIncludeAllEvents) {
750 if (event->dtStart().time() < myFromTime) {
751 myFromTime = event->dtStart().time();
752 }
753 if (event->dtEnd().time() > myToTime) {
754 myToTime = event->dtEnd().time();
755 }
756 }
757 }
758 if (allDayEvents > maxAllDayEvents) {
759 maxAllDayEvents = allDayEvents;
760 }
761 curDate = curDate.addDays(1);
762 }
763
764 p.setFont(QFont(QStringLiteral("sans-serif"), 11, QFont::Normal));
765 const int lineSpacing = p.fontMetrics().lineSpacing();
766
767 int timelineWidth = TIMELINE_WIDTH + padding();
768
769 QRect dowBox(box);
770 dowBox.setLeft(box.left() + timelineWidth);
771 dowBox.setHeight(mSubHeaderHeight);
772 drawDaysOfWeek(p, fromDate, toDate, dowBox);
773
774 int tlTop = dowBox.bottom();
775
776 int alldayHeight = 0;
777 if (maxAllDayEvents > 0) {
778 // Draw the side bar for all-day events.
779 const auto alldayLabel = i18nc("label for timetable all-day boxes", "All day");
780 const QFont oldFont(p.font());
781 p.setFont(QFont(QStringLiteral("sans-serif"), 9, QFont::Normal));
782 const auto labelHeight = p.fontMetrics().horizontalAdvance(alldayLabel) + 2 * padding();
783 alldayHeight = std::max(maxAllDayEvents * lineSpacing + 2 * padding(), labelHeight);
785 BOX_BORDER_WIDTH,
786 QRect(0, tlTop, TIMELINE_WIDTH, alldayHeight),
787 alldayLabel,
789 p.setFont(oldFont);
790 tlTop += alldayHeight + padding();
791 }
792
793 QRect tlBox(box);
794 tlBox.setWidth(TIMELINE_WIDTH);
795 tlBox.setTop(tlTop);
796 drawTimeLine(p, myFromTime, myToTime, tlBox);
797
798 // draw each day
799 curDate = fromDate;
800 int i = 0;
801 double cellWidth = double(dowBox.width() - 1) / double(fromDate.daysTo(toDate) + 1);
802 QRect allDayBox(dowBox.left(), dowBox.bottom(), cellWidth, alldayHeight);
803 const QList<QDate> workDays = CalendarSupport::workDays(fromDate, toDate);
804 while (curDate <= toDate) {
807
808 allDayBox.setLeft(dowBox.left() + int(i * cellWidth));
809 allDayBox.setRight(dowBox.left() + int((i + 1) * cellWidth));
810 if (maxAllDayEvents > 0) {
811 if (const auto h = holidayEvent(curDate)) {
812 eventList.prepend(h);
813 }
814 drawAllDayBox(p, eventList, curDate, allDayBox, workDays);
815 }
816
817 QRect dayBox(allDayBox);
818 dayBox.setTop(tlTop);
819 dayBox.setBottom(box.bottom());
820 drawAgendaDayBox(p, eventList, curDate, false, myFromTime, myToTime, dayBox, mIncludeDescription, mIncludeCategories, mExcludeTime, workDays);
821
822 ++i;
823 curDate = curDate.addDays(1);
824 }
825}
826
827/**************************************************************
828 * Print Day
829 **************************************************************/
830
831CalPrintDay::CalPrintDay()
832 : CalPrintTimetable()
833{
834}
835
836CalPrintDay::~CalPrintDay() = default;
837
838QWidget *CalPrintDay::createConfigWidget(QWidget *w)
839{
840 return new CalPrintDayConfig(w);
841}
842
843void CalPrintDay::readSettingsWidget()
844{
845 auto cfg = dynamic_cast<CalPrintDayConfig *>((QWidget *)mConfigWidget);
846 if (cfg) {
847 mFromDate = cfg->mFromDate->date();
848 mToDate = cfg->mToDate->date();
849
850 if (cfg->mPrintTypeFilofax->isChecked()) {
851 mDayPrintType = Filofax;
852 } else if (cfg->mPrintTypeTimetable->isChecked()) {
853 mDayPrintType = Timetable;
854 } else {
855 mDayPrintType = SingleTimetable;
856 }
857
858 mStartTime = cfg->mFromTime->time();
859 mEndTime = cfg->mToTime->time();
860 mIncludeAllEvents = cfg->mIncludeAllEvents->isChecked();
861
862 mIncludeDescription = cfg->mIncludeDescription->isChecked();
863 mIncludeCategories = cfg->mIncludeCategories->isChecked();
864 mSingleLineLimit = cfg->mSingleLineLimit->isChecked();
865 mIncludeTodos = cfg->mIncludeTodos->isChecked();
866 mUseColors = cfg->mColors->isChecked();
867 mPrintFooter = cfg->mPrintFooter->isChecked();
868 mShowNoteLines = cfg->mShowNoteLines->isChecked();
869 mExcludeTime = cfg->mExcludeTime->isChecked();
870 mExcludeConfidential = cfg->mExcludeConfidential->isChecked();
871 mExcludePrivate = cfg->mExcludePrivate->isChecked();
872 }
873}
874
875void CalPrintDay::setSettingsWidget()
876{
877 auto cfg = dynamic_cast<CalPrintDayConfig *>((QWidget *)mConfigWidget);
878 if (cfg) {
879 cfg->mFromDate->setDate(mFromDate);
880 cfg->mToDate->setDate(mToDate);
881
882 cfg->mPrintTypeFilofax->setChecked(mDayPrintType == Filofax);
883 cfg->mPrintTypeTimetable->setChecked(mDayPrintType == Timetable);
884 cfg->mPrintTypeSingleTimetable->setChecked(mDayPrintType == SingleTimetable);
885
886 cfg->mFromTime->setTime(mStartTime);
887 cfg->mToTime->setTime(mEndTime);
888 cfg->mIncludeAllEvents->setChecked(mIncludeAllEvents);
889
890 cfg->mIncludeDescription->setChecked(mIncludeDescription);
891 cfg->mIncludeCategories->setChecked(mIncludeCategories);
892 cfg->mSingleLineLimit->setChecked(mSingleLineLimit);
893 cfg->mIncludeTodos->setChecked(mIncludeTodos);
894 cfg->mColors->setChecked(mUseColors);
895 cfg->mPrintFooter->setChecked(mPrintFooter);
896 cfg->mShowNoteLines->setChecked(mShowNoteLines);
897 cfg->mExcludeTime->setChecked(mExcludeTime);
898 cfg->mExcludeConfidential->setChecked(mExcludeConfidential);
899 cfg->mExcludePrivate->setChecked(mExcludePrivate);
900 }
901}
902
903void CalPrintDay::doLoadConfig()
904{
905 CalPrintTimetable::doLoadConfig();
906 if (mConfig) {
907 KConfigGroup grp(mConfig, groupName());
908 mDayPrintType = static_cast<eDayPrintType>(grp.readEntry("Print type", static_cast<int>(Timetable)));
909 }
910 setSettingsWidget();
911}
912
913void CalPrintDay::doSaveConfig()
914{
915 readSettingsWidget();
916 if (mConfig) {
917 KConfigGroup grp(mConfig, groupName());
918 grp.writeEntry("Print type", int(mDayPrintType));
919 }
920 CalPrintTimetable::doSaveConfig();
921}
922
923void CalPrintDay::setDateRange(const QDate &from, const QDate &to)
924{
926 auto cfg = dynamic_cast<CalPrintDayConfig *>((QWidget *)mConfigWidget);
927 if (cfg) {
928 cfg->mFromDate->setDate(from);
929 cfg->mToDate->setDate(to);
930 }
931}
932
933void CalPrintDay::drawDays(QPainter &p, QRect box)
934{
935 const int numberOfDays = mFromDate.daysTo(mToDate) + 1;
936 int vcells;
937 const bool portrait = (box.height() > box.width());
938 int cellWidth;
939 if (portrait) {
940 // 2 columns
941 vcells = std::ceil(static_cast<double>(numberOfDays) / 2.0);
942 if (numberOfDays > 1) {
943 cellWidth = box.width() / 2;
944 } else {
945 cellWidth = box.width();
946 }
947 } else {
948 // landscape: N columns
949 vcells = 1;
950 cellWidth = box.width() / numberOfDays;
951 }
952 const int cellHeight = box.height() / vcells;
953 QDate weekDate = mFromDate;
954 for (int i = 0; i < numberOfDays; ++i, weekDate = weekDate.addDays(1)) {
955 const int hpos = i / vcells;
956 const int vpos = i % vcells;
957 const QRect dayBox(box.left() + cellWidth * hpos, box.top() + cellHeight * vpos, cellWidth, cellHeight);
958 drawDayBox(p, weekDate, mStartTime, mEndTime, dayBox, true, true, true, mSingleLineLimit, mIncludeDescription, mIncludeCategories);
959 } // for i through all selected days
960}
961
962void CalPrintDay::print(QPainter &p, int width, int height)
963{
964 QDate curDay(mFromDate);
965
966 QRect headerBox(0, 0, width, headerHeight());
967 QRect footerBox(0, height - footerHeight(), width, footerHeight());
968 height -= footerHeight();
969 QRect daysBox(headerBox);
970 daysBox.setTop(headerBox.bottom() + padding());
971 daysBox.setBottom(height);
972
973 auto local = QLocale::system();
974
975 switch (mDayPrintType) {
976 case Filofax:
977 case SingleTimetable: {
978 QString line1 = local.toString(mFromDate, QLocale::ShortFormat);
979 QString line2 = local.toString(mToDate, QLocale::ShortFormat);
980 QString title;
981 if (mFromDate == mToDate) {
982 title = line1;
983 } else {
984 title = i18nc("date from-to", "%1\u2013%2", line1, line2);
985 }
986 drawHeader(p, title, mFromDate, QDate(), headerBox);
987 if (mDayPrintType == Filofax) {
988 drawDays(p, daysBox);
989 } else if (mDayPrintType == SingleTimetable) {
990 drawTimeTable(p, mFromDate, mToDate, daysBox);
991 }
992 if (mPrintFooter) {
993 drawFooter(p, footerBox);
994 }
995 break;
996 }
997
998 case Timetable:
999 default:
1000 do {
1001 QTime curStartTime(mStartTime);
1002 QTime curEndTime(mEndTime);
1003
1004 // For an invalid time range, simply show one hour, starting at the hour
1005 // before the given start time
1006 if (curEndTime <= curStartTime) {
1007 curStartTime = QTime(curStartTime.hour(), 0, 0);
1008 curEndTime = curStartTime.addSecs(3600);
1009 }
1010
1011 drawHeader(p, local.toString(curDay, QLocale::ShortFormat), curDay, QDate(), headerBox);
1012 drawTimeTable(p, curDay, curDay, daysBox);
1013 if (mPrintFooter) {
1014 drawFooter(p, footerBox);
1015 }
1016
1017 curDay = curDay.addDays(1);
1018 if (curDay <= mToDate) {
1019 mPrinter->newPage();
1020 }
1021 } while (curDay <= mToDate);
1022 } // switch
1023}
1024
1025/**************************************************************
1026 * Print Week
1027 **************************************************************/
1028
1029CalPrintWeek::CalPrintWeek()
1030 : CalPrintTimetable()
1031{
1032}
1033
1034CalPrintWeek::~CalPrintWeek() = default;
1035
1036QWidget *CalPrintWeek::createConfigWidget(QWidget *w)
1037{
1038 return new CalPrintWeekConfig(w);
1039}
1040
1041void CalPrintWeek::readSettingsWidget()
1042{
1043 auto cfg = dynamic_cast<CalPrintWeekConfig *>((QWidget *)mConfigWidget);
1044 if (cfg) {
1045 mFromDate = cfg->mFromDate->date();
1046 mToDate = cfg->mToDate->date();
1047
1048 if (cfg->mPrintTypeFilofax->isChecked()) {
1049 mWeekPrintType = Filofax;
1050 } else if (cfg->mPrintTypeTimetable->isChecked()) {
1051 mWeekPrintType = Timetable;
1052 } else if (cfg->mPrintTypeSplitWeek->isChecked()) {
1053 mWeekPrintType = SplitWeek;
1054 } else {
1055 mWeekPrintType = Timetable;
1056 }
1057
1058 mStartTime = cfg->mFromTime->time();
1059 mEndTime = cfg->mToTime->time();
1060 mIncludeAllEvents = cfg->mIncludeAllEvents->isChecked();
1061
1062 mShowNoteLines = cfg->mShowNoteLines->isChecked();
1063 mSingleLineLimit = cfg->mSingleLineLimit->isChecked();
1064 mIncludeTodos = cfg->mIncludeTodos->isChecked();
1065 mUseColors = cfg->mColors->isChecked();
1066 mPrintFooter = cfg->mPrintFooter->isChecked();
1067 mIncludeDescription = cfg->mIncludeDescription->isChecked();
1068 mIncludeCategories = cfg->mIncludeCategories->isChecked();
1069 mExcludeTime = cfg->mExcludeTime->isChecked();
1070 mExcludeConfidential = cfg->mExcludeConfidential->isChecked();
1071 mExcludePrivate = cfg->mExcludePrivate->isChecked();
1072 }
1073}
1074
1075void CalPrintWeek::setSettingsWidget()
1076{
1077 auto cfg = dynamic_cast<CalPrintWeekConfig *>((QWidget *)mConfigWidget);
1078 if (cfg) {
1079 cfg->mFromDate->setDate(mFromDate);
1080 cfg->mToDate->setDate(mToDate);
1081
1082 cfg->mPrintTypeFilofax->setChecked(mWeekPrintType == Filofax);
1083 cfg->mPrintTypeTimetable->setChecked(mWeekPrintType == Timetable);
1084 cfg->mPrintTypeSplitWeek->setChecked(mWeekPrintType == SplitWeek);
1085
1086 cfg->mFromTime->setTime(mStartTime);
1087 cfg->mToTime->setTime(mEndTime);
1088 cfg->mIncludeAllEvents->setChecked(mIncludeAllEvents);
1089
1090 cfg->mShowNoteLines->setChecked(mShowNoteLines);
1091 cfg->mSingleLineLimit->setChecked(mSingleLineLimit);
1092 cfg->mIncludeTodos->setChecked(mIncludeTodos);
1093 cfg->mColors->setChecked(mUseColors);
1094 cfg->mPrintFooter->setChecked(mPrintFooter);
1095 cfg->mIncludeDescription->setChecked(mIncludeDescription);
1096 cfg->mIncludeCategories->setChecked(mIncludeCategories);
1097 cfg->mExcludeTime->setChecked(mExcludeTime);
1098 cfg->mExcludeConfidential->setChecked(mExcludeConfidential);
1099 cfg->mExcludePrivate->setChecked(mExcludePrivate);
1100 }
1102}
1103
1104void CalPrintWeek::doLoadConfig()
1105{
1106 CalPrintTimetable::doLoadConfig();
1107 if (mConfig) {
1108 KConfigGroup grp(mConfig, groupName());
1109 mWeekPrintType = (eWeekPrintType)(grp.readEntry("Print type", (int)Filofax));
1110 }
1111 setSettingsWidget();
1112}
1113
1114void CalPrintWeek::doSaveConfig()
1115{
1116 readSettingsWidget();
1117 if (mConfig) {
1118 KConfigGroup grp(mConfig, groupName());
1119 grp.writeEntry("Print type", int(mWeekPrintType));
1120 }
1121 CalPrintTimetable::doSaveConfig();
1122}
1123
1124QPageLayout::Orientation CalPrintWeek::defaultOrientation() const
1125{
1126 if (mWeekPrintType == Filofax) {
1127 return QPageLayout::Portrait;
1128 } else if (mWeekPrintType == SplitWeek) {
1129 return QPageLayout::Portrait;
1130 } else {
1132 }
1133}
1134
1135void CalPrintWeek::setDateRange(const QDate &from, const QDate &to)
1136{
1138 auto cfg = dynamic_cast<CalPrintWeekConfig *>((QWidget *)mConfigWidget);
1139 if (cfg) {
1140 cfg->mFromDate->setDate(from);
1141 cfg->mToDate->setDate(to);
1142 }
1143}
1144
1145void CalPrintWeek::drawWeek(QPainter &p, QDate qd, QRect box)
1146{
1147 QDate weekDate = qd;
1148 const bool portrait = (box.height() > box.width());
1149 int cellWidth;
1150 int vcells;
1151 if (portrait) {
1152 cellWidth = box.width() / 2;
1153 vcells = 3;
1154 } else {
1155 cellWidth = box.width() / 6;
1156 vcells = 1;
1157 }
1158 const int cellHeight = box.height() / vcells;
1159
1160 // correct begin of week
1161 int weekdayCol = weekdayColumn(qd.dayOfWeek());
1162 weekDate = qd.addDays(-weekdayCol);
1163
1164 for (int i = 0; i < 7; ++i, weekDate = weekDate.addDays(1)) {
1165 // Saturday and sunday share a cell, so we have to special-case sunday
1166 int hpos = ((i < 6) ? i : (i - 1)) / vcells;
1167 int vpos = ((i < 6) ? i : (i - 1)) % vcells;
1168 QRect dayBox(box.left() + cellWidth * hpos,
1169 box.top() + cellHeight * vpos + ((i == 6) ? (cellHeight / 2) : 0),
1170 cellWidth,
1171 (i < 5) ? (cellHeight) : (cellHeight / 2));
1172 drawDayBox(p, weekDate, mStartTime, mEndTime, dayBox, true, true, true, mSingleLineLimit, mIncludeDescription, mIncludeCategories);
1173 } // for i through all weekdays
1174}
1175
1176void CalPrintWeek::print(QPainter &p, int width, int height)
1177{
1178 QDate curWeek;
1179 QDate fromWeek;
1180 QDate toWeek;
1181
1182 // correct begin and end to first and last day of week
1183 int weekdayCol = weekdayColumn(mFromDate.dayOfWeek());
1184 fromWeek = mFromDate.addDays(-weekdayCol);
1185 weekdayCol = weekdayColumn(mToDate.dayOfWeek());
1186 toWeek = mToDate.addDays(6 - weekdayCol);
1187
1188 curWeek = fromWeek.addDays(6);
1189 auto local = QLocale::system();
1190
1191 QString line1;
1192 QString line2;
1193 QString title;
1194 QRect headerBox(0, 0, width, headerHeight());
1195 QRect footerBox(0, height - footerHeight(), width, footerHeight());
1196 height -= footerHeight();
1197
1198 QRect weekBox(headerBox);
1199 weekBox.setTop(headerBox.bottom() + padding());
1200 weekBox.setBottom(height);
1201
1202 switch (mWeekPrintType) {
1203 case Filofax:
1204 do {
1205 line1 = local.toString(curWeek.addDays(-6), QLocale::ShortFormat);
1206 line2 = local.toString(curWeek, QLocale::ShortFormat);
1207 title = i18nc("date from-to", "%1\u2013%2", line1, line2);
1208 drawHeader(p, title, curWeek.addDays(-6), QDate(), headerBox);
1209
1210 drawWeek(p, curWeek, weekBox);
1211
1212 if (mPrintFooter) {
1213 drawFooter(p, footerBox);
1214 }
1215
1216 curWeek = curWeek.addDays(7);
1217 if (curWeek <= toWeek) {
1218 mPrinter->newPage();
1219 }
1220 } while (curWeek <= toWeek);
1221 break;
1222
1223 case Timetable:
1224 default:
1225 do {
1226 line1 = local.toString(curWeek.addDays(-6), QLocale::ShortFormat);
1227 line2 = local.toString(curWeek, QLocale::ShortFormat);
1228 if (orientation() == QPageLayout::Landscape) {
1229 title = i18nc("date from - to (week number)", "%1\u2013%2 (Week %3)", line1, line2, curWeek.weekNumber());
1230 } else {
1231 title = i18nc("date from - to\\n(week number)", "%1\u2013%2\n(Week %3)", line1, line2, curWeek.weekNumber());
1232 }
1233 drawHeader(p, title, curWeek, QDate(), headerBox);
1234
1235 drawTimeTable(p, fromWeek, curWeek, weekBox);
1236
1237 if (mPrintFooter) {
1238 drawFooter(p, footerBox);
1239 }
1240
1241 fromWeek = fromWeek.addDays(7);
1242 curWeek = fromWeek.addDays(6);
1243 if (curWeek <= toWeek) {
1244 mPrinter->newPage();
1245 }
1246 } while (curWeek <= toWeek);
1247 break;
1248
1249 case SplitWeek: {
1250 QRect weekBox1(weekBox);
1251 // On the left side there are four days (mo-th) plus the timeline,
1252 // on the right there are only three days (fr-su) plus the timeline. Don't
1253 // use the whole width, but rather give them the same width as on the left.
1254 weekBox1.setRight(int((width - TIMELINE_WIDTH) * 3. / 4. + TIMELINE_WIDTH));
1255 do {
1256 QDate endLeft(fromWeek.addDays(3));
1257 int hh = headerHeight();
1258
1259 drawSplitHeaderRight(p, fromWeek, curWeek, QDate(), width, hh);
1260 drawTimeTable(p, fromWeek, endLeft, weekBox);
1261 if (mPrintFooter) {
1262 drawFooter(p, footerBox);
1263 }
1264 mPrinter->newPage();
1265 drawSplitHeaderRight(p, fromWeek, curWeek, QDate(), width, hh);
1266 drawTimeTable(p, endLeft.addDays(1), curWeek, weekBox1);
1267
1268 if (mPrintFooter) {
1269 drawFooter(p, footerBox);
1270 }
1271
1272 fromWeek = fromWeek.addDays(7);
1273 curWeek = fromWeek.addDays(6);
1274 if (curWeek <= toWeek) {
1275 mPrinter->newPage();
1276 }
1277 } while (curWeek <= toWeek);
1278 break;
1279 }
1280 }
1281}
1282
1283/**************************************************************
1284 * Print Month
1285 **************************************************************/
1286
1287CalPrintMonth::CalPrintMonth()
1289{
1290}
1291
1292CalPrintMonth::~CalPrintMonth() = default;
1293
1294QWidget *CalPrintMonth::createConfigWidget(QWidget *w)
1295{
1296 return new CalPrintMonthConfig(w);
1297}
1298
1299void CalPrintMonth::readSettingsWidget()
1300{
1301 auto cfg = dynamic_cast<CalPrintMonthConfig *>((QWidget *)mConfigWidget);
1302
1303 if (cfg) {
1304 mFromDate = QDate(cfg->mFromYear->value(), cfg->mFromMonth->currentIndex() + 1, 1);
1305 mToDate = QDate(cfg->mToYear->value(), cfg->mToMonth->currentIndex() + 1, 1);
1306
1307 mWeekNumbers = cfg->mWeekNumbers->isChecked();
1308 mRecurDaily = cfg->mRecurDaily->isChecked();
1309 mRecurWeekly = cfg->mRecurWeekly->isChecked();
1310 mIncludeTodos = cfg->mIncludeTodos->isChecked();
1311 mShowNoteLines = cfg->mShowNoteLines->isChecked();
1312 mSingleLineLimit = cfg->mSingleLineLimit->isChecked();
1313 mUseColors = cfg->mColors->isChecked();
1314 mPrintFooter = cfg->mPrintFooter->isChecked();
1315 mIncludeDescription = cfg->mIncludeDescription->isChecked();
1316 mIncludeCategories = cfg->mIncludeCategories->isChecked();
1317 mExcludeConfidential = cfg->mExcludeConfidential->isChecked();
1318 mExcludePrivate = cfg->mExcludePrivate->isChecked();
1319 }
1320}
1321
1322void CalPrintMonth::setSettingsWidget()
1323{
1324 auto cfg = dynamic_cast<CalPrintMonthConfig *>((QWidget *)mConfigWidget);
1325
1326 if (cfg) {
1327 setDateRange(mFromDate, mToDate);
1328
1329 cfg->mWeekNumbers->setChecked(mWeekNumbers);
1330 cfg->mRecurDaily->setChecked(mRecurDaily);
1331 cfg->mRecurWeekly->setChecked(mRecurWeekly);
1332 cfg->mIncludeTodos->setChecked(mIncludeTodos);
1333 cfg->mShowNoteLines->setChecked(mShowNoteLines);
1334 cfg->mSingleLineLimit->setChecked(mSingleLineLimit);
1335 cfg->mColors->setChecked(mUseColors);
1336 cfg->mPrintFooter->setChecked(mPrintFooter);
1337 cfg->mIncludeDescription->setChecked(mIncludeDescription);
1338 cfg->mIncludeCategories->setChecked(mIncludeCategories);
1339 cfg->mExcludeConfidential->setChecked(mExcludeConfidential);
1340 cfg->mExcludePrivate->setChecked(mExcludePrivate);
1341 }
1342}
1343
1344void CalPrintMonth::doLoadConfig()
1345{
1347 if (mConfig) {
1348 KConfigGroup grp(mConfig, groupName());
1349 mWeekNumbers = grp.readEntry("Print week numbers", true);
1350 mRecurDaily = grp.readEntry("Print daily incidences", true);
1351 mRecurWeekly = grp.readEntry("Print weekly incidences", true);
1352 mIncludeTodos = grp.readEntry("Include todos", false);
1353 mSingleLineLimit = grp.readEntry("Single line limit", false);
1354 mIncludeDescription = grp.readEntry("Include description", false);
1355 mIncludeCategories = grp.readEntry("Include categories", false);
1356 }
1357 setSettingsWidget();
1358}
1359
1360void CalPrintMonth::doSaveConfig()
1361{
1362 readSettingsWidget();
1363 if (mConfig) {
1364 KConfigGroup grp(mConfig, groupName());
1365 grp.writeEntry("Print week numbers", mWeekNumbers);
1366 grp.writeEntry("Print daily incidences", mRecurDaily);
1367 grp.writeEntry("Print weekly incidences", mRecurWeekly);
1368 grp.writeEntry("Include todos", mIncludeTodos);
1369 grp.writeEntry("Single line limit", mSingleLineLimit);
1370 grp.writeEntry("Include description", mIncludeDescription);
1371 grp.writeEntry("Include categories", mIncludeCategories);
1372 }
1374}
1375
1376void CalPrintMonth::setDateRange(const QDate &from, const QDate &to)
1377{
1379 auto cfg = dynamic_cast<CalPrintMonthConfig *>((QWidget *)mConfigWidget);
1380 if (cfg) {
1381 const QLocale locale;
1382 cfg->mFromMonth->clear();
1383 cfg->mToMonth->clear();
1384 for (int i = 1; i < 13; ++i) {
1385 const auto monthName = locale.standaloneMonthName(i, QLocale::LongFormat);
1386 cfg->mFromMonth->addItem(monthName);
1387 cfg->mToMonth->addItem(monthName);
1388 }
1389 cfg->mFromMonth->setCurrentIndex(from.month() - 1);
1390 cfg->mFromYear->setValue(to.year());
1391 cfg->mToMonth->setCurrentIndex(mToDate.month() - 1);
1392 cfg->mToYear->setValue(mToDate.year());
1393 }
1394}
1395
1396void CalPrintMonth::print(QPainter &p, int width, int height)
1397{
1398 QDate curMonth;
1399 QDate fromMonth;
1400 QDate toMonth;
1401
1402 fromMonth = mFromDate.addDays(-(mFromDate.day() - 1));
1403 toMonth = mToDate.addDays(mToDate.daysInMonth() - mToDate.day());
1404
1405 curMonth = fromMonth;
1406
1407 QRect headerBox(0, 0, width, headerHeight());
1408 QRect footerBox(0, height - footerHeight(), width, footerHeight());
1409 height -= footerHeight();
1410
1411 QRect monthBox(0, 0, width, height);
1412 monthBox.setTop(headerBox.bottom() + padding());
1413
1414 do {
1415 QString title(
1416 i18nc("monthname year", "%1 %2", QLocale::system().standaloneMonthName(curMonth.month(), QLocale::LongFormat), QString::number(curMonth.year())));
1417 QDate tmp(fromMonth);
1418 int weekdayCol = weekdayColumn(tmp.dayOfWeek());
1419 tmp = tmp.addDays(-weekdayCol);
1420
1421 drawHeader(p, title, curMonth.addMonths(-1), curMonth.addMonths(1), headerBox);
1423 curMonth,
1424 QTime(),
1425 QTime(),
1426 mWeekNumbers,
1427 mRecurDaily,
1428 mRecurWeekly,
1429 mSingleLineLimit,
1430 mIncludeDescription,
1431 mIncludeCategories,
1432 monthBox);
1433
1434 if (mPrintFooter) {
1435 drawFooter(p, footerBox);
1436 }
1437
1438 curMonth = curMonth.addDays(curMonth.daysInMonth());
1439 if (curMonth <= toMonth) {
1440 mPrinter->newPage();
1441 }
1442 } while (curMonth <= toMonth);
1443}
1444
1445/**************************************************************
1446 * Print Todos
1447 **************************************************************/
1448
1449CalPrintTodos::CalPrintTodos()
1451{
1452 mTodoSortField = TodoFieldUnset;
1453 mTodoSortDirection = TodoDirectionUnset;
1454}
1455
1456CalPrintTodos::~CalPrintTodos() = default;
1457
1458QWidget *CalPrintTodos::createConfigWidget(QWidget *w)
1459{
1460 return new CalPrintTodoConfig(w);
1461}
1462
1463void CalPrintTodos::readSettingsWidget()
1464{
1465 auto cfg = dynamic_cast<CalPrintTodoConfig *>((QWidget *)mConfigWidget);
1466
1467 if (cfg) {
1468 mPageTitle = cfg->mTitle->text();
1469
1470 if (cfg->mPrintAll->isChecked()) {
1471 mTodoPrintType = TodosAll;
1472 } else if (cfg->mPrintUnfinished->isChecked()) {
1473 mTodoPrintType = TodosUnfinished;
1474 } else if (cfg->mPrintDueRange->isChecked()) {
1475 mTodoPrintType = TodosDueRange;
1476 } else {
1477 mTodoPrintType = TodosAll;
1478 }
1479
1480 mFromDate = cfg->mFromDate->date();
1481 mToDate = cfg->mToDate->date();
1482
1483 mIncludeDescription = cfg->mDescription->isChecked();
1484 mIncludePriority = cfg->mPriority->isChecked();
1485 mIncludeCategories = cfg->mCategories->isChecked();
1486 mIncludeStartDate = cfg->mStartDate->isChecked();
1487 mIncludeDueDate = cfg->mDueDate->isChecked();
1488 mIncludePercentComplete = cfg->mPercentComplete->isChecked();
1489 mConnectSubTodos = cfg->mConnectSubTodos->isChecked();
1490 mStrikeOutCompleted = cfg->mStrikeOutCompleted->isChecked();
1491 mExcludeConfidential = cfg->mExcludeConfidential->isChecked();
1492 mExcludePrivate = cfg->mExcludePrivate->isChecked();
1493
1494 mTodoSortField = (eTodoSortField)cfg->mSortField->currentIndex();
1495 mTodoSortDirection = (eTodoSortDirection)cfg->mSortDirection->currentIndex();
1496
1497 mPrintFooter = cfg->mPrintFooter->isChecked();
1498 }
1499}
1500
1501void CalPrintTodos::setSettingsWidget()
1502{
1503 auto cfg = dynamic_cast<CalPrintTodoConfig *>((QWidget *)mConfigWidget);
1504 if (cfg) {
1505 cfg->mTitle->setText(mPageTitle);
1506
1507 cfg->mPrintAll->setChecked(mTodoPrintType == TodosAll);
1508 cfg->mPrintUnfinished->setChecked(mTodoPrintType == TodosUnfinished);
1509 cfg->mPrintDueRange->setChecked(mTodoPrintType == TodosDueRange);
1510
1511 cfg->mFromDate->setDate(mFromDate);
1512 cfg->mToDate->setDate(mToDate);
1513
1514 cfg->mDescription->setChecked(mIncludeDescription);
1515 cfg->mPriority->setChecked(mIncludePriority);
1516 cfg->mCategories->setChecked(mIncludeCategories);
1517 cfg->mStartDate->setChecked(mIncludeStartDate);
1518 cfg->mDueDate->setChecked(mIncludeDueDate);
1519 cfg->mPercentComplete->setChecked(mIncludePercentComplete);
1520 cfg->mConnectSubTodos->setChecked(mConnectSubTodos);
1521 cfg->mStrikeOutCompleted->setChecked(mStrikeOutCompleted);
1522 cfg->mExcludeConfidential->setChecked(mExcludeConfidential);
1523 cfg->mExcludePrivate->setChecked(mExcludePrivate);
1524
1525 if (mTodoSortField != TodoFieldUnset) {
1526 // do not insert if already done so.
1527 cfg->mSortField->addItem(i18nc("@option sort by summary", "Summary"));
1528 cfg->mSortField->addItem(i18nc("@option sort by start date/time", "Start Date"));
1529 cfg->mSortField->addItem(i18nc("@option sort by due date/time", "Due Date"));
1530 cfg->mSortField->addItem(i18nc("@option sort by priority", "Priority"));
1531 cfg->mSortField->addItem(i18nc("@option sort by percent completed", "Percent Complete"));
1532 cfg->mSortField->addItem(i18nc("@option sort by tags", "Tags"));
1533 cfg->mSortField->setCurrentIndex(mTodoSortField);
1534 }
1535
1536 if (mTodoSortDirection != TodoDirectionUnset) {
1537 // do not insert if already done so.
1538 cfg->mSortDirection->addItem(i18nc("@option sort in increasing order", "Ascending"));
1539 cfg->mSortDirection->addItem(i18nc("@option sort in descreasing order", "Descending"));
1540 cfg->mSortDirection->setCurrentIndex(mTodoSortDirection);
1541 }
1542
1543 cfg->mPrintFooter->setChecked(mPrintFooter);
1544 }
1545}
1546
1547void CalPrintTodos::doLoadConfig()
1548{
1550 if (mConfig) {
1551 KConfigGroup grp(mConfig, groupName());
1552 mPageTitle = grp.readEntry("Page title", i18n("To-do list"));
1553 mTodoPrintType = (eTodoPrintType)grp.readEntry("Print type", static_cast<int>(TodosAll));
1554 mIncludeDescription = grp.readEntry("Include description", true);
1555 mIncludePriority = grp.readEntry("Include priority", true);
1556 mIncludeCategories = grp.readEntry("Include categories", true);
1557 mIncludeStartDate = grp.readEntry("Include start date", true);
1558 mIncludeDueDate = grp.readEntry("Include due date", true);
1559 mIncludePercentComplete = grp.readEntry("Include percentage completed", true);
1560 mConnectSubTodos = grp.readEntry("Connect subtodos", true);
1561 mStrikeOutCompleted = grp.readEntry("Strike out completed summaries", true);
1562 mTodoSortField = (eTodoSortField)grp.readEntry("Sort field", static_cast<int>(TodoFieldSummary));
1563 mTodoSortDirection = (eTodoSortDirection)grp.readEntry("Sort direction", static_cast<int>(TodoDirectionAscending));
1564 }
1565 setSettingsWidget();
1566}
1567
1568void CalPrintTodos::doSaveConfig()
1569{
1570 readSettingsWidget();
1571 if (mConfig) {
1572 KConfigGroup grp(mConfig, groupName());
1573 grp.writeEntry("Page title", mPageTitle);
1574 grp.writeEntry("Print type", int(mTodoPrintType));
1575 grp.writeEntry("Include description", mIncludeDescription);
1576 grp.writeEntry("Include priority", mIncludePriority);
1577 grp.writeEntry("Include categories", mIncludeCategories);
1578 grp.writeEntry("Include start date", mIncludeStartDate);
1579 grp.writeEntry("Include due date", mIncludeDueDate);
1580 grp.writeEntry("Include percentage completed", mIncludePercentComplete);
1581 grp.writeEntry("Connect subtodos", mConnectSubTodos);
1582 grp.writeEntry("Strike out completed summaries", mStrikeOutCompleted);
1583 grp.writeEntry("Sort field", static_cast<int>(mTodoSortField));
1584 grp.writeEntry("Sort direction", static_cast<int>(mTodoSortDirection));
1585 }
1587}
1588
1589void CalPrintTodos::print(QPainter &p, int width, int height)
1590{
1591 int possummary = 100;
1592
1593 QRect headerBox(0, 0, width, headerHeight());
1594 QRect footerBox(0, height - footerHeight(), width, footerHeight());
1595 height -= footerHeight();
1596
1597 // Draw the First Page Header
1598 drawHeader(p, mPageTitle, mFromDate, QDate(), headerBox);
1599
1600 // Estimate widths of some data columns.
1601 QFont oldFont(p.font());
1602 p.setFont(QFont(QStringLiteral("sans-serif"), 10));
1603 const int widDate = p.fontMetrics().boundingRect(QLocale::system().toString(QDate(2222, 12, 22), QLocale::ShortFormat)).width();
1604 const int widPct = p.fontMetrics().boundingRect(i18n("%1%", 100)).width() + 27;
1605
1606 // Draw the Column Headers
1607 int mCurrentLinePos = headerHeight() + 5;
1608 QString outStr;
1609
1610 p.setFont(QFont(QStringLiteral("sans-serif"), 9, QFont::Bold));
1611 int lineSpacing = p.fontMetrics().lineSpacing();
1612 mCurrentLinePos += lineSpacing;
1613 int pospriority = -1;
1614 if (mIncludePriority) {
1615 outStr += i18n("Priority");
1616 pospriority = 0;
1617 p.drawText(pospriority, mCurrentLinePos - 2, outStr);
1618 }
1619
1620 int posSoFar = width; // Position of leftmost optional header.
1621
1622 int posdue = -1;
1623 if (mIncludeDueDate) {
1624 outStr.truncate(0);
1625 outStr += i18nc("@label to-do due date", "Due");
1626 const int widDue = std::max(p.fontMetrics().boundingRect(outStr).width(), widDate);
1627 posdue = posSoFar - widDue;
1628 p.drawText(posdue, mCurrentLinePos - 2, outStr);
1629 posSoFar = posdue;
1630 }
1631
1632 int posStart = -1;
1633 if (mIncludeStartDate) {
1634 outStr.truncate(0);
1635 outStr += i18nc("@label to-do start date", "Start");
1636 const int widStart = std::max(p.fontMetrics().boundingRect(outStr).width(), widDate);
1637 posStart = posSoFar - widStart - 5;
1638 p.drawText(posStart, mCurrentLinePos - 2, outStr);
1639 posSoFar = posStart;
1640 }
1641
1642 int poscomplete = -1;
1643 if (mIncludePercentComplete) {
1644 outStr.truncate(0);
1645 outStr += i18nc("@label to-do percentage complete", "Complete");
1646 const int widComplete = std::max(p.fontMetrics().boundingRect(outStr).width(), widPct);
1647 poscomplete = posSoFar - widComplete - 5;
1648 p.drawText(poscomplete, mCurrentLinePos - 2, outStr);
1649 posSoFar = poscomplete;
1650 }
1651
1652 int posCategories = -1;
1653 if (mIncludeCategories) {
1654 outStr.truncate(0);
1655 outStr += i18nc("@label to-do categories", "Tags");
1656 const int widCats = std::max(p.fontMetrics().boundingRect(outStr).width(), 100); // Arbitrary!
1657 posCategories = posSoFar - widCats - 5;
1658 p.drawText(posCategories, mCurrentLinePos - 2, outStr);
1659 }
1660
1661 p.setFont(QFont(QStringLiteral("sans-serif"), 10));
1662
1665
1667 switch (mTodoSortDirection) {
1668 case TodoDirectionAscending:
1670 break;
1671 case TodoDirectionDescending:
1673 break;
1674 case TodoDirectionUnset:
1675 break;
1676 }
1677
1679 switch (mTodoSortField) {
1680 case TodoFieldSummary:
1682 break;
1683 case TodoFieldStartDate:
1685 break;
1686 case TodoFieldDueDate:
1688 break;
1689 case TodoFieldPriority:
1691 break;
1692 case TodoFieldPercentComplete:
1694 break;
1695 case TodoFieldCategories:
1697 break;
1698 case TodoFieldUnset:
1699 break;
1700 }
1701
1702 // Create list of to-dos which will be printed
1703 todoList = mCalendar->todos(sortField, sortDirection);
1704 switch (mTodoPrintType) {
1705 case TodosAll:
1706 break;
1707 case TodosUnfinished:
1708 for (const KCalendarCore::Todo::Ptr &todo : std::as_const(todoList)) {
1709 Q_ASSERT(todo);
1710 if (!todo->isCompleted()) {
1711 tempList.append(todo);
1712 }
1713 }
1714 todoList = tempList;
1715 break;
1716 case TodosDueRange:
1717 for (const KCalendarCore::Todo::Ptr &todo : std::as_const(todoList)) {
1718 Q_ASSERT(todo);
1719 if (todo->hasDueDate()) {
1720 if (todo->dtDue().date() >= mFromDate && todo->dtDue().date() <= mToDate) {
1721 tempList.append(todo);
1722 }
1723 } else {
1724 tempList.append(todo);
1725 }
1726 }
1727 todoList = tempList;
1728 break;
1729 }
1730
1731 // Print to-dos
1732 int count = 0;
1733 for (const KCalendarCore::Todo::Ptr &todo : std::as_const(todoList)) {
1734 // Skip sub-to-dos. They will be printed recursively in drawTodo()
1735 if (todo->relatedTo().isEmpty()) { // review(AKONADI_PORT)
1736 count++;
1737 drawTodo(count,
1738 todo,
1739 p,
1740 sortField,
1741 sortDirection,
1742 mConnectSubTodos,
1743 mStrikeOutCompleted,
1744 mIncludeDescription,
1745 pospriority,
1746 possummary,
1747 posCategories,
1748 posStart,
1749 posdue,
1750 poscomplete,
1751 0,
1752 0,
1753 mCurrentLinePos,
1754 width,
1755 height,
1756 todoList,
1757 nullptr);
1758 }
1759 }
1760
1761 if (mPrintFooter) {
1762 drawFooter(p, footerBox);
1763 }
1764 p.setFont(oldFont);
1765}
1766
1767#include "moc_calprintdefaultplugins.cpp"
Base class for Calendar printing classes.
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.
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.
int headerHeight() const
Returns the height of the page header.
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 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.
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.
virtual void setSettingsWidget()
Set configuration widget to reflect settings of current object.
virtual void setDateRange(const QDate &from, const QDate &to)
Set date range which should be printed.
virtual QString groupName() const =0
Returns KConfig group name where store settings.
QPrinter * mPrinter
The printer object.
QString toString() const
KLocalizedString subs(const KLocalizedString &a, int fieldWidth=0, QChar fillChar=QLatin1Char(' ')) const
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
KLocalizedString KI18N_EXPORT ki18nc(const char *context, const char *text)
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Incidence::Ptr incidence(const Akonadi::Item &item)
AKONADI_CALENDAR_EXPORT KCalendarCore::Journal::Ptr journal(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)
KCALUTILS_EXPORT QString dateTimeToString(const QDateTime &date, bool dateOnly=false, bool shortfmt=true)
KCALUTILS_EXPORT QString recurrenceString(const KCalendarCore::Incidence::Ptr &incidence)
KCALUTILS_EXPORT QString incidenceSecrecy(KCalendarCore::Incidence::Secrecy secrecy)
QDate addDays(qint64 ndays) const const
QDate addMonths(int nmonths) const const
QDate currentDate()
int day() const const
int dayOfWeek() const const
int daysInMonth() const const
qint64 daysTo(QDate d) const const
int month() const const
int weekNumber(int *yearNumber) const const
int year() const const
QDateTime currentDateTime()
void setTime(QTime time)
QRect boundingRect(QChar ch) const const
int horizontalAdvance(QChar ch) const const
int lineSpacing() const const
typedef ConstIterator
void append(QList< T > &&value)
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
bool isEmpty() const const
void prepend(parameter_type value)
void push_back(parameter_type value)
void reserve(qsizetype size)
QString standaloneMonthName(int month, FormatType type) const const
QLocale system()
void drawText(const QPoint &position, const QString &text)
const QFont & font() const const
QFontMetrics fontMetrics() const const
void setFont(const QFont &font)
virtual bool newPage() override
int bottom() const const
int height() const const
int left() const const
int right() const const
void setBottom(int y)
void setRight(int x)
int top() const const
int width() const const
QSharedPointer< X > dynamicCast() const const
QSharedPointer< X > staticCast() const const
QString & append(QChar ch)
void clear()
bool isEmpty() const const
QString number(double n, char format, int precision)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
void truncate(qsizetype position)
QString join(QChar separator) const const
AlignLeft
TextSingleLine
QTextStream & right(QTextStream &stream)
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.