summaryrefslogtreecommitdiffstats
path: root/korganizer/printing/calprintpluginbase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'korganizer/printing/calprintpluginbase.cpp')
-rw-r--r--korganizer/printing/calprintpluginbase.cpp1674
1 files changed, 1674 insertions, 0 deletions
diff --git a/korganizer/printing/calprintpluginbase.cpp b/korganizer/printing/calprintpluginbase.cpp
new file mode 100644
index 00000000..44739db4
--- /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