1 /*
2   SPDX-FileCopyrightText: 1998 Preston Brown <pbrown@kde.org>
3   SPDX-FileCopyrightText: 2003 Reinhold Kainhofer <reinhold@kainhofer.com>
4   SPDX-FileCopyrightText: 2008 Ron Goodheart <rong.dev@gmail.com>
5   SPDX-FileCopyrightText: 2012-2013 Allen Winter <winter@kde.org>
6 
7   SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
8 */
9 
10 #pragma once
11 
12 #include "calendarsupport_export.h"
13 #include "printplugin.h"
14 
15 #include <Akonadi/Calendar/ETMCalendar>
16 
17 #include <KCalendarCore/Event>
18 #include <KCalendarCore/Journal>
19 #include <KCalendarCore/Todo>
20 
21 #include <QDateTime>
22 #include <QPainter>
23 
24 class PrintCellItem;
25 class QWidget;
26 
27 #define PORTRAIT_HEADER_HEIGHT 80 // header height, for portrait orientation
28 #define LANDSCAPE_HEADER_HEIGHT 54 // header height, for landscape orientation
29 #define SUBHEADER_HEIGHT 28 // subheader height, for all orientations
30 #define PORTRAIT_FOOTER_HEIGHT 16 // footer height, for portrait orientation
31 #define LANDSCAPE_FOOTER_HEIGHT 14 // footer height, for landscape orientation
32 #define MARGIN_SIZE 36 // margins, for all orientations
33 #define PADDING_SIZE 7 // padding between the various top-level boxes
34 #define BOX_BORDER_WIDTH 2 // width of the border of all top-level boxes
35 #define EVENT_BORDER_WIDTH 0 // with of the border of all incidence boxes
36 
37 #define TIMELINE_WIDTH 50 // width of timeline (day and timetable)
38 
39 namespace CalendarSupport
40 {
41 /**
42   Base class for Calendar printing classes. Each sub class represents one
43   calendar print format.
44 */
45 class CalPrintPluginBase : public PrintPlugin
46 {
47 public:
48     enum DisplayFlags { Text = 0x0001, TimeBoxes = 0x0002 };
49 
50 public:
51     /**
52       Constructor
53     */
54     CalPrintPluginBase();
55     ~CalPrintPluginBase() override;
56 
57     /**
58       Returns widget for configuring the print format.
59     */
60     QWidget *createConfigWidget(QWidget *) override;
61 
62     /**
63       Actually do the printing.
64 
65       @param p QPainter the print result is painted to
66       @param width Width of printable area
67       @param height Height of printable area
68     */
69 
70     virtual void print(QPainter &p, int width, int height) = 0;
71     /**
72       Start printing.
73     */
74     void doPrint(QPrinter *printer) override;
75 
76     void doLoadConfig() override;
77 
78     void doSaveConfig() override;
79 
80     /** HELPER FUNCTIONS */
81 public:
82     bool useColors() const;
83     void setUseColors(bool useColors);
84 
85     bool printFooter() const;
86     void setPrintFooter(bool printFooter);
87 
88     /**
89       Determines the column of the given weekday ( 1=Monday, 7=Sunday ), taking the
90       start of the week setting into account as given in kcontrol.
91       @param weekday Index of the weekday
92     */
93     static int weekdayColumn(int weekday);
94 
95     QPageLayout::Orientation orientation() const;
96 
97     /** Returns the height of the page header. If the height was explicitly
98         set using setHeaderHeight, that value is returned, otherwise a
99         default value based on the printer orientation.
100         @return height of the page header of the printout
101     */
102     int headerHeight() const;
103     void setHeaderHeight(const int height);
104 
105     int subHeaderHeight() const;
106     void setSubHeaderHeight(const int height);
107     /** Returns the height of the page footer. If the height was explicitly
108         set using setFooterHeight, that value is returned, otherwise a
109         default value based on the printer orientation.
110         @return height of the page footer of the printout
111     */
112     int footerHeight() const;
113     void setFooterHeight(const int height);
114 
115     int margin() const;
116     void setMargin(const int margin);
117 
118     int padding() const;
119     void setPadding(const int margin);
120 
121     int borderWidth() const;
122     void setBorderWidth(const int border);
123 
124     /*****************************************************************
125      **               PRINTING HELPER FUNCTIONS                     **
126      *****************************************************************/
127 public:
128     /**
129       Draw a box with given width at the given coordinates.
130       @param p The printer to be used
131       @param linewidth The border width of the box
132       @param rect The rectangle of the box
133     */
134     static void drawBox(QPainter &p, int linewidth, QRect rect);
135     /**
136       Draw a shaded box with given width at the given coordinates.
137       @param p The printer to be used
138       @param linewidth The border width of the box
139       @param brush The brush to fill the box
140       @param rect The rectangle of the box
141     */
142     static void drawShadedBox(QPainter &p, int linewidth, const QBrush &brush, QRect rect);
143 
144     /**
145       Print the given string (event summary) in the given rectangle. Margins
146       and justification (centered or not) are automatically adjusted.
147       @param p QPainter of the printout
148       @param box Coordinates of the surrounding event box
149       @param str The text to be printed in the box
150     */
151     void printEventString(QPainter &p, QRect box, const QString &str, int flags = -1);
152 
153     /**
154       Print the box for the given event with the given string.
155       @param p QPainter of the printout
156       @param linewidth is the width of the line used to draw the box, ignored if less than 1.
157       @param box Coordinates of the event's box
158       @param incidence The incidence (if available), from which the category
159                        color will be deduced, if applicable.
160       @param str The string to print inside the box
161       @param flags is a bitwise OR of Qt::AlignmentFlags and Qt::TextFlags values.
162     */
163     void showEventBox(QPainter &p, int linewidth, QRect box, const KCalendarCore::Incidence::Ptr &incidence, const QString &str, int flags = -1);
164 
165     /**
166       Draw a subheader box with a shaded background and the given string
167       @param p QPainter of the printout
168       @param str Text to be printed inside the box
169       @param box Coordinates of the box
170     */
171     void drawSubHeaderBox(QPainter &p, const QString &str, QRect box);
172 
173     /**
174       Draw an event box with vertical text.
175       @param p QPainter of the printout
176       @param linewidth is the width of the line used to draw the box, ignored if less than 1.
177       @param box Coordinates of the box
178       @param str ext to be printed inside the box
179       @param flags is a bitwise OR of Qt::AlignmentFlags and Qt::TextFlags values.
180     */
181     void drawVerticalBox(QPainter &p, int linewidth, QRect box, const QString &str, int flags = -1);
182 
183     /**
184       Draw a component box with a heading (printed in bold).
185       @param p QPainter of the printout
186       @param box Coordinates of the box
187       @param caption Caption string to be printed inside the box
188       @param contents Normal text contents of the box. If contents.isNull(),
189                       then no text will be printed, only the caption.
190       @param sameLine Whether the contents should start on the same line as
191                       the caption (the space below the caption text will be
192                       used as indentation in the subsequent lines) or on the
193                       next line (no indentation of the contents)
194       @param expand Whether to expand the box vertically to fit the
195                     whole text in it.
196       @param rickContents Whether contents contains rich text.
197       @return The bottom of the printed box. If expand==true, the bottom of
198               the drawn box is returned, if expand==false, the vertical
199               end of the printed contents inside the box is returned.
200               If you want to print some custom graphics or text below
201               the contents, use the return value as the top-value of your
202               custom contents in that case.
203     */
204     int drawBoxWithCaption(QPainter &p,
205                            QRect box,
206                            const QString &caption,
207                            const QString &contents,
208                            bool sameLine,
209                            bool expand,
210                            const QFont &captionFont,
211                            const QFont &textFont,
212                            bool richContents = false);
213 
214     /**
215       Draw the gray header bar of the printout to the QPainter.
216       It prints the given text and optionally one or two small
217       month views, as specified by the two QDate. The printed
218       text can also contain a line feed.
219       If month2 is invalid, only the month that contains month1
220       is printed.
221       E.g. the filofax week view draws just the current month,
222       while the month view draws the previous and the next month.
223       @param p QPainter of the printout
224       @param title The string printed as the title of the page
225                    (e.g. the date, date range or todo list title)
226       @param month1 Date specifying the month for the left one of
227                     the small month views in the title bar. If left
228                     empty, only month2 will be printed (or none,
229                     it that is invalid as well).
230       @param month2 Date specifying the month for the right one of
231                     the small month views in the title bar. If left
232                     empty, only month1 will be printed (or none,
233                     it that is invalid as well).
234       @param box coordinates of the title bar
235       @param expand Whether to expand the box vertically to fit the
236                     whole title in it.
237       @param backColor background color for the header box.
238       @return The bottom of the printed box. If expand==false, this
239               is box.bottom, otherwise it is larger than box.bottom
240               and matches the y-coordinate of the surrounding rectangle.
241     */
242     int drawHeader(QPainter &p, const QString &title, QDate month1, QDate month2, QRect box, bool expand = false, QColor backColor = QColor());
243 
244     /**
245       Draw a page footer containing the printing date and possibly
246       other things, like a page number.
247       @param p QPainter of the printout
248       @param box coordinates of the footer
249       @return The bottom of the printed box.
250     */
251     int drawFooter(QPainter &p, QRect box);
252 
253     /**
254       Draw a small calendar with the days of a month into the given area.
255       Used for example in the title bar of the sheet.
256       @param p QPainter of the printout
257       @param qd Arbitrary Date within the month to be printed.
258       @param box coordinates of the small calendar
259     */
260     void drawSmallMonth(QPainter &p, QDate qd, QRect box);
261 
262     /**
263       Draw a horizontal bar with the weekday names of the given date range
264       in the given area of the painter.
265       This is used for the weekday-bar on top of the timetable view and the month view.
266       @param p QPainter of the printout
267       @param fromDate First date of the printed dates
268       @param toDate Last date of the printed dates
269       @param box coordinates of the box for the days of the week
270     */
271     void drawDaysOfWeek(QPainter &p, QDate fromDate, QDate toDate, QRect box);
272 
273     /**
274       Draw a single weekday name in a box inside the given area of the painter.
275       This is called in a loop by drawDaysOfWeek.
276       @param p QPainter of the printout
277       @param qd Date of the printed day
278       @param box coordinates of the weekbox
279     */
280     void drawDaysOfWeekBox(QPainter &p, QDate qd, QRect box);
281 
282     /**
283       Draw a (vertical) time scale from time fromTime to toTime inside the
284       given area of the painter. Every hour will have a one-pixel line over
285       the whole width, every half-hour the line will only span the left half
286       of the width. This is used in the day and timetable print styles
287       @param p QPainter of the printout
288       @param fromTime Start time of the time range to display
289       @param toTime End time of the time range to display
290       @param box coordinates of the timeline
291     */
292     void drawTimeLine(QPainter &p, QTime fromTime, QTime toTime, QRect box);
293 
294     /**
295       Draw the agenda box for the day print style (the box showing all events of that day).
296       Also draws a grid with half-hour spacing of the grid lines.
297       Does NOT draw allday events.  Use drawAllDayBox for allday events.
298 
299       Obeys configuration options #mExcludeConfidential, #excludePrivate.
300       @param p QPainter of the printout
301       @param eventList The list of the events that are supposed to be printed
302              inside this box
303       @param qd The date of the currently printed day
304       @param expandable If true, the start and end times are adjusted to include
305              the whole range of all events of that day, not just of the given time range.
306              The height of the box will not be affected by this (but the height
307              of one hour will be scaled down so that the whole range fits into
308              the box. fromTime and toTime receive the actual time range printed
309              by this function).
310       @param fromTime Start of the time range to be printed. Might be adjusted
311                       to include all events if expandable==true
312       @param toTime End of the time range to be printed. Might be adjusted
313                    to include all events if expandable==true
314       @param box coordinates of the agenda day box.
315       @param includeDescription Whether to print the event description as well.
316       @param includeCategories Whether to print the event categories (tags) as well.
317       @param excludeTime Whether the time is printed in the detail area.
318       @param workDays List of workDays
319     */
320     void drawAgendaDayBox(QPainter &p,
321                           const KCalendarCore::Event::List &eventList,
322                           QDate qd,
323                           bool expandable,
324                           QTime fromTime,
325                           QTime toTime,
326                           QRect box,
327                           bool includeDescription,
328                           bool includeCategories,
329                           bool excludeTime,
330                           const QList<QDate> &workDays);
331 
332     void drawAgendaItem(PrintCellItem *item,
333                         QPainter &p,
334                         const QDateTime &startPrintDate,
335                         const QDateTime &endPrintDate,
336                         float minlen,
337                         QRect box,
338                         bool includeDescription,
339                         bool includeCategories,
340                         bool excludeTime);
341 
342     /**
343       Draw the box containing a list of all events of the given day (with their times,
344       of course). Used in the Filofax and the month print style.
345 
346       Obeys configuration options #mExcludeConfidential, #mExcludePrivate, #mShowNoteLines, #mUseColors.
347       @param p QPainter of the printout
348       @param qd The date of the currently printed day. All events of the calendar
349                 that appear on that day will be printed.
350       @param fromTime Start time of the time range to display
351       @param toTime End time of the time range to display
352       @param box coordinates of the day box.
353       @param fullDate Whether the title bar of the box should contain the full
354                       date string or just a short.
355       @param printRecurDaily Whether daily recurring incidences should be printed.
356       @param printRecurWeekly Whether weekly recurring incidences should be printed.
357       @param singleLineLimit Whether Incidence text wraps or truncates.
358       @param includeDescription Whether to print the event description as well.
359       @param includeCategories Whether to print the event categories (tags) as well.
360     */
361     void drawDayBox(QPainter &p,
362                     QDate qd,
363                     QTime fromTime,
364                     QTime toTime,
365                     QRect box,
366                     bool fullDate = false,
367                     bool printRecurDaily = true,
368                     bool printRecurWeekly = true,
369                     bool singleLineLimit = true,
370                     bool includeDescription = false,
371                     bool includeCategories = false);
372 
373     /**
374       Draw the month table of the month containing the date qd. Each day gets one
375       box (using drawDayBox) that contains a list of all events on that day. They are arranged
376       in a matrix, with the first column being the first day of the
377       week (so it might display some days of the previous and the next month).
378       Above the matrix there is a bar showing the weekdays (drawn using drawDaysOfWeek).
379 
380       Obeys configuration options #mExcludeConfidential, #mExcludePrivate, #mShowNoteLines, #mUseColors.
381       @param p QPainter of the printout
382       @param qd Arbitrary date within the month to be printed.
383       @param fromTime Start time of the displayed time range
384       @param toTime End time of the displayed time range
385       @param weeknumbers Whether the week numbers are printed left of each row of the matrix
386       @param recurDaily Whether daily recurring incidences should be printed.
387       @param recurWeekly Whether weekly recurring incidences should be printed.
388       @param singleLineLimit Whether Incidence text wraps or truncates.
389       @param includeDescription Whether descriptions are printed.
390       @param includeCategories Whether to print the event categories (tags) as well.
391       @param box coordinates of the month.
392     */
393     void drawMonthTable(QPainter &p,
394                         QDate qd,
395                         QTime fromTime,
396                         QTime toTime,
397                         bool weeknumbers,
398                         bool recurDaily,
399                         bool recurWeekly,
400                         bool singleLineLimit,
401                         bool includeDescription,
402                         bool includeCategories,
403                         QRect box);
404 
405     /**
406       Draw a vertical representation of the month containing the date dt. Each
407       day gets one line.
408 
409       Obeys configuration options #mExcludeConfidential, #excludePrivate.
410       @param p QPainter of the printout
411       @param dt Arbitrary date within the month to be printed
412       @param box coordinates of the box reserved for the month
413       @param maxdays Days to print. If a value of -1 is given, the number of days
414                      is deduced from the month. If maxdays is larger than the
415                      number of days in the month, the remaining boxes are
416                      shaded to indicate they are not days of the month.
417       @param subDailyFlags Bitfield consisting of DisplayFlags flags to determine
418                            how events that do not cross midnight should be printed.
419       @param holidaysFlags Bitfield consisting of DisplayFlags flags to determine
420                            how holidays should be printed.
421     */
422     void drawMonth(QPainter &p,
423                    QDate dt,
424                    QRect box,
425                    int maxdays = -1,
426                    int subDailyFlags = TimeBoxes,
427                    int holidaysFlags = Text);
428 
429     /**
430       Internal class representing the start of a todo.
431     */
432     class TodoParentStart;
433 
434     /**
435       Draws single to-do and its (indented) sub-to-dos, optionally connects them
436       by a tree-like line, and optionally shows due date, summary, description
437       and priority.
438       @param count The number of the currently printed to-do (count will be
439       incremented for each to-do drawn)
440       @param todo The to-do to be printed. It's sub-to-dos are recursively drawn,
441       so drawTodo should only be called on the to-dos of the highest level.
442       @param p QPainter of the printout
443       @param sortField Specifies on which attribute of the todo you want to sort.
444       @param sortDir Specifies if you want to sort ascending or descending.
445       @param connectSubTodos Whether sub-to-dos shall be connected with
446       their parent by a line (tree-like).
447       @param strikeoutCompleted Whether completed to-dos should be printed with
448       strike-out summaries.
449       @param desc Whether to print the whole description of the to-do
450       (the summary is always printed).
451       @param posPriority x-coordinate where the priority is supposed to be
452       printed. If negative, no priority will be printed.
453       @param posSummary x-coordinate where the summary of the to-do is supposed
454       to be printed.
455       @param posCategories x-coordinate where the categories (tags) should be
456       printed. If negative, no categories will be printed.
457       @param posStartDt x-coordinate where the due date is supposed to the be
458       printed. If negative, no start date will be printed.
459       @param posDueDt x-coordinate where the due date is supposed to the be
460       printed. If negative, no due date will be printed.
461       @param posPercentComplete x-coordinate where the percentage complete is
462       supposed to be printed. If negative, percentage complete will not be printed.
463       @param level Level of the current to-do in the to-do hierarchy (0 means
464       highest level of printed to-dos, 1 are their sub-to-dos, etc.)
465       @param x x-coordinate of the upper left coordinate of the first to-do.
466       @param y y-coordinate of the upper left coordinate of the first to-do.
467       @param width width of the whole to-do list.
468       @param pageHeight Total height allowed for the to-do list on a page.
469       If an to-do would be below that line, a new page is started.
470       @param todoList Contains a list of sub-todos for the specified @p todo .
471       @param r Internal (used when printing sub-to-dos to give information
472       about its parent)
473     */
474     void drawTodo(int &count,
475                   const KCalendarCore::Todo::Ptr &todo,
476                   QPainter &p,
477                   KCalendarCore::TodoSortField sortField,
478                   KCalendarCore::SortDirection sortDir,
479                   bool connectSubTodos,
480                   bool strikeoutCompleted,
481                   bool desc,
482                   int posPriority,
483                   int posSummary,
484                   int posCategories,
485                   int posStartDt,
486                   int posDueDt,
487                   int posPercentComplete,
488                   int level,
489                   int x,
490                   int &y,
491                   int width,
492                   int pageHeight,
493                   const KCalendarCore::Todo::List &todoList,
494                   TodoParentStart *r);
495 
496     /**
497       Draws text lines splitting on page boundaries.
498       @param p QPainter of the printout
499       @param x x-coordinate of the upper left coordinate of the first item
500       @param y y-coordinate of the upper left coordinate of the first item
501       @param width width of the whole list
502       @param pageHeight size of the page. A new page is started when the
503              text reaches the end of the page.
504     */
505     void drawTextLines(QPainter &p, const QString &entry, int x, int &y, int width, int pageHeight, bool richTextEntry);
506 
507     void drawSplitHeaderRight(QPainter &p, QDate fd, QDate td, QDate cd, int width, int height);
508 
509     /**
510       Draws dotted lines for notes in a box.
511       @param p QPainter of the printout
512       @param box coordinates of the box where the lines will be placed
513       @param startY starting y-coordinate for the first line
514     */
515     void drawNoteLines(QPainter &p, QRect box, int startY);
516 
517 protected:
518     QTime dayStart() const;
519     QColor categoryBgColor(const KCalendarCore::Incidence::Ptr &incidence) const;
520 
521     void drawIncidence(QPainter &p,
522                        QRect dayBox,
523                        const QString &time,
524                        const QString &summary,
525                        const QString &description,
526                        int &textY,
527                        bool singleLineLimit,
528                        bool includeDescription,
529                        bool richDescription);
530 
531     QString toPlainText(const QString &htmlText);
532 
533     void drawTodoLines(QPainter &p,
534                        const QString &entry,
535                        int x,
536                        int &y,
537                        int width,
538                        int pageHeight,
539                        bool richTextEntry,
540                        QList<TodoParentStart *> &startPoints,
541                        bool connectSubTodos);
542 
543     KCalendarCore::Event::Ptr holidayEvent(QDate date) const;
544 
545 protected:
546     bool mUseColors;    /**< Whether or not to use event category colors to draw the events. */
547     bool mPrintFooter;  /**< Whether or not to print a footer at the bottoms of pages. */
548     bool mShowNoteLines;    /**< Whether or not to print horizontal  lines in note areas. */
549     bool mExcludeConfidential;  /**< Whether or not to print incidences with secrecy "confidential". */
550     bool mExcludePrivate;   /**< Whether or not to print incidences with secrecy "private". */
551     int mHeaderHeight;
552     int mSubHeaderHeight;
553     int mFooterHeight;
554     int mMargin;
555     int mPadding;
556     int mBorder;
557 
558     static const QColor sHolidayBackground;
559 
560 private:
561     QColor categoryColor(const QStringList &categories) const;
562 
563     /**
564      * Sets the QPainter's brush and pen color according to the Incidence's category.
565      */
566     void setColorsByIncidenceCategory(QPainter &p, const KCalendarCore::Incidence::Ptr &incidence) const;
567 
568     QString holidayString(QDate date) const;
569 
570     /**
571      * Returns a nice QColor for text, give the input color &c.
572      */
573     QColor getTextColor(const QColor &c) const;
574 };
575 }
576 
577