korganizer

calprintpluginbase.cpp

00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 1998 Preston Brown <pbrown@kde.org>
00005     Copyright (c) 2003 Reinhold Kainhofer <reinhold@kainhofer.com>
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020 
00021     As a special exception, permission is given to link this program
00022     with any edition of Qt, and distribute the resulting executable,
00023     without including the source code for Qt in the source distribution.
00024 */
00025 
00026 #include <qpainter.h>
00027 #include <qlayout.h>
00028 #include <qframe.h>
00029 #include <qlabel.h>
00030 
00031 #include <kdebug.h>
00032 #include <kconfig.h>
00033 #include <kcalendarsystem.h>
00034 #include <kwordwrap.h>
00035 
00036 #include "calprintpluginbase.h"
00037 #include "cellitem.h"
00038 
00039 #ifndef KORG_NOPRINTER
00040 
00041 inline int round(const double x)
00042 {
00043   return int(x > 0.0 ? x + 0.5 : x - 0.5);
00044 }
00045 
00046 static QString cleanStr( const QString &instr )
00047 {
00048   QString ret = instr;
00049   return ret.replace( '\n', ' ' );
00050 }
00051 
00052 /******************************************************************
00053  **              The Todo positioning structure                  **
00054  ******************************************************************/
00055 class CalPrintPluginBase::TodoParentStart
00056 {
00057   public:
00058     TodoParentStart( QRect pt = QRect(), bool page = true )
00059       : mRect( pt ), mSamePage( page ) {}
00060 
00061     QRect mRect;
00062     bool mSamePage;
00063 };
00064 
00065 
00066 /******************************************************************
00067  **                     The Print item                           **
00068  ******************************************************************/
00069 
00070 
00071 class PrintCellItem : public KOrg::CellItem
00072 {
00073   public:
00074     PrintCellItem( Event *event, const QDateTime &start, const QDateTime &end )
00075       : mEvent( event ), mStart( start), mEnd( end )
00076     {
00077     }
00078 
00079     Event *event() const { return mEvent; }
00080 
00081     QString label() const { return mEvent->summary(); }
00082 
00083     QDateTime start() const { return mStart; }
00084     QDateTime end() const { return mEnd; }
00085 
00088     bool overlaps( KOrg::CellItem *o ) const
00089     {
00090       PrintCellItem *other = static_cast<PrintCellItem *>( o );
00091 
00092 #if 0
00093       kdDebug(5850) << "PrintCellItem::overlaps() " << event()->summary()
00094                     << " <-> " << other->event()->summary() << endl;
00095       kdDebug(5850) << "  start     : " << start.toString() << endl;
00096       kdDebug(5850) << "  end       : " << end.toString() << endl;
00097       kdDebug(5850) << "  otherStart: " << otherStart.toString() << endl;
00098       kdDebug(5850) << "  otherEnd  : " << otherEnd.toString() << endl;
00099 #endif
00100 
00101       return !( other->start() >= end() || other->end() <= start() );
00102     }
00103 
00104   private:
00105     Event *mEvent;
00106     QDateTime mStart, mEnd;
00107 };
00108 
00109 
00110 
00111 
00112 /******************************************************************
00113  **                    The Print plugin                          **
00114  ******************************************************************/
00115 
00116 
00117 CalPrintPluginBase::CalPrintPluginBase() : PrintPlugin(), mUseColors( true ),
00118     mHeaderHeight( -1 ), mSubHeaderHeight( SUBHEADER_HEIGHT ), mFooterHeight( -1 ),
00119     mMargin( MARGIN_SIZE ), mPadding( PADDING_SIZE), mCalSys( 0 )
00120 {
00121 }
00122 CalPrintPluginBase::~CalPrintPluginBase()
00123 {
00124 }
00125 
00126 
00127 
00128 QWidget *CalPrintPluginBase::createConfigWidget( QWidget *w )
00129 {
00130   QFrame *wdg = new QFrame( w );
00131   QVBoxLayout *layout = new QVBoxLayout( wdg );
00132 
00133   QLabel *title = new QLabel( description(), wdg );
00134   QFont titleFont( title->font() );
00135   titleFont.setPointSize( 20 );
00136   titleFont.setBold( true );
00137   title->setFont( titleFont );
00138 
00139   layout->addWidget( title );
00140   layout->addWidget( new QLabel( info(), wdg ) );
00141   layout->addSpacing( 20 );
00142   layout->addWidget( new QLabel( i18n("This printing style does not "
00143                                       "have any configuration options."),
00144                                  wdg ) );
00145   layout->addStretch();
00146   return wdg;
00147 }
00148 
00149 void CalPrintPluginBase::doPrint( KPrinter *printer )
00150 {
00151   if ( !printer ) return;
00152   mPrinter = printer;
00153   QPainter p;
00154 
00155   mPrinter->setColorMode( mUseColors?(KPrinter::Color):(KPrinter::GrayScale) );
00156 
00157   p.begin( mPrinter );
00158   // TODO: Fix the margins!!!
00159   // the painter initially begins at 72 dpi per the Qt docs.
00160   // we want half-inch margins.
00161   int margins = margin();
00162   p.setViewport( margins, margins,
00163                  p.viewport().width() - 2*margins,
00164                  p.viewport().height() - 2*margins );
00165 //   QRect vp( p.viewport() );
00166 // vp.setRight( vp.right()*2 );
00167 // vp.setBottom( vp.bottom()*2 );
00168 //   p.setWindow( vp );
00169   int pageWidth = p.window().width();
00170   int pageHeight = p.window().height();
00171 //   int pageWidth = p.viewport().width();
00172 //   int pageHeight = p.viewport().height();
00173 
00174   print( p, pageWidth, pageHeight );
00175 
00176   p.end();
00177   mPrinter = 0;
00178 }
00179 
00180 void CalPrintPluginBase::doLoadConfig()
00181 {
00182   if ( mConfig ) {
00183     KConfigGroupSaver saver( mConfig, description() );
00184     mConfig->sync();
00185     QDateTime currDate( QDate::currentDate() );
00186     mFromDate = mConfig->readDateTimeEntry( "FromDate", &currDate ).date();
00187     mToDate = mConfig->readDateTimeEntry( "ToDate" ).date();
00188     mUseColors = mConfig->readBoolEntry( "UseColors", true );
00189     setUseColors( mUseColors );
00190     loadConfig();
00191   } else {
00192     kdDebug(5850) << "No config available in loadConfig!!!!" << endl;
00193   }
00194 }
00195 
00196 void CalPrintPluginBase::doSaveConfig()
00197 {
00198   if ( mConfig ) {
00199     KConfigGroupSaver saver( mConfig, description() );
00200     saveConfig();
00201     mConfig->writeEntry( "FromDate", QDateTime( mFromDate ) );
00202     mConfig->writeEntry( "ToDate", QDateTime( mToDate ) );
00203     mConfig->writeEntry( "UseColors", mUseColors );
00204     mConfig->sync();
00205   } else {
00206     kdDebug(5850) << "No config available in saveConfig!!!!" << endl;
00207   }
00208 }
00209 
00210 
00211 
00212 
00213 void CalPrintPluginBase::setKOrgCoreHelper( KOrg::CoreHelper*helper )
00214 {
00215   PrintPlugin::setKOrgCoreHelper( helper );
00216   if ( helper )
00217     setCalendarSystem( helper->calendarSystem() );
00218 }
00219 
00220 bool CalPrintPluginBase::useColors() const
00221 {
00222   return mUseColors;
00223 }
00224 void CalPrintPluginBase::setUseColors( bool useColors )
00225 {
00226   mUseColors = useColors;
00227 }
00228 
00229 KPrinter::Orientation CalPrintPluginBase::orientation() const
00230 {
00231   return (mPrinter)?(mPrinter->orientation()):(KPrinter::Portrait);
00232 }
00233 
00234 
00235 
00236 QTime CalPrintPluginBase::dayStart()
00237 {
00238   QTime start( 8,0,0 );
00239   if ( mCoreHelper ) start = mCoreHelper->dayStart();
00240   return start;
00241 }
00242 
00243 void CalPrintPluginBase::setCategoryColors( QPainter &p, Incidence *incidence )
00244 {
00245   QColor bgColor = categoryBgColor( incidence );
00246   if ( bgColor.isValid() )
00247     p.setBrush( bgColor );
00248   QColor tColor( textColor( bgColor ) );
00249   if ( tColor.isValid() )
00250     p.setPen( tColor );
00251 }
00252 
00253 QColor CalPrintPluginBase::categoryBgColor( Incidence *incidence )
00254 {
00255   if (mCoreHelper && incidence)
00256     return mCoreHelper->categoryColor( incidence->categories() );
00257   else
00258     return QColor();
00259 }
00260 
00261 QColor CalPrintPluginBase::textColor( const QColor &color )
00262 {
00263   return (mCoreHelper)?(mCoreHelper->textColor( color )):QColor();
00264 }
00265 
00266 bool CalPrintPluginBase::isWorkingDay( const QDate &dt )
00267 {
00268   return (mCoreHelper)?( mCoreHelper->isWorkingDay( dt ) ):true;
00269 }
00270 
00271 QString CalPrintPluginBase::holidayString( const QDate &dt )
00272 {
00273   return (mCoreHelper)?(mCoreHelper->holidayString(dt)):(QString::null);
00274 }
00275 
00276 
00277 Event *CalPrintPluginBase::holiday( const QDate &dt )
00278 {
00279   QString hstring( holidayString( dt ) );
00280   if ( !hstring.isEmpty() ) {
00281     Event*holiday=new Event();
00282     holiday->setSummary( hstring );
00283     holiday->setDtStart( dt );
00284     holiday->setDtEnd( dt );
00285     holiday->setFloats( true );
00286     holiday->setCategories( i18n("Holiday") );
00287     return holiday;
00288   }
00289   return 0;
00290 }
00291 
00292 const KCalendarSystem *CalPrintPluginBase::calendarSystem() const
00293 {
00294   return mCalSys;
00295 }
00296 void CalPrintPluginBase::setCalendarSystem( const KCalendarSystem *calsys )
00297 {
00298   mCalSys = calsys;
00299 }
00300 
00301 int CalPrintPluginBase::headerHeight() const
00302 {
00303   if ( mHeaderHeight >= 0 )
00304     return mHeaderHeight;
00305   else if ( orientation() == KPrinter::Portrait )
00306     return PORTRAIT_HEADER_HEIGHT;
00307   else
00308     return LANDSCAPE_HEADER_HEIGHT;
00309 }
00310 void CalPrintPluginBase::setHeaderHeight( const int height )
00311 {
00312   mHeaderHeight = height;
00313 }
00314 
00315 int CalPrintPluginBase::subHeaderHeight() const
00316 {
00317   return mSubHeaderHeight;
00318 }
00319 void CalPrintPluginBase::setSubHeaderHeight( const int height )
00320 {
00321   mSubHeaderHeight = height;
00322 }
00323 
00324 int CalPrintPluginBase::footerHeight() const
00325 {
00326   if ( mFooterHeight >= 0 )
00327     return mFooterHeight;
00328   else if ( orientation() == KPrinter::Portrait )
00329     return PORTRAIT_FOOTER_HEIGHT;
00330   else
00331     return LANDSCAPE_FOOTER_HEIGHT;
00332 }
00333 void CalPrintPluginBase::setFooterHeight( const int height )
00334 {
00335   mFooterHeight = height;
00336 }
00337 
00338 int CalPrintPluginBase::margin() const
00339 {
00340   return mMargin;
00341 }
00342 void CalPrintPluginBase::setMargin( const int margin )
00343 {
00344   mMargin = margin;
00345 }
00346 
00347 int CalPrintPluginBase::padding() const
00348 {
00349   return mPadding;
00350 }
00351 void CalPrintPluginBase::setPadding( const int padding )
00352 {
00353   mPadding = padding;
00354 }
00355 
00356 int CalPrintPluginBase::borderWidth() const
00357 {
00358   return mBorder;
00359 }
00360 void CalPrintPluginBase::setBorderWidth( const int borderwidth )
00361 {
00362   mBorder = borderwidth;
00363 }
00364 
00365 
00366 
00367 
00368 void CalPrintPluginBase::drawBox( QPainter &p, int linewidth, const QRect &rect )
00369 {
00370   QPen pen( p.pen() );
00371   QPen oldpen( pen );
00372   pen.setWidth( linewidth );
00373   p.setPen( pen );
00374   p.drawRect( rect );
00375   p.setPen( oldpen );
00376 }
00377 
00378 void CalPrintPluginBase::drawShadedBox( QPainter &p, int linewidth, const QBrush &brush, const QRect &rect )
00379 {
00380   QBrush oldbrush( p.brush() );
00381   p.setBrush( brush );
00382   drawBox( p, linewidth, rect );
00383   p.setBrush( oldbrush );
00384 }
00385 
00386 void CalPrintPluginBase::printEventString( QPainter &p, const QRect &box, const QString &str, int flags )
00387 {
00388   QRect newbox( box );
00389   newbox.addCoords( 3, 1, -1, -1 );
00390   p.drawText( newbox, (flags==-1)?(Qt::AlignTop | Qt::AlignJustify | Qt::BreakAnywhere):flags, str );
00391 }
00392 
00393 
00394 void CalPrintPluginBase::showEventBox( QPainter &p, int linewidth, const QRect &box,
00395                                        Incidence *incidence, const QString &str, int flags )
00396 {
00397   QPen oldpen( p.pen() );
00398   QBrush oldbrush( p.brush() );
00399   QColor bgColor( categoryBgColor( incidence ) );
00400   if ( mUseColors & bgColor.isValid() ) {
00401     p.setBrush( bgColor );
00402   } else {
00403     p.setBrush( QColor( 232, 232, 232 ) );
00404   }
00405   drawBox( p, ( linewidth > 0 ) ? linewidth : EVENT_BORDER_WIDTH, box );
00406 
00407   if ( mUseColors && bgColor.isValid() ) {
00408     p.setPen( textColor( bgColor ) );
00409   }
00410   printEventString( p, box, str, flags );
00411   p.setPen( oldpen );
00412   p.setBrush( oldbrush );
00413 }
00414 
00415 
00416 void CalPrintPluginBase::drawSubHeaderBox(QPainter &p, const QString &str, const QRect &box )
00417 {
00418   drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), box );
00419   QFont oldfont( p.font() );
00420   p.setFont( QFont( "sans-serif", 10, QFont::Bold ) );
00421   p.drawText( box, Qt::AlignCenter | Qt::AlignVCenter, str );
00422   p.setFont( oldfont );
00423 }
00424 
00425 void CalPrintPluginBase::drawVerticalBox( QPainter &p, int linewidth, const QRect &box,
00426                                           const QString &str, int flags )
00427 {
00428   p.save();
00429   p.rotate( -90 );
00430   QRect rotatedBox( -box.top()-box.height(), box.left(), box.height(), box.width() );
00431   showEventBox( p, linewidth, rotatedBox, 0, str,
00432                 ( flags == -1 ) ? Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine : flags );
00433 
00434   p.restore();
00435 }
00436 
00437 
00438 
00440 // Return value: If expand, bottom of the printed box, otherwise vertical end
00441 // of the printed contents inside the box.
00442 
00443 int CalPrintPluginBase::drawBoxWithCaption( QPainter &p, const QRect &allbox,
00444         const QString &caption, const QString &contents, bool sameLine, bool expand, const QFont &captionFont, const QFont &textFont )
00445 {
00446   QFont oldFont( p.font() );
00447 //   QFont captionFont( "sans-serif", 11, QFont::Bold );
00448 //   QFont textFont( "sans-serif", 11, QFont::Normal );
00449 //   QFont captionFont( "Tahoma", 11, QFont::Bold );
00450 //   QFont textFont( "Tahoma", 11, QFont::Normal );
00451 
00452 
00453   QRect box( allbox );
00454 
00455   // Bounding rectangle for caption, single-line, clip on the right
00456   QRect captionBox( box.left() + padding(), box.top() + padding(), 0, 0 );
00457   p.setFont( captionFont );
00458   captionBox = p.boundingRect( captionBox, Qt::AlignLeft | Qt::AlignTop | Qt::SingleLine, caption );
00459   p.setFont( oldFont );
00460   if ( captionBox.right() > box.right() )
00461     captionBox.setRight( box.right() );
00462   if ( expand && captionBox.bottom() + padding() > box.bottom() )
00463     box.setBottom( captionBox.bottom() + padding() );
00464 
00465   // Bounding rectangle for the contents (if any), word break, clip on the bottom
00466   QRect textBox( captionBox );
00467   if ( !contents.isEmpty() ) {
00468     if ( sameLine ) {
00469       textBox.setLeft( captionBox.right() + padding() );
00470     } else {
00471       textBox.setTop( captionBox.bottom() + padding() );
00472     }
00473     textBox.setRight( box.right() );
00474     textBox.setHeight( 0 );
00475     p.setFont( textFont );
00476     textBox = p.boundingRect( textBox, Qt::WordBreak | Qt::AlignTop | Qt::AlignLeft, contents );
00477     p.setFont( oldFont );
00478     if ( textBox.bottom() + padding() > box.bottom() ) {
00479       if ( expand ) {
00480         box.setBottom( textBox.bottom() + padding() );
00481       } else {
00482         textBox.setBottom( box.bottom() );
00483       }
00484     }
00485   }
00486 
00487   drawBox( p, BOX_BORDER_WIDTH, box );
00488   p.setFont( captionFont );
00489   p.drawText( captionBox, Qt::AlignLeft | Qt::AlignTop | Qt::SingleLine, caption );
00490   if ( !contents.isEmpty() ) {
00491     p.setFont( textFont );
00492     p.drawText( textBox, Qt::WordBreak | Qt::AlignTop | Qt::AlignLeft, contents );
00493   }
00494   p.setFont( oldFont );
00495 
00496   if ( expand ) {
00497     return box.bottom();
00498   } else {
00499     return textBox.bottom();
00500   }
00501 }
00502 
00503 
00505 
00506 int CalPrintPluginBase::drawHeader( QPainter &p, QString title,
00507     const QDate &month1, const QDate &month2, const QRect &allbox, bool expand )
00508 {
00509   // print previous month for month view, print current for to-do, day and week
00510   int smallMonthWidth = (allbox.width()/4) - 10;
00511   if (smallMonthWidth>100) smallMonthWidth=100;
00512 
00513   int right = allbox.right();
00514   if ( month1.isValid() ) right -= (20+smallMonthWidth);
00515   if ( month2.isValid() ) right -= (20+smallMonthWidth);
00516   QRect box( allbox );
00517   QRect textRect( allbox );
00518   textRect.addCoords( 5, 0, 0, 0 );
00519   textRect.setRight( right );
00520 
00521 
00522   QFont oldFont( p.font() );
00523   QFont newFont("sans-serif", (textRect.height()<60)?16:18, QFont::Bold);
00524   if ( expand ) {
00525     p.setFont( newFont );
00526     QRect boundingR = p.boundingRect( textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::WordBreak, title );
00527     p.setFont( oldFont );
00528     int h = boundingR.height();
00529     if ( h > allbox.height() ) {
00530       box.setHeight( h );
00531       textRect.setHeight( h );
00532     }
00533   }
00534 
00535   drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), box );
00536 
00537   QRect monthbox( box.right()-10-smallMonthWidth, box.top(), smallMonthWidth, box.height() );
00538   if (month2.isValid()) {
00539     drawSmallMonth( p, QDate(month2.year(), month2.month(), 1), monthbox );
00540     monthbox.moveBy( -20 - smallMonthWidth, 0 );
00541   }
00542   if (month1.isValid()) {
00543     drawSmallMonth( p, QDate(month1.year(), month1.month(), 1), monthbox );
00544     monthbox.moveBy( -20 - smallMonthWidth, 0 );
00545   }
00546 
00547   // Set the margins
00548   p.setFont( newFont );
00549   p.drawText( textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::WordBreak, title );
00550   p.setFont( oldFont );
00551 
00552   return textRect.bottom();
00553 }
00554 
00555 
00556 int CalPrintPluginBase::drawFooter( QPainter &p, QRect &footbox )
00557 {
00558   QFont oldfont( p.font() );
00559   p.setFont( QFont( "sans-serif", 6 ) );
00560   QFontMetrics fm( p.font() );
00561   QString dateStr = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(), false );
00562   p.drawText( footbox, Qt::AlignCenter | Qt::AlignVCenter | Qt::SingleLine,
00563               i18n( "print date: formatted-datetime", "printed: %1" ).arg( dateStr ) );
00564   p.setFont( oldfont );
00565 
00566   return footbox.bottom();
00567 }
00568 
00569 void CalPrintPluginBase::drawSmallMonth(QPainter &p, const QDate &qd,
00570     const QRect &box )
00571 {
00572 
00573   int weekdayCol = weekdayColumn( qd.dayOfWeek() );
00574   int month = qd.month();
00575   QDate monthDate(QDate(qd.year(), qd.month(), 1));
00576   // correct begin of week
00577   QDate monthDate2( monthDate.addDays( -weekdayCol ) );
00578 
00579   double cellWidth = double(box.width())/double(7);
00580   int rownr = 3 + ( qd.daysInMonth() + weekdayCol - 1 ) / 7;
00581   // 3 Pixel after month name, 2 after day names, 1 after the calendar
00582   double cellHeight = (box.height() - 5) / rownr;
00583   QFont oldFont( p.font() );
00584   p.setFont(QFont("sans-serif", int(cellHeight-1), QFont::Normal));
00585 
00586   // draw the title
00587   if ( mCalSys ) {
00588     QRect titleBox( box );
00589     titleBox.setHeight( int(cellHeight+1) );
00590     p.drawText( titleBox, Qt::AlignTop | Qt::AlignHCenter, mCalSys->monthName( qd ) );
00591   }
00592 
00593   // draw days of week
00594   QRect wdayBox( box );
00595   wdayBox.setTop( int( box.top() + 3 + cellHeight ) );
00596   wdayBox.setHeight( int(2*cellHeight)-int(cellHeight) );
00597 
00598   if ( mCalSys ) {
00599     for (int col = 0; col < 7; ++col) {
00600       QString tmpStr = mCalSys->weekDayName( monthDate2 )[0].upper();
00601       wdayBox.setLeft( int(box.left() + col*cellWidth) );
00602       wdayBox.setRight( int(box.left() + (col+1)*cellWidth) );
00603       p.drawText( wdayBox, Qt::AlignCenter, tmpStr );
00604       monthDate2 = monthDate2.addDays( 1 );
00605     }
00606   }
00607 
00608   // draw separator line
00609   int calStartY = wdayBox.bottom() + 2;
00610   p.drawLine( box.left(), calStartY, box.right(), calStartY );
00611   monthDate = monthDate.addDays( -weekdayCol );
00612 
00613   for ( int row = 0; row < (rownr-2); row++ ) {
00614     for ( int col = 0; col < 7; col++ ) {
00615       if ( monthDate.month() == month ) {
00616         QRect dayRect( int( box.left() + col*cellWidth ), int( calStartY + row*cellHeight ), 0, 0 );
00617         dayRect.setRight( int( box.left() + (col+1)*cellWidth ) );
00618         dayRect.setBottom( int( calStartY + (row+1)*cellHeight ) );
00619         p.drawText( dayRect, Qt::AlignCenter, QString::number( monthDate.day() ) );
00620       }
00621       monthDate = monthDate.addDays(1);
00622     }
00623   }
00624   p.setFont( oldFont );
00625 }
00626 
00627 
00628 
00629 
00630 
00632 
00633 /*
00634  * This routine draws a header box over the main part of the calendar
00635  * containing the days of the week.
00636  */
00637 void CalPrintPluginBase::drawDaysOfWeek(QPainter &p,
00638     const QDate &fromDate, const QDate &toDate, const QRect &box )
00639 {
00640   double cellWidth = double(box.width()) / double(fromDate.daysTo( toDate )+1);
00641   QDate cellDate( fromDate );
00642   QRect dateBox( box );
00643   int i = 0;
00644 
00645   while ( cellDate <= toDate ) {
00646     dateBox.setLeft( box.left() + int(i*cellWidth) );
00647     dateBox.setRight( box.left() + int((i+1)*cellWidth) );
00648     drawDaysOfWeekBox(p, cellDate, dateBox );
00649     cellDate = cellDate.addDays(1);
00650     i++;
00651   }
00652 }
00653 
00654 
00655 void CalPrintPluginBase::drawDaysOfWeekBox(QPainter &p, const QDate &qd,
00656     const QRect &box )
00657 {
00658   drawSubHeaderBox( p, (mCalSys)?(mCalSys->weekDayName( qd )):(QString::null), box );
00659 }
00660 
00661 
00662 void CalPrintPluginBase::drawTimeLine( QPainter &p, const QTime &fromTime,
00663                                        const QTime &toTime, const QRect &box )
00664 {
00665   drawBox( p, BOX_BORDER_WIDTH, box );
00666 
00667   int totalsecs = fromTime.secsTo( toTime );
00668   float minlen = (float)box.height() * 60. / (float)totalsecs;
00669   float cellHeight = ( 60. * (float)minlen );
00670   float currY = box.top();
00671   // TODO: Don't use half of the width, but less, for the minutes!
00672   int xcenter = box.left() + box.width() / 2;
00673 
00674   QTime curTime( fromTime );
00675   QTime endTime( toTime );
00676   if ( fromTime.minute() > 30 ) {
00677     curTime = QTime( fromTime.hour()+1, 0, 0 );
00678   } else if ( fromTime.minute() > 0 ) {
00679     curTime = QTime( fromTime.hour(), 30, 0 );
00680     float yy = currY + minlen * (float)fromTime.secsTo( curTime ) / 60.;
00681     p.drawLine( xcenter, (int)yy, box.right(), (int)yy );
00682     curTime = QTime( fromTime.hour() + 1, 0, 0 );
00683   }
00684   currY += ( float( fromTime.secsTo( curTime ) * minlen ) / 60. );
00685 
00686   while ( curTime < endTime ) {
00687     p.drawLine( box.left(), (int)currY, box.right(), (int)currY );
00688     int newY = (int)( currY + cellHeight / 2. );
00689     QString numStr;
00690     if ( newY < box.bottom() ) {
00691       QFont oldFont( p.font() );
00692       // draw the time:
00693       if ( !KGlobal::locale()->use12Clock() ) {
00694         p.drawLine( xcenter, (int)newY, box.right(), (int)newY );
00695         numStr.setNum( curTime.hour() );
00696         if  ( cellHeight > 30 ) {
00697           p.setFont( QFont( "sans-serif", 14, QFont::Bold ) );
00698         } else {
00699           p.setFont( QFont( "sans-serif", 12, QFont::Bold ) );
00700         }
00701         p.drawText( box.left() + 4, (int)currY + 2, box.width() / 2 - 2, (int)cellHeight,
00702                     Qt::AlignTop | Qt::AlignRight, numStr );
00703         p.setFont( QFont ( "helvetica", 10, QFont::Normal ) );
00704         p.drawText( xcenter + 4, (int)currY + 2, box.width() / 2 + 2, (int)(cellHeight / 2 ) - 3,
00705                     Qt::AlignTop | Qt::AlignLeft, "00" );
00706       } else {
00707         p.drawLine( box.left(), (int)newY, box.right(), (int)newY );
00708         QTime time( curTime.hour(), 0 );
00709         numStr = KGlobal::locale()->formatTime( time );
00710         if ( box.width() < 60 ) {
00711           p.setFont( QFont( "sans-serif", 7, QFont::Bold ) ); // for weekprint
00712         } else {
00713           p.setFont( QFont( "sans-serif", 12, QFont::Bold ) ); // for dayprint
00714         }
00715         p.drawText( box.left() + 2, (int)currY + 2, box.width() - 4, (int)cellHeight / 2 - 3,
00716                     Qt::AlignTop|Qt::AlignLeft, numStr );
00717       }
00718       currY += cellHeight;
00719       p.setFont( oldFont );
00720     } // enough space for half-hour line and time
00721     if ( curTime.secsTo( endTime ) > 3600 ) {
00722       curTime = curTime.addSecs( 3600 );
00723     } else {
00724       curTime = endTime;
00725     }
00726   } // currTime<endTime
00727 }
00728 
00735 int CalPrintPluginBase::drawAllDayBox(QPainter &p, Event::List &eventList,
00736     const QDate &qd, bool expandable, const QRect &box )
00737 {
00738   Event::List::Iterator it, itold;
00739 
00740   int offset=box.top();
00741 
00742   QString multiDayStr;
00743 
00744   Event*hd = holiday( qd );
00745   if ( hd ) eventList.prepend( hd );
00746 
00747   it = eventList.begin();
00748   Event *currEvent = 0;
00749   // First, print all floating events
00750   while( it!=eventList.end() ) {
00751     currEvent=*it;
00752     itold=it;
00753     ++it;
00754     if ( currEvent && currEvent->doesFloat() ) {
00755       // set the colors according to the categories
00756       if ( expandable ) {
00757         QRect eventBox( box );
00758         eventBox.setTop( offset );
00759         showEventBox( p, EVENT_BORDER_WIDTH, eventBox, currEvent, currEvent->summary() );
00760         offset += box.height();
00761       } else {
00762         if ( !multiDayStr.isEmpty() ) multiDayStr += ", ";
00763         multiDayStr += currEvent->summary();
00764       }
00765       eventList.remove( itold );
00766     }
00767   }
00768   if ( hd ) delete hd;
00769 
00770   int ret = box.height();
00771   QRect eventBox( box );
00772   if (!expandable) {
00773     if (!multiDayStr.isEmpty()) {
00774       drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 128, 128, 128 ), eventBox );
00775       printEventString( p, eventBox, multiDayStr );
00776     } else {
00777       drawBox( p, BOX_BORDER_WIDTH, eventBox );
00778     }
00779   } else {
00780     ret = offset - box.top();
00781     eventBox.setBottom( ret );
00782     drawBox( p, BOX_BORDER_WIDTH, eventBox );
00783   }
00784   return ret;
00785 }
00786 
00787 
00788 void CalPrintPluginBase::drawAgendaDayBox( QPainter &p, Event::List &events,
00789                                      const QDate &qd, bool expandable,
00790                                      QTime &fromTime, QTime &toTime,
00791                                      const QRect &oldbox )
00792 {
00793   if ( !isWorkingDay( qd ) ) {
00794     drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), oldbox );
00795   } else {
00796     drawBox( p, BOX_BORDER_WIDTH, oldbox );
00797   }
00798   QRect box( oldbox );
00799   // Account for the border with and cut away that margin from the interior
00800 //   box.setRight( box.right()-BOX_BORDER_WIDTH );
00801 
00802   Event *event;
00803 
00804   if ( expandable ) {
00805     // Adapt start/end times to include complete events
00806     Event::List::ConstIterator it;
00807     for ( it = events.begin(); it != events.end(); ++it ) {
00808       event = *it;
00809       if ( event->dtStart().time() < fromTime )
00810         fromTime = event->dtStart().time();
00811       if ( event->dtEnd().time() > toTime )
00812         toTime = event->dtEnd().time();
00813     }
00814   }
00815 
00816   // Show at least one hour
00817 //   if ( fromTime.secsTo( toTime ) < 3600 ) {
00818 //     fromTime = QTime( fromTime.hour(), 0, 0 );
00819 //     toTime = fromTime.addSecs( 3600 );
00820 //   }
00821 
00822   // calculate the height of a cell and of a minute
00823   int totalsecs = fromTime.secsTo( toTime );
00824   float minlen = box.height() * 60. / totalsecs;
00825   float cellHeight = 60. * minlen;
00826   float currY = box.top();
00827 
00828   // print grid:
00829   QTime curTime( QTime( fromTime.hour(), 0, 0 ) );
00830   currY += fromTime.secsTo( curTime ) * minlen / 60;
00831 
00832   while ( curTime < toTime && curTime.isValid() ) {
00833     if ( currY > box.top() )
00834       p.drawLine( box.left(), int( currY ), box.right(), int( currY ) );
00835     currY += cellHeight / 2;
00836     if ( ( currY > box.top() ) && ( currY < box.bottom() ) ) {
00837       // enough space for half-hour line
00838       QPen oldPen( p.pen() );
00839       p.setPen( QColor( 192, 192, 192 ) );
00840       p.drawLine( box.left(), int( currY ), box.right(), int( currY ) );
00841       p.setPen( oldPen );
00842     }
00843     if ( curTime.secsTo( toTime ) > 3600 )
00844       curTime = curTime.addSecs( 3600 );
00845     else curTime = toTime;
00846     currY += cellHeight / 2;
00847   }
00848 
00849   QDateTime startPrintDate = QDateTime( qd, fromTime );
00850   QDateTime endPrintDate = QDateTime( qd, toTime );
00851 
00852   // Calculate horizontal positions and widths of events taking into account
00853   // overlapping events
00854 
00855   QPtrList<KOrg::CellItem> cells;
00856   cells.setAutoDelete( true );
00857 
00858   Event::List::ConstIterator itEvents;
00859   for( itEvents = events.begin(); itEvents != events.end(); ++itEvents ) {
00860     QValueList<QDateTime> times = (*itEvents)->startDateTimesForDate( qd );
00861     for ( QValueList<QDateTime>::ConstIterator it = times.begin();
00862           it != times.end(); ++it ) {
00863       cells.append( new PrintCellItem( *itEvents, (*it), (*itEvents)->endDateForStart( *it ) ) );
00864     }
00865   }
00866 
00867   QPtrListIterator<KOrg::CellItem> it1( cells );
00868   for( it1.toFirst(); it1.current(); ++it1 ) {
00869     KOrg::CellItem *placeItem = it1.current();
00870     KOrg::CellItem::placeItem( cells, placeItem );
00871   }
00872 
00873 //   p.setFont( QFont( "sans-serif", 10 ) );
00874 
00875   for( it1.toFirst(); it1.current(); ++it1 ) {
00876     PrintCellItem *placeItem = static_cast<PrintCellItem *>( it1.current() );
00877     drawAgendaItem( placeItem, p, startPrintDate, endPrintDate, minlen, box );
00878   }
00879 //   p.setFont( oldFont );
00880 }
00881 
00882 
00883 
00884 void CalPrintPluginBase::drawAgendaItem( PrintCellItem *item, QPainter &p,
00885                                    const QDateTime &startPrintDate,
00886                                    const QDateTime &endPrintDate,
00887                                    float minlen, const QRect &box )
00888 {
00889   Event *event = item->event();
00890 
00891   // start/end of print area for event
00892   QDateTime startTime = item->start();
00893   QDateTime endTime = item->end();
00894   if ( ( startTime < endPrintDate && endTime > startPrintDate ) ||
00895        ( endTime > startPrintDate && startTime < endPrintDate ) ) {
00896     if ( startTime < startPrintDate ) startTime = startPrintDate;
00897     if ( endTime > endPrintDate ) endTime = endPrintDate;
00898     int currentWidth = box.width() / item->subCells();
00899     int currentX = box.left() + item->subCell() * currentWidth;
00900     int currentYPos = int( box.top() + startPrintDate.secsTo( startTime ) *
00901                            minlen / 60. );
00902     int currentHeight = int( box.top() + startPrintDate.secsTo( endTime ) * minlen / 60. ) - currentYPos;
00903 
00904     QRect eventBox( currentX, currentYPos, currentWidth, currentHeight );
00905     QString str;
00906     if ( event->location().isEmpty() ) {
00907       str = i18n( "starttime - endtime summary",
00908                   "%1-%2 %3" ).
00909             arg( KGlobal::locale()->formatTime( startTime.time() ) ).
00910             arg( KGlobal::locale()->formatTime( endTime.time() ) ).
00911             arg( cleanStr( event->summary() ) );
00912     } else {
00913       str = i18n( "starttime - endtime summary, location",
00914                   "%1-%2 %3, %4" ).
00915             arg( KGlobal::locale()->formatTime( startTime.time() ) ).
00916             arg( KGlobal::locale()->formatTime( endTime.time() ) ).
00917             arg( cleanStr( event->summary() ) ).
00918             arg( cleanStr( event->location() ) );
00919     }
00920     showEventBox( p, EVENT_BORDER_WIDTH, eventBox, event, str );
00921   }
00922 }
00923 
00924 //TODO TODO TODO
00925 void CalPrintPluginBase::drawDayBox( QPainter &p, const QDate &qd,
00926     const QRect &box,
00927     bool fullDate, bool printRecurDaily, bool printRecurWeekly )
00928 {
00929   QString dayNumStr;
00930   const KLocale*local = KGlobal::locale();
00931 
00932   // This has to be localized
00933   if ( fullDate && mCalSys ) {
00934 
00935     dayNumStr = i18n("weekday month date", "%1 %2 %3")
00936         .arg( mCalSys->weekDayName( qd ) )
00937         .arg( mCalSys->monthName( qd ) )
00938         .arg( qd.day() );
00939 //    dayNumStr = local->formatDate(qd);
00940   } else {
00941     dayNumStr = QString::number( qd.day() );
00942   }
00943 
00944   QRect subHeaderBox( box );
00945   subHeaderBox.setHeight( mSubHeaderHeight );
00946   drawShadedBox( p, BOX_BORDER_WIDTH, p.backgroundColor(), box );
00947   drawShadedBox( p, 0, QColor( 232, 232, 232 ), subHeaderBox );
00948   drawBox( p, BOX_BORDER_WIDTH, box );
00949   QString hstring( holidayString( qd ) );
00950   QFont oldFont( p.font() );
00951 
00952   QRect headerTextBox( subHeaderBox );
00953   headerTextBox.setLeft( subHeaderBox.left()+5 );
00954   headerTextBox.setRight( subHeaderBox.right()-5 );
00955   if (!hstring.isEmpty()) {
00956     p.setFont( QFont( "sans-serif", 8, QFont::Bold, true ) );
00957 
00958     p.drawText( headerTextBox, Qt::AlignLeft | Qt::AlignVCenter, hstring );
00959   }
00960   p.setFont(QFont("sans-serif", 10, QFont::Bold));
00961   p.drawText( headerTextBox, Qt::AlignRight | Qt::AlignVCenter, dayNumStr);
00962 
00963   Event::List eventList = mCalendar->events( qd,
00964                                              EventSortStartDate,
00965                                              SortDirectionAscending );
00966   QString timeText;
00967   p.setFont( QFont( "sans-serif", 8 ) );
00968 
00969   int textY=mSubHeaderHeight+3; // gives the relative y-coord of the next printed entry
00970   Event::List::ConstIterator it;
00971 
00972   unsigned int visibleEventsCounter = 0;
00973   for( it = eventList.begin(); it != eventList.end() && textY<box.height(); ++it ) {
00974     Event *currEvent = *it;
00975     if ( ( !printRecurDaily  && currEvent->recurrenceType() == Recurrence::rDaily  ) ||
00976          ( !printRecurWeekly && currEvent->recurrenceType() == Recurrence::rWeekly ) ) {
00977       continue;
00978     }
00979     if ( currEvent->doesFloat() || currEvent->isMultiDay() ) {
00980       timeText = "";
00981     } else {
00982       timeText = local->formatTime( currEvent->dtStart().time() );
00983     }
00984 
00985     QString str;
00986     if ( !currEvent->location().isEmpty() ) {
00987       str = i18n( "summary, location", "%1, %2" ).
00988             arg( currEvent->summary() ).arg( currEvent->location() );
00989     } else {
00990       str = currEvent->summary();
00991     }
00992 
00993     const int newHeight = calculateIncidenceHeight( p, box, timeText, str, textY );
00994     if ( newHeight < (box.height() - 8) ) {
00995       drawIncidence( p, box, timeText, str, textY );
00996       visibleEventsCounter++;
00997     } else {
00998       const QChar downArrow( 0x21e3 );
00999       const unsigned int invisibleIncidences = ((eventList.count() - visibleEventsCounter) + mCalendar->todos( qd ).count());
01000       const QString warningMsg = QString( "%1 (%2)" ).arg( downArrow ).arg( invisibleIncidences );
01001 
01002       QFontMetrics fm( p.font() );
01003       QRect msgRect = fm.boundingRect( warningMsg );
01004       msgRect.setRect( box.right() - msgRect.width() - 4, box.bottom() - msgRect.height() - 4, msgRect.width() + 4, msgRect.height() + 4 );
01005 
01006       p.save();
01007       p.setPen( Qt::red );
01008       p.drawText( msgRect, Qt::AlignLeft, warningMsg );
01009       p.restore();
01010     }
01011   }
01012 
01013   unsigned int visibleTodosCounter = 0;
01014   if ( textY < (box.height() - 8) ) {
01015     Todo::List todos = mCalendar->todos( qd );
01016     Todo::List::ConstIterator it2;
01017     for ( it2 = todos.begin(); it2 != todos.end() && textY <box.height(); ++it2 ) {
01018       Todo *todo = *it2;
01019       if ( ( !printRecurDaily  && todo->recurrenceType() == Recurrence::rDaily  ) ||
01020            ( !printRecurWeekly && todo->recurrenceType() == Recurrence::rWeekly ) ) {
01021         continue;
01022       }
01023       if ( todo->hasStartDate() && !todo->doesFloat() ) {
01024         timeText = KGlobal::locale()->formatTime( todo->dtStart().time() ) + " ";
01025       } else {
01026         timeText = "";
01027       }
01028       QString summaryStr;
01029       if ( !todo->location().isEmpty() ) {
01030         summaryStr = i18n( "summary, location", "%1, %2" ).
01031                      arg( todo->summary() ).arg( todo->location() );
01032       } else {
01033         summaryStr = todo->summary();
01034       }
01035       QString str;
01036       if ( todo->hasDueDate() ) {
01037         if ( !todo->doesFloat() ) {
01038           str = i18n( "%1 (Due: %2)" ).
01039                 arg( summaryStr ).
01040                 arg( KGlobal::locale()->formatDateTime( todo->dtDue() ) );
01041         } else {
01042           str = i18n( "%1 (Due: %2)" ).
01043                 arg( summaryStr ).
01044                 arg( KGlobal::locale()->formatDate( todo->dtDue().date(), true ) );
01045         }
01046       } else {
01047         str = summaryStr;
01048       }
01049       const int newHeight = calculateIncidenceHeight( p, box, timeText, i18n("To-do: %1").arg( str ), textY );
01050       if ( newHeight < box.height() - 8 ) {
01051         drawIncidence( p, box, timeText, i18n("To-do: %1").arg( str ), textY );
01052         visibleTodosCounter++;
01053       } else {
01054         const QChar downArrow( 0x21e3 );
01055         const unsigned int invisibleIncidences = (todos.count() - visibleTodosCounter);
01056         const QString warningMsg = QString( "%1 (%2)" ).arg( downArrow ).arg( invisibleIncidences );
01057 
01058         QFontMetrics fm( p.font() );
01059         QRect msgRect = fm.boundingRect( warningMsg );
01060         msgRect.setRect( box.right() - msgRect.width() - 4, box.bottom() - msgRect.height() - 4, msgRect.width() + 4, msgRect.height() + 4 );
01061 
01062         p.save();
01063         p.setPen( Qt::red );
01064         p.drawText( msgRect, Qt::AlignLeft, warningMsg );
01065         p.restore();
01066       }
01067     }
01068   }
01069 
01070   p.setFont( oldFont );
01071 }
01072 
01073 int CalPrintPluginBase::calculateIncidenceHeight( QPainter &p, const QRect &dayBox, const QString &time, const QString &summary, int _textY ) const
01074 {
01075   int textY = _textY;
01076 
01077   int flags = Qt::AlignLeft | Qt::AlignTop;
01078   QFontMetrics fm = p.fontMetrics();
01079   QRect timeBound = p.boundingRect( dayBox.x() + 5, dayBox.y() + textY,
01080                                     dayBox.width() - 10, fm.lineSpacing(),
01081                                     flags, time );
01082 
01083   int summaryWidth = time.isEmpty() ? 0 : timeBound.width() + 4;
01084   int summaryHeight = time.isEmpty() ? 0 : timeBound.height() + 1;
01085 
01086   // first check if the summary matches right to the time
01087   QRect summaryBound = QRect( dayBox.x() + 5 + summaryWidth, dayBox.y() + textY,
01088                               dayBox.width() - summaryWidth -5, dayBox.height() );
01089 
01090   KWordWrap *ww = KWordWrap::formatText( fm, summaryBound, flags, summary );
01091   if (!ww->wrappedString().contains("\n")) { // does match right to the time
01092     textY += ww->boundingRect().height();
01093     delete ww;
01094   } else { // does not match, so place it below the time to save space
01095     QRect summaryBound = QRect( dayBox.x() + 10, dayBox.y() + summaryHeight + textY,
01096                                 dayBox.width() - 10, dayBox.height() );
01097 
01098     KWordWrap *ww = KWordWrap::formatText( fm, summaryBound, flags, summary );
01099     textY += ww->boundingRect().height() + summaryHeight;
01100     delete ww;
01101   }
01102 
01103   return textY;
01104 }
01105 
01106 // TODO TODO TODO
01107 void CalPrintPluginBase::drawIncidence( QPainter &p, const QRect &dayBox, const QString &time, const QString &summary, int &textY )
01108 {
01109   kdDebug(5850) << "summary = " << summary << endl;
01110 
01111   int flags = Qt::AlignLeft | Qt::AlignTop;
01112   QFontMetrics fm = p.fontMetrics();
01113   QRect timeBound = p.boundingRect( dayBox.x() + 5, dayBox.y() + textY,
01114                                     dayBox.width() - 10, fm.lineSpacing(),
01115                                     flags, time );
01116   p.drawText( timeBound, flags, time );
01117 
01118   int summaryWidth = time.isEmpty() ? 0 : timeBound.width() + 4;
01119   int summaryHeight = time.isEmpty() ? 0 : timeBound.height() + 1;
01120 
01121   // first check if the summary matches right to the time
01122   QRect summaryBound = QRect( dayBox.x() + 5 + summaryWidth, dayBox.y() + textY,
01123                               dayBox.width() - summaryWidth -5, dayBox.height() );
01124 
01125   KWordWrap *ww = KWordWrap::formatText( fm, summaryBound, flags, summary );
01126   if (!ww->wrappedString().contains("\n")) { // does match right to the time
01127     ww->drawText( &p, dayBox.x() + 5 + summaryWidth, dayBox.y() + textY, flags );
01128     textY += ww->boundingRect().height();
01129     delete ww;
01130   } else { // does not match, so place it below the time to save space
01131     QRect summaryBound = QRect( dayBox.x() + 10, dayBox.y() + summaryHeight + textY,
01132                                 dayBox.width() - 10, dayBox.height() );
01133 
01134     KWordWrap *ww = KWordWrap::formatText( fm, summaryBound, flags, summary );
01135     ww->drawText( &p, dayBox.x() + 10, dayBox.y() + summaryHeight + textY, flags );
01136     textY += ww->boundingRect().height() + summaryHeight;
01137     delete ww;
01138   }
01139 }
01140 
01141 
01143 
01144 void CalPrintPluginBase::drawWeek(QPainter &p, const QDate &qd, const QRect &box )
01145 {
01146   QDate weekDate = qd;
01147   bool portrait = ( box.height() > box.width() );
01148   int cellWidth, cellHeight;
01149   int vcells;
01150   if (portrait) {
01151     cellWidth = box.width()/2;
01152     vcells=3;
01153   } else {
01154     cellWidth = box.width()/6;
01155     vcells=1;
01156   }
01157   cellHeight = box.height()/vcells;
01158 
01159   // correct begin of week
01160   int weekdayCol = weekdayColumn( qd.dayOfWeek() );
01161   weekDate = qd.addDays( -weekdayCol );
01162 
01163   for (int i = 0; i < 7; i++, weekDate = weekDate.addDays(1)) {
01164     // Saturday and sunday share a cell, so we have to special-case sunday
01165     int hpos = ((i<6)?i:(i-1)) / vcells;
01166     int vpos = ((i<6)?i:(i-1)) % vcells;
01167     QRect dayBox( box.left()+cellWidth*hpos, box.top()+cellHeight*vpos + ((i==6)?(cellHeight/2):0),
01168         cellWidth, (i<5)?(cellHeight):(cellHeight/2) );
01169     drawDayBox(p, weekDate, dayBox, true);
01170   } // for i through all weekdays
01171 }
01172 
01173 
01174 void CalPrintPluginBase::drawTimeTable(QPainter &p,
01175     const QDate &fromDate, const QDate &toDate,
01176     QTime &fromTime, QTime &toTime,
01177     const QRect &box)
01178 {
01179   // timeline is 1 hour:
01180   int alldayHeight = (int)( 3600.*box.height()/(fromTime.secsTo(toTime)+3600.) );
01181   int timelineWidth = TIMELINE_WIDTH;
01182 
01183   QRect dowBox( box );
01184   dowBox.setLeft( box.left() + timelineWidth );
01185   dowBox.setHeight( mSubHeaderHeight );
01186   drawDaysOfWeek( p, fromDate, toDate, dowBox );
01187 
01188   QRect tlBox( box );
01189   tlBox.setWidth( timelineWidth );
01190   tlBox.setTop( dowBox.bottom() + BOX_BORDER_WIDTH + alldayHeight );
01191   drawTimeLine( p, fromTime, toTime, tlBox );
01192 
01193   // draw each day
01194   QDate curDate(fromDate);
01195   int i=0;
01196   double cellWidth = double(dowBox.width()) / double(fromDate.daysTo(toDate)+1);
01197   while (curDate<=toDate) {
01198     QRect allDayBox( dowBox.left()+int(i*cellWidth), dowBox.bottom() + BOX_BORDER_WIDTH,
01199                      int((i+1)*cellWidth)-int(i*cellWidth), alldayHeight );
01200     QRect dayBox( allDayBox );
01201     dayBox.setTop( tlBox.top() );
01202     dayBox.setBottom( box.bottom() );
01203     Event::List eventList = mCalendar->events(curDate,
01204                                               EventSortStartDate,
01205                                               SortDirectionAscending);
01206     alldayHeight = drawAllDayBox( p, eventList, curDate, false, allDayBox );
01207     drawAgendaDayBox( p, eventList, curDate, false, fromTime, toTime, dayBox );
01208     i++;
01209     curDate=curDate.addDays(1);
01210   }
01211 
01212 }
01213 
01214 
01216 
01217 class MonthEventStruct
01218 {
01219   public:
01220     MonthEventStruct() : event(0) {}
01221     MonthEventStruct( const QDateTime &s, const QDateTime &e, Event *ev)
01222     {
01223       event = ev;
01224       start = s;
01225       end = e;
01226       if ( event->doesFloat() ) {
01227         start = QDateTime( start.date(), QTime(0,0,0) );
01228         end = QDateTime( end.date().addDays(1), QTime(0,0,0) ).addSecs(-1);
01229       }
01230     }
01231     bool operator<(const MonthEventStruct &mes) { return start < mes.start; }
01232     QDateTime start;
01233     QDateTime end;
01234     Event *event;
01235 };
01236 
01237 void CalPrintPluginBase::drawMonth( QPainter &p, const QDate &dt, const QRect &box, int maxdays, int subDailyFlags, int holidaysFlags )
01238 {
01239   const KCalendarSystem *calsys = calendarSystem();
01240   QRect subheaderBox( box );
01241   subheaderBox.setHeight( subHeaderHeight() );
01242   QRect borderBox( box );
01243   borderBox.setTop( subheaderBox.bottom()+1 );
01244   drawSubHeaderBox( p, calsys->monthName(dt), subheaderBox );
01245   // correct for half the border width
01246   int correction = (BOX_BORDER_WIDTH/*-1*/)/2;
01247   QRect daysBox( borderBox );
01248   daysBox.addCoords( correction, correction, -correction, -correction );
01249 
01250   int daysinmonth = calsys->daysInMonth( dt );
01251   if ( maxdays <= 0 ) maxdays = daysinmonth;
01252 
01253   int d;
01254   float dayheight = float(daysBox.height()) / float( maxdays );
01255 
01256   QColor holidayColor( 240, 240, 240 );
01257   QColor workdayColor( 255, 255, 255 );
01258   int dayNrWidth = p.fontMetrics().width( "99" );
01259 
01260   // Fill the remaining space (if a month has less days than others) with a crossed-out pattern
01261   if ( daysinmonth<maxdays ) {
01262     QRect dayBox( box.left(), daysBox.top() + round(dayheight*daysinmonth), box.width(), 0 );
01263     dayBox.setBottom( daysBox.bottom() );
01264     p.fillRect( dayBox, Qt::DiagCrossPattern );
01265   }
01266   // Backgrounded boxes for each day, plus day numbers
01267   QBrush oldbrush( p.brush() );
01268   for ( d = 0; d < daysinmonth; ++d ) {
01269     QDate day;
01270     calsys->setYMD( day, dt.year(), dt.month(), d+1 );
01271     QRect dayBox( daysBox.left()/*+rand()%50*/, daysBox.top() + round(dayheight*d), daysBox.width()/*-rand()%50*/, 0 );
01272     // 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!
01273     dayBox.setBottom( daysBox.top()+round(dayheight*(d+1)) - 1 );
01274 
01275     p.setBrush( isWorkingDay( day )?workdayColor:holidayColor );
01276     p.drawRect( dayBox );
01277     QRect dateBox( dayBox );
01278     dateBox.setWidth( dayNrWidth+3 );
01279     p.drawText( dateBox, Qt::AlignRight | Qt::AlignVCenter | Qt::SingleLine,
01280                 QString::number(d+1) );
01281   }
01282   p.setBrush( oldbrush );
01283   int xstartcont = box.left() + dayNrWidth + 5;
01284 
01285   QDate start, end;
01286   calsys->setYMD( start, dt.year(), dt.month(), 1 );
01287   end = calsys->addMonths( start, 1 );
01288   end = calsys->addDays( end, -1 );
01289 
01290   Event::List events = mCalendar->events( start, end );
01291   QMap<int, QStringList> textEvents;
01292   QPtrList<KOrg::CellItem> timeboxItems;
01293   timeboxItems.setAutoDelete( true );
01294 
01295 
01296   // 1) For multi-day events, show boxes spanning several cells, use CellItem
01297   //    print the summary vertically
01298   // 2) For sub-day events, print the concated summaries into the remaining
01299   //    space of the box (optional, depending on the given flags)
01300   // 3) Draw some kind of timeline showing free and busy times
01301 
01302   // Holidays
01303   Event::List holidays;
01304   holidays.setAutoDelete( true );
01305   for ( QDate d(start); d <= end; d = d.addDays(1) ) {
01306     Event *e = holiday( d );
01307     if ( e ) {
01308       holidays.append( e );
01309       if ( holidaysFlags & TimeBoxes ) {
01310         timeboxItems.append( new PrintCellItem( e, QDateTime(d, QTime(0,0,0) ),
01311             QDateTime( d.addDays(1), QTime(0,0,0) ) ) );
01312       }
01313       if ( holidaysFlags & Text ) {
01314         textEvents[ d.day() ] << e->summary();
01315       }
01316     }
01317   }
01318 
01319   QValueList<MonthEventStruct> monthentries;
01320 
01321   for ( Event::List::ConstIterator evit = events.begin();
01322         evit != events.end(); ++evit ) {
01323     Event *e = (*evit);
01324     if (!e) continue;
01325     if ( e->doesRecur() ) {
01326       if ( e->recursOn( start ) ) {
01327         // This occurrence has possibly started before the beginning of the
01328         // month, so obtain the start date before the beginning of the month
01329         QValueList<QDateTime> starttimes = e->startDateTimesForDate( start );
01330         QValueList<QDateTime>::ConstIterator it = starttimes.begin();
01331         for ( ; it != starttimes.end(); ++it ) {
01332           monthentries.append( MonthEventStruct( *it, e->endDateForStart( *it ), e ) );
01333         }
01334       }
01335       // Loop through all remaining days of the month and check if the event
01336       // begins on that day (don't use Event::recursOn, as that will
01337       // also return events that have started earlier. These start dates
01338       // however, have already been treated!
01339       Recurrence *recur = e->recurrence();
01340       QDate d1( start.addDays(1) );
01341       while ( d1 <= end ) {
01342         if ( recur->recursOn(d1) ) {
01343           TimeList times( recur->recurTimesOn( d1 ) );
01344           for ( TimeList::ConstIterator it = times.begin();
01345                 it != times.end(); ++it ) {
01346             QDateTime d1start( d1, *it );
01347             monthentries.append( MonthEventStruct( d1start, e->endDateForStart( d1start ), e ) );
01348           }
01349         }
01350         d1 = d1.addDays(1);
01351       }
01352     } else {
01353       monthentries.append( MonthEventStruct( e->dtStart(), e->dtEnd(), e ) );
01354     }
01355   }
01356   qHeapSort( monthentries );
01357 
01358   QValueList<MonthEventStruct>::ConstIterator mit = monthentries.begin();
01359   QDateTime endofmonth( end, QTime(0,0,0) );
01360   endofmonth = endofmonth.addDays(1);
01361   for ( ; mit != monthentries.end(); ++mit ) {
01362     if ( (*mit).start.date() == (*mit).end.date() ) {
01363       // Show also single-day events as time line boxes
01364       if ( subDailyFlags & TimeBoxes ) {
01365         timeboxItems.append( new PrintCellItem( (*mit).event, (*mit).start, (*mit).end ) );
01366       }
01367       // Show as text in the box
01368       if ( subDailyFlags & Text ) {
01369         textEvents[ (*mit).start.date().day() ] << (*mit).event->summary();
01370       }
01371     } else {
01372       // Multi-day events are always shown as time line boxes
01373       QDateTime thisstart( (*mit).start );
01374       QDateTime thisend( (*mit).end );
01375       if ( thisstart.date()<start ) thisstart = start;
01376       if ( thisend>endofmonth ) thisend = endofmonth;
01377       timeboxItems.append( new PrintCellItem( (*mit).event, thisstart, thisend ) );
01378     }
01379   }
01380 
01381   // For Multi-day events, line them up nicely so that the boxes don't overlap
01382   QPtrListIterator<KOrg::CellItem> it1( timeboxItems );
01383   for( it1.toFirst(); it1.current(); ++it1 ) {
01384     KOrg::CellItem *placeItem = it1.current();
01385     KOrg::CellItem::placeItem( timeboxItems, placeItem );
01386   }
01387   QDateTime starttime( start, QTime( 0, 0, 0 ) );
01388   int newxstartcont = xstartcont;
01389 
01390   QFont oldfont( p.font() );
01391   p.setFont( QFont( "sans-serif", 7 ) );
01392   for( it1.toFirst(); it1.current(); ++it1 ) {
01393     PrintCellItem *placeItem = static_cast<PrintCellItem *>( it1.current() );
01394     int minsToStart = starttime.secsTo( placeItem->start() )/60;
01395     int minsToEnd = starttime.secsTo( placeItem->end() )/60;
01396 
01397     QRect eventBox( xstartcont + placeItem->subCell()*17,
01398            daysBox.top() + round( double( minsToStart*daysBox.height()) / double(maxdays*24*60) ),
01399            14, 0 );
01400     eventBox.setBottom( daysBox.top() + round( double( minsToEnd*daysBox.height()) / double(maxdays*24*60) ) );
01401     drawVerticalBox( p, 0, eventBox, placeItem->event()->summary() );
01402     newxstartcont = QMAX( newxstartcont, eventBox.right() );
01403   }
01404   xstartcont = newxstartcont;
01405 
01406   // For Single-day events, simply print their summaries into the remaining
01407   // space of the day's cell
01408   for ( int d=0; d<daysinmonth; ++d ) {
01409     QStringList dayEvents( textEvents[d+1] );
01410     QString txt = dayEvents.join(", ");
01411     QRect dayBox( xstartcont, daysBox.top()+round(dayheight*d), 0, 0 );
01412     dayBox.setRight( box.right() );
01413     dayBox.setBottom( daysBox.top()+round(dayheight*(d+1)) );
01414     printEventString(p, dayBox, txt, Qt::AlignTop | Qt::AlignLeft | Qt::BreakAnywhere );
01415   }
01416   p.setFont( oldfont );
01417 //   p.setBrush( Qt::NoBrush );
01418   drawBox( p, BOX_BORDER_WIDTH, borderBox );
01419   p.restore();
01420 }
01421 
01423 
01424 void CalPrintPluginBase::drawMonthTable(QPainter &p, const QDate &qd, bool weeknumbers,
01425                                bool recurDaily, bool recurWeekly,
01426                                const QRect &box)
01427 {
01428   int yoffset = mSubHeaderHeight;
01429   int xoffset = 0;
01430   QDate monthDate(QDate(qd.year(), qd.month(), 1));
01431   QDate monthFirst(monthDate);
01432   QDate monthLast(monthDate.addMonths(1).addDays(-1));
01433 
01434 
01435   int weekdayCol = weekdayColumn( monthDate.dayOfWeek() );
01436   monthDate = monthDate.addDays(-weekdayCol);
01437 
01438   if (weeknumbers) {
01439     xoffset += 14;
01440   }
01441 
01442   int rows=(weekdayCol + qd.daysInMonth() - 1)/7 +1;
01443   double cellHeight = ( box.height() - yoffset ) / (1.*rows);
01444   double cellWidth = ( box.width() - xoffset ) / 7.;
01445 
01446   // Precalculate the grid...
01447   // rows is at most 6, so using 8 entries in the array is fine, too!
01448   int coledges[8], rowedges[8];
01449   for ( int i = 0; i <= 7; i++ ) {
01450     rowedges[i] = int( box.top() + yoffset + i*cellHeight );
01451     coledges[i] = int( box.left() + xoffset + i*cellWidth );
01452   }
01453 
01454   if (weeknumbers) {
01455     QFont oldFont(p.font());
01456     QFont newFont(p.font());
01457     newFont.setPointSize(6);
01458     p.setFont(newFont);
01459     QDate weekDate(monthDate);
01460     for (int row = 0; row<rows; ++row ) {
01461       int calWeek = weekDate.weekNumber();
01462       QRect rc( box.left(), rowedges[row], coledges[0] - 3 - box.left(), rowedges[row+1]-rowedges[row] );
01463       p.drawText( rc, Qt::AlignRight | Qt::AlignVCenter, QString::number( calWeek ) );
01464       weekDate = weekDate.addDays( 7 );
01465     }
01466     p.setFont( oldFont );
01467   }
01468 
01469   QRect daysOfWeekBox( box );
01470   daysOfWeekBox.setHeight( mSubHeaderHeight );
01471   daysOfWeekBox.setLeft( box.left()+xoffset );
01472   drawDaysOfWeek( p, monthDate, monthDate.addDays( 6 ), daysOfWeekBox );
01473 
01474   QColor back = p.backgroundColor();
01475   bool darkbg = false;
01476   for ( int row = 0; row < rows; ++row ) {
01477     for ( int col = 0; col < 7; ++col ) {
01478       // show days from previous/next month with a grayed background
01479       if ( (monthDate < monthFirst) || (monthDate > monthLast) ) {
01480         p.setBackgroundColor( back.dark( 120 ) );
01481         darkbg = true;
01482       }
01483       QRect dayBox( coledges[col], rowedges[row], coledges[col+1]-coledges[col], rowedges[row+1]-rowedges[row] );
01484       drawDayBox(p, monthDate, dayBox, false, recurDaily, recurWeekly );
01485       if ( darkbg ) {
01486         p.setBackgroundColor( back );
01487         darkbg = false;
01488       }
01489       monthDate = monthDate.addDays(1);
01490     }
01491   }
01492 }
01493 
01494 
01496 
01497 void CalPrintPluginBase::drawTodo( int &count, Todo *todo, QPainter &p,
01498                                TodoSortField sortField, SortDirection sortDir,
01499                                bool connectSubTodos, bool strikeoutCompleted,
01500                                bool desc, int posPriority, int posSummary,
01501                                int posDueDt, int posPercentComplete,
01502                                int level, int x, int &y, int width,
01503                                int pageHeight, const Todo::List &todoList,
01504                                TodoParentStart *r )
01505 {
01506   QString outStr;
01507   const KLocale *local = KGlobal::locale();
01508   QRect rect;
01509   TodoParentStart startpt;
01510 
01511   // This list keeps all starting points of the parent to-dos so the connection
01512   // lines of the tree can easily be drawn (needed if a new page is started)
01513   static QPtrList<TodoParentStart> startPoints;
01514   if ( level < 1 ) {
01515     startPoints.clear();
01516   }
01517 
01518   // Compute the right hand side of the to-do box
01519   int rhs = posPercentComplete;
01520   if ( rhs < 0 ) rhs = posDueDt; //not printing percent completed
01521   if ( rhs < 0 ) rhs = x+width;  //not printing due dates either
01522 
01523   // size of to-do
01524   outStr=todo->summary();
01525   int left = posSummary + ( level*10 );
01526   rect = p.boundingRect( left, y, ( rhs-left-5 ), -1, Qt::WordBreak, outStr );
01527   if ( !todo->description().isEmpty() && desc ) {
01528     outStr = todo->description();
01529     rect = p.boundingRect( left+20, rect.bottom()+5, width-(left+10-x), -1,
01530                            Qt::WordBreak, outStr );
01531   }
01532   // if too big make new page
01533   if ( rect.bottom() > pageHeight ) {
01534     // first draw the connection lines from parent to-dos:
01535     if ( level > 0 && connectSubTodos ) {
01536       TodoParentStart *rct;
01537       for ( rct = startPoints.first(); rct; rct = startPoints.next() ) {
01538         int start;
01539         int center = rct->mRect.left() + (rct->mRect.width()/2);
01540         int to = p.viewport().bottom();
01541 
01542         // draw either from start point of parent or from top of the page
01543         if ( rct->mSamePage )
01544           start = rct->mRect.bottom() + 1;
01545         else
01546           start = p.viewport().top();
01547         p.moveTo( center, start );
01548         p.lineTo( center, to );
01549         rct->mSamePage = false;
01550       }
01551     }
01552     y=0;
01553     mPrinter->newPage();
01554   }
01555 
01556   // If this is a sub-to-do, r will not be 0, and we want the LH side
01557   // of the priority line up to the RH side of the parent to-do's priority
01558   bool showPriority = posPriority>=0;
01559   int lhs = posPriority;
01560   if ( r ) {
01561     lhs = r->mRect.right() + 1;
01562   }
01563 
01564   outStr.setNum( todo->priority() );
01565   rect = p.boundingRect( lhs, y + 10, 5, -1, Qt::AlignCenter, outStr );
01566   // Make it a more reasonable size
01567   rect.setWidth(18);
01568   rect.setHeight(18);
01569 
01570   // Draw a checkbox
01571   p.setBrush( QBrush( Qt::NoBrush ) );
01572   p.drawRect( rect );
01573   if ( todo->isCompleted() ) {
01574     // cross out the rectangle for completed to-dos
01575     p.drawLine( rect.topLeft(), rect.bottomRight() );
01576     p.drawLine( rect.topRight(), rect.bottomLeft() );
01577   }
01578   lhs = rect.right() + 3;
01579 
01580   // Priority
01581   if ( todo->priority() > 0 && showPriority ) {
01582     p.drawText( rect, Qt::AlignCenter, outStr );
01583   }
01584   startpt.mRect = rect; //save for later
01585 
01586   // Connect the dots
01587   if ( level > 0 && connectSubTodos ) {
01588     int bottom;
01589     int center( r->mRect.left() + (r->mRect.width()/2) );
01590     if ( r->mSamePage )
01591       bottom = r->mRect.bottom() + 1;
01592     else
01593       bottom = 0;
01594     int to( rect.top() + (rect.height()/2) );
01595     int endx( rect.left() );
01596     p.moveTo( center, bottom );
01597     p.lineTo( center, to );
01598     p.lineTo( endx, to );
01599   }
01600 
01601   // summary
01602   outStr=todo->summary();
01603   rect = p.boundingRect( lhs, rect.top(), (rhs-(left + rect.width() + 5)),
01604                          -1, Qt::WordBreak, outStr );
01605 
01606   QRect newrect;
01607   //FIXME: the following code prints underline rather than strikeout text
01608 #if 0
01609   QFont f( p.font() );
01610   if ( todo->isCompleted() && strikeoutCompleted ) {
01611     f.setStrikeOut( true );
01612     p.setFont( f );
01613   }
01614   p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
01615   f.setStrikeOut( false );
01616   p.setFont( f );
01617 #endif
01618   //TODO: Remove this section when the code above is fixed
01619   p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
01620   if ( todo->isCompleted() && strikeoutCompleted ) {
01621     // strike out the summary text if to-do is complete
01622     // Note: we tried to use a strike-out font and for unknown reasons the
01623     // result was underline instead of strike-out, so draw the lines ourselves.
01624     int delta = p.fontMetrics().lineSpacing();
01625     int lines = ( rect.height() / delta ) + 1;
01626     for ( int i=0; i<lines; i++ ) {
01627       p.moveTo( rect.left(),  rect.top() + ( delta/2 ) + ( i*delta ) );
01628       p.lineTo( rect.right(), rect.top() + ( delta/2 ) + ( i*delta ) );
01629     }
01630   }
01631 
01632   // due date
01633   if ( todo->hasDueDate() && posDueDt>=0 ) {
01634     outStr = local->formatDate( todo->dtDue().date(), true );
01635     rect = p.boundingRect( posDueDt, y, x + width, -1,
01636                            Qt::AlignTop | Qt::AlignLeft, outStr );
01637     p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr );
01638   }
01639 
01640   // percentage completed
01641   bool showPercentComplete = posPercentComplete>=0;
01642   if ( showPercentComplete ) {
01643     int lwidth = 24;
01644     int lheight = 12;
01645     //first, draw the progress bar
01646     int progress = (int)(( lwidth*todo->percentComplete())/100.0 + 0.5);
01647 
01648     p.setBrush( QBrush( Qt::NoBrush ) );
01649     p.drawRect( posPercentComplete, y+3, lwidth, lheight );
01650     if ( progress > 0 ) {
01651       p.setBrush( QColor( 128, 128, 128 ) );
01652       p.drawRect( posPercentComplete, y+3, progress, lheight );
01653     }
01654 
01655     //now, write the percentage
01656     outStr = i18n( "%1%" ).arg( todo->percentComplete() );
01657     rect = p.boundingRect( posPercentComplete+lwidth+3, y, x + width, -1,
01658                            Qt::AlignTop | Qt::AlignLeft, outStr );
01659     p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr );
01660   }
01661 
01662   // description
01663   if ( !todo->description().isEmpty() && desc ) {
01664     y = newrect.bottom() + 5;
01665     outStr = todo->description();
01666     rect = p.boundingRect( left+20, y, x+width-(left+10), -1,
01667                            Qt::WordBreak, outStr );
01668     p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
01669   }
01670 
01671   // Set the new line position
01672   y = newrect.bottom() + 10; //set the line position
01673 
01674   // If the to-do has sub-to-dos, we need to call ourselves recursively
01675 #if 0
01676   Incidence::List l = todo->relations();
01677   Incidence::List::ConstIterator it;
01678   startPoints.append( &startpt );
01679   for( it = l.begin(); it != l.end(); ++it ) {
01680     count++;
01681     // In the future, to-dos might also be related to events
01682     // Manually check if the sub-to-do is in the list of to-dos to print
01683     // The problem is that relations() does not apply filters, so
01684     // we need to compare manually with the complete filtered list!
01685     Todo* subtodo = dynamic_cast<Todo *>( *it );
01686     if (subtodo && todoList.contains( subtodo ) ) {
01687       drawTodo( count, subtodo, p, connectSubTodos, strikeoutCompleted,
01688                 desc, posPriority, posSummary, posDueDt, posPercentComplete,
01689                 level+1, x, y, width, pageHeight, todoList, &startpt );
01690     }
01691   }
01692 #endif
01693   // Make a list of all the sub-to-dos related to this to-do.
01694   Todo::List t;
01695   Incidence::List l = todo->relations();
01696   Incidence::List::ConstIterator it;
01697   for( it=l.begin(); it!=l.end(); ++it ) {
01698     // In the future, to-dos might also be related to events
01699     // Manually check if the sub-to-do is in the list of to-dos to print
01700     // The problem is that relations() does not apply filters, so
01701     // we need to compare manually with the complete filtered list!
01702     Todo* subtodo = dynamic_cast<Todo *>( *it );
01703     if ( subtodo && todoList.contains( subtodo ) ) {
01704       t.append( subtodo );
01705     }
01706   }
01707 
01708   // Sort the sub-to-dos and then print them
01709   Todo::List sl = mCalendar->sortTodos( &t, sortField, sortDir );
01710   Todo::List::ConstIterator isl;
01711   startPoints.append( &startpt );
01712   for( isl = sl.begin(); isl != sl.end(); ++isl ) {
01713     count++;
01714     drawTodo( count, ( *isl ), p, sortField, sortDir,
01715               connectSubTodos, strikeoutCompleted,
01716               desc, posPriority, posSummary, posDueDt, posPercentComplete,
01717               level+1, x, y, width, pageHeight, todoList, &startpt );
01718   }
01719   startPoints.remove( &startpt );
01720 }
01721 
01722 int CalPrintPluginBase::weekdayColumn( int weekday )
01723 {
01724   return ( weekday + 7 - KGlobal::locale()->weekStartDay() ) % 7;
01725 }
01726 
01727 void CalPrintPluginBase::drawJournalField( QPainter &p, QString field, QString text,
01728                                        int x, int &y, int width, int pageHeight )
01729 {
01730   if ( text.isEmpty() ) return;
01731 
01732   QString entry( field.arg( text ) );
01733 
01734   QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, entry) );
01735   if ( rect.bottom() > pageHeight) {
01736     // Start new page...
01737     // FIXME: If it's a multi-line text, draw a few lines on this page, and the
01738     // remaining lines on the next page.
01739     y=0;
01740     mPrinter->newPage();
01741     rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, entry);
01742   }
01743   QRect newrect;
01744   p.drawText( rect, Qt::WordBreak, entry, -1, &newrect );
01745   y = newrect.bottom() + 7;
01746 }
01747 
01748 void CalPrintPluginBase::drawJournal( Journal * journal, QPainter &p, int x, int &y,
01749                                   int width, int pageHeight )
01750 {
01751   QFont oldFont( p.font() );
01752   p.setFont( QFont( "sans-serif", 15 ) );
01753   QString headerText;
01754   QString dateText( KGlobal::locale()->
01755         formatDate( journal->dtStart().date(), false ) );
01756 
01757   if ( journal->summary().isEmpty() ) {
01758     headerText = dateText;
01759   } else {
01760     headerText = i18n("Description - date", "%1 - %2")
01761                      .arg( journal->summary() )
01762                      .arg( dateText );
01763   }
01764 
01765   QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText) );
01766   if ( rect.bottom() > pageHeight) {
01767     // Start new page...
01768     y=0;
01769     mPrinter->newPage();
01770     rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText );
01771   }
01772   QRect newrect;
01773   p.drawText( rect, Qt::WordBreak, headerText, -1, &newrect );
01774   p.setFont( oldFont );
01775 
01776   y = newrect.bottom() + 4;
01777 
01778   p.drawLine( x + 3, y, x + width - 6, y );
01779   y += 5;
01780 
01781   drawJournalField( p, i18n("Person: %1"), journal->organizer().fullName(), x, y, width, pageHeight );
01782   drawJournalField( p, i18n("%1"), journal->description(), x, y, width, pageHeight );
01783   y += 10;
01784 }
01785 
01786 
01787 void CalPrintPluginBase::drawSplitHeaderRight( QPainter &p, const QDate &fd,
01788                                            const QDate &td,
01789                                            const QDate &,
01790                                            int width, int )
01791 {
01792   QFont oldFont( p.font() );
01793 
01794   QPen oldPen( p.pen() );
01795   QPen pen( Qt::black, 4 );
01796 
01797   QString title;
01798   if ( mCalSys ) {
01799     if ( fd.month() == td.month() ) {
01800       title = i18n("Date range: Month dayStart - dayEnd", "%1 %2 - %3")
01801         .arg( mCalSys->monthName( fd.month(), false ) )
01802         .arg( mCalSys->dayString( fd, false ) )
01803         .arg( mCalSys->dayString( td, false ) );
01804     } else {
01805       title = i18n("Date range: monthStart dayStart - monthEnd dayEnd", "%1 %2 - %3 %4")
01806         .arg( mCalSys->monthName( fd.month(), false ) )
01807         .arg( mCalSys->dayString( fd, false ) )
01808         .arg( mCalSys->monthName( td.month(), false ) )
01809         .arg( mCalSys->dayString( td, false ) );
01810     }
01811   }
01812 
01813   QFont serifFont("Times", 30);
01814   p.setFont(serifFont);
01815 
01816   int lineSpacing = p.fontMetrics().lineSpacing();
01817   p.drawText( 0, lineSpacing * 0, width, lineSpacing,
01818               Qt::AlignRight | Qt::AlignTop, title );
01819 
01820   title.truncate(0);
01821 
01822   p.setPen( pen );
01823   p.drawLine(300, lineSpacing * 1, width, lineSpacing * 1);
01824   p.setPen( oldPen );
01825 
01826   p.setFont(QFont("Times", 20, QFont::Bold, TRUE));
01827   int newlineSpacing = p.fontMetrics().lineSpacing();
01828   title += QString::number(fd.year());
01829   p.drawText( 0, lineSpacing * 1 + 4, width, newlineSpacing,
01830               Qt::AlignRight | Qt::AlignTop, title );
01831 
01832   p.setFont( oldFont );
01833 }
01834 
01835 #endif
KDE Home | KDE Accessibility Home | Description of Access Keys