File indexing completed on 2025-01-05 04:47:41
0001 /* 0002 SPDX-FileCopyrightText: 1998 Preston Brown <pbrown@kde.org> 0003 SPDX-FileCopyrightText: 2003 Reinhold Kainhofer <reinhold@kainhofer.com> 0004 SPDX-FileCopyrightText: 2003 Cornelius Schumacher <schumacher@kde.org> 0005 SPDX-FileCopyrightText: 2008 Ron Goodheart <rong.dev@gmail.com> 0006 SPDX-FileCopyrightText: 2010-2024 Laurent Montel <montel@kde.org> 0007 SPDX-FileCopyrightText: 2012-2013 Allen Winter <winter@kde.org> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0 0010 */ 0011 0012 #include "calprintdefaultplugins.h" 0013 #include "kcalprefs.h" 0014 #include "utils.h" 0015 0016 #include <cmath> 0017 0018 #include <Akonadi/CalendarUtils> 0019 #include <Akonadi/Item> 0020 0021 #include <KCalendarCore/Visitor> 0022 0023 #include <KCalUtils/IncidenceFormatter> 0024 #include <KCalUtils/Stringify> 0025 0026 #include <KConfigGroup> 0027 0028 #include <QPainter> 0029 0030 using namespace CalendarSupport; 0031 0032 /************************************************************** 0033 * Print Incidence 0034 **************************************************************/ 0035 0036 CalPrintIncidence::CalPrintIncidence() 0037 : CalPrintPluginBase() 0038 { 0039 } 0040 0041 CalPrintIncidence::~CalPrintIncidence() = default; 0042 0043 QWidget *CalPrintIncidence::createConfigWidget(QWidget *w) 0044 { 0045 return new CalPrintIncidenceConfig(w); 0046 } 0047 0048 void CalPrintIncidence::readSettingsWidget() 0049 { 0050 auto cfg = dynamic_cast<CalPrintIncidenceConfig *>((QWidget *)mConfigWidget); 0051 if (cfg) { 0052 mUseColors = cfg->mColors->isChecked(); 0053 mPrintFooter = cfg->mPrintFooter->isChecked(); 0054 mShowOptions = cfg->mShowDetails->isChecked(); 0055 mShowSubitemsNotes = cfg->mShowSubitemsNotes->isChecked(); 0056 mShowAttendees = cfg->mShowAttendees->isChecked(); 0057 mShowAttachments = cfg->mShowAttachments->isChecked(); 0058 mShowNoteLines = cfg->mShowNoteLines->isChecked(); 0059 } 0060 } 0061 0062 void CalPrintIncidence::setSettingsWidget() 0063 { 0064 auto cfg = dynamic_cast<CalPrintIncidenceConfig *>((QWidget *)mConfigWidget); 0065 if (cfg) { 0066 cfg->mColors->setChecked(mUseColors); 0067 cfg->mPrintFooter->setChecked(mPrintFooter); 0068 cfg->mShowDetails->setChecked(mShowOptions); 0069 cfg->mShowSubitemsNotes->setChecked(mShowSubitemsNotes); 0070 cfg->mShowAttendees->setChecked(mShowAttendees); 0071 cfg->mShowAttachments->setChecked(mShowAttachments); 0072 cfg->mShowNoteLines->setChecked(mShowNoteLines); 0073 } 0074 } 0075 0076 void CalPrintIncidence::doLoadConfig() 0077 { 0078 CalPrintPluginBase::doLoadConfig(); 0079 if (mConfig) { 0080 KConfigGroup grp(mConfig, groupName()); 0081 mShowOptions = grp.readEntry("Show Options", false); 0082 mShowSubitemsNotes = grp.readEntry("Show Subitems and Notes", false); 0083 mShowAttendees = grp.readEntry("Use Attendees", false); 0084 mShowAttachments = grp.readEntry("Use Attachments", false); 0085 } 0086 setSettingsWidget(); 0087 } 0088 0089 void CalPrintIncidence::doSaveConfig() 0090 { 0091 readSettingsWidget(); 0092 if (mConfig) { 0093 KConfigGroup grp(mConfig, groupName()); 0094 grp.writeEntry("Show Options", mShowOptions); 0095 grp.writeEntry("Show Subitems and Notes", mShowSubitemsNotes); 0096 grp.writeEntry("Use Attendees", mShowAttendees); 0097 grp.writeEntry("Use Attachments", mShowAttachments); 0098 } 0099 CalPrintPluginBase::doSaveConfig(); 0100 } 0101 0102 class TimePrintStringsVisitor : public KCalendarCore::Visitor 0103 { 0104 public: 0105 TimePrintStringsVisitor() = default; 0106 0107 bool act(KCalendarCore::IncidenceBase::Ptr incidence) 0108 { 0109 return incidence->accept(*this, incidence); 0110 } 0111 0112 QString mStartCaption, mStartString; 0113 QString mEndCaption, mEndString; 0114 QString mDurationCaption, mDurationString; 0115 0116 protected: 0117 bool visit(const KCalendarCore::Event::Ptr &event) override 0118 { 0119 if (event->dtStart().isValid()) { 0120 mStartCaption = i18n("Start date: "); 0121 mStartString = KCalUtils::IncidenceFormatter::dateTimeToString(event->dtStart(), event->allDay(), false); 0122 } else { 0123 mStartCaption = i18n("No start date"); 0124 mStartString.clear(); 0125 } 0126 0127 if (event->hasEndDate()) { 0128 mEndCaption = i18n("End date: "); 0129 mEndString = KCalUtils::IncidenceFormatter::dateTimeToString(event->dtEnd(), event->allDay(), false); 0130 } else if (event->hasDuration()) { 0131 mEndCaption = i18n("Duration: "); 0132 int mins = event->duration().asSeconds() / 60; 0133 if (mins >= 60) { 0134 mEndString += i18np("1 hour ", "%1 hours ", mins / 60); 0135 } 0136 if (mins % 60 > 0) { 0137 mEndString += i18np("1 minute ", "%1 minutes ", mins % 60); 0138 } 0139 } else { 0140 mEndCaption = i18n("No end date"); 0141 mEndString.clear(); 0142 } 0143 return true; 0144 } 0145 0146 bool visit(const KCalendarCore::Todo::Ptr &todo) override 0147 { 0148 if (todo->hasStartDate()) { 0149 mStartCaption = i18n("Start date: "); 0150 mStartString = KCalUtils::IncidenceFormatter::dateTimeToString(todo->dtStart(), todo->allDay(), false); 0151 } else { 0152 mStartCaption = i18n("No start date"); 0153 mStartString.clear(); 0154 } 0155 0156 if (todo->hasDueDate()) { 0157 mEndCaption = i18n("Due date: "); 0158 mEndString = KCalUtils::IncidenceFormatter::dateTimeToString(todo->dtDue(), todo->allDay(), false); 0159 } else { 0160 mEndCaption = i18n("No due date"); 0161 mEndString.clear(); 0162 } 0163 return true; 0164 } 0165 0166 bool visit(const KCalendarCore::Journal::Ptr &journal) override 0167 { 0168 mStartCaption = i18n("Start date: "); 0169 mStartString = KCalUtils::IncidenceFormatter::dateTimeToString(journal->dtStart(), journal->allDay(), false); 0170 mEndCaption.clear(); 0171 mEndString.clear(); 0172 return true; 0173 } 0174 0175 bool visit(const KCalendarCore::FreeBusy::Ptr &fb) override 0176 { 0177 Q_UNUSED(fb) 0178 return true; 0179 } 0180 }; 0181 0182 int CalPrintIncidence::printCaptionAndText(QPainter &p, QRect box, const QString &caption, const QString &text, const QFont &captionFont, const QFont &textFont) 0183 { 0184 QFontMetrics captionFM(captionFont); 0185 int textWd = captionFM.horizontalAdvance(caption); 0186 QRect textRect(box); 0187 0188 QFont oldFont(p.font()); 0189 p.setFont(captionFont); 0190 p.drawText(box, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, caption); 0191 0192 if (!text.isEmpty()) { 0193 textRect.setLeft(textRect.left() + textWd); 0194 p.setFont(textFont); 0195 p.drawText(textRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, text); 0196 } 0197 p.setFont(oldFont); 0198 return textRect.bottom(); 0199 } 0200 0201 void CalPrintIncidence::print(QPainter &p, int width, int height) 0202 { 0203 QFont oldFont(p.font()); 0204 QFont textFont(QStringLiteral("sans-serif"), 11, QFont::Normal); 0205 QFont captionFont(QStringLiteral("sans-serif"), 11, QFont::Bold); 0206 p.setFont(textFont); 0207 int lineHeight = p.fontMetrics().lineSpacing(); 0208 QString cap; 0209 QString txt; 0210 0211 KCalendarCore::Incidence::List::ConstIterator it; 0212 for (it = mSelectedIncidences.constBegin(); it != mSelectedIncidences.constEnd(); ++it) { 0213 // don't do anything on a 0-pointer! 0214 if (!(*it)) { 0215 continue; 0216 } 0217 if (it != mSelectedIncidences.constBegin()) { 0218 mPrinter->newPage(); 0219 } 0220 0221 const bool isJournal = ((*it)->type() == KCalendarCore::Incidence::TypeJournal); 0222 0223 // PAGE Layout (same for landscape and portrait! astonishingly, it looks good with both!): 0224 // +-----------------------------------+ 0225 // | Header: Summary | 0226 // +===================================+ 0227 // | start: ______ end: _________ | 0228 // | repeats: ___________________ | 0229 // | reminder: __________________ | 0230 // +-----------------------------------+ 0231 // | Location: ______________________ | 0232 // +------------------------+----------+ 0233 // | Description: | Notes or | 0234 // | | Subitems | 0235 // | | | 0236 // | | | 0237 // | | | 0238 // | | | 0239 // | | | 0240 // | | | 0241 // | | | 0242 // | | | 0243 // +------------------------+----------+ 0244 // | Attachments: | Settings | 0245 // | | | 0246 // +------------------------+----------+ 0247 // | Attendees: | 0248 // | | 0249 // +-----------------------------------+ 0250 // | Categories: _____________________ | 0251 // +-----------------------------------+ 0252 0253 QRect box(0, 0, width, height); 0254 QRect titleBox(box); 0255 titleBox.setHeight(headerHeight()); 0256 QColor headerColor = mUseColors ? categoryBgColor(*it) : QColor(); 0257 // Draw summary as header, no small calendars in title bar, expand height if needed 0258 int titleBottom = drawHeader(p, (*it)->summary(), QDate(), QDate(), titleBox, true, headerColor); 0259 titleBox.setBottom(titleBottom); 0260 0261 QRect timesBox(titleBox); 0262 timesBox.setTop(titleBox.bottom() + padding()); 0263 timesBox.setHeight(height / 8); 0264 0265 TimePrintStringsVisitor stringVis; 0266 int h = timesBox.top(); 0267 if (stringVis.act(*it)) { 0268 QRect textRect(timesBox.left() + padding(), timesBox.top() + padding(), 0, lineHeight); 0269 textRect.setRight(timesBox.center().x()); 0270 h = printCaptionAndText(p, textRect, stringVis.mStartCaption, stringVis.mStartString, captionFont, textFont); 0271 0272 textRect.setLeft(textRect.right()); 0273 textRect.setRight(timesBox.right() - padding()); 0274 h = qMax(printCaptionAndText(p, textRect, stringVis.mEndCaption, stringVis.mEndString, captionFont, textFont), h); 0275 } 0276 0277 // Recurrence Printing 0278 if ((*it)->recurs()) { 0279 QRect recurBox(timesBox.left() + padding(), h + padding(), timesBox.right() - padding(), lineHeight); 0280 KCalendarCore::Recurrence *recurs = (*it)->recurrence(); 0281 QString displayString = KCalUtils::IncidenceFormatter::recurrenceString((*it)); 0282 // exception dates 0283 QString exceptString; 0284 if (!recurs->exDates().isEmpty()) { 0285 exceptString = i18nc("except for listed dates", " except"); 0286 for (int i = 0; i < recurs->exDates().size(); ++i) { 0287 exceptString.append(QLatin1Char(' ')); 0288 exceptString.append(QLocale::system().toString(recurs->exDates().at(i), QLocale::ShortFormat)); 0289 } 0290 } 0291 displayString.append(exceptString); 0292 h = qMax(printCaptionAndText(p, recurBox, i18n("Repeats: "), displayString, captionFont, textFont), h); 0293 } 0294 0295 if (!isJournal) { 0296 // Alarms Printing 0297 QRect alarmBox(timesBox.left() + padding(), h + padding(), timesBox.right() - padding(), lineHeight); 0298 KCalendarCore::Alarm::List alarms = (*it)->alarms(); 0299 if (alarms.isEmpty()) { 0300 cap = i18n("No reminders"); 0301 txt.clear(); 0302 } else { 0303 cap = i18np("Reminder: ", "%1 reminders: ", alarms.count()); 0304 0305 QStringList alarmStrings; 0306 KCalendarCore::Alarm::List::ConstIterator it; 0307 alarmStrings.reserve(alarms.count()); 0308 for (it = alarms.constBegin(); it != alarms.constEnd(); ++it) { 0309 KCalendarCore::Alarm::Ptr alarm = *it; 0310 0311 // Alarm offset, copied from koeditoralarms.cpp: 0312 KLocalizedString offsetstr; 0313 int offset = 0; 0314 if (alarm->hasStartOffset()) { 0315 offset = alarm->startOffset().asSeconds(); 0316 if (offset < 0) { 0317 offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 before the start"); 0318 offset = -offset; 0319 } else { 0320 offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 after the start"); 0321 } 0322 } else if (alarm->hasEndOffset()) { 0323 offset = alarm->endOffset().asSeconds(); 0324 if (offset < 0) { 0325 offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 before the end"); 0326 offset = -offset; 0327 } else { 0328 offsetstr = ki18nc("N days/hours/minutes before/after the start/end", "%1 after the end"); 0329 } 0330 } 0331 0332 offset = offset / 60; // make minutes 0333 int useoffset = 0; 0334 0335 if (offset % (24 * 60) == 0 && offset > 0) { // divides evenly into days? 0336 useoffset = offset / (24 * 60); 0337 offsetstr = offsetstr.subs(i18np("1 day", "%1 days", useoffset)); 0338 } else if (offset % 60 == 0 && offset > 0) { // divides evenly into hours? 0339 useoffset = offset / 60; 0340 offsetstr = offsetstr.subs(i18np("1 hour", "%1 hours", useoffset)); 0341 } else { 0342 useoffset = offset; 0343 offsetstr = offsetstr.subs(i18np("1 minute", "%1 minutes", useoffset)); 0344 } 0345 alarmStrings << offsetstr.toString(); 0346 } 0347 txt = alarmStrings.join(i18nc("Spacer for the joined list of categories/tags", ", ")); 0348 } 0349 h = qMax(printCaptionAndText(p, alarmBox, cap, txt, captionFont, textFont), h); 0350 } 0351 QRect organizerBox(timesBox.left() + padding(), h + padding(), timesBox.right() - padding(), lineHeight); 0352 h = qMax(printCaptionAndText(p, organizerBox, i18n("Organizer: "), (*it)->organizer().fullName(), captionFont, textFont), h); 0353 0354 // Finally, draw the frame around the time information... 0355 timesBox.setBottom(qMax(timesBox.bottom(), h + padding())); 0356 drawBox(p, BOX_BORDER_WIDTH, timesBox); 0357 0358 QRect locationBox(timesBox); 0359 locationBox.setTop(timesBox.bottom() + padding()); 0360 locationBox.setHeight(0); 0361 int locationBottom = 0; 0362 if (!isJournal) { 0363 locationBottom = drawBoxWithCaption(p, 0364 locationBox, 0365 i18n("Location: "), 0366 (*it)->location(), 0367 /*sameLine=*/true, 0368 /*expand=*/true, 0369 captionFont, 0370 textFont); 0371 } 0372 locationBox.setBottom(locationBottom); 0373 0374 // Now start constructing the boxes from the bottom: 0375 QRect footerBox(locationBox); 0376 footerBox.setBottom(box.bottom()); 0377 footerBox.setTop(footerBox.bottom() - lineHeight - 2 * padding()); 0378 0379 QRect categoriesBox(footerBox); 0380 categoriesBox.setBottom(footerBox.top()); 0381 categoriesBox.setTop(categoriesBox.bottom() - lineHeight - 2 * padding()); 0382 QRect attendeesBox(box.left(), categoriesBox.top() - padding() - box.height() / 9, box.width(), box.height() / 9); 0383 QRect attachmentsBox(box.left(), attendeesBox.top() - padding() - box.height() / 9, box.width() * 3 / 4 - padding(), box.height() / 9); 0384 QRect optionsBox(isJournal ? box.left() : attachmentsBox.right() + padding(), attachmentsBox.top(), 0, 0); 0385 optionsBox.setRight(box.right()); 0386 optionsBox.setBottom(attachmentsBox.bottom()); 0387 QRect notesBox(optionsBox.left(), isJournal ? (timesBox.bottom() + padding()) : (locationBox.bottom() + padding()), optionsBox.width(), 0); 0388 notesBox.setBottom(optionsBox.top() - padding()); 0389 QRect descriptionBox(notesBox); 0390 descriptionBox.setLeft(box.left()); 0391 descriptionBox.setRight(attachmentsBox.right()); 0392 0393 // Adjust boxes depending on the show options... 0394 if (!mShowSubitemsNotes || isJournal) { 0395 descriptionBox.setRight(box.right()); 0396 } 0397 if (!mShowAttachments || !mShowAttendees) { 0398 descriptionBox.setBottom(attachmentsBox.bottom()); 0399 optionsBox.setTop(attendeesBox.top()); 0400 optionsBox.setBottom(attendeesBox.bottom()); 0401 notesBox.setBottom(attachmentsBox.bottom()); 0402 if (mShowOptions) { 0403 attendeesBox.setRight(attachmentsBox.right()); 0404 } 0405 if (!mShowAttachments && !mShowAttendees) { 0406 if (mShowSubitemsNotes) { 0407 descriptionBox.setBottom(attendeesBox.bottom()); 0408 } 0409 if (!mShowOptions) { 0410 descriptionBox.setBottom(attendeesBox.bottom()); 0411 notesBox.setBottom(attendeesBox.bottom()); 0412 } 0413 } 0414 } 0415 if (mShowAttachments && !isJournal) { 0416 if (!mShowOptions) { 0417 attachmentsBox.setRight(box.right()); 0418 attachmentsBox.setRight(box.right()); 0419 } 0420 if (!mShowAttendees) { 0421 attachmentsBox.setTop(attendeesBox.top()); 0422 attachmentsBox.setBottom(attendeesBox.bottom()); 0423 } 0424 } 0425 int newBottom = drawBoxWithCaption(p, 0426 descriptionBox, 0427 i18n("Description:"), 0428 (*it)->description(), 0429 /*sameLine=*/false, 0430 /*expand=*/false, 0431 captionFont, 0432 textFont, 0433 (*it)->descriptionIsRich()); 0434 if (mShowNoteLines) { 0435 drawNoteLines(p, descriptionBox, newBottom); 0436 } 0437 0438 if (mShowSubitemsNotes && !isJournal) { 0439 KCalendarCore::Todo::List relations; 0440 for (const auto &incidence : mCalendar->incidences()) { 0441 auto todo = incidence.dynamicCast<KCalendarCore::Todo>(); 0442 if (!todo) { 0443 continue; 0444 } 0445 if (todo->relatedTo() != (*it)->uid()) { 0446 continue; 0447 } 0448 relations.push_back(todo); 0449 } 0450 0451 if (relations.isEmpty() || (*it)->type() != KCalendarCore::Incidence::TypeTodo) { 0452 int notesPosition = drawBoxWithCaption(p, 0453 notesBox, 0454 i18n("Notes:"), 0455 QString(), 0456 /*sameLine=*/false, 0457 /*expand=*/false, 0458 captionFont, 0459 textFont); 0460 if (mShowNoteLines) { 0461 drawNoteLines(p, notesBox, notesPosition); 0462 } 0463 } else { 0464 QString subitemCaption; 0465 if (relations.isEmpty()) { 0466 subitemCaption = i18n("No Subitems"); 0467 txt.clear(); 0468 } else { 0469 subitemCaption = i18np("1 Subitem:", "%1 Subitems:", relations.count()); 0470 } 0471 0472 QString subitemString; 0473 QString statusString; 0474 QString datesString; 0475 int count = 0; 0476 for (const auto &todo : std::as_const(relations)) { 0477 ++count; 0478 if (!todo) { // defensive, skip any zero pointers 0479 continue; 0480 } 0481 // format the status 0482 statusString = KCalUtils::Stringify::incidenceStatus(todo->status()); 0483 if (statusString.isEmpty()) { 0484 if (todo->status() == KCalendarCore::Incidence::StatusNone) { 0485 statusString = i18nc("no status", "none"); 0486 } else { 0487 statusString = i18nc("unknown status", "unknown"); 0488 } 0489 } 0490 // format the dates if provided 0491 datesString.clear(); 0492 if (todo->dtStart().isValid()) { 0493 datesString += 0494 i18nc("subitem start date", "Start Date: %1\n", QLocale().toString(todo->dtStart().toLocalTime().date(), QLocale::ShortFormat)); 0495 if (!todo->allDay()) { 0496 datesString += 0497 i18nc("subitem start time", "Start Time: %1\n", QLocale().toString(todo->dtStart().toLocalTime().time(), QLocale::ShortFormat)); 0498 } 0499 } 0500 if (todo->dateTime(KCalendarCore::Incidence::RoleEnd).isValid()) { 0501 subitemString += 0502 i18nc("subitem due date", 0503 "Due Date: %1\n", 0504 QLocale().toString(todo->dateTime(KCalendarCore::Incidence ::RoleEnd).toLocalTime().date(), QLocale::ShortFormat)); 0505 0506 if (!todo->allDay()) { 0507 subitemString += 0508 i18nc("subitem due time", 0509 "Due Time: %1\n", 0510 QLocale().toString(todo->dateTime(KCalendarCore::Incidence::RoleEnd).toLocalTime().time(), QLocale::ShortFormat)); 0511 } 0512 } 0513 subitemString += i18nc("subitem counter", "%1: ", count); 0514 subitemString += todo->summary(); 0515 subitemString += QLatin1Char('\n'); 0516 if (!datesString.isEmpty()) { 0517 subitemString += datesString; 0518 subitemString += QLatin1Char('\n'); 0519 } 0520 subitemString += i18nc("subitem Status: statusString", "Status: %1\n", statusString); 0521 subitemString += KCalUtils::IncidenceFormatter::recurrenceString(todo) + QLatin1Char('\n'); 0522 subitemString += i18nc("subitem Priority: N", "Priority: %1\n", QString::number(todo->priority())); 0523 subitemString += i18nc("subitem Secrecy: secrecyString", "Secrecy: %1\n", KCalUtils::Stringify::incidenceSecrecy(todo->secrecy())); 0524 subitemString += QLatin1Char('\n'); 0525 } 0526 drawBoxWithCaption(p, 0527 notesBox, 0528 subitemCaption, 0529 subitemString, 0530 /*sameLine=*/false, 0531 /*expand=*/false, 0532 captionFont, 0533 textFont); 0534 } 0535 } 0536 0537 if (mShowAttachments && !isJournal) { 0538 const KCalendarCore::Attachment::List attachments = (*it)->attachments(); 0539 QString attachmentCaption; 0540 if (attachments.isEmpty()) { 0541 attachmentCaption = i18n("No Attachments"); 0542 txt.clear(); 0543 } else { 0544 attachmentCaption = i18np("1 Attachment:", "%1 Attachments:", attachments.count()); 0545 } 0546 QString attachmentString; 0547 KCalendarCore::Attachment::List::ConstIterator ait = attachments.constBegin(); 0548 for (; ait != attachments.constEnd(); ++ait) { 0549 if (!attachmentString.isEmpty()) { 0550 attachmentString += i18nc("Spacer for list of attachments", " "); 0551 } 0552 attachmentString.append((*ait).label()); 0553 } 0554 drawBoxWithCaption(p, 0555 attachmentsBox, 0556 attachmentCaption, 0557 attachmentString, 0558 /*sameLine=*/false, 0559 /*expand=*/false, 0560 captionFont, 0561 textFont); 0562 } 0563 if (mShowAttendees) { 0564 const KCalendarCore::Attendee::List attendees = (*it)->attendees(); 0565 QString attendeeCaption; 0566 if (attendees.isEmpty()) { 0567 attendeeCaption = i18n("No Attendees"); 0568 } else { 0569 attendeeCaption = i18np("1 Attendee:", "%1 Attendees:", attendees.count()); 0570 } 0571 QString attendeeString; 0572 KCalendarCore::Attendee::List::ConstIterator ait = attendees.constBegin(); 0573 for (; ait != attendees.constEnd(); ++ait) { 0574 if (!attendeeString.isEmpty()) { 0575 attendeeString += QLatin1Char('\n'); 0576 } 0577 attendeeString += i18nc( 0578 "Formatting of an attendee: " 0579 "'Name (Role): Status', e.g. 'Reinhold Kainhofer " 0580 "<reinhold@kainhofer.com> (Participant): Awaiting Response'", 0581 "%1 (%2): %3", 0582 (*ait).fullName(), 0583 KCalUtils::Stringify::attendeeRole((*ait).role()), 0584 KCalUtils::Stringify::attendeeStatus((*ait).status())); 0585 } 0586 drawBoxWithCaption(p, 0587 attendeesBox, 0588 attendeeCaption, 0589 attendeeString, 0590 /*sameLine=*/false, 0591 /*expand=*/false, 0592 captionFont, 0593 textFont); 0594 } 0595 0596 if (mShowOptions) { 0597 QString optionsString; 0598 if (!KCalUtils::Stringify::incidenceStatus((*it)->status()).isEmpty()) { 0599 optionsString += i18n("Status: %1", KCalUtils::Stringify::incidenceStatus((*it)->status())); 0600 optionsString += QLatin1Char('\n'); 0601 } 0602 if (!KCalUtils::Stringify::incidenceSecrecy((*it)->secrecy()).isEmpty()) { 0603 optionsString += i18n("Secrecy: %1", KCalUtils::Stringify::incidenceSecrecy((*it)->secrecy())); 0604 optionsString += QLatin1Char('\n'); 0605 } 0606 if ((*it)->type() == KCalendarCore::Incidence::TypeEvent) { 0607 KCalendarCore::Event::Ptr e = (*it).staticCast<KCalendarCore::Event>(); 0608 if (e->transparency() == KCalendarCore::Event::Opaque) { 0609 optionsString += i18n("Show as: Busy"); 0610 } else { 0611 optionsString += i18n("Show as: Free"); 0612 } 0613 optionsString += QLatin1Char('\n'); 0614 } else if ((*it)->type() == KCalendarCore::Incidence::TypeTodo) { 0615 KCalendarCore::Todo::Ptr t = (*it).staticCast<KCalendarCore::Todo>(); 0616 if (t->isOverdue()) { 0617 optionsString += i18n("This task is overdue!"); 0618 optionsString += QLatin1Char('\n'); 0619 } 0620 } else if ((*it)->type() == KCalendarCore::Incidence::TypeJournal) { 0621 // TODO: Anything Journal-specific? 0622 } 0623 drawBoxWithCaption(p, optionsBox, i18n("Settings: "), optionsString, /*sameLine=*/false, /*expand=*/false, captionFont, textFont); 0624 } 0625 0626 drawBoxWithCaption(p, 0627 categoriesBox, 0628 i18n("Tags: "), 0629 (*it)->categories().join(i18nc("Spacer for the joined list of categories/tags", ", ")), 0630 /*sameLine=*/true, 0631 /*expand=*/false, 0632 captionFont, 0633 textFont); 0634 0635 if (mPrintFooter) { 0636 drawFooter(p, footerBox); 0637 } 0638 } 0639 p.setFont(oldFont); 0640 } 0641 0642 /************************************************************** 0643 * Print Timetables 0644 **************************************************************/ 0645 0646 CalPrintTimetable::CalPrintTimetable() 0647 : CalPrintPluginBase() 0648 { 0649 } 0650 0651 CalPrintTimetable::~CalPrintTimetable() = default; 0652 0653 void CalPrintTimetable::doLoadConfig() 0654 { 0655 CalPrintPluginBase::doLoadConfig(); 0656 if (mConfig) { 0657 KConfigGroup grp(mConfig, groupName()); 0658 QDate dt = QDate::currentDate(); // any valid QDate will do 0659 QTime tm1(dayStart()); 0660 QDateTime startTm(dt, tm1); 0661 QDateTime endTm(dt, tm1.addSecs(12 * 60 * 60)); 0662 mStartTime = grp.readEntry("Start time", startTm).time(); 0663 mEndTime = grp.readEntry("End time", endTm).time(); 0664 mIncludeDescription = grp.readEntry("Include description", false); 0665 mIncludeCategories = grp.readEntry("Include categories", false); 0666 mIncludeTodos = grp.readEntry("Include todos", false); 0667 mIncludeAllEvents = grp.readEntry("Include all events", false); 0668 mSingleLineLimit = grp.readEntry("Single line limit", false); 0669 mExcludeTime = grp.readEntry("Exclude time", false); 0670 } 0671 } 0672 0673 void CalPrintTimetable::doSaveConfig() 0674 { 0675 if (mConfig) { 0676 KConfigGroup grp(mConfig, groupName()); 0677 QDateTime dt = QDateTime::currentDateTime(); // any valid QDateTime will do 0678 dt.setTime(mStartTime); 0679 grp.writeEntry("Start time", dt); 0680 dt.setTime(mEndTime); 0681 grp.writeEntry("End time", dt); 0682 grp.writeEntry("Include description", mIncludeDescription); 0683 grp.writeEntry("Include categories", mIncludeCategories); 0684 grp.writeEntry("Include todos", mIncludeTodos); 0685 grp.writeEntry("Include all events", mIncludeAllEvents); 0686 grp.writeEntry("Single line limit", mSingleLineLimit); 0687 grp.writeEntry("Exclude time", mExcludeTime); 0688 } 0689 CalPrintPluginBase::doSaveConfig(); 0690 } 0691 0692 static QString cleanString(const QString &instr) 0693 { 0694 QString ret = instr; 0695 return ret.replace(QLatin1Char('\n'), QLatin1Char(' ')); 0696 } 0697 0698 void CalPrintTimetable::drawAllDayBox(QPainter &p, const KCalendarCore::Event::List &eventList, QDate qd, QRect box, const QList<QDate> &workDays) 0699 { 0700 int lineSpacing = p.fontMetrics().lineSpacing(); 0701 0702 if (!workDays.contains(qd)) { 0703 drawShadedBox(p, BOX_BORDER_WIDTH, sHolidayBackground, box); 0704 } else { 0705 drawBox(p, BOX_BORDER_WIDTH, box); 0706 } 0707 0708 QRect eventBox(box); 0709 eventBox.setTop(box.top() + padding()); 0710 eventBox.setBottom(eventBox.top() + lineSpacing); 0711 0712 for (const KCalendarCore::Event::Ptr &currEvent : std::as_const(eventList)) { 0713 if (!currEvent || !currEvent->allDay() || (mExcludeConfidential && currEvent->secrecy() == KCalendarCore::Incidence::SecrecyConfidential) 0714 || (mExcludePrivate && currEvent->secrecy() == KCalendarCore::Incidence::SecrecyPrivate)) { 0715 continue; 0716 } 0717 QString str; 0718 if (currEvent->location().isEmpty()) { 0719 str = cleanString(currEvent->summary()); 0720 } else { 0721 str = i18nc("summary, location", "%1, %2", cleanString(currEvent->summary()), cleanString(currEvent->location())); 0722 } 0723 if (mIncludeCategories && !currEvent->categoriesStr().isEmpty()) { 0724 str = i18nc("summary, categories", "%1, %2", str, currEvent->categoriesStr()); 0725 } 0726 printEventString(p, eventBox, str); 0727 eventBox.setTop(eventBox.bottom()); 0728 eventBox.setBottom(eventBox.top() + lineSpacing); 0729 } 0730 } 0731 0732 void CalPrintTimetable::drawTimeTable(QPainter &p, QDate fromDate, QDate toDate, QRect box) 0733 { 0734 QTime myFromTime = mStartTime; 0735 QTime myToTime = mEndTime; 0736 int maxAllDayEvents = 0; 0737 QDate curDate(fromDate); 0738 while (curDate <= toDate) { 0739 KCalendarCore::Event::List eventList = mCalendar->events(curDate, QTimeZone::systemTimeZone()); 0740 int allDayEvents = holiday(curDate).isEmpty() ? 0 : 1; 0741 for (const KCalendarCore::Event::Ptr &event : std::as_const(eventList)) { 0742 Q_ASSERT(event); 0743 if (!event || (mExcludeConfidential && event->secrecy() == KCalendarCore::Incidence::SecrecyConfidential) 0744 || (mExcludePrivate && event->secrecy() == KCalendarCore::Incidence::SecrecyPrivate)) { 0745 continue; 0746 } 0747 if (event->allDay()) { 0748 allDayEvents += 1; 0749 } else if (mIncludeAllEvents) { 0750 if (event->dtStart().time() < myFromTime) { 0751 myFromTime = event->dtStart().time(); 0752 } 0753 if (event->dtEnd().time() > myToTime) { 0754 myToTime = event->dtEnd().time(); 0755 } 0756 } 0757 } 0758 if (allDayEvents > maxAllDayEvents) { 0759 maxAllDayEvents = allDayEvents; 0760 } 0761 curDate = curDate.addDays(1); 0762 } 0763 0764 p.setFont(QFont(QStringLiteral("sans-serif"), 11, QFont::Normal)); 0765 const int lineSpacing = p.fontMetrics().lineSpacing(); 0766 0767 int timelineWidth = TIMELINE_WIDTH + padding(); 0768 0769 QRect dowBox(box); 0770 dowBox.setLeft(box.left() + timelineWidth); 0771 dowBox.setHeight(mSubHeaderHeight); 0772 drawDaysOfWeek(p, fromDate, toDate, dowBox); 0773 0774 int tlTop = dowBox.bottom(); 0775 0776 int alldayHeight = 0; 0777 if (maxAllDayEvents > 0) { 0778 // Draw the side bar for all-day events. 0779 const auto alldayLabel = i18nc("label for timetable all-day boxes", "All day"); 0780 const QFont oldFont(p.font()); 0781 p.setFont(QFont(QStringLiteral("sans-serif"), 9, QFont::Normal)); 0782 const auto labelHeight = p.fontMetrics().horizontalAdvance(alldayLabel) + 2 * padding(); 0783 alldayHeight = std::max(maxAllDayEvents * lineSpacing + 2 * padding(), labelHeight); 0784 drawVerticalBox(p, 0785 BOX_BORDER_WIDTH, 0786 QRect(0, tlTop, TIMELINE_WIDTH, alldayHeight), 0787 alldayLabel, 0788 Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextWordWrap); 0789 p.setFont(oldFont); 0790 tlTop += alldayHeight + padding(); 0791 } 0792 0793 QRect tlBox(box); 0794 tlBox.setWidth(TIMELINE_WIDTH); 0795 tlBox.setTop(tlTop); 0796 drawTimeLine(p, myFromTime, myToTime, tlBox); 0797 0798 // draw each day 0799 curDate = fromDate; 0800 int i = 0; 0801 double cellWidth = double(dowBox.width() - 1) / double(fromDate.daysTo(toDate) + 1); 0802 QRect allDayBox(dowBox.left(), dowBox.bottom(), cellWidth, alldayHeight); 0803 const QList<QDate> workDays = CalendarSupport::workDays(fromDate, toDate); 0804 while (curDate <= toDate) { 0805 KCalendarCore::Event::List eventList = 0806 mCalendar->events(curDate, QTimeZone::systemTimeZone(), KCalendarCore::EventSortStartDate, KCalendarCore::SortDirectionAscending); 0807 0808 allDayBox.setLeft(dowBox.left() + int(i * cellWidth)); 0809 allDayBox.setRight(dowBox.left() + int((i + 1) * cellWidth)); 0810 if (maxAllDayEvents > 0) { 0811 if (const auto h = holidayEvent(curDate)) { 0812 eventList.prepend(h); 0813 } 0814 drawAllDayBox(p, eventList, curDate, allDayBox, workDays); 0815 } 0816 0817 QRect dayBox(allDayBox); 0818 dayBox.setTop(tlTop); 0819 dayBox.setBottom(box.bottom()); 0820 drawAgendaDayBox(p, eventList, curDate, false, myFromTime, myToTime, dayBox, mIncludeDescription, mIncludeCategories, mExcludeTime, workDays); 0821 0822 ++i; 0823 curDate = curDate.addDays(1); 0824 } 0825 } 0826 0827 /************************************************************** 0828 * Print Day 0829 **************************************************************/ 0830 0831 CalPrintDay::CalPrintDay() 0832 : CalPrintTimetable() 0833 { 0834 } 0835 0836 CalPrintDay::~CalPrintDay() = default; 0837 0838 QWidget *CalPrintDay::createConfigWidget(QWidget *w) 0839 { 0840 return new CalPrintDayConfig(w); 0841 } 0842 0843 void CalPrintDay::readSettingsWidget() 0844 { 0845 auto cfg = dynamic_cast<CalPrintDayConfig *>((QWidget *)mConfigWidget); 0846 if (cfg) { 0847 mFromDate = cfg->mFromDate->date(); 0848 mToDate = cfg->mToDate->date(); 0849 0850 if (cfg->mPrintTypeFilofax->isChecked()) { 0851 mDayPrintType = Filofax; 0852 } else if (cfg->mPrintTypeTimetable->isChecked()) { 0853 mDayPrintType = Timetable; 0854 } else { 0855 mDayPrintType = SingleTimetable; 0856 } 0857 0858 mStartTime = cfg->mFromTime->time(); 0859 mEndTime = cfg->mToTime->time(); 0860 mIncludeAllEvents = cfg->mIncludeAllEvents->isChecked(); 0861 0862 mIncludeDescription = cfg->mIncludeDescription->isChecked(); 0863 mIncludeCategories = cfg->mIncludeCategories->isChecked(); 0864 mSingleLineLimit = cfg->mSingleLineLimit->isChecked(); 0865 mIncludeTodos = cfg->mIncludeTodos->isChecked(); 0866 mUseColors = cfg->mColors->isChecked(); 0867 mPrintFooter = cfg->mPrintFooter->isChecked(); 0868 mShowNoteLines = cfg->mShowNoteLines->isChecked(); 0869 mExcludeTime = cfg->mExcludeTime->isChecked(); 0870 mExcludeConfidential = cfg->mExcludeConfidential->isChecked(); 0871 mExcludePrivate = cfg->mExcludePrivate->isChecked(); 0872 } 0873 } 0874 0875 void CalPrintDay::setSettingsWidget() 0876 { 0877 auto cfg = dynamic_cast<CalPrintDayConfig *>((QWidget *)mConfigWidget); 0878 if (cfg) { 0879 cfg->mFromDate->setDate(mFromDate); 0880 cfg->mToDate->setDate(mToDate); 0881 0882 cfg->mPrintTypeFilofax->setChecked(mDayPrintType == Filofax); 0883 cfg->mPrintTypeTimetable->setChecked(mDayPrintType == Timetable); 0884 cfg->mPrintTypeSingleTimetable->setChecked(mDayPrintType == SingleTimetable); 0885 0886 cfg->mFromTime->setTime(mStartTime); 0887 cfg->mToTime->setTime(mEndTime); 0888 cfg->mIncludeAllEvents->setChecked(mIncludeAllEvents); 0889 0890 cfg->mIncludeDescription->setChecked(mIncludeDescription); 0891 cfg->mIncludeCategories->setChecked(mIncludeCategories); 0892 cfg->mSingleLineLimit->setChecked(mSingleLineLimit); 0893 cfg->mIncludeTodos->setChecked(mIncludeTodos); 0894 cfg->mColors->setChecked(mUseColors); 0895 cfg->mPrintFooter->setChecked(mPrintFooter); 0896 cfg->mShowNoteLines->setChecked(mShowNoteLines); 0897 cfg->mExcludeTime->setChecked(mExcludeTime); 0898 cfg->mExcludeConfidential->setChecked(mExcludeConfidential); 0899 cfg->mExcludePrivate->setChecked(mExcludePrivate); 0900 } 0901 } 0902 0903 void CalPrintDay::doLoadConfig() 0904 { 0905 CalPrintTimetable::doLoadConfig(); 0906 if (mConfig) { 0907 KConfigGroup grp(mConfig, groupName()); 0908 mDayPrintType = static_cast<eDayPrintType>(grp.readEntry("Print type", static_cast<int>(Timetable))); 0909 } 0910 setSettingsWidget(); 0911 } 0912 0913 void CalPrintDay::doSaveConfig() 0914 { 0915 readSettingsWidget(); 0916 if (mConfig) { 0917 KConfigGroup grp(mConfig, groupName()); 0918 grp.writeEntry("Print type", int(mDayPrintType)); 0919 } 0920 CalPrintTimetable::doSaveConfig(); 0921 } 0922 0923 void CalPrintDay::setDateRange(const QDate &from, const QDate &to) 0924 { 0925 CalPrintPluginBase::setDateRange(from, to); 0926 auto cfg = dynamic_cast<CalPrintDayConfig *>((QWidget *)mConfigWidget); 0927 if (cfg) { 0928 cfg->mFromDate->setDate(from); 0929 cfg->mToDate->setDate(to); 0930 } 0931 } 0932 0933 void CalPrintDay::drawDays(QPainter &p, QRect box) 0934 { 0935 const int numberOfDays = mFromDate.daysTo(mToDate) + 1; 0936 int vcells; 0937 const bool portrait = (box.height() > box.width()); 0938 int cellWidth; 0939 if (portrait) { 0940 // 2 columns 0941 vcells = std::ceil(static_cast<double>(numberOfDays) / 2.0); 0942 if (numberOfDays > 1) { 0943 cellWidth = box.width() / 2; 0944 } else { 0945 cellWidth = box.width(); 0946 } 0947 } else { 0948 // landscape: N columns 0949 vcells = 1; 0950 cellWidth = box.width() / numberOfDays; 0951 } 0952 const int cellHeight = box.height() / vcells; 0953 QDate weekDate = mFromDate; 0954 for (int i = 0; i < numberOfDays; ++i, weekDate = weekDate.addDays(1)) { 0955 const int hpos = i / vcells; 0956 const int vpos = i % vcells; 0957 const QRect dayBox(box.left() + cellWidth * hpos, box.top() + cellHeight * vpos, cellWidth, cellHeight); 0958 drawDayBox(p, weekDate, mStartTime, mEndTime, dayBox, true, true, true, mSingleLineLimit, mIncludeDescription, mIncludeCategories); 0959 } // for i through all selected days 0960 } 0961 0962 void CalPrintDay::print(QPainter &p, int width, int height) 0963 { 0964 QDate curDay(mFromDate); 0965 0966 QRect headerBox(0, 0, width, headerHeight()); 0967 QRect footerBox(0, height - footerHeight(), width, footerHeight()); 0968 height -= footerHeight(); 0969 QRect daysBox(headerBox); 0970 daysBox.setTop(headerBox.bottom() + padding()); 0971 daysBox.setBottom(height); 0972 0973 auto local = QLocale::system(); 0974 0975 switch (mDayPrintType) { 0976 case Filofax: 0977 case SingleTimetable: { 0978 QString line1 = local.toString(mFromDate, QLocale::ShortFormat); 0979 QString line2 = local.toString(mToDate, QLocale::ShortFormat); 0980 QString title; 0981 if (mFromDate == mToDate) { 0982 title = line1; 0983 } else { 0984 title = i18nc("date from-to", "%1\u2013%2", line1, line2); 0985 } 0986 drawHeader(p, title, mFromDate, QDate(), headerBox); 0987 if (mDayPrintType == Filofax) { 0988 drawDays(p, daysBox); 0989 } else if (mDayPrintType == SingleTimetable) { 0990 drawTimeTable(p, mFromDate, mToDate, daysBox); 0991 } 0992 if (mPrintFooter) { 0993 drawFooter(p, footerBox); 0994 } 0995 break; 0996 } 0997 0998 case Timetable: 0999 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 1029 CalPrintWeek::CalPrintWeek() 1030 : CalPrintTimetable() 1031 { 1032 } 1033 1034 CalPrintWeek::~CalPrintWeek() = default; 1035 1036 QWidget *CalPrintWeek::createConfigWidget(QWidget *w) 1037 { 1038 return new CalPrintWeekConfig(w); 1039 } 1040 1041 void 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 1075 void 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 } 1101 CalPrintTimetable::setSettingsWidget(); 1102 } 1103 1104 void 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 1114 void 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 1124 QPageLayout::Orientation CalPrintWeek::defaultOrientation() const 1125 { 1126 if (mWeekPrintType == Filofax) { 1127 return QPageLayout::Portrait; 1128 } else if (mWeekPrintType == SplitWeek) { 1129 return QPageLayout::Portrait; 1130 } else { 1131 return QPageLayout::Landscape; 1132 } 1133 } 1134 1135 void CalPrintWeek::setDateRange(const QDate &from, const QDate &to) 1136 { 1137 CalPrintPluginBase::setDateRange(from, to); 1138 auto cfg = dynamic_cast<CalPrintWeekConfig *>((QWidget *)mConfigWidget); 1139 if (cfg) { 1140 cfg->mFromDate->setDate(from); 1141 cfg->mToDate->setDate(to); 1142 } 1143 } 1144 1145 void 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 1176 void 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 1287 CalPrintMonth::CalPrintMonth() 1288 : CalPrintPluginBase() 1289 { 1290 } 1291 1292 CalPrintMonth::~CalPrintMonth() = default; 1293 1294 QWidget *CalPrintMonth::createConfigWidget(QWidget *w) 1295 { 1296 return new CalPrintMonthConfig(w); 1297 } 1298 1299 void 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 1322 void 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 1344 void CalPrintMonth::doLoadConfig() 1345 { 1346 CalPrintPluginBase::doLoadConfig(); 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 1360 void 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 } 1373 CalPrintPluginBase::doSaveConfig(); 1374 } 1375 1376 void CalPrintMonth::setDateRange(const QDate &from, const QDate &to) 1377 { 1378 CalPrintPluginBase::setDateRange(from, to); 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 1396 void 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); 1422 drawMonthTable(p, 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 1449 CalPrintTodos::CalPrintTodos() 1450 : CalPrintPluginBase() 1451 { 1452 mTodoSortField = TodoFieldUnset; 1453 mTodoSortDirection = TodoDirectionUnset; 1454 } 1455 1456 CalPrintTodos::~CalPrintTodos() = default; 1457 1458 QWidget *CalPrintTodos::createConfigWidget(QWidget *w) 1459 { 1460 return new CalPrintTodoConfig(w); 1461 } 1462 1463 void 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 1501 void 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 1547 void CalPrintTodos::doLoadConfig() 1548 { 1549 CalPrintPluginBase::doLoadConfig(); 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 1568 void 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 } 1586 CalPrintPluginBase::doSaveConfig(); 1587 } 1588 1589 void 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 1663 KCalendarCore::Todo::List todoList; 1664 KCalendarCore::Todo::List tempList; 1665 1666 KCalendarCore::SortDirection sortDirection = KCalendarCore::SortDirectionAscending; 1667 switch (mTodoSortDirection) { 1668 case TodoDirectionAscending: 1669 sortDirection = KCalendarCore::SortDirectionAscending; 1670 break; 1671 case TodoDirectionDescending: 1672 sortDirection = KCalendarCore::SortDirectionDescending; 1673 break; 1674 case TodoDirectionUnset: 1675 break; 1676 } 1677 1678 KCalendarCore::TodoSortField sortField = KCalendarCore::TodoSortSummary; 1679 switch (mTodoSortField) { 1680 case TodoFieldSummary: 1681 sortField = KCalendarCore::TodoSortSummary; 1682 break; 1683 case TodoFieldStartDate: 1684 sortField = KCalendarCore::TodoSortStartDate; 1685 break; 1686 case TodoFieldDueDate: 1687 sortField = KCalendarCore::TodoSortDueDate; 1688 break; 1689 case TodoFieldPriority: 1690 sortField = KCalendarCore::TodoSortPriority; 1691 break; 1692 case TodoFieldPercentComplete: 1693 sortField = KCalendarCore::TodoSortPercentComplete; 1694 break; 1695 case TodoFieldCategories: 1696 sortField = KCalendarCore::TodoSortCategories; 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"