diff options
Diffstat (limited to 'korganizer/printing')
-rw-r--r-- | korganizer/printing/Makefile.am | 34 | ||||
-rw-r--r-- | korganizer/printing/calprintdayconfig_base.ui | 257 | ||||
-rw-r--r-- | korganizer/printing/calprintdefaultplugins.cpp | 1186 | ||||
-rw-r--r-- | korganizer/printing/calprintdefaultplugins.h | 209 | ||||
-rw-r--r-- | korganizer/printing/calprinter.cpp | 278 | ||||
-rw-r--r-- | korganizer/printing/calprinter.h | 136 | ||||
-rw-r--r-- | korganizer/printing/calprintincidenceconfig_base.ui | 103 | ||||
-rw-r--r-- | korganizer/printing/calprintmonthconfig_base.ui | 210 | ||||
-rw-r--r-- | korganizer/printing/calprintpluginbase.cpp | 1674 | ||||
-rw-r--r-- | korganizer/printing/calprintpluginbase.h | 514 | ||||
-rw-r--r-- | korganizer/printing/calprinttodoconfig_base.ui | 455 | ||||
-rw-r--r-- | korganizer/printing/calprintweekconfig_base.ui | 300 | ||||
-rw-r--r-- | korganizer/printing/cellitem.cpp | 98 | ||||
-rw-r--r-- | korganizer/printing/cellitem.h | 68 |
14 files changed, 5522 insertions, 0 deletions
diff --git a/korganizer/printing/Makefile.am b/korganizer/printing/Makefile.am new file mode 100644 index 000000000..2a194bbfa --- /dev/null +++ b/korganizer/printing/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/korganizer/interfaces \ + -I$(top_srcdir)/korganizer \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + $(all_includes) + + +lib_LTLIBRARIES = libkocorehelper.la libkorg_stdprinting.la + + +libkocorehelper_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) \ + -no-undefined -version-info 1:0 +libkocorehelper_la_LIBADD = $(LIB_KDEUI) +libkocorehelper_la_SOURCES = cellitem.cpp + +libkorg_stdprinting_la_SOURCES = calprinter.cpp calprintpluginbase.cpp \ + calprintdefaultplugins.cpp \ + calprintdayconfig_base.ui calprintmonthconfig_base.ui \ + calprinttodoconfig_base.ui calprintweekconfig_base.ui \ + calprintincidenceconfig_base.ui +libkorg_stdprinting_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) \ + -no-undefined -version-info 1:0 +libkorg_stdprinting_la_LIBADD = $(LIB_KDEUI) libkocorehelper.la \ + $(top_builddir)/libkdepim/libkdepim.la \ + $(top_builddir)/libkcal/libkcal.la \ + -lkdeprint + + +calprintdir = $(includedir)/korganizer +calprint_HEADERS = calprintpluginbase.h calprinter.h +noinst_HEADERS = cellitem.h + diff --git a/korganizer/printing/calprintdayconfig_base.ui b/korganizer/printing/calprintdayconfig_base.ui new file mode 100644 index 000000000..8abfaa1c4 --- /dev/null +++ b/korganizer/printing/calprintdayconfig_base.ui @@ -0,0 +1,257 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintDayConfig_Base</class> +<comment>Configuration page for the print day mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintDay_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>386</width> + <height>202</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>mIncludeTodos</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Include to-&dos that are due on the printed day(s)</string> + </property> + <property name="whatsThis" stdset="0"> + <string>You should check this option if you want to print to-dos which are due on one of the dates which are in the supplied date range.</string> + </property> + </widget> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>mDateRangeGroup</cstring> + </property> + <property name="title"> + <string>Date && Time Range</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="0" column="4"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>121</width> + <height>21</height> + </size> + </property> + </spacer> + <spacer row="1" column="4"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>121</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>mFromDateLabel</cstring> + </property> + <property name="text"> + <string>&Start date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromDate</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>End date</i> option. This option is used to define the start date.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>mToTimeLabel</cstring> + </property> + <property name="text"> + <string>End ti&me:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToTime</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>It is possible to print only those events which are inside a given timerange. With this time selection box you can define the end of this time range. The start time should be defined with the <i>Start time</i> option. Note you can automatically modify these settings if you check <i>Extend time range to include all events</i>.</string> + </property> + </widget> + <widget class="QTimeEdit" row="1" column="3"> + <property name="name"> + <cstring>mToTime</cstring> + </property> + <property name="time"> + <time> + <hour>18</hour> + <minute>0</minute> + <second>0</second> + </time> + </property> + <property name="display"> + <set>Minutes|Hours</set> + </property> + <property name="whatsThis" stdset="0"> + <string>It's possible to print only those events which are inside a given timerange. With this time selection box you can define the end of this time range. The start time should be defined with the <i>Start time</i> option. Note you can automatically modify these settings if you check <i>Extend time range to include all events</i>.</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>mIncludeAllEvents</cstring> + </property> + <property name="text"> + <string>E&xtend time range to include all events</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this option to automatically determine the required time range, so all events will be shown.</string> + </property> + </widget> + <widget class="KDateEdit" row="0" column="1"> + <property name="name"> + <cstring>mFromDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>End date</i> option. This option is used to define the start date.</string> + </property> + </widget> + <widget class="QTimeEdit" row="0" column="3"> + <property name="name"> + <cstring>mFromTime</cstring> + </property> + <property name="time"> + <time> + <hour>8</hour> + <minute>0</minute> + <second>0</second> + </time> + </property> + <property name="display"> + <set>Minutes|Hours</set> + </property> + <property name="whatsThis" stdset="0"> + <string>It's possible to print only those events which are inside a given timerange. With this time selection box you can define the start of this time range. The end time should be defined with the <i>End time</i> option. Note you can automatically modify these settings if you check <i>Extend time range to include all events</i>.</string> + </property> + </widget> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>mFromTimeLabel</cstring> + </property> + <property name="text"> + <string>Start &time:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromTime</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>It is possible to print only those events which are inside a given timerange. With this time selection box you can define the start of this time range. The end time should be defined with the <i>End time</i> option. Note you can automatically modify these settings if you check <i>Extend time range to include all events</i>.</string> + </property> + </widget> + <widget class="KDateEdit" row="1" column="1"> + <property name="name"> + <cstring>mToDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>Start date</i> option. This option is used to define the end date.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>mToDateLabel</cstring> + </property> + <property name="text"> + <string>&End date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToDate</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>Start date</i> option. This option is used to define the end date.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox" row="2" column="0"> + <property name="name"> + <cstring>mColors</cstring> + </property> + <property name="text"> + <string>&Use colors</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to use colors to distinguish certain categories on the print, check this option.</string> + </property> + </widget> + <spacer row="3" column="0"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>201</height> + </size> + </property> + </spacer> + </grid> +</widget> +<tabstops> + <tabstop>mFromDate</tabstop> + <tabstop>mFromTime</tabstop> + <tabstop>mToDate</tabstop> + <tabstop>mToTime</tabstop> + <tabstop>mIncludeAllEvents</tabstop> + <tabstop>mIncludeTodos</tabstop> + <tabstop>mColors</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">kdateedit.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>libkdepim/kdateedit.h</includehint> + <includehint>libkdepim/kdateedit.h</includehint> +</includehints> +</UI> diff --git a/korganizer/printing/calprintdefaultplugins.cpp b/korganizer/printing/calprintdefaultplugins.cpp new file mode 100644 index 000000000..d12df1e26 --- /dev/null +++ b/korganizer/printing/calprintdefaultplugins.cpp @@ -0,0 +1,1186 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2003 Reinhold Kainhofer <reinhold@kainhofer.com> + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef KORG_NOPRINTER + +#include <qpainter.h> +#include <qdatetimeedit.h> +#include <qcheckbox.h> +#include <qlineedit.h> +#include <qbuttongroup.h> + +#include <kdebug.h> +#include <kconfig.h> +#include <kcalendarsystem.h> +#include <knuminput.h> +#include <kcombobox.h> + +#include "calprintdefaultplugins.h" + +#include "calprintincidenceconfig_base.h" +#include "calprintdayconfig_base.h" +#include "calprintweekconfig_base.h" +#include "calprintmonthconfig_base.h" +#include "calprinttodoconfig_base.h" + + +/************************************************************** + * Print Incidence + **************************************************************/ + +CalPrintIncidence::CalPrintIncidence() : CalPrintPluginBase() +{ +} + +CalPrintIncidence::~CalPrintIncidence() +{ +} + +QWidget *CalPrintIncidence::createConfigWidget( QWidget *w ) +{ + return new CalPrintIncidenceConfig_Base( w ); +} + +void CalPrintIncidence::readSettingsWidget() +{ + CalPrintIncidenceConfig_Base *cfg = + dynamic_cast<CalPrintIncidenceConfig_Base*>( mConfigWidget ); + if ( cfg ) { + mUseColors = cfg->mColors->isChecked(); + mShowOptions = cfg->mShowDetails->isChecked(); + mShowSubitemsNotes = cfg->mShowSubitemsNotes->isChecked(); + mShowAttendees = cfg->mShowAttendees->isChecked(); + mShowAttachments = cfg->mShowAttachments->isChecked(); + } +} + +void CalPrintIncidence::setSettingsWidget() +{ + CalPrintIncidenceConfig_Base *cfg = + dynamic_cast<CalPrintIncidenceConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mColors->setChecked( mUseColors ); + cfg->mShowDetails->setChecked(mShowOptions); + cfg->mShowSubitemsNotes->setChecked(mShowSubitemsNotes); + cfg->mShowAttendees->setChecked(mShowAttendees); + cfg->mShowAttachments->setChecked(mShowAttachments); + } +} + +void CalPrintIncidence::loadConfig() +{ + if ( mConfig ) { + mUseColors = mConfig->readBoolEntry( "Use Colors", false ); + mShowOptions = mConfig->readBoolEntry( "Show Options", false ); + mShowSubitemsNotes = mConfig->readBoolEntry( "Show Subitems and Notes", false ); + mShowAttendees = mConfig->readBoolEntry( "Use Attendees", false ); + mShowAttachments = mConfig->readBoolEntry( "Use Attachments", false ); + } + setSettingsWidget(); +} + +void CalPrintIncidence::saveConfig() +{ + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "Use Colors", mUseColors ); + mConfig->writeEntry( "Show Options", mShowOptions ); + mConfig->writeEntry( "Show Subitems and Notes", mShowSubitemsNotes ); + mConfig->writeEntry( "Use Attendees", mShowAttendees ); + mConfig->writeEntry( "Use Attachments", mShowAttachments ); + } +} + + +class TimePrintStringsVisitor : public IncidenceBase::Visitor +{ + public: + TimePrintStringsVisitor() {} + + bool act( IncidenceBase *incidence ) + { + return incidence->accept( *this ); + } + QString mStartCaption, mStartString; + QString mEndCaption, mEndString; + QString mDurationCaption, mDurationString; + + protected: + bool visit( Event *event ) { + if ( event->dtStart().isValid() ) { + mStartCaption = i18n("Start date: "); + // Show date/time or only date, depending on whether it's an all-day event +// TODO: Add shortfmt param to dtStartStr, dtEndStr and dtDueStr!!! + mStartString = (event->doesFloat()) ? (event->dtStartDateStr(false)) : (event->dtStartStr()); + } else { + mStartCaption = i18n("No start date"); + mStartString = QString::null; + } + + if ( event->hasEndDate() ) { + mEndCaption = i18n("End date: "); + mEndString = (event->doesFloat()) ? (event->dtEndDateStr(false)) : (event->dtEndStr()); + } else if ( event->hasDuration() ) { + mEndCaption = i18n("Duration: "); + int mins = event->duration() / 60; + if ( mins >= 60 ) { + mEndString += i18n( "1 hour ", "%n hours ", mins/60 ); + } + if ( mins%60 > 0 ) { + mEndString += i18n( "1 minute ", "%n minutes ", mins%60 ); + } + } else { + mEndCaption = i18n("No end date"); + mEndString = QString::null; + } + return true; + } + bool visit( Todo *todo ) { + if ( todo->hasStartDate() ) { + mStartCaption = i18n("Start date: "); + // Show date/time or only date, depending on whether it's an all-day event +// TODO: Add shortfmt param to dtStartStr, dtEndStr and dtDueStr!!! + mStartString = (todo->doesFloat()) ? (todo->dtStartDateStr(false)) : (todo->dtStartStr()); + } else { + mStartCaption = i18n("No start date"); + mStartString = QString::null; + } + + if ( todo->hasDueDate() ) { + mEndCaption = i18n("Due date: "); + mEndString = (todo->doesFloat()) ? (todo->dtDueDateStr(false)) : (todo->dtDueStr()); + } else { + mEndCaption = i18n("No due date"); + mEndString = QString::null; + } + return true; + } + bool visit( Journal *journal ) { + mStartCaption = i18n("Start date: "); +// TODO: Add shortfmt param to dtStartStr, dtEndStr and dtDueStr!!! + mStartString = (journal->doesFloat()) ? (journal->dtStartDateStr(false)) : (journal->dtStartStr()); + mEndCaption = QString::null; + mEndString = QString::null; + return true; + } +}; + +int CalPrintIncidence::printCaptionAndText( QPainter &p, const QRect &box, const QString &caption, const QString &text, QFont captionFont, QFont textFont ) +{ + QFontMetrics captionFM( captionFont ); + int textWd = captionFM.width( caption ); + QRect textRect( box ); + + QFont oldFont( p.font() ); + p.setFont( captionFont ); + p.drawText( box, Qt::AlignLeft|Qt::AlignTop|Qt::SingleLine, caption ); + + if ( !text.isEmpty() ) { + textRect.setLeft( textRect.left() + textWd ); + p.setFont( textFont ); + p.drawText( textRect, Qt::AlignLeft|Qt::AlignTop|Qt::SingleLine, text ); + } + p.setFont( oldFont ); + return textRect.bottom(); +} + +#include <qfontdatabase.h> +void CalPrintIncidence::print( QPainter &p, int width, int height ) +{ + KLocale *local = KGlobal::locale(); + + QFont oldFont(p.font()); + QFont textFont( "sans-serif", 11, QFont::Normal ); + QFont captionFont( "sans-serif", 11, QFont::Bold ); + p.setFont( textFont ); + int lineHeight = p.fontMetrics().lineSpacing(); + QString cap, txt; + + + Incidence::List::ConstIterator it; + for ( it=mSelectedIncidences.begin(); it!=mSelectedIncidences.end(); ++it ) { + // don't do anything on a 0-pointer! + if ( !(*it) ) continue; + if ( it != mSelectedIncidences.begin() ) mPrinter->newPage(); + + + // PAGE Layout (same for landscape and portrait! astonishingly, it looks good with both!): + // +-----------------------------------+ + // | Header: Summary | + // +===================================+ + // | start: ______ end: _________ | + // | repeats: ___________________ | + // | reminder: __________________ | + // +-----------------------------------+ + // | Location: ______________________ | + // +------------------------+----------+ + // | Description: | Notes or | + // | | Subitems | + // | | | + // | | | + // | | | + // | | | + // | | | + // | | | + // | | | + // | | | + // +------------------------+----------+ + // | Attachments: | Settings | + // | | | + // +------------------------+----------+ + // | Attendees: | + // | | + // +-----------------------------------+ + // | Categories: _____________________ | + // +-----------------------------------+ + + QRect box( 0, 0, width, height ); + QRect titleBox( box ); + titleBox.setHeight( headerHeight() ); + // Draw summary as header, no small calendars in title bar, expand height if needed + int titleBottom = drawHeader( p, (*it)->summary(), QDate(), QDate(), titleBox, true ); + titleBox.setBottom( titleBottom ); + + QRect timesBox( titleBox ); + timesBox.setTop( titleBox.bottom() + padding() ); + timesBox.setHeight( height / 8 ); + + TimePrintStringsVisitor stringVis; + int h = timesBox.top(); + if ( stringVis.act(*it) ) { + QRect textRect( timesBox.left()+padding(), timesBox.top()+padding(), 0, lineHeight ); + textRect.setRight( timesBox.center().x() ); + h = printCaptionAndText( p, textRect, stringVis.mStartCaption, stringVis.mStartString, captionFont, textFont ); + + textRect.setLeft( textRect.right() ); + textRect.setRight( timesBox.right() - padding() ); + h = QMAX( printCaptionAndText( p, textRect, stringVis.mEndCaption, stringVis.mEndString, captionFont, textFont ), h ); + } + + + if ( (*it)->doesRecur() ) { + QRect recurBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight ); + // TODO: Convert the recurrence to a string and print it out! + QString recurString( "TODO: Convert Repeat to String!" ); + h = QMAX( printCaptionAndText( p, recurBox, i18n("Repeats: "), recurString, captionFont, textFont ), h ); + } + + QRect alarmBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight ); + Alarm::List alarms = (*it)->alarms(); + if ( alarms.count() == 0 ) { + cap = i18n("No reminders"); + txt = QString::null; + } else { + cap = i18n("Reminder: ", "%n reminders: ", alarms.count() ); + + QStringList alarmStrings; + KCal::Alarm::List::ConstIterator it; + for ( it = alarms.begin(); it != alarms.end(); ++it ) { + Alarm *alarm = *it; + + // Alarm offset, copied from koeditoralarms.cpp: + QString offsetstr; + int offset = 0; + if ( alarm->hasStartOffset() ) { + offset = alarm->startOffset().asSeconds(); + if ( offset < 0 ) { + offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 before the start"); + offset = -offset; + } else { + offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 after the start"); + } + } else if ( alarm->hasEndOffset() ) { + offset = alarm->endOffset().asSeconds(); + if ( offset < 0 ) { + offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 before the end"); + offset = -offset; + } else { + offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 after the end"); + } + } + + offset = offset / 60; // make minutes + int useoffset = offset; + + if ( offset % (24*60) == 0 && offset>0 ) { // divides evenly into days? + useoffset = offset / (24*60); + offsetstr = offsetstr.arg( i18n("1 day", "%n days", useoffset ) ); + } else if (offset % 60 == 0 && offset>0 ) { // divides evenly into hours? + useoffset = offset / 60; + offsetstr = offsetstr.arg( i18n("1 hour", "%n hours", useoffset ) ); + } else { + useoffset = offset; + offsetstr = offsetstr.arg( i18n("1 minute", "%n minutes", useoffset ) ); + } + alarmStrings << offsetstr; + } + txt = alarmStrings.join( i18n("Spacer for the joined list of categories", ", ") ); + + } + h = QMAX( printCaptionAndText( p, alarmBox, cap, txt, captionFont, textFont ), h ); + + + QRect organizerBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight ); + h = QMAX( printCaptionAndText( p, organizerBox, i18n("Organizer: "), (*it)->organizer().fullName(), captionFont, textFont ), h ); + + // Finally, draw the frame around the time information... + timesBox.setBottom( QMAX( timesBox.bottom(), h+padding() ) ); + drawBox( p, BOX_BORDER_WIDTH, timesBox ); + + + QRect locationBox( timesBox ); + locationBox.setTop( timesBox.bottom() + padding() ); + locationBox.setHeight( 0 ); + int locationBottom = drawBoxWithCaption( p, locationBox, i18n("Location: "), + (*it)->location(), /*sameLine=*/true, /*expand=*/true, captionFont, textFont ); + locationBox.setBottom( locationBottom ); + + + // Now start constructing the boxes from the bottom: + QRect categoriesBox( locationBox ); + categoriesBox.setBottom( box.bottom() ); + categoriesBox.setTop( categoriesBox.bottom() - lineHeight - 2*padding() ); + + + QRect attendeesBox( box.left(), categoriesBox.top()-padding()-box.height()/9, box.width(), box.height()/9 ); + if ( !mShowAttendees ) { + attendeesBox.setTop( categoriesBox.top() ); + } + QRect attachmentsBox( box.left(), attendeesBox.top()-padding()-box.height()/9, box.width()*3/4 - padding(), box.height()/9 ); + QRect optionsBox( attachmentsBox.right() + padding(), attachmentsBox.top(), 0, 0 ); + optionsBox.setRight( box.right() ); + optionsBox.setBottom( attachmentsBox.bottom() ); + QRect notesBox( optionsBox.left(), locationBox.bottom() + padding(), optionsBox.width(), 0 ); + notesBox.setBottom( optionsBox.top() - padding() ); + + // TODO: Adjust boxes depending on the show options... +// if ( !mShowOptions ) { +// optionsBox.left() +// bool mShowOptions; +// // bool mShowSubitemsNotes; +// bool mShowAttendees; +// bool mShowAttachments; + + + QRect descriptionBox( notesBox ); + descriptionBox.setLeft( box.left() ); + descriptionBox.setRight( mShowOptions?(attachmentsBox.right()):(box.right()) ); + + drawBoxWithCaption( p, descriptionBox, i18n("Description:"), + (*it)->description(), /*sameLine=*/false, + /*expand=*/false, captionFont, textFont ); + + if ( mShowSubitemsNotes ) { + if ( (*it)->relations().isEmpty() || (*it)->type() != "Todo" ) { + int notesPosition = drawBoxWithCaption( p, notesBox, i18n("Notes:"), + QString::null, /*sameLine=*/false, /*expand=*/false, + captionFont, textFont ); + QPen oldPen( p.pen() ); + p.setPen( Qt::DotLine ); + while ( (notesPosition += int(1.5*lineHeight)) < notesBox.bottom() ) { + p.drawLine( notesBox.left()+padding(), notesPosition, notesBox.right()-padding(), notesPosition ); + } + p.setPen( oldPen ); + } else { + int subitemsStart = drawBoxWithCaption( p, notesBox, i18n("Subitems:"), + (*it)->description(), /*sameLine=*/false, + /*expand=*/false, captionFont, textFont ); + // TODO: Draw subitems + } + } + + if ( mShowAttachments ) { + int attachStart = drawBoxWithCaption( p, attachmentsBox, + i18n("Attachments:"), QString::null, /*sameLine=*/false, + /*expand=*/false, captionFont, textFont ); + // TODO: Print out the attachments somehow + } + + if ( mShowAttendees ) { + Attendee::List attendees = (*it)->attendees(); + QString attendeeCaption; + if ( attendees.count() == 0 ) + attendeeCaption = i18n("No Attendees"); + else + attendeeCaption = i18n("1 Attendee:", "%n Attendees:", attendees.count() ); + QString attendeeString; + for ( Attendee::List::ConstIterator ait = attendees.begin(); ait != attendees.end(); ++ait ) { + if ( !attendeeString.isEmpty() ) attendeeString += "\n"; + attendeeString += i18n("Formatting of an attendee: " + "'Name (Role): Status', e.g. 'Reinhold Kainhofer " + "<reinhold@kainhofer.com> (Participant): Awaiting Response'", + "%1 (%2): %3") + .arg( (*ait)->fullName() ) + .arg( (*ait)->roleStr() ).arg( (*ait)->statusStr() ); + } + drawBoxWithCaption( p, attendeesBox, i18n("Attendees:"), attendeeString, + /*sameLine=*/false, /*expand=*/false, captionFont, textFont ); + } + + if ( mShowOptions ) { + QString optionsString; + if ( !(*it)->statusStr().isEmpty() ) { + optionsString += i18n("Status: %1").arg( (*it)->statusStr() ); + optionsString += "\n"; + } + if ( !(*it)->secrecyStr().isEmpty() ) { + optionsString += i18n("Secrecy: %1").arg( (*it)->secrecyStr() ); + optionsString += "\n"; + } + if ( (*it)->type() == "Event" ) { + Event *e = static_cast<Event*>(*it); + if ( e->transparency() == Event::Opaque ) { + optionsString += i18n("Show as: Busy"); + } else { + optionsString += i18n("Show as: Free"); + } + optionsString += "\n"; + } else if ( (*it)->type() == "Todo" ) { + Todo *t = static_cast<Todo*>(*it); + if ( t->isOverdue() ) { + optionsString += i18n("This task is overdue!"); + optionsString += "\n"; + } + } else if ( (*it)->type() == "Journal" ) { + //TODO: Anything Journal-specific? + } + drawBoxWithCaption( p, optionsBox, i18n("Settings: "), + optionsString, /*sameLine=*/false, /*expand=*/false, captionFont, textFont ); + } + + drawBoxWithCaption( p, categoriesBox, i18n("Categories: "), + (*it)->categories().join( i18n("Spacer for the joined list of categories", ", ") ), + /*sameLine=*/true, /*expand=*/false, captionFont, textFont ); + } + p.setFont( oldFont ); +} + +/************************************************************** + * Print Day + **************************************************************/ + +CalPrintDay::CalPrintDay() : CalPrintPluginBase() +{ +} + +CalPrintDay::~CalPrintDay() +{ +} + +QWidget *CalPrintDay::createConfigWidget( QWidget *w ) +{ + return new CalPrintDayConfig_Base( w ); +} + +void CalPrintDay::readSettingsWidget() +{ + CalPrintDayConfig_Base *cfg = + dynamic_cast<CalPrintDayConfig_Base*>( mConfigWidget ); + if ( cfg ) { + mFromDate = cfg->mFromDate->date(); + mToDate = cfg->mToDate->date(); + + mStartTime = cfg->mFromTime->time(); + mEndTime = cfg->mToTime->time(); + mIncludeAllEvents = cfg->mIncludeAllEvents->isChecked(); + + mIncludeTodos = cfg->mIncludeTodos->isChecked(); + mUseColors = cfg->mColors->isChecked(); + } +} + +void CalPrintDay::setSettingsWidget() +{ + CalPrintDayConfig_Base *cfg = + dynamic_cast<CalPrintDayConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( mFromDate ); + cfg->mToDate->setDate( mToDate ); + + cfg->mFromTime->setTime( mStartTime ); + cfg->mToTime->setTime( mEndTime ); + cfg->mIncludeAllEvents->setChecked( mIncludeAllEvents ); + + cfg->mIncludeTodos->setChecked( mIncludeTodos ); + cfg->mColors->setChecked( mUseColors ); + } +} + +void CalPrintDay::loadConfig() +{ + if ( mConfig ) { + QDate dt; + QTime tm1( dayStart() ); + QDateTime startTm( dt, tm1 ); + QDateTime endTm( dt, tm1.addSecs( 12 * 60 * 60 ) ); + mStartTime = mConfig->readDateTimeEntry( "Start time", &startTm ).time(); + mEndTime = mConfig->readDateTimeEntry( "End time", &endTm ).time(); + mIncludeTodos = mConfig->readBoolEntry( "Include todos", false ); + mIncludeAllEvents = mConfig->readBoolEntry( "Include all events", false ); + } + setSettingsWidget(); +} + +void CalPrintDay::saveConfig() +{ + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "Start time", QDateTime( QDate(), mStartTime ) ); + mConfig->writeEntry( "End time", QDateTime( QDate(), mEndTime ) ); + mConfig->writeEntry( "Include todos", mIncludeTodos ); + mConfig->writeEntry( "Include all events", mIncludeAllEvents ); + } +} + +void CalPrintDay::setDateRange( const QDate& from, const QDate& to ) +{ + CalPrintPluginBase::setDateRange( from, to ); + CalPrintDayConfig_Base *cfg = + dynamic_cast<CalPrintDayConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( from ); + cfg->mToDate->setDate( to ); + } +} + +void CalPrintDay::print( QPainter &p, int width, int height ) +{ + QDate curDay( mFromDate ); + + do { + QTime curStartTime( mStartTime ); + QTime curEndTime( mEndTime ); + + // For an invalid time range, simply show one hour, starting at the hour + // before the given start time + if ( curEndTime <= curStartTime ) { + curStartTime = QTime( curStartTime.hour(), 0, 0 ); + curEndTime = curStartTime.addSecs( 3600 ); + } + + KLocale *local = KGlobal::locale(); + QRect headerBox( 0, 0, width, headerHeight() ); + drawHeader( p, local->formatDate( curDay ), curDay, QDate(), headerBox ); + + + Event::List eventList = mCalendar->events( curDay, + EventSortStartDate, + SortDirectionAscending ); + + p.setFont( QFont( "sans-serif", 12 ) ); + + // TODO: Find a good way to determine the height of the all-day box + QRect allDayBox( TIMELINE_WIDTH + padding(), headerBox.bottom() + padding(), + 0, height / 20 ); + allDayBox.setRight( width ); + int allDayHeight = drawAllDayBox( p, eventList, curDay, true, allDayBox ); + + QRect dayBox( allDayBox ); + dayBox.setTop( allDayHeight /*allDayBox.bottom()*/ ); + dayBox.setBottom( height ); + drawAgendaDayBox( p, eventList, curDay, mIncludeAllEvents, + curStartTime, curEndTime, dayBox ); + + QRect tlBox( dayBox ); + tlBox.setLeft( 0 ); + tlBox.setWidth( TIMELINE_WIDTH ); + drawTimeLine( p, curStartTime, curEndTime, tlBox ); + curDay = curDay.addDays( 1 ); + if ( curDay <= mToDate ) mPrinter->newPage(); + } while ( curDay <= mToDate ); +} + + + +/************************************************************** + * Print Week + **************************************************************/ + +CalPrintWeek::CalPrintWeek() : CalPrintPluginBase() +{ +} + +CalPrintWeek::~CalPrintWeek() +{ +} + +QWidget *CalPrintWeek::createConfigWidget( QWidget *w ) +{ + return new CalPrintWeekConfig_Base( w ); +} + +void CalPrintWeek::readSettingsWidget() +{ + CalPrintWeekConfig_Base *cfg = + dynamic_cast<CalPrintWeekConfig_Base*>( mConfigWidget ); + if ( cfg ) { + mFromDate = cfg->mFromDate->date(); + mToDate = cfg->mToDate->date(); + + mWeekPrintType = (eWeekPrintType)( cfg->mPrintType->id( + cfg->mPrintType->selected() ) ); + + mStartTime = cfg->mFromTime->time(); + mEndTime = cfg->mToTime->time(); + + mIncludeTodos = cfg->mIncludeTodos->isChecked(); + mUseColors = cfg->mColors->isChecked(); + } +} + +void CalPrintWeek::setSettingsWidget() +{ + CalPrintWeekConfig_Base *cfg = + dynamic_cast<CalPrintWeekConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( mFromDate ); + cfg->mToDate->setDate( mToDate ); + + cfg->mPrintType->setButton( mWeekPrintType ); + + cfg->mFromTime->setTime( mStartTime ); + cfg->mToTime->setTime( mEndTime ); + + cfg->mIncludeTodos->setChecked( mIncludeTodos ); + cfg->mColors->setChecked( mUseColors ); + } +} + +void CalPrintWeek::loadConfig() +{ + if ( mConfig ) { + QDate dt; + QTime tm1( dayStart() ); + QDateTime startTm( dt, tm1 ); + QDateTime endTm( dt, tm1.addSecs( 43200 ) ); + mStartTime = mConfig->readDateTimeEntry( "Start time", &startTm ).time(); + mEndTime = mConfig->readDateTimeEntry( "End time", &endTm ).time(); + mIncludeTodos = mConfig->readBoolEntry( "Include todos", false ); + mWeekPrintType =(eWeekPrintType)( mConfig->readNumEntry( "Print type", (int)Filofax ) ); + } + setSettingsWidget(); +} + +void CalPrintWeek::saveConfig() +{ + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "Start time", QDateTime( QDate(), mStartTime ) ); + mConfig->writeEntry( "End time", QDateTime( QDate(), mEndTime ) ); + mConfig->writeEntry( "Include todos", mIncludeTodos ); + mConfig->writeEntry( "Print type", int( mWeekPrintType ) ); + } +} + +KPrinter::Orientation CalPrintWeek::defaultOrientation() +{ + if ( mWeekPrintType == Filofax ) return KPrinter::Portrait; + else if ( mWeekPrintType == SplitWeek ) return KPrinter::Portrait; + else return KPrinter::Landscape; +} + +void CalPrintWeek::setDateRange( const QDate &from, const QDate &to ) +{ + CalPrintPluginBase::setDateRange( from, to ); + CalPrintWeekConfig_Base *cfg = + dynamic_cast<CalPrintWeekConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( from ); + cfg->mToDate->setDate( to ); + } +} + +void CalPrintWeek::print( QPainter &p, int width, int height ) +{ + QDate curWeek, fromWeek, toWeek; + + // correct begin and end to first and last day of week + int weekdayCol = weekdayColumn( mFromDate.dayOfWeek() ); + fromWeek = mFromDate.addDays( -weekdayCol ); + weekdayCol = weekdayColumn( mFromDate.dayOfWeek() ); + toWeek = mToDate.addDays( 6 - weekdayCol ); + + curWeek = fromWeek.addDays( 6 ); + KLocale *local = KGlobal::locale(); + + QString line1, line2, title; + QRect headerBox( 0, 0, width, headerHeight() ); + QRect weekBox( headerBox ); + weekBox.setTop( headerBox.bottom() + padding() ); + weekBox.setBottom( height ); + + switch ( mWeekPrintType ) { + case Filofax: + do { + line1 = local->formatDate( curWeek.addDays( -6 ) ); + line2 = local->formatDate( curWeek ); + if ( orientation() == KPrinter::Landscape ) { + title = i18n("date from-to", "%1 - %2"); + } else { + title = i18n("date from-\nto", "%1 -\n%2");; + } + title = title.arg( line1 ).arg( line2 ); + drawHeader( p, title, curWeek.addDays( -6 ), QDate(), headerBox ); + drawWeek( p, curWeek, weekBox ); + curWeek = curWeek.addDays( 7 ); + if ( curWeek <= toWeek ) + mPrinter->newPage(); + } while ( curWeek <= toWeek ); + break; + + case Timetable: + default: + do { + line1 = local->formatDate( curWeek.addDays( -6 ) ); + line2 = local->formatDate( curWeek ); + if ( orientation() == KPrinter::Landscape ) { + title = i18n("date from - to (week number)", "%1 - %2 (Week %3)"); + } else { + title = i18n("date from -\nto (week number)", "%1 -\n%2 (Week %3)"); + } + title = title.arg( line1 ).arg( line2 ).arg( curWeek.weekNumber() ); + drawHeader( p, title, curWeek, QDate(), headerBox ); + QRect weekBox( headerBox ); + weekBox.setTop( headerBox.bottom() + padding() ); + weekBox.setBottom( height ); + + drawTimeTable( p, fromWeek, curWeek, mStartTime, mEndTime, weekBox ); + fromWeek = fromWeek.addDays( 7 ); + curWeek = fromWeek.addDays( 6 ); + if ( curWeek <= toWeek ) + mPrinter->newPage(); + } while ( curWeek <= toWeek ); + break; + + case SplitWeek: { + QRect weekBox1( weekBox ); + // On the left side there are four days (mo-th) plus the timeline, + // on the right there are only three days (fr-su) plus the timeline. Don't + // use the whole width, but rather give them the same width as on the left. + weekBox1.setRight( int( ( width - TIMELINE_WIDTH ) * 3. / 4. + TIMELINE_WIDTH ) ); + do { + QDate endLeft( fromWeek.addDays( 3 ) ); + int hh = headerHeight(); + + drawTimeTable( p, fromWeek, endLeft, + mStartTime, mEndTime, weekBox ); + mPrinter->newPage(); + drawSplitHeaderRight( p, fromWeek, curWeek, QDate(), width, hh ); + drawTimeTable( p, endLeft.addDays( 1 ), curWeek, + mStartTime, mEndTime, weekBox1 ); + + fromWeek = fromWeek.addDays( 7 ); + curWeek = fromWeek.addDays( 6 ); + if ( curWeek <= toWeek ) + mPrinter->newPage(); + } while ( curWeek <= toWeek ); + } + break; + } +} + + + + +/************************************************************** + * Print Month + **************************************************************/ + +CalPrintMonth::CalPrintMonth() : CalPrintPluginBase() +{ +} + +CalPrintMonth::~CalPrintMonth() +{ +} + +QWidget *CalPrintMonth::createConfigWidget( QWidget *w ) +{ + return new CalPrintMonthConfig_Base( w ); +} + +void CalPrintMonth::readSettingsWidget() +{ + CalPrintMonthConfig_Base *cfg = + dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget ); + if ( cfg ) { + mFromDate = QDate( cfg->mFromYear->value(), cfg->mFromMonth->currentItem()+1, 1 ); + mToDate = QDate( cfg->mToYear->value(), cfg->mToMonth->currentItem()+1, 1 ); + + mWeekNumbers = cfg->mWeekNumbers->isChecked(); + mRecurDaily = cfg->mRecurDaily->isChecked(); + mRecurWeekly = cfg->mRecurWeekly->isChecked(); + mIncludeTodos = cfg->mIncludeTodos->isChecked(); +// mUseColors = cfg->mColors->isChecked(); + } +} + +void CalPrintMonth::setSettingsWidget() +{ + CalPrintMonthConfig_Base *cfg = + dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget ); + setDateRange( mFromDate, mToDate ); + if ( cfg ) { + cfg->mWeekNumbers->setChecked( mWeekNumbers ); + cfg->mRecurDaily->setChecked( mRecurDaily ); + cfg->mRecurWeekly->setChecked( mRecurWeekly ); + cfg->mIncludeTodos->setChecked( mIncludeTodos ); +// cfg->mColors->setChecked( mUseColors ); + } +} + +void CalPrintMonth::loadConfig() +{ + if ( mConfig ) { + mWeekNumbers = mConfig->readBoolEntry( "Print week numbers", true ); + mRecurDaily = mConfig->readBoolEntry( "Print daily incidences", true ); + mRecurWeekly = mConfig->readBoolEntry( "Print weekly incidences", true ); + mIncludeTodos = mConfig->readBoolEntry( "Include todos", false ); + } + setSettingsWidget(); +} + +void CalPrintMonth::saveConfig() +{ + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "Print week numbers", mWeekNumbers ); + mConfig->writeEntry( "Print daily incidences", mRecurDaily ); + mConfig->writeEntry( "Print weekly incidences", mRecurWeekly ); + mConfig->writeEntry( "Include todos", mIncludeTodos ); + } +} + +void CalPrintMonth::setDateRange( const QDate &from, const QDate &to ) +{ + CalPrintPluginBase::setDateRange( from, to ); + CalPrintMonthConfig_Base *cfg = + dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget ); + const KCalendarSystem *calSys = calendarSystem(); + if ( cfg && calSys ) { + cfg->mFromMonth->clear(); + for ( int i=0; i<calSys->monthsInYear( mFromDate ); ++i ) { + cfg->mFromMonth->insertItem( calSys->monthName( i+1, mFromDate.year() ) ); + } + cfg->mToMonth->clear(); + for ( int i=0; i<calSys->monthsInYear( mToDate ); ++i ) { + cfg->mToMonth->insertItem( calSys->monthName( i+1, mToDate.year() ) ); + } + } + if ( cfg ) { + cfg->mFromMonth->setCurrentItem( from.month()-1 ); + cfg->mFromYear->setValue( to.year() ); + cfg->mToMonth->setCurrentItem( mToDate.month()-1 ); + cfg->mToYear->setValue( mToDate.year() ); + } +} + +void CalPrintMonth::print( QPainter &p, int width, int height ) +{ + QDate curMonth, fromMonth, toMonth; + + fromMonth = mFromDate.addDays( -( mFromDate.day() - 1 ) ); + toMonth = mToDate.addDays( mToDate.daysInMonth() - mToDate.day() ); + + curMonth = fromMonth; + const KCalendarSystem *calSys = calendarSystem(); + if ( !calSys ) return; + + QRect headerBox( 0, 0, width, headerHeight() ); + QRect monthBox( 0, 0, width, height ); + monthBox.setTop( headerBox.bottom() + padding() ); + + do { + QString title( i18n("monthname year", "%1 %2") ); + title = title.arg( calSys->monthName( curMonth ) ) + .arg( curMonth.year() ); + QDate tmp( fromMonth ); + int weekdayCol = weekdayColumn( tmp.dayOfWeek() ); + tmp = tmp.addDays( -weekdayCol ); + + drawHeader( p, title, curMonth.addMonths( -1 ), curMonth.addMonths( 1 ), + headerBox ); + drawMonthTable( p, curMonth, mWeekNumbers, mRecurDaily, mRecurWeekly, monthBox ); + curMonth = curMonth.addDays( curMonth.daysInMonth() ); + if ( curMonth <= toMonth ) mPrinter->newPage(); + } while ( curMonth <= toMonth ); + +} + + + + +/************************************************************** + * Print Todos + **************************************************************/ + +CalPrintTodos::CalPrintTodos() : CalPrintPluginBase() +{ + mTodoSortField = TodoFieldUnset; + mTodoSortDirection = TodoDirectionUnset; +} + +CalPrintTodos::~CalPrintTodos() +{ +} + +QWidget *CalPrintTodos::createConfigWidget( QWidget *w ) +{ + return new CalPrintTodoConfig_Base( w ); +} + +void CalPrintTodos::readSettingsWidget() +{ + CalPrintTodoConfig_Base *cfg = + dynamic_cast<CalPrintTodoConfig_Base *>( mConfigWidget ); + if ( cfg ) { + mPageTitle = cfg->mTitle->text(); + + mTodoPrintType = (eTodoPrintType)( cfg->mPrintType->id( + cfg->mPrintType->selected() ) ); + + mFromDate = cfg->mFromDate->date(); + mToDate = cfg->mToDate->date(); + + mIncludeDescription = cfg->mDescription->isChecked(); + mIncludePriority = cfg->mPriority->isChecked(); + mIncludeDueDate = cfg->mDueDate->isChecked(); + mIncludePercentComplete = cfg->mPercentComplete->isChecked(); + mConnectSubTodos = cfg->mConnectSubTodos->isChecked(); + mStrikeOutCompleted = cfg->mStrikeOutCompleted->isChecked(); + + mTodoSortField = (eTodoSortField)cfg->mSortField->currentItem(); + mTodoSortDirection = (eTodoSortDirection)cfg->mSortDirection->currentItem(); + } +} + +void CalPrintTodos::setSettingsWidget() +{ +// kdDebug(5850) << "CalPrintTodos::setSettingsWidget" << endl; + + CalPrintTodoConfig_Base *cfg = + dynamic_cast<CalPrintTodoConfig_Base *>( mConfigWidget ); + if ( cfg ) { + cfg->mTitle->setText( mPageTitle ); + + cfg->mPrintType->setButton( mTodoPrintType ); + + cfg->mFromDate->setDate( mFromDate ); + cfg->mToDate->setDate( mToDate ); + + cfg->mDescription->setChecked( mIncludeDescription ); + cfg->mPriority->setChecked( mIncludePriority ); + cfg->mDueDate->setChecked( mIncludeDueDate ); + cfg->mPercentComplete->setChecked( mIncludePercentComplete ); + cfg->mConnectSubTodos->setChecked( mConnectSubTodos ); + cfg->mStrikeOutCompleted->setChecked( mStrikeOutCompleted ); + + if ( mTodoSortField != TodoFieldUnset ) { + // do not insert if already done so. + cfg->mSortField->insertItem( i18n("Summary") ); + cfg->mSortField->insertItem( i18n("Start Date") ); + cfg->mSortField->insertItem( i18n("Due Date") ); + cfg->mSortField->insertItem( i18n("Priority") ); + cfg->mSortField->insertItem( i18n("Percent Complete") ); + cfg->mSortField->setCurrentItem( (int)mTodoSortField ); + } + + if ( mTodoSortDirection != TodoDirectionUnset ) { + // do not insert if already done so. + cfg->mSortDirection->insertItem( i18n("Ascending") ); + cfg->mSortDirection->insertItem( i18n("Descending") ); + cfg->mSortDirection->setCurrentItem( (int)mTodoSortDirection ); + } + } +} + +void CalPrintTodos::loadConfig() +{ + if ( mConfig ) { + mPageTitle = mConfig->readEntry( "Page title", i18n("To-do list") ); + mTodoPrintType = (eTodoPrintType)mConfig->readNumEntry( "Print type", (int)TodosAll ); + mIncludeDescription = mConfig->readBoolEntry( "Include description", true ); + mIncludePriority = mConfig->readBoolEntry( "Include priority", true ); + mIncludeDueDate = mConfig->readBoolEntry( "Include due date", true ); + mIncludePercentComplete = mConfig->readBoolEntry( "Include percentage completed", true ); + mConnectSubTodos = mConfig->readBoolEntry( "Connect subtodos", true ); + mStrikeOutCompleted = mConfig->readBoolEntry( "Strike out completed summaries", true ); + mTodoSortField = (eTodoSortField)mConfig->readNumEntry( "Sort field", (int)TodoFieldSummary ); + mTodoSortDirection = (eTodoSortDirection)mConfig->readNumEntry( "Sort direction", (int)TodoDirectionAscending ); + } + setSettingsWidget(); +} + +void CalPrintTodos::saveConfig() +{ + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "Page title", mPageTitle ); + mConfig->writeEntry( "Print type", int( mTodoPrintType ) ); + mConfig->writeEntry( "Include description", mIncludeDescription ); + mConfig->writeEntry( "Include priority", mIncludePriority ); + mConfig->writeEntry( "Include due date", mIncludeDueDate ); + mConfig->writeEntry( "Include percentage completed", mIncludePercentComplete ); + mConfig->writeEntry( "Connect subtodos", mConnectSubTodos ); + mConfig->writeEntry( "Strike out completed summaries", mStrikeOutCompleted ); + mConfig->writeEntry( "Sort field", mTodoSortField ); + mConfig->writeEntry( "Sort direction", mTodoSortDirection ); + } +} + +void CalPrintTodos::print( QPainter &p, int width, int height ) +{ + // TODO: Find a good way to guarantee a nicely designed output + int pospriority = 10; + int possummary = 60; + int posdue = width - 65; + int poscomplete = posdue - 70; //Complete column is to right of the Due column + int lineSpacing = 15; + int fontHeight = 10; + + // Draw the First Page Header + drawHeader( p, mPageTitle, mFromDate, QDate(), + QRect( 0, 0, width, headerHeight() ) ); + + // Draw the Column Headers + int mCurrentLinePos = headerHeight() + 5; + QString outStr; + QFont oldFont( p.font() ); + + p.setFont( QFont( "sans-serif", 10, QFont::Bold ) ); + lineSpacing = p.fontMetrics().lineSpacing(); + mCurrentLinePos += lineSpacing; + if ( mIncludePriority ) { + outStr += i18n( "Priority" ); + p.drawText( pospriority, mCurrentLinePos - 2, outStr ); + } else { + possummary = 10; + pospriority = -1; + } + + outStr.truncate( 0 ); + outStr += i18n( "Summary" ); + p.drawText( possummary, mCurrentLinePos - 2, outStr ); + + if ( mIncludePercentComplete ) { + if ( !mIncludeDueDate ) //move Complete column to the right + poscomplete = posdue; //if not print the Due Date column + outStr.truncate( 0 ); + outStr += i18n( "Complete" ); + p.drawText( poscomplete, mCurrentLinePos - 2, outStr ); + } else { + poscomplete = -1; + } + + if ( mIncludeDueDate ) { + outStr.truncate( 0 ); + outStr += i18n( "Due" ); + p.drawText( posdue, mCurrentLinePos - 2, outStr ); + } else { + posdue = -1; + } + + p.setFont( QFont( "sans-serif", 10 ) ); + fontHeight = p.fontMetrics().height(); + + Todo::List todoList; + Todo::List tempList; + Todo::List::ConstIterator it; + + // Convert sort options to the corresponding enums + TodoSortField sortField = TodoSortSummary; + switch( mTodoSortField ) { + case TodoFieldSummary: + sortField = TodoSortSummary; break; + case TodoFieldStartDate: + sortField = TodoSortStartDate; break; + case TodoFieldDueDate: + sortField = TodoSortDueDate; break; + case TodoFieldPriority: + sortField = TodoSortPriority; break; + case TodoFieldPercentComplete: + sortField = TodoSortPercentComplete; break; + case TodoFieldUnset: + break; + } + + SortDirection sortDirection; + switch( mTodoSortDirection ) { + case TodoDirectionAscending: + sortDirection = SortDirectionAscending; break; + case TodoDirectionDescending: + sortDirection = SortDirectionDescending; break; + case TodoDirectionUnset: + break; + } + + // Create list of to-dos which will be printed + todoList = mCalendar->todos( sortField, sortDirection ); + switch( mTodoPrintType ) { + case TodosAll: + break; + case TodosUnfinished: + for( it = todoList.begin(); it!= todoList.end(); ++it ) { + if ( !(*it)->isCompleted() ) + tempList.append( *it ); + } + todoList = tempList; + break; + case TodosDueRange: + for( it = todoList.begin(); it!= todoList.end(); ++it ) { + if ( (*it)->hasDueDate() ) { + if ( (*it)->dtDue().date() >= mFromDate && + (*it)->dtDue().date() <= mToDate ) + tempList.append( *it ); + } else { + tempList.append( *it ); + } + } + todoList = tempList; + break; + } + + // Print to-dos + int count = 0; + for ( it=todoList.begin(); it!=todoList.end(); ++it ) { + Todo *currEvent = *it; + + // Skip sub-to-dos. They will be printed recursively in drawTodo() + if ( !currEvent->relatedTo() ) { + count++; + drawTodo( count, currEvent, p, + sortField, sortDirection, + mConnectSubTodos, + mStrikeOutCompleted, mIncludeDescription, + pospriority, possummary, posdue, poscomplete, + 0, 0, mCurrentLinePos, width, height, todoList ); + } + } + p.setFont( oldFont ); +} + + +#endif diff --git a/korganizer/printing/calprintdefaultplugins.h b/korganizer/printing/calprintdefaultplugins.h new file mode 100644 index 000000000..463312ff2 --- /dev/null +++ b/korganizer/printing/calprintdefaultplugins.h @@ -0,0 +1,209 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2003 Reinhold Kainhofer <reinhold@kainhofer.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef CALPRINTDEFAULTPLUGINS_H +#define CALPRINTDEFAULTPLUGINS_H + + +#include <klocale.h> +#include "calprintpluginbase.h" + +#ifndef KORG_NOPRINTER +namespace KCal { +class Calendar; +} + +using namespace KCal; +using namespace KOrg; + +class CalPrintIncidence : public CalPrintPluginBase +{ + public: + CalPrintIncidence(); + virtual ~CalPrintIncidence(); + virtual QString description() { return i18n("Print &incidence"); } + virtual QString info() { return i18n("Prints an incidence on one page"); } + virtual int sortID() { return CalPrinterBase::Incidence; } + // Enable the Print Incidence option only if there are selected incidences. + virtual bool enabled() + { + if ( mSelectedIncidences.count() > 0 ) { + return true; + } else { + return false; + } + } + virtual QWidget *createConfigWidget(QWidget*); + virtual KPrinter::Orientation defaultOrientation() + { return KPrinter::Portrait; } + + public: + void print( QPainter &p, int width, int height ); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + protected: + int printCaptionAndText( QPainter &p, const QRect &box, const QString &caption, + const QString &text, QFont captionFont, QFont textFont ); + + + protected: + bool mShowOptions; + bool mShowSubitemsNotes; + bool mShowAttendees; + bool mShowAttachments; +}; + + +class CalPrintDay : public CalPrintPluginBase +{ + public: + CalPrintDay(); + virtual ~CalPrintDay(); + virtual QString description() { return i18n("Print da&y"); } + virtual QString info() { return i18n("Prints all events of a single day on one page"); } + virtual int sortID() { return CalPrinterBase::Day; } + virtual bool enabled() { return true; } + virtual QWidget *createConfigWidget( QWidget* ); + + public: + void print(QPainter &p, int width, int height); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + virtual void setDateRange( const QDate& from, const QDate& to ); + + protected: + QTime mStartTime, mEndTime; + bool mIncludeTodos; + bool mIncludeAllEvents; +}; + +class CalPrintWeek : public CalPrintPluginBase +{ + public: + CalPrintWeek(); + virtual ~CalPrintWeek(); + virtual QString description() { return i18n("Print &week"); } + virtual QString info() { return i18n("Prints all events of one week on one page"); } + virtual int sortID() { return CalPrinterBase::Week; } + virtual bool enabled() { return true; } + virtual QWidget *createConfigWidget(QWidget*); + /** + Returns the default orientation for the eWeekPrintType. + */ + virtual KPrinter::Orientation defaultOrientation(); + + public: + void print(QPainter &p, int width, int height); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + virtual void setDateRange( const QDate& from, const QDate& to ); + + protected: + enum eWeekPrintType { Filofax=0, Timetable, SplitWeek } mWeekPrintType; + QTime mStartTime, mEndTime; + bool mIncludeTodos; +}; + +class CalPrintMonth : public CalPrintPluginBase +{ + public: + CalPrintMonth(); + virtual ~CalPrintMonth(); + virtual QString description() { return i18n("Print mont&h"); } + virtual QString info() { return i18n("Prints all events of one month on one page"); } + virtual int sortID() { return CalPrinterBase::Month; } + virtual bool enabled() { return true; } + virtual QWidget *createConfigWidget(QWidget*); + virtual KPrinter::Orientation defaultOrientation() { return KPrinter::Landscape; } + + public: + void print(QPainter &p, int width, int height); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + virtual void setDateRange( const QDate& from, const QDate& to ); + + protected: + bool mWeekNumbers; + bool mRecurDaily; + bool mRecurWeekly; + bool mIncludeTodos; +}; + +class CalPrintTodos : public CalPrintPluginBase +{ + public: + CalPrintTodos(); + virtual ~CalPrintTodos(); + virtual QString description() { return i18n("Print to-&dos"); } + virtual QString info() { return i18n("Prints all to-dos in a (tree-like) list"); } + virtual int sortID() { return CalPrinterBase::Todolist; } + virtual bool enabled() { return true; } + virtual QWidget *createConfigWidget(QWidget*); + + public: + void print( QPainter &p, int width, int height ); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + + protected: + QString mPageTitle; + + enum eTodoPrintType { + TodosAll = 0, TodosUnfinished, TodosDueRange + } mTodoPrintType; + + enum eTodoSortField { + TodoFieldSummary=0, + TodoFieldStartDate, TodoFieldDueDate, + TodoFieldPriority, TodoFieldPercentComplete, + TodoFieldUnset + } mTodoSortField; + + enum eTodoSortDirection { + TodoDirectionAscending=0, TodoDirectionDescending, + TodoDirectionUnset + } mTodoSortDirection; + + bool mIncludeDescription; + bool mIncludePriority; + bool mIncludeDueDate; + bool mIncludePercentComplete; + bool mConnectSubTodos; + bool mStrikeOutCompleted; + bool mSortField; + bool mSortDirection; +}; + +#endif +#endif diff --git a/korganizer/printing/calprinter.cpp b/korganizer/printing/calprinter.cpp new file mode 100644 index 000000000..066c9c296 --- /dev/null +++ b/korganizer/printing/calprinter.cpp @@ -0,0 +1,278 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qvbuttongroup.h> +#include <qwidgetstack.h> +#include <qradiobutton.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qvbox.h> +#include <qsplitter.h> + +#include <kprinter.h> +#include <ksimpleconfig.h> +#include <kdebug.h> +#include <kdeversion.h> + +#include "korganizer/corehelper.h" + +#include "calprinter.h" +#ifndef KORG_NOPRINTER +#include "calprinter.moc" + +#include "calprintdefaultplugins.h" + +CalPrinter::CalPrinter( QWidget *parent, Calendar *calendar, KOrg::CoreHelper *helper ) + : QObject( parent, "CalPrinter" ) +{ + mParent = parent; + mConfig = new KSimpleConfig( "korganizer_printing.rc" ); + mCoreHelper = helper; + + init( calendar ); +} + +CalPrinter::~CalPrinter() +{ + kdDebug(5850) << "~CalPrinter()" << endl; + + mPrintPlugins.clear(); + + delete mConfig; +} + +void CalPrinter::init( Calendar *calendar ) +{ + mCalendar = calendar; + + mPrintPlugins.clear(); + mPrintPlugins.setAutoDelete( true ); + + mPrintPlugins = mCoreHelper->loadPrintPlugins(); + mPrintPlugins.prepend( new CalPrintTodos() ); + mPrintPlugins.prepend( new CalPrintMonth() ); + mPrintPlugins.prepend( new CalPrintWeek() ); + mPrintPlugins.prepend( new CalPrintDay() ); + mPrintPlugins.prepend( new CalPrintIncidence() ); + + KOrg::PrintPlugin::List::Iterator it = mPrintPlugins.begin(); + for ( ; it != mPrintPlugins.end(); ++it ) { + if ( *it ) { + (*it)->setConfig( mConfig ); + (*it)->setCalendar( mCalendar ); + (*it)->setKOrgCoreHelper( mCoreHelper ); + (*it)->doLoadConfig(); + } + } +} + +void CalPrinter::setDateRange( const QDate &fd, const QDate &td ) +{ + KOrg::PrintPlugin::List::Iterator it = mPrintPlugins.begin(); + for ( ; it != mPrintPlugins.end(); ++it ) { + (*it)->setDateRange( fd, td ); + } +} + +void CalPrinter::print( int type, const QDate &fd, const QDate &td, + Incidence::List selectedIncidences, bool preview ) +{ + KOrg::PrintPlugin::List::Iterator it = mPrintPlugins.begin(); + for ( it = mPrintPlugins.begin(); it != mPrintPlugins.end(); ++it ) { + (*it)->setSelectedIncidences( selectedIncidences ); + } + CalPrintDialog printDialog( mPrintPlugins, mParent ); + printDialog.setOrientation( CalPrinter::ePrintOrientation( mConfig->readNumEntry("Orientation", 1 ) ) ); + printDialog.setPreview( preview ); + printDialog.setPrintType( type ); + setDateRange( fd, td ); + + if ( printDialog.exec() == QDialog::Accepted ) { + mConfig->writeEntry( "Orientation", printDialog.orientation() ); + + // Save all changes in the dialog + for ( it = mPrintPlugins.begin(); it != mPrintPlugins.end(); ++it ) { + (*it)->doSaveConfig(); + } + doPrint( printDialog.selectedPlugin(), printDialog.orientation(), preview ); + } + for ( it = mPrintPlugins.begin(); it != mPrintPlugins.end(); ++it ) { + (*it)->setSelectedIncidences( Incidence::List() ); + } +} + +void CalPrinter::doPrint( KOrg::PrintPlugin *selectedStyle, + CalPrinter::ePrintOrientation dlgorientation, bool preview ) +{ + if ( !selectedStyle ) { + KMessageBox::error( mParent, + i18n("Unable to print, no valid print style was returned."), + i18n("Printing error") ); + return; + } + KPrinter printer; + + printer.setPreviewOnly( preview ); + switch ( dlgorientation ) { + case eOrientPlugin: + printer.setOrientation( selectedStyle->defaultOrientation() ); + break; + case eOrientPortrait: + printer.setOrientation( KPrinter::Portrait ); + break; + case eOrientLandscape: + printer.setOrientation( KPrinter::Landscape ); + break; + case eOrientPrinter: + default: + break; + } + + if ( preview || printer.setup( mParent, i18n("Print Calendar") ) ) { + selectedStyle->doPrint( &printer ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void CalPrinter::updateConfig() +{ +} + + + +/****************************************************************************/ + +CalPrintDialog::CalPrintDialog( KOrg::PrintPlugin::List plugins, + QWidget *parent, const char *name ) + : KDialogBase( parent, name, /*modal*/true, i18n("Print"), Ok | Cancel ) +{ + QVBox *page = makeVBoxMainWidget(); + + QSplitter *splitter = new QSplitter( page ); + splitter->setOrientation( QSplitter::Horizontal ); + + mTypeGroup = new QVButtonGroup( i18n("Print Style"), splitter, "buttonGroup" ); + // use the minimal width possible = max width of the radio buttons, not extensible +/* mTypeGroup->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)4, + (QSizePolicy::SizeType)5, 0, 0, + mTypeGroup->sizePolicy().hasHeightForWidth() ) );*/ + + QWidget *splitterRight = new QWidget( splitter, "splitterRight" ); + QGridLayout *splitterRightLayout = new QGridLayout( splitterRight ); + splitterRightLayout->setMargin( marginHint() ); + splitterRightLayout->setSpacing( spacingHint() ); + + mConfigArea = new QWidgetStack( splitterRight, "configWidgetStack" ); + splitterRightLayout->addMultiCellWidget( mConfigArea, 0,0, 0,1 ); + + QLabel *orientationLabel = new QLabel( i18n("Page &orientation:"), + splitterRight, "orientationLabel" ); + splitterRightLayout->addWidget( orientationLabel, 1, 0 ); + + mOrientationSelection = new QComboBox( splitterRight, "orientationCombo" ); + mOrientationSelection->insertItem( i18n("Use Default Orientation of Selected Style") ); + mOrientationSelection->insertItem( i18n("Use Printer Default") ); + mOrientationSelection->insertItem( i18n("Portrait") ); + mOrientationSelection->insertItem( i18n("Landscape") ); + splitterRightLayout->addWidget( mOrientationSelection, 1, 1 ); + + // signals and slots connections + connect( mTypeGroup, SIGNAL( clicked( int ) ), SLOT( setPrintType( int ) ) ); + orientationLabel->setBuddy( mOrientationSelection ); + + // First insert the config widgets into the widget stack. This possibly assigns + // proper ids (when two plugins have the same sortID), so store them in a map + // and use these new IDs to later sort the plugins for the type selection. + for ( KOrg::PrintPlugin::List::Iterator it = plugins.begin(); + it != plugins.end(); ++it ) { + int newid = mConfigArea->addWidget( (*it)->configWidget( mConfigArea ), (*it)->sortID() ); + mPluginIDs[newid] = (*it); + } + // Insert all plugins with in sorted order; plugins with clashing IDs will be first... + QMap<int, KOrg::PrintPlugin*>::ConstIterator mapit; + for ( mapit = mPluginIDs.begin(); mapit != mPluginIDs.end(); ++mapit ) { + KOrg::PrintPlugin *p = mapit.data(); + QRadioButton *radioButton = new QRadioButton( p->description(), mTypeGroup ); + radioButton->setEnabled( p->enabled() ); + mTypeGroup->insert( radioButton, mapit.key() ); +// radioButton->setMinimumHeight( radioButton->sizeHint().height() - 5 ); + } + + setMinimumSize( minimumSizeHint() ); + resize( minimumSizeHint() ); +} + +CalPrintDialog::~CalPrintDialog() +{ +} + +void CalPrintDialog::setPreview(bool preview) +{ +#if KDE_IS_VERSION( 3, 1, 93 ) + setButtonOK( preview ? i18n("&Preview") : KStdGuiItem::print() ); +#else + setButtonOKText( preview ? i18n("&Preview") : i18n("&Print...") ); +#endif +} + +void CalPrintDialog::setPrintType( int i ) +{ + mTypeGroup->setButton( i ); + mConfigArea->raiseWidget( i ); +} + +void CalPrintDialog::setOrientation( CalPrinter::ePrintOrientation orientation ) +{ + mOrientation = orientation; + mOrientationSelection->setCurrentItem( mOrientation ); +} + +KOrg::PrintPlugin *CalPrintDialog::selectedPlugin() +{ + int id = mTypeGroup->selectedId(); + if ( mPluginIDs.contains( id ) ) { + return mPluginIDs[id]; + } else { + return 0; + } +} + +void CalPrintDialog::slotOk() +{ + mOrientation = (CalPrinter::ePrintOrientation)mOrientationSelection->currentItem(); + + QMap<int, KOrg::PrintPlugin*>::Iterator it = mPluginIDs.begin(); + for ( ; it != mPluginIDs.end(); ++it ) { + if ( it.data() ) + it.data()->readSettingsWidget(); + } + + KDialogBase::slotOk(); +} + +#endif diff --git a/korganizer/printing/calprinter.h b/korganizer/printing/calprinter.h new file mode 100644 index 000000000..e05073e58 --- /dev/null +++ b/korganizer/printing/calprinter.h @@ -0,0 +1,136 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _CALPRINTER_H +#define _CALPRINTER_H + +#ifndef KORG_NOPRINTER + +#include <qptrlist.h> +#include <kdialogbase.h> +#include <korganizer/baseview.h> +#include <korganizer/printplugin.h> +#include <kdepimmacros.h> + +namespace KOrg { +class CoreHelper; +} +using namespace KCal; + +class QVButtonGroup; +class QWidgetStack; +class CalPrintDialog; +class KConfig; +class QComboBox; +class QLabel; + +/** + CalPrinter is a class for printing Calendars. It can print in several + different formats (day, week, month). It also provides a way for setting + up the printer and remembering these preferences. +*/ +class KDE_EXPORT CalPrinter : public QObject, public KOrg::CalPrinterBase +{ + Q_OBJECT + + public: + enum ePrintOrientation { + eOrientPlugin=0, + eOrientPrinter, + eOrientPortrait, + eOrientLandscape + }; + public: + /** + \param par parent widget for dialogs + \param cal calendar to be printed + \param helper is a pointer to the KOrg::CoreHelper object + */ + CalPrinter( QWidget *par, Calendar *cal, KOrg::CoreHelper *helper ); + virtual ~CalPrinter(); + + void init( Calendar *calendar ); + + /** + Set date range to be printed. + + \param start Start date + \param end End date + */ + void setDateRange( const QDate &start, const QDate &end ); + + public slots: + void updateConfig(); + + private slots: + void doPrint( KOrg::PrintPlugin *selectedStyle, CalPrinter::ePrintOrientation dlgorientation, bool preview = false ); + + public: + void print( int type, const QDate &fd, const QDate &td, + Incidence::List selectedIncidences = Incidence::List(), bool preview = false ); + + Calendar *calendar() const; + KConfig *config() const; + + protected: + KOrg::PrintPlugin::List mPrintPlugins; + + private: + Calendar *mCalendar; + QWidget *mParent; + KConfig *mConfig; + KOrg::CoreHelper *mCoreHelper; +}; + +class CalPrintDialog : public KDialogBase +{ + Q_OBJECT + public: + CalPrintDialog( KOrg::PrintPlugin::List plugins, + QWidget *parent = 0, const char *name = 0 ); + virtual ~CalPrintDialog(); + KOrg::PrintPlugin *selectedPlugin(); + void setOrientation( CalPrinter::ePrintOrientation orientation ); + CalPrinter::ePrintOrientation orientation() { return mOrientation; } + + public slots: + void setPrintType( int ); + void setPreview( bool ); + + protected slots: + void slotOk(); + + private: + QVButtonGroup *mTypeGroup; + QWidgetStack *mConfigArea; + QMap<int, KOrg::PrintPlugin*> mPluginIDs; + QString mPreviewText; + QComboBox *mOrientationSelection; + + CalPrinter::ePrintOrientation mOrientation; +}; + +#endif + +#endif diff --git a/korganizer/printing/calprintincidenceconfig_base.ui b/korganizer/printing/calprintincidenceconfig_base.ui new file mode 100644 index 000000000..5a85fb714 --- /dev/null +++ b/korganizer/printing/calprintincidenceconfig_base.ui @@ -0,0 +1,103 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintIncidenceConfig_Base</class> +<comment>Configuration page for printing incidences.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintIncidence_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>277</width> + <height>206</height> + </rect> + </property> + <property name="caption"> + <string>CalPrintIncidence_Base</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>mComponentsGroup</cstring> + </property> + <property name="title"> + <string>Include Information</string> + </property> + <property name="selectedId" stdset="0"> + <number>-1</number> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mShowDetails</cstring> + </property> + <property name="text"> + <string>Detai&ls (visiblility, secrecy, etc.)</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mShowSubitemsNotes</cstring> + </property> + <property name="text"> + <string>&Notes, Subitems</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mShowAttendees</cstring> + </property> + <property name="text"> + <string>&Attendees</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mShowAttachments</cstring> + </property> + <property name="text"> + <string>Attach&ments</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mColors</cstring> + </property> + <property name="text"> + <string>&Use colors</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to use colors to distinguish certain categories on the print, check this option.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>201</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/korganizer/printing/calprintmonthconfig_base.ui b/korganizer/printing/calprintmonthconfig_base.ui new file mode 100644 index 000000000..001729582 --- /dev/null +++ b/korganizer/printing/calprintmonthconfig_base.ui @@ -0,0 +1,210 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintMonthConfig_Base</class> +<comment>Configuration page for the print day mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintMonth_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>463</width> + <height>161</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <spacer row="5" column="0"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>mDateRangeGroup</cstring> + </property> + <property name="title"> + <string>Date && Time Range</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>mFromDateLabel</cstring> + </property> + <property name="text"> + <string>&Start month:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromMonth</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the first month to be printed. Use the option <i>End month</i> to define the last month in this range.</string> + </property> + </widget> + <widget class="KComboBox"> + <property name="name"> + <cstring>mFromMonth</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the first month to be printed. Use the on <i>End month</i> to define the last month in this range.</string> + </property> + </widget> + <widget class="KIntSpinBox"> + <property name="name"> + <cstring>mFromYear</cstring> + </property> + <property name="maxValue"> + <number>3000</number> + </property> + <property name="value"> + <number>2007</number> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the first month to be printed. Use the on <i>End month</i> to define the last month in this range.</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>mToDateLabel</cstring> + </property> + <property name="text"> + <string>&End month:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToMonth</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the last month to be printed. Use the option <i>Start month</i> to define the first month in this range.</string> + </property> + </widget> + <widget class="KComboBox"> + <property name="name"> + <cstring>mToMonth</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the last month to be printed. Use the option <i>Start month</i> to define the first month in this range.</string> + </property> + </widget> + <widget class="KIntSpinBox"> + <property name="name"> + <cstring>mToYear</cstring> + </property> + <property name="maxValue"> + <number>3000</number> + </property> + <property name="value"> + <number>2007</number> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the last month to be printed. Use the option <i>Start month</i> to define the first month in this range.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>17</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QCheckBox" row="4" column="0"> + <property name="name"> + <cstring>mIncludeTodos</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Include to-&dos that are due on the printed day(s)</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this option if you want to have to-dos on the print, placed by their due date.</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>mWeekNumbers</cstring> + </property> + <property name="text"> + <string>Print week &numbers</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable this to print week numbers at the left of each row.</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0"> + <property name="name"> + <cstring>mRecurDaily</cstring> + </property> + <property name="text"> + <string>Print daily re&curring to-dos and events</string> + </property> + <property name="whatsThis" stdset="0"> + <string>With this option it is possible to leave out the daily recurring to-dos and events in the print. They take a lot of space and make the month view needlessly complicated.</string> + </property> + </widget> + <widget class="QCheckBox" row="3" column="0"> + <property name="name"> + <cstring>mRecurWeekly</cstring> + </property> + <property name="text"> + <string>Print weekl&y recurring to-dos and events</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Similar to "Print daily recurring to-dos and events". Weekly to-dos and events will be omitted when making a print of the selected month.</string> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>mWeekNumbers</tabstop> + <tabstop>mRecurDaily</tabstop> + <tabstop>mRecurWeekly</tabstop> + <tabstop>mIncludeTodos</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">kdateedit.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kcombobox.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/korganizer/printing/calprintpluginbase.cpp b/korganizer/printing/calprintpluginbase.cpp new file mode 100644 index 000000000..44739db48 --- /dev/null +++ b/korganizer/printing/calprintpluginbase.cpp @@ -0,0 +1,1674 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2003 Reinhold Kainhofer <reinhold@kainhofer.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qpainter.h> +#include <qlayout.h> +#include <qframe.h> +#include <qlabel.h> + +#include <kdebug.h> +#include <kconfig.h> +#include <kcalendarsystem.h> +#include <kwordwrap.h> + +#include "calprintpluginbase.h" +#include "cellitem.h" + +#ifndef KORG_NOPRINTER + +inline int round(const double x) + { + return int(x > 0.0 ? x + 0.5 : x - 0.5); + } +/****************************************************************** + ** The Todo positioning structure ** + ******************************************************************/ +class CalPrintPluginBase::TodoParentStart +{ + public: + TodoParentStart( QRect pt = QRect(), bool page = true ) + : mRect( pt ), mSamePage( page ) {} + + QRect mRect; + bool mSamePage; +}; + + +/****************************************************************** + ** The Print item ** + ******************************************************************/ + + +class PrintCellItem : public KOrg::CellItem +{ + public: + PrintCellItem( Event *event, const QDateTime &start, const QDateTime &end ) + : mEvent( event ), mStart( start), mEnd( end ) + { + } + + Event *event() const { return mEvent; } + + QString label() const { return mEvent->summary(); } + + QDateTime start() const { return mStart; } + QDateTime end() const { return mEnd; } + + /** Calculate the start and end date/time of the recurrence that + happens on the given day */ + bool overlaps( KOrg::CellItem *o ) const + { + PrintCellItem *other = static_cast<PrintCellItem *>( o ); + +#if 0 + kdDebug(5850) << "PrintCellItem::overlaps() " << event()->summary() + << " <-> " << other->event()->summary() << endl; + kdDebug(5850) << " start : " << start.toString() << endl; + kdDebug(5850) << " end : " << end.toString() << endl; + kdDebug(5850) << " otherStart: " << otherStart.toString() << endl; + kdDebug(5850) << " otherEnd : " << otherEnd.toString() << endl; +#endif + + return !( other->start() >= end() || other->end() <= start() ); + } + + private: + Event *mEvent; + QDateTime mStart, mEnd; +}; + + + + +/****************************************************************** + ** The Print plugin ** + ******************************************************************/ + + +CalPrintPluginBase::CalPrintPluginBase() : PrintPlugin(), mUseColors( true ), + mHeaderHeight(-1), mSubHeaderHeight( SUBHEADER_HEIGHT ), + mMargin( MARGIN_SIZE ), mPadding( PADDING_SIZE), mCalSys( 0 ) +{ +} +CalPrintPluginBase::~CalPrintPluginBase() +{ +} + + + +QWidget *CalPrintPluginBase::createConfigWidget( QWidget *w ) +{ + QFrame *wdg = new QFrame( w ); + QVBoxLayout *layout = new QVBoxLayout( wdg ); + + QLabel *title = new QLabel( description(), wdg ); + QFont titleFont( title->font() ); + titleFont.setPointSize( 20 ); + titleFont.setBold( true ); + title->setFont( titleFont ); + + layout->addWidget( title ); + layout->addWidget( new QLabel( info(), wdg ) ); + layout->addSpacing( 20 ); + layout->addWidget( new QLabel( i18n("This printing style does not " + "have any configuration options."), + wdg ) ); + layout->addStretch(); + return wdg; +} + +void CalPrintPluginBase::doPrint( KPrinter *printer ) +{ + if ( !printer ) return; + mPrinter = printer; + QPainter p; + + mPrinter->setColorMode( mUseColors?(KPrinter::Color):(KPrinter::GrayScale) ); + + p.begin( mPrinter ); + // TODO: Fix the margins!!! + // the painter initially begins at 72 dpi per the Qt docs. + // we want half-inch margins. + int margins = margin(); + p.setViewport( margins, margins, + p.viewport().width() - 2*margins, + p.viewport().height() - 2*margins ); +// QRect vp( p.viewport() ); +// vp.setRight( vp.right()*2 ); +// vp.setBottom( vp.bottom()*2 ); +// p.setWindow( vp ); + int pageWidth = p.window().width(); + int pageHeight = p.window().height(); +// int pageWidth = p.viewport().width(); +// int pageHeight = p.viewport().height(); + + print( p, pageWidth, pageHeight ); + + p.end(); + mPrinter = 0; +} + +void CalPrintPluginBase::doLoadConfig() +{ + if ( mConfig ) { + KConfigGroupSaver saver( mConfig, description() ); + mConfig->sync(); + QDateTime currDate( QDate::currentDate() ); + mFromDate = mConfig->readDateTimeEntry( "FromDate", &currDate ).date(); + mToDate = mConfig->readDateTimeEntry( "ToDate" ).date(); + mUseColors = mConfig->readBoolEntry( "UseColors", true ); + setUseColors( mUseColors ); + loadConfig(); + } else { + kdDebug(5850) << "No config available in loadConfig!!!!" << endl; + } +} + +void CalPrintPluginBase::doSaveConfig() +{ + if ( mConfig ) { + KConfigGroupSaver saver( mConfig, description() ); + saveConfig(); + mConfig->writeEntry( "FromDate", QDateTime( mFromDate ) ); + mConfig->writeEntry( "ToDate", QDateTime( mToDate ) ); + mConfig->writeEntry( "UseColors", mUseColors ); + mConfig->sync(); + } else { + kdDebug(5850) << "No config available in saveConfig!!!!" << endl; + } +} + + + + +void CalPrintPluginBase::setKOrgCoreHelper( KOrg::CoreHelper*helper ) +{ + PrintPlugin::setKOrgCoreHelper( helper ); + if ( helper ) + setCalendarSystem( helper->calendarSystem() ); +} + +bool CalPrintPluginBase::useColors() const +{ + return mUseColors; +} +void CalPrintPluginBase::setUseColors( bool useColors ) +{ + mUseColors = useColors; +} + +KPrinter::Orientation CalPrintPluginBase::orientation() const +{ + return (mPrinter)?(mPrinter->orientation()):(KPrinter::Portrait); +} + + + +QTime CalPrintPluginBase::dayStart() +{ + QTime start( 8,0,0 ); + if ( mCoreHelper ) start = mCoreHelper->dayStart(); + return start; +} + +void CalPrintPluginBase::setCategoryColors( QPainter &p, Incidence *incidence ) +{ + QColor bgColor = categoryBgColor( incidence ); + if ( bgColor.isValid() ) + p.setBrush( bgColor ); + QColor tColor( textColor( bgColor ) ); + if ( tColor.isValid() ) + p.setPen( tColor ); +} + +QColor CalPrintPluginBase::categoryBgColor( Incidence *incidence ) +{ + if (mCoreHelper && incidence) + return mCoreHelper->categoryColor( incidence->categories() ); + else + return QColor(); +} + +QColor CalPrintPluginBase::textColor( const QColor &color ) +{ + return (mCoreHelper)?(mCoreHelper->textColor( color )):QColor(); +} + +bool CalPrintPluginBase::isWorkingDay( const QDate &dt ) +{ + return (mCoreHelper)?( mCoreHelper->isWorkingDay( dt ) ):true; +} + +QString CalPrintPluginBase::holidayString( const QDate &dt ) +{ + return (mCoreHelper)?(mCoreHelper->holidayString(dt)):(QString::null); +} + + +Event *CalPrintPluginBase::holiday( const QDate &dt ) +{ + QString hstring( holidayString( dt ) ); + if ( !hstring.isEmpty() ) { + Event*holiday=new Event(); + holiday->setSummary( hstring ); + holiday->setDtStart( dt ); + holiday->setDtEnd( dt ); + holiday->setFloats( true ); + holiday->setCategories( i18n("Holiday") ); + return holiday; + } + return 0; +} + +const KCalendarSystem *CalPrintPluginBase::calendarSystem() const +{ + return mCalSys; +} +void CalPrintPluginBase::setCalendarSystem( const KCalendarSystem *calsys ) +{ + mCalSys = calsys; +} + +int CalPrintPluginBase::headerHeight() const +{ + if ( mHeaderHeight >= 0 ) + return mHeaderHeight; + else if ( orientation() == KPrinter::Portrait ) + return PORTRAIT_HEADER_HEIGHT; + else + return LANDSCAPE_HEADER_HEIGHT; +} +void CalPrintPluginBase::setHeaderHeight( const int height ) +{ + mHeaderHeight = height; +} + +int CalPrintPluginBase::subHeaderHeight() const +{ + return mSubHeaderHeight; +} +void CalPrintPluginBase::setSubHeaderHeight( const int height ) +{ + mSubHeaderHeight = height; +} + +int CalPrintPluginBase::margin() const +{ + return mMargin; +} +void CalPrintPluginBase::setMargin( const int margin ) +{ + mMargin = margin; +} + +int CalPrintPluginBase::padding() const +{ + return mPadding; +} +void CalPrintPluginBase::setPadding( const int padding ) +{ + mPadding = padding; +} + +int CalPrintPluginBase::borderWidth() const +{ + return mBorder; +} +void CalPrintPluginBase::setBorderWidth( const int borderwidth ) +{ + mBorder = borderwidth; +} + + + + +void CalPrintPluginBase::drawBox( QPainter &p, int linewidth, const QRect &rect ) +{ + QPen pen( p.pen() ); + QPen oldpen( pen ); + pen.setWidth( linewidth ); + p.setPen( pen ); + p.drawRect( rect ); + p.setPen( oldpen ); +} + +void CalPrintPluginBase::drawShadedBox( QPainter &p, int linewidth, const QBrush &brush, const QRect &rect ) +{ + QBrush oldbrush( p.brush() ); + p.setBrush( brush ); + drawBox( p, linewidth, rect ); + p.setBrush( oldbrush ); +} + +void CalPrintPluginBase::printEventString( QPainter &p, const QRect &box, const QString &str, int flags ) +{ + QRect newbox( box ); + newbox.addCoords( 3, 1, -1, -1 ); + p.drawText( newbox, (flags==-1)?(Qt::AlignTop | Qt::AlignJustify | Qt::BreakAnywhere):flags, str ); +} + + +void CalPrintPluginBase::showEventBox( QPainter &p, const QRect &box, Incidence *incidence, const QString &str, int flags ) +{ + QPen oldpen( p.pen() ); + QBrush oldbrush( p.brush() ); + QColor bgColor( categoryBgColor( incidence ) ); + if ( mUseColors & bgColor.isValid() ) { + p.setBrush( bgColor ); + } else { + p.setBrush( QColor( 232, 232, 232 ) ); + } + drawBox( p, EVENT_BORDER_WIDTH, box ); + + if ( mUseColors && bgColor.isValid() ) { + p.setPen( textColor( bgColor ) ); + } + printEventString( p, box, str, flags ); + p.setPen( oldpen ); + p.setBrush( oldbrush ); +} + + +void CalPrintPluginBase::drawSubHeaderBox(QPainter &p, const QString &str, + const QRect &box ) +{ + drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), box ); + QFont oldfont( p.font() ); + p.setFont( QFont( "sans-serif", 10, QFont::Bold ) ); + p.drawText( box, Qt::AlignCenter | Qt::AlignVCenter, str ); + p.setFont( oldfont ); +} + +void CalPrintPluginBase::drawVerticalBox( QPainter &p, const QRect &box, const QString &str ) +{ + p.save(); + p.rotate( -90 ); + QRect rotatedBox( -box.top()-box.height(), box.left(), box.height(), box.width() ); + showEventBox( p, rotatedBox, 0, str, Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine ); + + p.restore(); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// Return value: If expand, bottom of the printed box, otherwise vertical end +// of the printed contents inside the box. + +int CalPrintPluginBase::drawBoxWithCaption( QPainter &p, const QRect &allbox, + const QString &caption, const QString &contents, bool sameLine, bool expand, const QFont &captionFont, const QFont &textFont ) +{ + QFont oldFont( p.font() ); +// QFont captionFont( "sans-serif", 11, QFont::Bold ); +// QFont textFont( "sans-serif", 11, QFont::Normal ); +// QFont captionFont( "Tahoma", 11, QFont::Bold ); +// QFont textFont( "Tahoma", 11, QFont::Normal ); + + + QRect box( allbox ); + + // Bounding rectangle for caption, single-line, clip on the right + QRect captionBox( box.left() + padding(), box.top() + padding(), 0, 0 ); + p.setFont( captionFont ); + captionBox = p.boundingRect( captionBox, Qt::AlignLeft | Qt::AlignTop | Qt::SingleLine, caption ); + p.setFont( oldFont ); + if ( captionBox.right() > box.right() ) + captionBox.setRight( box.right() ); + if ( expand && captionBox.bottom() + padding() > box.bottom() ) + box.setBottom( captionBox.bottom() + padding() ); + + // Bounding rectangle for the contents (if any), word break, clip on the bottom + QRect textBox( captionBox ); + if ( !contents.isEmpty() ) { + if ( sameLine ) { + textBox.setLeft( captionBox.right() + padding() ); + } else { + textBox.setTop( captionBox.bottom() + padding() ); + } + textBox.setRight( box.right() ); + textBox.setHeight( 0 ); + p.setFont( textFont ); + textBox = p.boundingRect( textBox, Qt::WordBreak | Qt::AlignTop | Qt::AlignLeft, contents ); + p.setFont( oldFont ); + if ( textBox.bottom() + padding() > box.bottom() ) { + if ( expand ) { + box.setBottom( textBox.bottom() + padding() ); + } else { + textBox.setBottom( box.bottom() ); + } + } + } + + drawBox( p, BOX_BORDER_WIDTH, box ); + p.setFont( captionFont ); + p.drawText( captionBox, Qt::AlignLeft | Qt::AlignTop | Qt::SingleLine, caption ); + if ( !contents.isEmpty() ) { + p.setFont( textFont ); + p.drawText( textBox, Qt::WordBreak | Qt::AlignTop | Qt::AlignLeft, contents ); + } + p.setFont( oldFont ); + + if ( expand ) { + return box.bottom(); + } else { + return textBox.bottom(); + } +} + + +/////////////////////////////////////////////////////////////////////////////// + +int CalPrintPluginBase::drawHeader( QPainter &p, QString title, + const QDate &month1, const QDate &month2, const QRect &allbox, bool expand ) +{ + // print previous month for month view, print current for to-do, day and week + int smallMonthWidth = (allbox.width()/4) - 10; + if (smallMonthWidth>100) smallMonthWidth=100; + + int right = allbox.right(); + if ( month1.isValid() ) right -= (20+smallMonthWidth); + if ( month2.isValid() ) right -= (20+smallMonthWidth); + QRect box( allbox ); + QRect textRect( allbox ); + textRect.addCoords( 5, 0, 0, 0 ); + textRect.setRight( right ); + + + QFont oldFont( p.font() ); + QFont newFont("sans-serif", (textRect.height()<60)?16:18, QFont::Bold); + if ( expand ) { + p.setFont( newFont ); + QRect boundingR = p.boundingRect( textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::WordBreak, title ); + p.setFont( oldFont ); + int h = boundingR.height(); + if ( h > allbox.height() ) { + box.setHeight( h ); + textRect.setHeight( h ); + } + } + + drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), box ); + + QRect monthbox( box.right()-10-smallMonthWidth, box.top(), smallMonthWidth, box.height() ); + if (month2.isValid()) { + drawSmallMonth( p, QDate(month2.year(), month2.month(), 1), monthbox ); + monthbox.moveBy( -20 - smallMonthWidth, 0 ); + } + if (month1.isValid()) { + drawSmallMonth( p, QDate(month1.year(), month1.month(), 1), monthbox ); + monthbox.moveBy( -20 - smallMonthWidth, 0 ); + } + + // Set the margins + p.setFont( newFont ); + p.drawText( textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::WordBreak, title ); + p.setFont( oldFont ); + + return textRect.bottom(); +} + + +void CalPrintPluginBase::drawSmallMonth(QPainter &p, const QDate &qd, + const QRect &box ) +{ + + int weekdayCol = weekdayColumn( qd.dayOfWeek() ); + int month = qd.month(); + QDate monthDate(QDate(qd.year(), qd.month(), 1)); + // correct begin of week + QDate monthDate2( monthDate.addDays( -weekdayCol ) ); + + double cellWidth = double(box.width())/double(7); + int rownr = 3 + ( qd.daysInMonth() + weekdayCol - 1 ) / 7; + // 3 Pixel after month name, 2 after day names, 1 after the calendar + double cellHeight = (box.height() - 5) / rownr; + QFont oldFont( p.font() ); + p.setFont(QFont("sans-serif", int(cellHeight-1), QFont::Normal)); + + // draw the title + if ( mCalSys ) { + QRect titleBox( box ); + titleBox.setHeight( int(cellHeight+1) ); + p.drawText( titleBox, Qt::AlignTop | Qt::AlignHCenter, mCalSys->monthName( qd ) ); + } + + // draw days of week + QRect wdayBox( box ); + wdayBox.setTop( int( box.top() + 3 + cellHeight ) ); + wdayBox.setHeight( int(2*cellHeight)-int(cellHeight) ); + + if ( mCalSys ) { + for (int col = 0; col < 7; ++col) { + QString tmpStr = mCalSys->weekDayName( monthDate2 )[0].upper(); + wdayBox.setLeft( int(box.left() + col*cellWidth) ); + wdayBox.setRight( int(box.left() + (col+1)*cellWidth) ); + p.drawText( wdayBox, Qt::AlignCenter, tmpStr ); + monthDate2 = monthDate2.addDays( 1 ); + } + } + + // draw separator line + int calStartY = wdayBox.bottom() + 2; + p.drawLine( box.left(), calStartY, box.right(), calStartY ); + monthDate = monthDate.addDays( -weekdayCol ); + + for ( int row = 0; row < (rownr-2); row++ ) { + for ( int col = 0; col < 7; col++ ) { + if ( monthDate.month() == month ) { + QRect dayRect( int( box.left() + col*cellWidth ), int( calStartY + row*cellHeight ), 0, 0 ); + dayRect.setRight( int( box.left() + (col+1)*cellWidth ) ); + dayRect.setBottom( int( calStartY + (row+1)*cellHeight ) ); + p.drawText( dayRect, Qt::AlignCenter, QString::number( monthDate.day() ) ); + } + monthDate = monthDate.addDays(1); + } + } + p.setFont( oldFont ); +} + + + + + +/////////////////////////////////////////////////////////////////////////////// + +/* + * This routine draws a header box over the main part of the calendar + * containing the days of the week. + */ +void CalPrintPluginBase::drawDaysOfWeek(QPainter &p, + const QDate &fromDate, const QDate &toDate, const QRect &box ) +{ + double cellWidth = double(box.width()) / double(fromDate.daysTo( toDate )+1); + QDate cellDate( fromDate ); + QRect dateBox( box ); + int i = 0; + + while ( cellDate <= toDate ) { + dateBox.setLeft( box.left() + int(i*cellWidth) ); + dateBox.setRight( box.left() + int((i+1)*cellWidth) ); + drawDaysOfWeekBox(p, cellDate, dateBox ); + cellDate = cellDate.addDays(1); + i++; + } +} + + +void CalPrintPluginBase::drawDaysOfWeekBox(QPainter &p, const QDate &qd, + const QRect &box ) +{ + drawSubHeaderBox( p, (mCalSys)?(mCalSys->weekDayName( qd )):(QString::null), box ); +} + + +void CalPrintPluginBase::drawTimeLine(QPainter &p, + const QTime &fromTime, const QTime &toTime, + const QRect &box) +{ + drawBox( p, BOX_BORDER_WIDTH, box ); + + int totalsecs=fromTime.secsTo(toTime); + float minlen=(float)box.height()*60./(float)totalsecs; + float cellHeight=(60.*(float)minlen); + float currY=box.top(); + // TODO: Don't use half of the width, but less, for the minutes! + int xcenter = box.left()+box.width()/2; + + QTime curTime( fromTime ); + QTime endTime( toTime ); + if ( fromTime.minute() > 30 ) + curTime = QTime( fromTime.hour()+1, 0, 0 ); + else if ( fromTime.minute() > 0 ) { + curTime = QTime( fromTime.hour(), 30, 0 ); + float yy = currY + minlen*(float)fromTime.secsTo( curTime )/60.; + p.drawLine( xcenter, (int)yy, box.right(), (int)yy ); + curTime = QTime( fromTime.hour()+1, 0, 0 ); + } + currY += ( float( fromTime.secsTo(curTime)*minlen ) / 60. ); + + while ( curTime < endTime ) { + p.drawLine( box.left(), (int)currY, box.right(), (int)currY ); + int newY=(int)(currY+cellHeight/2.); + QString numStr; + if ( newY < box.bottom() ) { + QFont oldFont( p.font() ); + // draw the time: + if ( !KGlobal::locale()->use12Clock() ) { + p.drawLine( xcenter, (int)newY, box.right(), (int)newY); + numStr.setNum(curTime.hour()); + if (cellHeight > 30) { + p.setFont(QFont("sans-serif", 16, QFont::Bold)); + } else { + p.setFont(QFont("sans-serif", 12, QFont::Bold)); + } + p.drawText( box.left()+2, (int)currY+2, box.width()/2-2, (int)cellHeight, + Qt::AlignTop | Qt::AlignRight, numStr); + p.setFont(QFont("sans-serif", 10, QFont::Normal)); + p.drawText( xcenter, (int)currY+2, box.width()/2+2, (int)(cellHeight/2)-3, + Qt::AlignTop | Qt::AlignLeft, "00"); + } else { + p.drawLine( box.left(), (int)newY, box.right(), (int)newY); + QTime time( curTime.hour(), 0 ); + numStr = KGlobal::locale()->formatTime( time ); + if ( box.width() < 60 ) { + p.setFont(QFont("sans-serif", 8, QFont::Bold)); // for weekprint + } else { + p.setFont(QFont("sans-serif", 12, QFont::Bold)); // for dayprint + } + p.drawText(box.left()+2, (int)currY+2, box.width()-4, (int)cellHeight/2-3, + Qt::AlignTop|Qt::AlignLeft, numStr); + } + currY+=cellHeight; + p.setFont( oldFont ); + } // enough space for half-hour line and time + if (curTime.secsTo(endTime)>3600) + curTime=curTime.addSecs(3600); + else curTime=endTime; + } // currTime<endTime +} + + +/////////////////////////////////////////////////////////////////////////////// + +/** prints the all-day box for the agenda print view. if expandable is set, + height is the cell height of a single cell, and the returned height will + be the total height used for the all-day events. If !expandable, only one + cell will be used, and multiple events are concatenated using ", ". +*/ +int CalPrintPluginBase::drawAllDayBox(QPainter &p, Event::List &eventList, + const QDate &qd, bool expandable, const QRect &box ) +{ + Event::List::Iterator it, itold; + + int offset=box.top(); + + QString multiDayStr; + + Event*hd = holiday( qd ); + if ( hd ) eventList.prepend( hd ); + + it = eventList.begin(); + Event *currEvent = 0; + // First, print all floating events + while( it!=eventList.end() ) { + currEvent=*it; + itold=it; + ++it; + if ( currEvent && currEvent->doesFloat() ) { + // set the colors according to the categories + if ( expandable ) { + QRect eventBox( box ); + eventBox.setTop( offset ); + showEventBox( p, eventBox, currEvent, currEvent->summary() ); + offset += box.height(); + } else { + if ( !multiDayStr.isEmpty() ) multiDayStr += ", "; + multiDayStr += currEvent->summary(); + } + eventList.remove( itold ); + } + } + if ( hd ) delete hd; + + int ret = box.height(); + QRect eventBox( box ); + if (!expandable) { + if (!multiDayStr.isEmpty()) { + drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 128, 128, 128 ), eventBox ); + printEventString( p, eventBox, multiDayStr ); + } else { + drawBox( p, BOX_BORDER_WIDTH, eventBox ); + } + } else { + ret = offset - box.top(); + eventBox.setBottom( ret ); + drawBox( p, BOX_BORDER_WIDTH, eventBox ); + } + return ret; +} + + +void CalPrintPluginBase::drawAgendaDayBox( QPainter &p, Event::List &events, + const QDate &qd, bool expandable, + QTime &fromTime, QTime &toTime, + const QRect &oldbox ) +{ + if ( !isWorkingDay( qd ) ) { + drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), oldbox ); + } else { + drawBox( p, BOX_BORDER_WIDTH, oldbox ); + } + QRect box( oldbox ); + // Account for the border with and cut away that margin from the interior +// box.setRight( box.right()-BOX_BORDER_WIDTH ); + + Event *event; + + if ( expandable ) { + // Adapt start/end times to include complete events + Event::List::ConstIterator it; + for ( it = events.begin(); it != events.end(); ++it ) { + event = *it; + if ( event->dtStart().time() < fromTime ) + fromTime = event->dtStart().time(); + if ( event->dtEnd().time() > toTime ) + toTime = event->dtEnd().time(); + } + } + + // Show at least one hour +// if ( fromTime.secsTo( toTime ) < 3600 ) { +// fromTime = QTime( fromTime.hour(), 0, 0 ); +// toTime = fromTime.addSecs( 3600 ); +// } + + // calculate the height of a cell and of a minute + int totalsecs = fromTime.secsTo( toTime ); + float minlen = box.height() * 60. / totalsecs; + float cellHeight = 60. * minlen; + float currY = box.top(); + + // print grid: + QTime curTime( QTime( fromTime.hour(), 0, 0 ) ); + currY += fromTime.secsTo( curTime ) * minlen / 60; + + while ( curTime < toTime && curTime.isValid() ) { + if ( currY > box.top() ) + p.drawLine( box.left(), int( currY ), box.right(), int( currY ) ); + currY += cellHeight / 2; + if ( ( currY > box.top() ) && ( currY < box.bottom() ) ) { + // enough space for half-hour line + QPen oldPen( p.pen() ); + p.setPen( QColor( 192, 192, 192 ) ); + p.drawLine( box.left(), int( currY ), box.right(), int( currY ) ); + p.setPen( oldPen ); + } + if ( curTime.secsTo( toTime ) > 3600 ) + curTime = curTime.addSecs( 3600 ); + else curTime = toTime; + currY += cellHeight / 2; + } + + QDateTime startPrintDate = QDateTime( qd, fromTime ); + QDateTime endPrintDate = QDateTime( qd, toTime ); + + // Calculate horizontal positions and widths of events taking into account + // overlapping events + + QPtrList<KOrg::CellItem> cells; + cells.setAutoDelete( true ); + + Event::List::ConstIterator itEvents; + for( itEvents = events.begin(); itEvents != events.end(); ++itEvents ) { + QValueList<QDateTime> times = (*itEvents)->startDateTimesForDate( qd ); + for ( QValueList<QDateTime>::ConstIterator it = times.begin(); + it != times.end(); ++it ) { + cells.append( new PrintCellItem( *itEvents, (*it), (*itEvents)->endDateForStart( *it ) ) ); + } + } + + QPtrListIterator<KOrg::CellItem> it1( cells ); + for( it1.toFirst(); it1.current(); ++it1 ) { + KOrg::CellItem *placeItem = it1.current(); + KOrg::CellItem::placeItem( cells, placeItem ); + } + +// p.setFont( QFont( "sans-serif", 10 ) ); + + for( it1.toFirst(); it1.current(); ++it1 ) { + PrintCellItem *placeItem = static_cast<PrintCellItem *>( it1.current() ); + drawAgendaItem( placeItem, p, startPrintDate, endPrintDate, minlen, box ); + } +// p.setFont( oldFont ); +} + + + +void CalPrintPluginBase::drawAgendaItem( PrintCellItem *item, QPainter &p, + const QDateTime &startPrintDate, + const QDateTime &endPrintDate, + float minlen, const QRect &box ) +{ + Event *event = item->event(); + + // start/end of print area for event + QDateTime startTime = item->start(); + QDateTime endTime = item->end(); + if ( ( startTime < endPrintDate && endTime > startPrintDate ) || + ( endTime > startPrintDate && startTime < endPrintDate ) ) { + if ( startTime < startPrintDate ) startTime = startPrintDate; + if ( endTime > endPrintDate ) endTime = endPrintDate; + int currentWidth = box.width() / item->subCells(); + int currentX = box.left() + item->subCell() * currentWidth; + int currentYPos = int( box.top() + startPrintDate.secsTo( startTime ) * + minlen / 60. ); + int currentHeight = int( box.top() + startPrintDate.secsTo( endTime ) * minlen / 60. ) - currentYPos; + + QRect eventBox( currentX, currentYPos, currentWidth, currentHeight ); + showEventBox( p, eventBox, event, event->summary() ); + } +} + +//TODO TODO TODO +void CalPrintPluginBase::drawDayBox( QPainter &p, const QDate &qd, + const QRect &box, + bool fullDate, bool printRecurDaily, bool printRecurWeekly ) +{ + QString dayNumStr; + QString ampm; + const KLocale*local = KGlobal::locale(); + + + // This has to be localized + if ( fullDate && mCalSys ) { + + dayNumStr = i18n("weekday month date", "%1 %2 %3") + .arg( mCalSys->weekDayName( qd ) ) + .arg( mCalSys->monthName( qd ) ) + .arg( qd.day() ); +// dayNumStr = local->formatDate(qd); + } else { + dayNumStr = QString::number( qd.day() ); + } + + QRect subHeaderBox( box ); + subHeaderBox.setHeight( mSubHeaderHeight ); + drawShadedBox( p, BOX_BORDER_WIDTH, p.backgroundColor(), box ); + drawShadedBox( p, 0, QColor( 232, 232, 232 ), subHeaderBox ); + drawBox( p, BOX_BORDER_WIDTH, box ); + QString hstring( holidayString( qd ) ); + QFont oldFont( p.font() ); + + QRect headerTextBox( subHeaderBox ); + headerTextBox.setLeft( subHeaderBox.left()+5 ); + headerTextBox.setRight( subHeaderBox.right()-5 ); + if (!hstring.isEmpty()) { + p.setFont( QFont( "sans-serif", 8, QFont::Bold, true ) ); + + p.drawText( headerTextBox, Qt::AlignLeft | Qt::AlignVCenter, hstring ); + } + p.setFont(QFont("sans-serif", 10, QFont::Bold)); + p.drawText( headerTextBox, Qt::AlignRight | Qt::AlignVCenter, dayNumStr); + + Event::List eventList = mCalendar->events( qd, + EventSortStartDate, + SortDirectionAscending ); + QString text; + p.setFont( QFont( "sans-serif", 8 ) ); + + int textY=mSubHeaderHeight+3; // gives the relative y-coord of the next printed entry + Event::List::ConstIterator it; + + for( it = eventList.begin(); it != eventList.end() && textY<box.height(); ++it ) { + Event *currEvent = *it; + if ( ( !printRecurDaily && currEvent->recurrenceType() == Recurrence::rDaily ) || + ( !printRecurWeekly && currEvent->recurrenceType() == Recurrence::rWeekly ) ) { + continue; } + if ( currEvent->doesFloat() || currEvent->isMultiDay() ) + text = ""; + else + text = local->formatTime( currEvent->dtStart().time() ); + + drawIncidence( p, box, text, currEvent->summary(), textY ); + } + + if ( textY<box.height() ) { + Todo::List todos = mCalendar->todos( qd ); + Todo::List::ConstIterator it2; + for( it2 = todos.begin(); it2 != todos.end() && textY<box.height(); ++it2 ) { + Todo *todo = *it2; + if ( ( !printRecurDaily && todo->recurrenceType() == Recurrence::rDaily ) || + ( !printRecurWeekly && todo->recurrenceType() == Recurrence::rWeekly ) ) + continue; + if ( todo->hasDueDate() && !todo->doesFloat() ) + text += KGlobal::locale()->formatTime(todo->dtDue().time()) + " "; + else + text = ""; + drawIncidence( p, box, text, i18n("To-do: %1").arg(todo->summary()), textY ); + } + } + + p.setFont( oldFont ); +} + +// TODO TODO TODO +void CalPrintPluginBase::drawIncidence( QPainter &p, const QRect &dayBox, const QString &time, const QString &summary, int &textY ) +{ + kdDebug(5850) << "summary = " << summary << endl; + + int flags = Qt::AlignLeft; + QFontMetrics fm = p.fontMetrics(); + QRect timeBound = p.boundingRect( dayBox.x() + 5, dayBox.y() + textY, + dayBox.width() - 10, fm.lineSpacing(), + flags, time ); + p.drawText( timeBound, flags, time ); + + int summaryWidth = time.isEmpty() ? 0 : timeBound.width() + 4; + QRect summaryBound = QRect( dayBox.x() + 5 + summaryWidth, dayBox.y() + textY, + dayBox.width() - summaryWidth -5, dayBox.height() ); + + KWordWrap *ww = KWordWrap::formatText( fm, summaryBound, flags, summary ); + ww->drawText( &p, dayBox.x() + 5 + summaryWidth, dayBox.y() + textY, flags ); + + textY += ww->boundingRect().height(); + + delete ww; +} + + +/////////////////////////////////////////////////////////////////////////////// + +void CalPrintPluginBase::drawWeek(QPainter &p, const QDate &qd, const QRect &box ) +{ + QDate weekDate = qd; + bool portrait = ( box.height() > box.width() ); + int cellWidth, cellHeight; + int vcells; + if (portrait) { + cellWidth = box.width()/2; + vcells=3; + } else { + cellWidth = box.width()/6; + vcells=1; + } + cellHeight = box.height()/vcells; + + // correct begin of week + int weekdayCol = weekdayColumn( qd.dayOfWeek() ); + weekDate = qd.addDays( -weekdayCol ); + + for (int i = 0; i < 7; i++, weekDate = weekDate.addDays(1)) { + // Saturday and sunday share a cell, so we have to special-case sunday + int hpos = ((i<6)?i:(i-1)) / vcells; + int vpos = ((i<6)?i:(i-1)) % vcells; + QRect dayBox( box.left()+cellWidth*hpos, box.top()+cellHeight*vpos + ((i==6)?(cellHeight/2):0), + cellWidth, (i<5)?(cellHeight):(cellHeight/2) ); + drawDayBox(p, weekDate, dayBox, true); + } // for i through all weekdays +} + + +void CalPrintPluginBase::drawTimeTable(QPainter &p, + const QDate &fromDate, const QDate &toDate, + QTime &fromTime, QTime &toTime, + const QRect &box) +{ + // timeline is 1 hour: + int alldayHeight = (int)( 3600.*box.height()/(fromTime.secsTo(toTime)+3600.) ); + int timelineWidth = TIMELINE_WIDTH; + + QRect dowBox( box ); + dowBox.setLeft( box.left() + timelineWidth ); + dowBox.setHeight( mSubHeaderHeight ); + drawDaysOfWeek( p, fromDate, toDate, dowBox ); + + QRect tlBox( box ); + tlBox.setWidth( timelineWidth ); + tlBox.setTop( dowBox.bottom() + BOX_BORDER_WIDTH + alldayHeight ); + drawTimeLine( p, fromTime, toTime, tlBox ); + + // draw each day + QDate curDate(fromDate); + int i=0; + double cellWidth = double(dowBox.width()) / double(fromDate.daysTo(toDate)+1); + while (curDate<=toDate) { + QRect allDayBox( dowBox.left()+int(i*cellWidth), dowBox.bottom() + BOX_BORDER_WIDTH, + int((i+1)*cellWidth)-int(i*cellWidth), alldayHeight ); + QRect dayBox( allDayBox ); + dayBox.setTop( tlBox.top() ); + dayBox.setBottom( box.bottom() ); + Event::List eventList = mCalendar->events(curDate, + EventSortStartDate, + SortDirectionAscending); + alldayHeight = drawAllDayBox( p, eventList, curDate, false, allDayBox ); + drawAgendaDayBox( p, eventList, curDate, false, fromTime, toTime, dayBox ); + i++; + curDate=curDate.addDays(1); + } + +} + + +/////////////////////////////////////////////////////////////////////////////// + +class MonthEventStruct +{ + public: + MonthEventStruct() : event(0) {} + MonthEventStruct( const QDateTime &s, const QDateTime &e, Event *ev) + { + event = ev; + start = s; + end = e; + if ( event->doesFloat() ) { + start = QDateTime( start.date(), QTime(0,0,0) ); + end = QDateTime( end.date().addDays(1), QTime(0,0,0) ).addSecs(-1); + } + } + bool operator<(const MonthEventStruct &mes) { return start < mes.start; } + QDateTime start; + QDateTime end; + Event *event; +}; + +void CalPrintPluginBase::drawMonth( QPainter &p, const QDate &dt, const QRect &box, int maxdays, int subDailyFlags, int holidaysFlags ) +{ + const KCalendarSystem *calsys = calendarSystem(); + QRect subheaderBox( box ); + subheaderBox.setHeight( subHeaderHeight() ); + QRect borderBox( box ); + borderBox.setTop( subheaderBox.bottom()+1 ); + drawSubHeaderBox( p, calsys->monthName(dt), subheaderBox ); + // correct for half the border width + int correction = (BOX_BORDER_WIDTH/*-1*/)/2; + QRect daysBox( borderBox ); + daysBox.addCoords( correction, correction, -correction, -correction ); + + int daysinmonth = calsys->daysInMonth( dt ); + if ( maxdays <= 0 ) maxdays = daysinmonth; + + int d; + float dayheight = float(daysBox.height()) / float( maxdays ); + + QColor holidayColor( 240, 240, 240 ); + QColor workdayColor( 255, 255, 255 ); + int dayNrWidth = p.fontMetrics().width( "99" ); + + // Fill the remaining space (if a month has less days than others) with a crossed-out pattern + if ( daysinmonth<maxdays ) { + QRect dayBox( box.left(), daysBox.top() + round(dayheight*daysinmonth), box.width(), 0 ); + dayBox.setBottom( daysBox.bottom() ); + p.fillRect( dayBox, Qt::DiagCrossPattern ); + } + // Backgrounded boxes for each day, plus day numbers + QBrush oldbrush( p.brush() ); + for ( d = 0; d < daysinmonth; ++d ) { + QDate day; + calsys->setYMD( day, dt.year(), dt.month(), d+1 ); + QRect dayBox( daysBox.left()/*+rand()%50*/, daysBox.top() + round(dayheight*d), daysBox.width()/*-rand()%50*/, 0 ); + // FIXME: When using a border width of 0 for event boxes, don't let the rectangles overlap, i.e. subtract 1 from the top or bottom! + dayBox.setBottom( daysBox.top()+round(dayheight*(d+1)) - 1 ); + + p.setBrush( isWorkingDay( day )?workdayColor:holidayColor ); + p.drawRect( dayBox ); + QRect dateBox( dayBox ); + dateBox.setWidth( dayNrWidth+3 ); + p.drawText( dateBox, Qt::AlignRight | Qt::AlignVCenter | Qt::SingleLine, + QString::number(d+1) ); + } + p.setBrush( oldbrush ); + int xstartcont = box.left() + dayNrWidth + 5; + + QDate start, end; + calsys->setYMD( start, dt.year(), dt.month(), 1 ); + end = calsys->addMonths( start, 1 ); + end = calsys->addDays( end, -1 ); + + Event::List events = mCalendar->events( start, end ); + QMap<int, QStringList> textEvents; + QPtrList<KOrg::CellItem> timeboxItems; + timeboxItems.setAutoDelete( true ); + + + // 1) For multi-day events, show boxes spanning several cells, use CellItem + // print the summary vertically + // 2) For sub-day events, print the concated summaries into the remaining + // space of the box (optional, depending on the given flags) + // 3) Draw some kind of timeline showing free and busy times + + // Holidays + Event::List holidays; + holidays.setAutoDelete( true ); + for ( QDate d(start); d <= end; d = d.addDays(1) ) { + Event *e = holiday( d ); + if ( e ) { + holidays.append( e ); + if ( holidaysFlags & TimeBoxes ) { + timeboxItems.append( new PrintCellItem( e, QDateTime(d, QTime(0,0,0) ), + QDateTime( d.addDays(1), QTime(0,0,0) ) ) ); + } + if ( holidaysFlags & Text ) { + textEvents[ d.day() ] << e->summary(); + } + } + } + + QValueList<MonthEventStruct> monthentries; + + for ( Event::List::ConstIterator evit = events.begin(); + evit != events.end(); ++evit ) { + Event *e = (*evit); + if (!e) continue; + if ( e->doesRecur() ) { + if ( e->recursOn( start ) ) { + // This occurrence has possibly started before the beginning of the + // month, so obtain the start date before the beginning of the month + QValueList<QDateTime> starttimes = e->startDateTimesForDate( start ); + QValueList<QDateTime>::ConstIterator it = starttimes.begin(); + for ( ; it != starttimes.end(); ++it ) { + monthentries.append( MonthEventStruct( *it, e->endDateForStart( *it ), e ) ); + } + } + // Loop through all remaining days of the month and check if the event + // begins on that day (don't use Event::recursOn, as that will + // also return events that have started earlier. These start dates + // however, have already been treated! + Recurrence *recur = e->recurrence(); + QDate d1( start.addDays(1) ); + while ( d1 <= end ) { + if ( recur->recursOn(d1) ) { + TimeList times( recur->recurTimesOn( d1 ) ); + for ( TimeList::ConstIterator it = times.begin(); + it != times.end(); ++it ) { + QDateTime d1start( d1, *it ); + monthentries.append( MonthEventStruct( d1start, e->endDateForStart( d1start ), e ) ); + } + } + d1 = d1.addDays(1); + } + } else { + monthentries.append( MonthEventStruct( e->dtStart(), e->dtEnd(), e ) ); + } + } + qHeapSort( monthentries ); + + QValueList<MonthEventStruct>::ConstIterator mit = monthentries.begin(); + QDateTime endofmonth( end, QTime(0,0,0) ); + endofmonth = endofmonth.addDays(1); + for ( ; mit != monthentries.end(); ++mit ) { + if ( (*mit).start.date() == (*mit).end.date() ) { + // Show also single-day events as time line boxes + if ( subDailyFlags & TimeBoxes ) { + timeboxItems.append( new PrintCellItem( (*mit).event, (*mit).start, (*mit).end ) ); + } + // Show as text in the box + if ( subDailyFlags & Text ) { + textEvents[ (*mit).start.date().day() ] << (*mit).event->summary(); + } + } else { + // Multi-day events are always shown as time line boxes + QDateTime thisstart( (*mit).start ); + QDateTime thisend( (*mit).end ); + if ( thisstart.date()<start ) thisstart = start; + if ( thisend>endofmonth ) thisend = endofmonth; + timeboxItems.append( new PrintCellItem( (*mit).event, thisstart, thisend ) ); + } + } + + // For Multi-day events, line them up nicely so that the boxes don't overlap + QPtrListIterator<KOrg::CellItem> it1( timeboxItems ); + for( it1.toFirst(); it1.current(); ++it1 ) { + KOrg::CellItem *placeItem = it1.current(); + KOrg::CellItem::placeItem( timeboxItems, placeItem ); + } + QDateTime starttime( start, QTime( 0, 0, 0 ) ); + int newxstartcont = xstartcont; + + QFont oldfont( p.font() ); + p.setFont( QFont( "sans-serif", 7 ) ); + for( it1.toFirst(); it1.current(); ++it1 ) { + PrintCellItem *placeItem = static_cast<PrintCellItem *>( it1.current() ); + int minsToStart = starttime.secsTo( placeItem->start() )/60; + int minsToEnd = starttime.secsTo( placeItem->end() )/60; + + QRect eventBox( xstartcont + placeItem->subCell()*17, + daysBox.top() + round( double( minsToStart*daysBox.height()) / double(maxdays*24*60) ), + 14, 0 ); + eventBox.setBottom( daysBox.top() + round( double( minsToEnd*daysBox.height()) / double(maxdays*24*60) ) ); + drawVerticalBox( p, eventBox, placeItem->event()->summary() ); + newxstartcont = QMAX( newxstartcont, eventBox.right() ); + } + xstartcont = newxstartcont; + + // For Single-day events, simply print their summaries into the remaining + // space of the day's cell + for ( int d=0; d<daysinmonth; ++d ) { + QStringList dayEvents( textEvents[d+1] ); + QString txt = dayEvents.join(", "); + QRect dayBox( xstartcont, daysBox.top()+round(dayheight*d), 0, 0 ); + dayBox.setRight( box.right() ); + dayBox.setBottom( daysBox.top()+round(dayheight*(d+1)) ); + printEventString(p, dayBox, txt, Qt::AlignTop | Qt::AlignLeft | Qt::BreakAnywhere ); + } + p.setFont( oldfont ); +// p.setBrush( Qt::NoBrush ); + drawBox( p, BOX_BORDER_WIDTH, borderBox ); + p.restore(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void CalPrintPluginBase::drawMonthTable(QPainter &p, const QDate &qd, bool weeknumbers, + bool recurDaily, bool recurWeekly, + const QRect &box) +{ + int yoffset = mSubHeaderHeight; + int xoffset = 0; + QDate monthDate(QDate(qd.year(), qd.month(), 1)); + QDate monthFirst(monthDate); + QDate monthLast(monthDate.addMonths(1).addDays(-1)); + + + int weekdayCol = weekdayColumn( monthDate.dayOfWeek() ); + monthDate = monthDate.addDays(-weekdayCol); + + if (weeknumbers) { + xoffset += 14; + } + + int rows=(weekdayCol + qd.daysInMonth() - 1)/7 +1; + double cellHeight = ( box.height() - yoffset ) / (1.*rows); + double cellWidth = ( box.width() - xoffset ) / 7.; + + // Precalculate the grid... + // rows is at most 6, so using 8 entries in the array is fine, too! + int coledges[8], rowedges[8]; + for ( int i = 0; i <= 7; i++ ) { + rowedges[i] = int( box.top() + yoffset + i*cellHeight ); + coledges[i] = int( box.left() + xoffset + i*cellWidth ); + } + + if (weeknumbers) { + QFont oldFont(p.font()); + QFont newFont(p.font()); + newFont.setPointSize(6); + p.setFont(newFont); + QDate weekDate(monthDate); + for (int row = 0; row<rows; ++row ) { + int calWeek = weekDate.weekNumber(); + QRect rc( box.left(), rowedges[row], coledges[0] - 3 - box.left(), rowedges[row+1]-rowedges[row] ); + p.drawText( rc, Qt::AlignRight | Qt::AlignVCenter, QString::number( calWeek ) ); + weekDate = weekDate.addDays( 7 ); + } + p.setFont( oldFont ); + } + + QRect daysOfWeekBox( box ); + daysOfWeekBox.setHeight( mSubHeaderHeight ); + daysOfWeekBox.setLeft( box.left()+xoffset ); + drawDaysOfWeek( p, monthDate, monthDate.addDays( 6 ), daysOfWeekBox ); + + QColor back = p.backgroundColor(); + bool darkbg = false; + for ( int row = 0; row < rows; ++row ) { + for ( int col = 0; col < 7; ++col ) { + // show days from previous/next month with a grayed background + if ( (monthDate < monthFirst) || (monthDate > monthLast) ) { + p.setBackgroundColor( back.dark( 120 ) ); + darkbg = true; + } + QRect dayBox( coledges[col], rowedges[row], coledges[col+1]-coledges[col], rowedges[row+1]-rowedges[row] ); + drawDayBox(p, monthDate, dayBox, false, recurDaily, recurWeekly ); + if ( darkbg ) { + p.setBackgroundColor( back ); + darkbg = false; + } + monthDate = monthDate.addDays(1); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// + +void CalPrintPluginBase::drawTodo( int &count, Todo *todo, QPainter &p, + TodoSortField sortField, SortDirection sortDir, + bool connectSubTodos, bool strikeoutCompleted, + bool desc, int posPriority, int posSummary, + int posDueDt, int posPercentComplete, + int level, int x, int &y, int width, + int pageHeight, const Todo::List &todoList, + TodoParentStart *r ) +{ + QString outStr; + const KLocale *local = KGlobal::locale(); + QRect rect; + TodoParentStart startpt; + + // This list keeps all starting points of the parent to-dos so the connection + // lines of the tree can easily be drawn (needed if a new page is started) + static QPtrList<TodoParentStart> startPoints; + if ( level < 1 ) { + startPoints.clear(); + } + + // Compute the right hand side of the to-do box + int rhs = posPercentComplete; + if ( rhs < 0 ) rhs = posDueDt; //not printing percent completed + if ( rhs < 0 ) rhs = x+width; //not printing due dates either + + // size of to-do + outStr=todo->summary(); + int left = posSummary + ( level*10 ); + rect = p.boundingRect( left, y, ( rhs-left-5 ), -1, Qt::WordBreak, outStr ); + if ( !todo->description().isEmpty() && desc ) { + outStr = todo->description(); + rect = p.boundingRect( left+20, rect.bottom()+5, width-(left+10-x), -1, + Qt::WordBreak, outStr ); + } + // if too big make new page + if ( rect.bottom() > pageHeight ) { + // first draw the connection lines from parent to-dos: + if ( level > 0 && connectSubTodos ) { + TodoParentStart *rct; + for ( rct = startPoints.first(); rct; rct = startPoints.next() ) { + int start; + int center = rct->mRect.left() + (rct->mRect.width()/2); + int to = p.viewport().bottom(); + + // draw either from start point of parent or from top of the page + if ( rct->mSamePage ) + start = rct->mRect.bottom() + 1; + else + start = p.viewport().top(); + p.moveTo( center, start ); + p.lineTo( center, to ); + rct->mSamePage = false; + } + } + y=0; + mPrinter->newPage(); + } + + // If this is a sub-to-do, r will not be 0, and we want the LH side + // of the priority line up to the RH side of the parent to-do's priority + bool showPriority = posPriority>=0; + int lhs = posPriority; + if ( r ) { + lhs = r->mRect.right() + 1; + } + + outStr.setNum( todo->priority() ); + rect = p.boundingRect( lhs, y + 10, 5, -1, Qt::AlignCenter, outStr ); + // Make it a more reasonable size + rect.setWidth(18); + rect.setHeight(18); + + // Draw a checkbox + p.setBrush( QBrush( Qt::NoBrush ) ); + p.drawRect( rect ); + if ( todo->isCompleted() ) { + // cross out the rectangle for completed to-dos + p.drawLine( rect.topLeft(), rect.bottomRight() ); + p.drawLine( rect.topRight(), rect.bottomLeft() ); + } + lhs = rect.right() + 3; + + // Priority + if ( todo->priority() > 0 && showPriority ) { + p.drawText( rect, Qt::AlignCenter, outStr ); + } + startpt.mRect = rect; //save for later + + // Connect the dots + if ( level > 0 && connectSubTodos ) { + int bottom; + int center( r->mRect.left() + (r->mRect.width()/2) ); + if ( r->mSamePage ) + bottom = r->mRect.bottom() + 1; + else + bottom = 0; + int to( rect.top() + (rect.height()/2) ); + int endx( rect.left() ); + p.moveTo( center, bottom ); + p.lineTo( center, to ); + p.lineTo( endx, to ); + } + + // summary + outStr=todo->summary(); + rect = p.boundingRect( lhs, rect.top(), (rhs-(left + rect.width() + 5)), + -1, Qt::WordBreak, outStr ); + + QRect newrect; + //FIXME: the following code prints underline rather than strikeout text +#if 0 + QFont f( p.font() ); + if ( todo->isCompleted() && strikeoutCompleted ) { + f.setStrikeOut( true ); + p.setFont( f ); + } + p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect ); + f.setStrikeOut( false ); + p.setFont( f ); +#endif + //TODO: Remove this section when the code above is fixed + p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect ); + if ( todo->isCompleted() && strikeoutCompleted ) { + // strike out the summary text if to-do is complete + // Note: we tried to use a strike-out font and for unknown reasons the + // result was underline instead of strike-out, so draw the lines ourselves. + int delta = p.fontMetrics().lineSpacing(); + int lines = ( rect.height() / delta ) + 1; + for ( int i=0; i<lines; i++ ) { + p.moveTo( rect.left(), rect.top() + ( delta/2 ) + ( i*delta ) ); + p.lineTo( rect.right(), rect.top() + ( delta/2 ) + ( i*delta ) ); + } + } + + // due date + if ( todo->hasDueDate() && posDueDt>=0 ) { + outStr = local->formatDate( todo->dtDue().date(), true ); + rect = p.boundingRect( posDueDt, y, x + width, -1, + Qt::AlignTop | Qt::AlignLeft, outStr ); + p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr ); + } + + // percentage completed + bool showPercentComplete = posPercentComplete>=0; + if ( showPercentComplete ) { + int lwidth = 24; + int lheight = 12; + //first, draw the progress bar + int progress = (int)(( lwidth*todo->percentComplete())/100.0 + 0.5); + + p.setBrush( QBrush( Qt::NoBrush ) ); + p.drawRect( posPercentComplete, y+3, lwidth, lheight ); + if ( progress > 0 ) { + p.setBrush( QColor( 128, 128, 128 ) ); + p.drawRect( posPercentComplete, y+3, progress, lheight ); + } + + //now, write the percentage + outStr = i18n( "%1%" ).arg( todo->percentComplete() ); + rect = p.boundingRect( posPercentComplete+lwidth+3, y, x + width, -1, + Qt::AlignTop | Qt::AlignLeft, outStr ); + p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr ); + } + + // description + if ( !todo->description().isEmpty() && desc ) { + y = newrect.bottom() + 5; + outStr = todo->description(); + rect = p.boundingRect( left+20, y, x+width-(left+10), -1, + Qt::WordBreak, outStr ); + p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect ); + } + + // Set the new line position + y = newrect.bottom() + 10; //set the line position + + // If the to-do has sub-to-dos, we need to call ourselves recursively +#if 0 + Incidence::List l = todo->relations(); + Incidence::List::ConstIterator it; + startPoints.append( &startpt ); + for( it = l.begin(); it != l.end(); ++it ) { + count++; + // In the future, to-dos might also be related to events + // Manually check if the sub-to-do is in the list of to-dos to print + // The problem is that relations() does not apply filters, so + // we need to compare manually with the complete filtered list! + Todo* subtodo = dynamic_cast<Todo *>( *it ); + if (subtodo && todoList.contains( subtodo ) ) { + drawTodo( count, subtodo, p, connectSubTodos, strikeoutCompleted, + desc, posPriority, posSummary, posDueDt, posPercentComplete, + level+1, x, y, width, pageHeight, todoList, &startpt ); + } + } +#endif + // Make a list of all the sub-to-dos related to this to-do. + Todo::List t; + Incidence::List l = todo->relations(); + Incidence::List::ConstIterator it; + for( it=l.begin(); it!=l.end(); ++it ) { + // In the future, to-dos might also be related to events + // Manually check if the sub-to-do is in the list of to-dos to print + // The problem is that relations() does not apply filters, so + // we need to compare manually with the complete filtered list! + Todo* subtodo = dynamic_cast<Todo *>( *it ); + if ( subtodo && todoList.contains( subtodo ) ) { + t.append( subtodo ); + } + } + + // Sort the sub-to-dos and then print them + Todo::List sl = mCalendar->sortTodos( &t, sortField, sortDir ); + Todo::List::ConstIterator isl; + startPoints.append( &startpt ); + for( isl = sl.begin(); isl != sl.end(); ++isl ) { + count++; + drawTodo( count, ( *isl ), p, sortField, sortDir, + connectSubTodos, strikeoutCompleted, + desc, posPriority, posSummary, posDueDt, posPercentComplete, + level+1, x, y, width, pageHeight, todoList, &startpt ); + } + startPoints.remove( &startpt ); +} + +int CalPrintPluginBase::weekdayColumn( int weekday ) +{ + return ( weekday + 7 - KGlobal::locale()->weekStartDay() ) % 7; +} + +void CalPrintPluginBase::drawJournalField( QPainter &p, QString field, QString text, + int x, int &y, int width, int pageHeight ) +{ + if ( text.isEmpty() ) return; + + QString entry( field.arg( text ) ); + + QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, entry) ); + if ( rect.bottom() > pageHeight) { + // Start new page... + // FIXME: If it's a multi-line text, draw a few lines on this page, and the + // remaining lines on the next page. + y=0; + mPrinter->newPage(); + rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, entry); + } + QRect newrect; + p.drawText( rect, Qt::WordBreak, entry, -1, &newrect ); + y = newrect.bottom() + 7; +} + +void CalPrintPluginBase::drawJournal( Journal * journal, QPainter &p, int x, int &y, + int width, int pageHeight ) +{ + QFont oldFont( p.font() ); + p.setFont( QFont( "sans-serif", 15 ) ); + QString headerText; + QString dateText( KGlobal::locale()-> + formatDate( journal->dtStart().date(), false ) ); + + if ( journal->summary().isEmpty() ) { + headerText = dateText; + } else { + headerText = i18n("Description - date", "%1 - %2") + .arg( journal->summary() ) + .arg( dateText ); + } + + QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText) ); + if ( rect.bottom() > pageHeight) { + // Start new page... + y=0; + mPrinter->newPage(); + rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText ); + } + QRect newrect; + p.drawText( rect, Qt::WordBreak, headerText, -1, &newrect ); + p.setFont( oldFont ); + + y = newrect.bottom() + 4; + + p.drawLine( x + 3, y, x + width - 6, y ); + y += 5; + + drawJournalField( p, i18n("Person: %1"), journal->organizer().fullName(), x, y, width, pageHeight ); + drawJournalField( p, i18n("%1"), journal->description(), x, y, width, pageHeight ); + y += 10; +} + + +void CalPrintPluginBase::drawSplitHeaderRight( QPainter &p, const QDate &fd, + const QDate &td, + const QDate &, + int width, int ) +{ + QFont oldFont( p.font() ); + + QPen oldPen( p.pen() ); + QPen pen( Qt::black, 4 ); + + QString title; + if ( mCalSys ) { + if ( fd.month() == td.month() ) { + title = i18n("Date range: Month dayStart - dayEnd", "%1 %2 - %3") + .arg( mCalSys->monthName( fd.month(), false ) ) + .arg( mCalSys->dayString( fd, false ) ) + .arg( mCalSys->dayString( td, false ) ); + } else { + title = i18n("Date range: monthStart dayStart - monthEnd dayEnd", "%1 %2 - %3 %4") + .arg( mCalSys->monthName( fd.month(), false ) ) + .arg( mCalSys->dayString( fd, false ) ) + .arg( mCalSys->monthName( td.month(), false ) ) + .arg( mCalSys->dayString( td, false ) ); + } + } + + QFont serifFont("Times", 30); + p.setFont(serifFont); + + int lineSpacing = p.fontMetrics().lineSpacing(); + p.drawText( 0, lineSpacing * 0, width, lineSpacing, + Qt::AlignRight | Qt::AlignTop, title ); + + title.truncate(0); + + p.setPen( pen ); + p.drawLine(300, lineSpacing * 1, width, lineSpacing * 1); + p.setPen( oldPen ); + + p.setFont(QFont("Times", 20, QFont::Bold, TRUE)); + int newlineSpacing = p.fontMetrics().lineSpacing(); + title += QString::number(fd.year()); + p.drawText( 0, lineSpacing * 1 + 4, width, newlineSpacing, + Qt::AlignRight | Qt::AlignTop, title ); + + p.setFont( oldFont ); +} + +#endif diff --git a/korganizer/printing/calprintpluginbase.h b/korganizer/printing/calprintpluginbase.h new file mode 100644 index 000000000..9312d0042 --- /dev/null +++ b/korganizer/printing/calprintpluginbase.h @@ -0,0 +1,514 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2003 Reinhold Kainhofer <reinhold@kainhofer.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef CALPRINTPLUGINBASE_H +#define CALPRINTPLUGINBASE_H +// #define KORG_NOPRINTER + +#ifndef KORG_NOPRINTER + +#include <qdatetime.h> +#include <kprinter.h> +#include <kdepimmacros.h> +#include <libkcal/calendar.h> +#include <libkcal/event.h> +#include <libkcal/todo.h> +#include "korganizer/printplugin.h" +#include "korganizer/corehelper.h" + + +class PrintCellItem; + +class QWidget; + +using namespace KCal; + + +#define PORTRAIT_HEADER_HEIGHT 72 // header height, for portrait orientation +#define LANDSCAPE_HEADER_HEIGHT 54 // header height, for landscape orientation +#define SUBHEADER_HEIGHT 20 // subheader height, for all orientations +#define MARGIN_SIZE 36 // margins, for all orientations +#define PADDING_SIZE 7 // padding between the various top-level boxes +#define BOX_BORDER_WIDTH 2 // width of the border of all top-level boxes +#define EVENT_BORDER_WIDTH 0 // with of the border of all incidence boxes + +#define TIMELINE_WIDTH 50 // width of timeline (day and timetable) + +/** + Base class for KOrganizer printing classes. Each sub class represents one + calendar print format. +*/ +class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin +{ + public: + enum DisplayFlags { + Text=0x0001, + TimeBoxes=0x0002 + }; + + public: + /** + Constructor + */ + CalPrintPluginBase(); + virtual ~CalPrintPluginBase(); + + /** + Returns widget for configuring the print format. + */ + virtual QWidget *createConfigWidget( QWidget * ); + + /** + Actually do the printing. + + \param p QPainter the print result is painted to + \param width Width of printable area + \param height Height of printable area + */ + virtual void print( QPainter &p, int width, int height ) = 0; + /** + Start printing. + */ + virtual void doPrint( KPrinter *printer ); + + /** + Load print format configuration from config file. + */ + virtual void loadConfig() = 0; + /** + Write print format configuration to config file. + */ + virtual void saveConfig() = 0; + + /** + Load complete config. This also calls loadConfig() of the derived class. + */ + void doLoadConfig(); + /** + Save complete config. This also calls saveConfig() of the derived class. + */ + void doSaveConfig(); + + /** HELPER FUNCTIONS */ + public: + void setKOrgCoreHelper( KOrg::CoreHelper*helper ); + bool useColors() const; + void setUseColors( bool useColors ); + + /** Helper functions to hide the KOrg::CoreHelper */ + QColor categoryBgColor( Incidence *incidence ); + QColor textColor( const QColor &color ); + QTime dayStart(); + bool isWorkingDay( const QDate &dt ); + QString holidayString( const QDate &dt ); + Event *holiday( const QDate &dt ); + + /** + Determines the column of the given weekday ( 1=Monday, 7=Sunday ), taking the + start of the week setting into account as given in kcontrol. + \param weekday Index of the weekday + */ + static int weekdayColumn( int weekday ); + void setCategoryColors( QPainter &p, Incidence *incidence ); + + KPrinter::Orientation orientation() const; + + /** Returns the height of the page header. If the height was explicitly + set using setHeaderHeight, that value is returned, otherwise a + default value based on the printer orientation. + \return height of the page header of the printout + */ + int headerHeight() const; + void setHeaderHeight( const int height ); + + int subHeaderHeight() const; + void setSubHeaderHeight( const int height ); + + int margin() const; + void setMargin( const int margin ); + + int padding() const; + void setPadding( const int margin ); + + int borderWidth() const; + void setBorderWidth( const int border ); + + const KCalendarSystem *calendarSystem() const; + void setCalendarSystem( const KCalendarSystem *calsys ); + + + /***************************************************************** + ** PRINTING HELPER FUNCTIONS ** + *****************************************************************/ + public: + /** + Draw a box with given width at the given coordinates. + \param p The printer to be used + \param linewidth The border width of the box + \param rect The rectangle of the box + */ + static void drawBox( QPainter &p, int linewidth, const QRect &rect ); + /** + Draw a shaded box with given width at the given coordinates. + \param p The printer to be used + \param linewidth The border width of the box + \param brush The brush to fill the box + \param rect The rectangle of the box + */ + static void drawShadedBox( QPainter &p, int linewidth, const QBrush &brush, const QRect &rect ); + + /** + Print the given string (event summary) in the given rectangle. Margins + and justification (centered or not) are automatically adjusted. + \param p QPainter of the printout + \param box Coordinates of the surrounding event box + \param str The text to be printed in the box + */ + void printEventString( QPainter &p, const QRect &box, const QString &str, int flags = -1 ); + + /** + Print the box for the given event with the given string. + \param p QPainer of the printout + \param box Coordinates of the event's box + \param incidence The incidence (if available), from which the category + color will be deduced, if applicable. + \param str The string to print inside the box + */ + void showEventBox( QPainter &p, const QRect &box, Incidence *incidence, const QString &str, int flags = -1 ); + + /** + Draw a subheader box with a shaded background and the given string + \param p QPainter of the printout + \param str Text to be printed inside the box + \param box Coordinates of the box + */ + void drawSubHeaderBox(QPainter &p, const QString &str, const QRect &box ); + + /** + Draw an event box with vertical text. + \param p QPainter of the printout + \param box Coordinates of the box + \param str ext to be printed inside the box + */ + void drawVerticalBox( QPainter &p, const QRect &box, const QString &str ); + + /** + Draw a component box with a heading (printed in bold). + \param p QPainter of the printout + \param box Coordinates of the box + \param caption Caption string to be printed inside the box + \param contents Normal text contents of the box. If contents.isNull(), + then no text will be printed, only the caption. + \param sameLine Whether the contents should start on the same line as + the caption (the space below the caption text will be + used as indentation in the subsequent lines) or on the + next line (no indentation of the contents) + \param expand Whether to expand the box vertically to fit the + whole text in it. + \return The bottom of the printed box. If expand==true, the bottom of + the drawn box is returned, if expand==false, the vertical + end of the printed contents inside the box is returned. + If you want to print some custom graphics or text below + the contents, use the return value as the top-value of your + custom contents in that case. + */ + int drawBoxWithCaption( QPainter &p, const QRect &box, const QString &caption, + const QString &contents, + bool sameLine, bool expand, const QFont &captionFont, const QFont &textFont ); + + /** + Draw the gray header bar of the printout to the QPainter. + It prints the given text and optionally one or two small + month views, as specified by the two QDate. The printed + text can also contain a line feed. + If month2 is invalid, only the month that contains month1 + is printed. + E.g. the filofax week view draws just the current month, + while the month view draws the previous and the next month. + \param p QPainter of the printout + \param title The string printed as the title of the page + (e.g. the date, date range or todo list title) + \param month1 Date specifying the month for the left one of + the small month views in the title bar. If left + empty, only month2 will be printed (or none, + it that is invalid as well). + \param month2 Date specifying the month for the right one of + the small month views in the title bar. If left + empty, only month1 will be printed (or none, + it that is invalid as well). + \param box coordinates of the title bar + \param expand Whether to expand the box vertically to fit the + whole title in it. + \return The bottom of the printed box. If expand==false, this + is box.bottom, otherwise it is larger than box.bottom + and matches the y-coordinate of the surrounding rectangle. + */ + int drawHeader( QPainter &p, QString title, + const QDate &month1, const QDate &month2, + const QRect &box, bool expand = false ); + /** + Draw a small calendar with the days of a month into the given area. + Used for example in the title bar of the sheet. + \param p QPainter of the printout + \param qd Arbitrary Date within the month to be printed. + \param box coordinates of the small calendar + */ + void drawSmallMonth( QPainter &p, const QDate &qd, const QRect &box ); + + /** + Draw a horizontal bar with the weekday names of the given date range + in the given area of the painter. + This is used for the weekday-bar on top of the timetable view and the month view. + \param p QPainter of the printout + \param fromDate First date of the printed dates + \param toDate Last date of the printed dates + \param box coordinates of the box for the days of the week + */ + void drawDaysOfWeek( QPainter &p, + const QDate &fromDate, const QDate &toDate, + const QRect &box ); + /** + Draw a single weekday name in a box inside the given area of the painter. + This is called in a loop by drawDaysOfWeek. + \param p QPainter of the printout + \param qd Date of the printed day + \param box coordinates of the weekbox + */ + void drawDaysOfWeekBox( QPainter &p, const QDate &qd, const QRect &box ); + /** + Draw a (vertical) time scale from time fromTime to toTime inside the given area of the painter. + Every hour will have a one-pixel line over the whole width, every + half-hour the line will only span the left half of the width. + This is used in the day and timetable print styles + \param p QPainter of the printout + \param fromTime Start time of the time range to display + \param toTime End time of the time range to display + \param box coordinates of the timeline + */ + void drawTimeLine( QPainter &p, + const QTime &fromTime, const QTime &toTime, + const QRect &box ); + + /** + Draw the all-day box for the agenda print view (the box on top which + doesn't have a time on the time scale associated). If expandable is set, + height is the cell height of a single cell, and the returned height will + be the total height used for the all-day events. If !expandable, only one + cell will be used, and multiple events are concatenated using ", ". + \param p QPainter of the printout + \param eventList The list of all-day events that are supposed to be printed + inside this box + \param qd The date of the currently printed day + \param expandable If true, height is the height of one single cell, the printout + will use as many cells as events in the list and return the total height + needed for all of them. If false, height specifies the total height + allowed for all events, and the events are displayed in one cell, + with their summaries concatenated by ", ". + \param box coordinates of the all day box. + \return The height used for the all-day box. + */ + int drawAllDayBox( QPainter &p, Event::List &eventList, + const QDate &qd, bool expandable, + const QRect &box ); + /** + Draw the agenda box for the day print style (the box showing all events of that day). + Also draws a grid with half-hour spacing of the grid lines. + \param p QPainter of the printout + \param eventList The list of the events that are supposed to be printed + inside this box + \param qd The date of the currently printed day + \param expandable If true, the start and end times are adjusted to include + the whole range of all events of that day, not just of the given time range. + The height of the box will not be affected by this (but the height + of one hour will be scaled down so that the whole range fits into + the box. fromTime and toTime receive the actual time range printed + by this function). + \param fromTime Start of the time range to be printed. Might be adjusted + to include all events if expandable==true + \param toTime End of the time range to be printed. Might be adjusted + to include all events if expandable==true + \param box coordinates of the agenda day box. + */ + void drawAgendaDayBox( QPainter &p, Event::List &eventList, + const QDate &qd, bool expandable, + QTime &fromTime, QTime &toTime, + const QRect &box ); + + void drawAgendaItem( PrintCellItem *item, QPainter &p, + const QDateTime &startPrintDate, + const QDateTime &endPrintDate, + float minlen, const QRect &box ); + + /** + Draw the box containing a list of all events of the given day (with their times, + of course). Used in the Filofax and the month print style. + \param p QPainter of the printout + \param qd The date of the currently printed day. All events of the calendar + that appear on that day will be printed. + \param box coordinates of the day box. + \param fullDate Whether the title bar of the box should contain the full + date string or just a short. + \param printRecurDaily Whether daily recurring incidences should be printed. + \param printRecurWeekly Whether weekly recurring incidences should be printed. + */ + void drawDayBox( QPainter &p, const QDate &qd, + const QRect &box, + bool fullDate = false, bool printRecurDaily = true, + bool printRecurWeekly = true ); + /** + Draw the week (filofax) table of the week containing the date qd. The first + three days of the week will be shown in the first column (using drawDayBox), + the remaining four in the second column, where the last two days of the week + (typically Saturday and Sunday) only get half the height of the other day boxes. + \param p QPainter of the printout + \param qd Arbitrary date within the week to be printed. + \param box coordinates of the week box. + */ + void drawWeek( QPainter &p, const QDate &qd, + const QRect &box ); + /** + Draw the timetable view of the given time range from fromDate to toDate. + On the left side the time scale is printed (using drawTimeLine), then each + day gets one column (printed using drawAgendaDayBox), + and the events are displayed as boxes (like in korganizer's day/week view). + The first cell of each column contains the all-day events (using + drawAllDayBox with expandable=false). + The given time range cannot be expanded to include all events. + \param p QPainter of the printout + \param fromDate First day to be included in the page + \param toDate Last day to be included in the page + \param fromTime Start time of the displayed time range + \param toTime End time of the displayed time range + \param box coordinates of the time table. + */ + void drawTimeTable( QPainter &p, const QDate &fromDate, const QDate &toDate, + QTime &fromTime, QTime &toTime, + const QRect &box ); + + /** + Draw the month table of the month containing the date qd. Each day gets one + box (using drawDayBox) that contains a list of all events on that day. They are arranged + in a matrix, with the first column being the first day of the + week (so it might display some days of the previous and the next month). + Above the matrix there is a bar showing the weekdays (drawn using drawDaysOfWeek). + \param p QPainter of the printout + \param qd Arbitrary date within the month to be printed. + \param recurDaily Whether daily recurring incidences should be printed. + \param recurWeekly Whether weekly recurring incidences should be printed. + \param weeknumbers Whether the week numbers are printed left of each row of the matrix + \param box coordinates of the month. + */ + void drawMonthTable( QPainter &p, const QDate &qd, bool weeknumbers, + bool recurDaily, bool recurWeekly, + const QRect &box ); + /** + Draw a vertical representation of the month containing the date dt. Each + day gets one line. + \param p QPainter of the printout + \param dt Arbitrary date within the month to be printed + \param box coordinates of the box reserved for the month + \param maxdays Days to print. If a value of -1 is given, the number of days + is deduced from the month. If maxdays is larger than the + number of days in the month, the remaining boxes are + shaded to indicate they are not days of the month. + \param subDailyFlags Bitfield consisting of DisplayFlags flags to determine + how events that do not cross midnight should be printed. + \param holidaysFlags Bitfield consisting of DisplayFlags flags to determine + how holidays should be printed. + */ + void drawMonth( QPainter &p, const QDate &dt, const QRect &box, int maxdays = -1, int subDailyFlags = TimeBoxes, int holidaysFlags = Text ); + + /** + Internal class representing the start of a todo. + */ + class TodoParentStart; + + /** + Draws single to-do and its (intented) sub-to-dos, optionally connects them by a tree-like line, and optionally shows due date, summary, description and priority. + \param count The number of the currently printed to-do (count will be incremented for each to-do drawn) + \param todo The to-do to be printed. It's sub-to-dos are recursively drawn, so drawTodo should only be called on the to-dos of the highest level. + \param p QPainter of the printout + \param sortField Specifies on which attribute of the todo you want to sort. + \param sortDir Specifies if you want to sort ascending or descending. + \param connectSubTodos Whether sub-to-dos shall be connected with their parent by a line (tree-like). + \param strikeoutCompleted Whether completed to-dos should be printed with strike-out summaries. + \param desc Whether to print the whole description of the to-do (the summary is always printed). + \param posPriority x-coordinate where the priority is supposed to be printed. If <0, no priority will be printed. + \param posSummary x-coordinate where the summary of the to-do is supposed to be printed. + \param posDueDt x-coordinate where the due date is supposed to the be printed. If <0, no due date will be printed. + \param posPercentComplete x-coordinate where the percentage complete is supposed to be printed. If <0, percentage complete will not be printed. + \param level Level of the current to-do in the to-do hierarchy (0 means highest level of printed to-dos, 1 are their sub-to-dos, etc.) + \param x x-coordinate of the upper left coordinate of the first to-do. + \param y y-coordinate of the upper left coordinate of the first to-do. + \param width width of the whole to-do list. + \param pageHeight Total height allowed for the to-do list on a page. If an to-do would be below that line, a new page is started. + \param todoList Contains a list of sub-todos for the specified @p todo . + \param r Internal (used when printing sub-to-dos to give information about its parent) + */ + void drawTodo( int &count, Todo *todo, QPainter &p, + TodoSortField sortField, SortDirection sortDir, + bool connectSubTodos, bool strikeoutCompleted, bool desc, + int posPriority, int posSummary, int posDueDt, + int posPercentComplete, int level, int x, int &y, + int width, int pageHeight, + const Todo::List &todoList, TodoParentStart *r = 0 ); + + /** + Draws single journal item. + \param journal The item to be printed. + \param p QPainter of the printout + \param x x-coordinate of the upper left coordinate of the first item + \param y y-coordinate of the upper left coordinate of the first item + \param width width of the whole list + \param pageHeight Total height allowed for the list on a page. If an item + would be below that line, a new page is started. + */ + void drawJournal( Journal * journal, QPainter &p, int x, int &y, + int width, int pageHeight ); + void drawJournalField( QPainter &p, QString field, QString text, + int x, int &y, int width, int pageHeight ); + + void drawSplitHeaderRight( QPainter &p, const QDate &fd, const QDate &td, + const QDate &cd, int width, int height ); + + + protected: + void drawIncidence( QPainter &p, const QRect &dayBox, const QString &time, + const QString &summary, int &textY ); + + protected: + bool mUseColors; + int mHeaderHeight; + int mSubHeaderHeight; + int mMargin; + int mPadding; + int mBorder; + const KCalendarSystem *mCalSys; + + public: +}; + +#endif + +#endif diff --git a/korganizer/printing/calprinttodoconfig_base.ui b/korganizer/printing/calprinttodoconfig_base.ui new file mode 100644 index 000000000..53fd3bfba --- /dev/null +++ b/korganizer/printing/calprinttodoconfig_base.ui @@ -0,0 +1,455 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintTodoConfig_Base</class> +<comment>Configuration page for the print day mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintTodoConfig_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>410</width> + <height>459</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>mTitleLabel</cstring> + </property> + <property name="text"> + <string>&Title:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mTitle</cstring> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>mTitle</cstring> + </property> + <property name="text"> + <string>To-do List</string> + </property> + </widget> + <widget class="QButtonGroup" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>mPrintType</cstring> + </property> + <property name="title"> + <string>To-dos to Print</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mPrintAll</cstring> + </property> + <property name="text"> + <string>Print &all to-dos</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mPrintUnfinished</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Print &unfinished to-dos only</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mPrintDueRange</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Print only to-dos due in the &range:</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>mFromDateLabel</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Start date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromDate</cstring> + </property> + </widget> + <widget class="KDateEdit"> + <property name="name"> + <cstring>mFromDate</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>End date</i> option. This option is used to define the start date.</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>mToDateLabel</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&End date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToDate</cstring> + </property> + </widget> + <widget class="KDateEdit"> + <property name="name"> + <cstring>mToDate</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>Start date</i> option. This option is used to define the end date.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QButtonGroup" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>includeInfoBox</cstring> + </property> + <property name="title"> + <string>Include Information</string> + </property> + <property name="checkable"> + <bool>false</bool> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>mPriority</cstring> + </property> + <property name="text"> + <string>&Priority</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>mDescription</cstring> + </property> + <property name="text"> + <string>&Description</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>mDueDate</cstring> + </property> + <property name="text"> + <string>Due date</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox" row="1" column="1"> + <property name="name"> + <cstring>mPercentComplete</cstring> + </property> + <property name="text"> + <string>Per&centage completed</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + <spacer row="5" column="1"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QGroupBox" row="3" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>sortingOptionsBox</cstring> + </property> + <property name="title"> + <string>Sorting Options</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>sortFieldLabel</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Sort field:</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="1"> + <property name="name"> + <cstring>mSortField</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>sortDirectionLabel</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Sort direction:</string> + </property> + </widget> + <widget class="QComboBox" row="1" column="1"> + <property name="name"> + <cstring>mSortDirection</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + <spacer row="0" column="2"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>121</width> + <height>20</height> + </size> + </property> + </spacer> + <spacer row="1" column="2"> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>121</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QButtonGroup" row="4" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>otherOptionsBox</cstring> + </property> + <property name="title"> + <string>Other Options</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mConnectSubTodos</cstring> + </property> + <property name="text"> + <string>Co&nnect sub-to-dos with its parent</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mStrikeOutCompleted</cstring> + </property> + <property name="text"> + <string>Strike &out completed to-do summaries</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>mPrintDueRange</sender> + <signal>toggled(bool)</signal> + <receiver>mFromDateLabel</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>mPrintDueRange</sender> + <signal>toggled(bool)</signal> + <receiver>mFromDate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>mPrintDueRange</sender> + <signal>toggled(bool)</signal> + <receiver>mToDate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>mPrintDueRange</sender> + <signal>toggled(bool)</signal> + <receiver>mToDateLabel</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>mTitle</tabstop> + <tabstop>mPrintAll</tabstop> + <tabstop>mFromDate</tabstop> + <tabstop>mToDate</tabstop> + <tabstop>mDescription</tabstop> + <tabstop>mDueDate</tabstop> + <tabstop>mPriority</tabstop> + <tabstop>mPercentComplete</tabstop> + <tabstop>mSortField</tabstop> + <tabstop>mSortDirection</tabstop> + <tabstop>mConnectSubTodos</tabstop> + <tabstop>mStrikeOutCompleted</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">kdateedit.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>libkdepim/kdateedit.h</includehint> + <includehint>libkdepim/kdateedit.h</includehint> +</includehints> +</UI> diff --git a/korganizer/printing/calprintweekconfig_base.ui b/korganizer/printing/calprintweekconfig_base.ui new file mode 100644 index 000000000..a14013cee --- /dev/null +++ b/korganizer/printing/calprintweekconfig_base.ui @@ -0,0 +1,300 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintWeekConfig_Base</class> +<comment>Configuration page for the print week mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintWeek_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>386</width> + <height>262</height> + </rect> + </property> + <property name="caption"> + <string>CalPrintWeek_Base</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <spacer row="4" column="0"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>27</height> + </size> + </property> + </spacer> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>mDateRangeGroup</cstring> + </property> + <property name="title"> + <string>Date && Time Range</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="0" column="4"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>mFromDateLabel</cstring> + </property> + <property name="text"> + <string>&Start date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromDate</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can choose which events should be printed based on their date. This check enables you to enter the start date of the date range. Use the <i>End date</i> to enter the end date of the daterange.</string> + </property> + </widget> + <widget class="KDateEdit" row="0" column="1"> + <property name="name"> + <cstring>mFromDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can choose which events should be printed based on their date. This check enables you to enter the start date of the date range. Use the <i>End date</i> to enter the end date of the daterange.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>mToTimeLabel</cstring> + </property> + <property name="text"> + <string>End ti&me:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToTime</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>All events which start later than the given time will not be printed.</string> + </property> + </widget> + <spacer row="1" column="4"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>110</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QTimeEdit" row="1" column="3"> + <property name="name"> + <cstring>mToTime</cstring> + </property> + <property name="time"> + <time> + <hour>18</hour> + <minute>0</minute> + <second>0</second> + </time> + </property> + <property name="display"> + <set>Minutes|Hours</set> + </property> + <property name="whatsThis" stdset="0"> + <string>All events which start later than the given time will not be printed.</string> + </property> + </widget> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>mFromTimeLabel</cstring> + </property> + <property name="text"> + <string>Start &time:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromTime</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>All events which start earlier than the given time will not be printed.</string> + </property> + </widget> + <widget class="QTimeEdit" row="0" column="3"> + <property name="name"> + <cstring>mFromTime</cstring> + </property> + <property name="time"> + <time> + <hour>8</hour> + <minute>0</minute> + <second>0</second> + </time> + </property> + <property name="display"> + <set>Minutes|Hours</set> + </property> + <property name="whatsThis" stdset="0"> + <string>All events which start earlier than the given time will not be printed.</string> + </property> + </widget> + <widget class="KDateEdit" row="1" column="1"> + <property name="name"> + <cstring>mToDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can choose which events should be printed based on their date. This check enables you to enter the end date of the date range. Use the <i>Start date</i> to enter the start date of the daterange.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>mToDateLabel</cstring> + </property> + <property name="text"> + <string>&End date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToDate</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can choose which events should be printed based on their date. This check enables you to enter the end date of the date range. Use the <i>Start date</i> to enter the start date of the daterange.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox" row="3" column="0"> + <property name="name"> + <cstring>mColors</cstring> + </property> + <property name="text"> + <string>&Use colors</string> + </property> + <property name="whatsThis" stdset="0"> + <string>The timetable view supports colors. If you want to make use of colors you should check this option. The category colors will be used.</string> + </property> + </widget> + <widget class="QButtonGroup" row="1" column="0"> + <property name="name"> + <cstring>mPrintType</cstring> + </property> + <property name="title"> + <string>Print Layout</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>mPrintTypeButton1</cstring> + </property> + <property name="text"> + <string>Print as &Filofax page</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="whatsThis" stdset="0"> + <string>The Filofax view prints one week per page, so all days have a large surface.</string> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>mPrintTypeButton2</cstring> + </property> + <property name="text"> + <string>Print as &timetable view</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This view is similar to the weekview in KOrganizer. The week is printed in landscape layout. You can even use the same colors for the items if you check <i>Use Colors</i>.</string> + </property> + </widget> + <widget class="QRadioButton" row="2" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>mPrintTypeButton3</cstring> + </property> + <property name="text"> + <string>Print as split week view</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This view is similar to the week view in KOrganizer. The only difference with the timetable view is the page layout. Timetables are printed in landscape, the split week view in portrait.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox" row="2" column="0"> + <property name="name"> + <cstring>mIncludeTodos</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Include to-&dos that are due on the printed day(s)</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this option if you want to have to-dos on the print, placed by their due date.</string> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>mFromDate</tabstop> + <tabstop>mFromTime</tabstop> + <tabstop>mToDate</tabstop> + <tabstop>mToTime</tabstop> + <tabstop>mPrintTypeButton1</tabstop> + <tabstop>mIncludeTodos</tabstop> + <tabstop>mColors</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">kdateedit.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>libkdepim/kdateedit.h</includehint> + <includehint>libkdepim/kdateedit.h</includehint> +</includehints> +</UI> diff --git a/korganizer/printing/cellitem.cpp b/korganizer/printing/cellitem.cpp new file mode 100644 index 000000000..67e52c58e --- /dev/null +++ b/korganizer/printing/cellitem.cpp @@ -0,0 +1,98 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "cellitem.h" + +#include <klocale.h> +#include <kdebug.h> + +#include <qintdict.h> + +using namespace KOrg; + +QString CellItem::label() const +{ + return i18n("<undefined>"); +} + +QPtrList<CellItem> CellItem::placeItem( QPtrList<CellItem> cells, + CellItem *placeItem ) +{ + kdDebug(5855) << "Placing " << placeItem->label() << endl; + + QPtrList<KOrg::CellItem> conflictItems; + int maxSubCells = 0; + QIntDict<KOrg::CellItem> subCellDict; + + // Find all items which are in same cell + QPtrListIterator<KOrg::CellItem> it2( cells ); + for( it2.toFirst(); it2.current(); ++it2 ) { + KOrg::CellItem *item = it2.current(); + if ( item == placeItem ) continue; + + if ( item->overlaps( placeItem ) ) { + kdDebug(5855) << " Overlaps: " << item->label() << endl; + + conflictItems.append( item ); + if ( item->subCells() > maxSubCells ) maxSubCells = item->subCells(); + subCellDict.insert( item->subCell(), item ); + } + } + + if ( conflictItems.count() > 0 ) { + // Look for unused sub cell and insert item + int i; + for( i = 0; i < maxSubCells; ++i ) { + kdDebug(5855) << " Trying subcell " << i << endl; + if ( !subCellDict.find( i ) ) { + kdDebug(5855) << " Use subcell " << i << endl; + placeItem->setSubCell( i ); + break; + } + } + if ( i == maxSubCells ) { + kdDebug(5855) << " New subcell " << i << endl; + placeItem->setSubCell( maxSubCells ); + maxSubCells++; // add new item to number of sub cells + } + + kdDebug(5855) << " Sub cells: " << maxSubCells << endl; + + // Write results to item to be placed + conflictItems.append( placeItem ); + placeItem->setSubCells( maxSubCells ); + + QPtrListIterator<KOrg::CellItem> it3( conflictItems ); + for( it3.toFirst(); it3.current(); ++it3 ) { + (*it3)->setSubCells( maxSubCells ); + } + // Todo: Adapt subCells of items conflicting with conflicting items + } else { + kdDebug(5855) << " no conflicts" << endl; + placeItem->setSubCell( 0 ); + placeItem->setSubCells( 1 ); + } + + return conflictItems; +} diff --git a/korganizer/printing/cellitem.h b/korganizer/printing/cellitem.h new file mode 100644 index 000000000..fa708147e --- /dev/null +++ b/korganizer/printing/cellitem.h @@ -0,0 +1,68 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORG_CELLITEM_H +#define KORG_CELLITEM_H + +#include <qstring.h> +#include <qptrlist.h> + +#include <kdepimmacros.h> + +namespace KOrg { + +class KDE_EXPORT CellItem +{ + public: + CellItem() + : mSubCells( 0 ), mSubCell( -1 ) + { + } + + void setSubCells( int v ) { mSubCells = v; } + int subCells() const { return mSubCells; } + + void setSubCell( int v ) { mSubCell = v; } + int subCell() const { return mSubCell; } + + virtual bool overlaps( CellItem *other ) const = 0; + + virtual QString label() const; + + /** + Place item \arg placeItem into stripe containing items \arg cells in a + way that items don't overlap. + + \return Placed items + */ + static QPtrList<CellItem> placeItem( QPtrList<CellItem> cells, + CellItem *placeItem ); + + private: + int mSubCells; + int mSubCell; +}; + +} + +#endif |