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   for( it1.toFirst(); it1.current(); ++it1 ) {
00874     PrintCellItem *placeItem = static_cast<PrintCellItem *>( it1.current() );
00875     drawAgendaItem( placeItem, p, startPrintDate, endPrintDate, minlen, box );
00876   }
00877 }
00878 
00879 void CalPrintPluginBase::drawAgendaItem( PrintCellItem *item, QPainter &p,
00880                                    const QDateTime &startPrintDate,
00881                                    const QDateTime &endPrintDate,
00882                                    float minlen, const QRect &box )
00883 {
00884   Event *event = item->event();
00885 
00886   // start/end of print area for event
00887   QDateTime startTime = item->start();
00888   QDateTime endTime = item->end();
00889   if ( ( startTime < endPrintDate && endTime > startPrintDate ) ||
00890        ( endTime > startPrintDate && startTime < endPrintDate ) ) {
00891     if ( startTime < startPrintDate ) startTime = startPrintDate;
00892     if ( endTime > endPrintDate ) endTime = endPrintDate;
00893     int currentWidth = box.width() / item->subCells();
00894     int currentX = box.left() + item->subCell() * currentWidth;
00895     int currentYPos = int( box.top() + startPrintDate.secsTo( startTime ) *
00896                            minlen / 60. );
00897     int currentHeight = int( box.top() + startPrintDate.secsTo( endTime ) * minlen / 60. ) - currentYPos;
00898 
00899     QRect eventBox( currentX, currentYPos, currentWidth, currentHeight );
00900     QString str;
00901     if ( event->location().isEmpty() ) {
00902       str = i18n( "starttime - endtime summary",
00903                   "%1-%2 %3" ).
00904             arg( KGlobal::locale()->formatTime( startTime.time() ) ).
00905             arg( KGlobal::locale()->formatTime( endTime.time() ) ).
00906             arg( cleanStr( event->summary() ) );
00907     } else {
00908       str = i18n( "starttime - endtime summary, location",
00909                   "%1-%2 %3, %4" ).
00910             arg( KGlobal::locale()->formatTime( startTime.time() ) ).
00911             arg( KGlobal::locale()->formatTime( endTime.time() ) ).
00912             arg( cleanStr( event->summary() ) ).
00913             arg( cleanStr( event->location() ) );
00914     }
00915     QFont oldFont( p.font() );
00916     if ( eventBox.height() < 24 ) {
00917       if ( eventBox.height() < 12 ) {
00918         if ( eventBox.height() < 8 ) {
00919           p.setFont( QFont( "sans-serif", 4 ) );
00920         } else {
00921           p.setFont( QFont( "sans-serif", 6 ) );
00922         }
00923       } else {
00924         p.setFont( QFont( "sans-serif", 8 ) );
00925       }
00926     } else {
00927       p.setFont( QFont( "sans-serif", 10 ) );
00928     }
00929     showEventBox( p, EVENT_BORDER_WIDTH, eventBox, event, str );
00930     p.setFont( oldFont );
00931   }
00932 }
00933 
00934 void CalPrintPluginBase::drawDayBox( QPainter &p, const QDate &qd,
00935                                      const QRect &box, bool fullDate,
00936                                      bool printRecurDaily, bool printRecurWeekly,
00937                                      bool singleLineLimit )
00938 {
00939   QString dayNumStr;
00940   const KLocale *local = KGlobal::locale();
00941 
00942   if ( fullDate && mCalSys ) {
00943     dayNumStr = i18n("weekday month date", "%1 %2 %3")
00944         .arg( mCalSys->weekDayName( qd ) )
00945         .arg( mCalSys->monthName( qd ) )
00946         .arg( qd.day() );
00947   } else {
00948     dayNumStr = QString::number( qd.day() );
00949   }
00950 
00951   QRect subHeaderBox( box );
00952   subHeaderBox.setHeight( mSubHeaderHeight );
00953   drawShadedBox( p, BOX_BORDER_WIDTH, p.backgroundColor(), box );
00954   drawShadedBox( p, 0, QColor( 232, 232, 232 ), subHeaderBox );
00955   drawBox( p, BOX_BORDER_WIDTH, box );
00956   QString hstring( holidayString( qd ) );
00957   QFont oldFont( p.font() );
00958 
00959   QRect headerTextBox( subHeaderBox );
00960   headerTextBox.setLeft( subHeaderBox.left()+5 );
00961   headerTextBox.setRight( subHeaderBox.right()-5 );
00962   if (!hstring.isEmpty()) {
00963     p.setFont( QFont( "sans-serif", 8, QFont::Bold, true ) );
00964 
00965     p.drawText( headerTextBox, Qt::AlignLeft | Qt::AlignVCenter, hstring );
00966   }
00967   p.setFont(QFont("sans-serif", 10, QFont::Bold));
00968   p.drawText( headerTextBox, Qt::AlignRight | Qt::AlignVCenter, dayNumStr);
00969 
00970   Event::List eventList = mCalendar->events( qd,
00971                                              EventSortStartDate,
00972                                              SortDirectionAscending );
00973   QString timeText;
00974   p.setFont( QFont( "sans-serif", 7 ) );
00975   const int maxHeight = box.height() - 11; // 11 => 1.5x of the font height
00976 
00977   int textY=mSubHeaderHeight; // gives the relative y-coord of the next printed entry
00978   unsigned int visibleEventsCounter = 0;
00979   Event::List::ConstIterator it;
00980   for( it = eventList.begin(); it != eventList.end() && textY < maxHeight; ++it ) {
00981     Event *currEvent = *it;
00982     if ( ( !printRecurDaily  && currEvent->recurrenceType() == Recurrence::rDaily  ) ||
00983          ( !printRecurWeekly && currEvent->recurrenceType() == Recurrence::rWeekly ) ) {
00984       continue;
00985     }
00986     if ( currEvent->doesFloat() || currEvent->isMultiDay() ) {
00987       timeText = "";
00988     } else {
00989       timeText = local->formatTime( currEvent->dtStart().time() ) + ' ';
00990     }
00991     p.save();
00992     setCategoryColors( p, currEvent );
00993     QString str;
00994     if ( !currEvent->location().isEmpty() ) {
00995       str = i18n( "summary, location", "%1, %2" ).
00996             arg( currEvent->summary() ).arg( currEvent->location() );
00997     } else {
00998       str = currEvent->summary();
00999     }
01000     drawIncidence( p, box, timeText,
01001                    str, currEvent->description(),
01002                    textY, singleLineLimit );
01003     p.restore();
01004     visibleEventsCounter++;
01005 
01006     if ( textY >= maxHeight ) {
01007       const QChar downArrow( 0x21e3 );
01008       const unsigned int invisibleIncidences = ((eventList.count() - visibleEventsCounter) + mCalendar->todos( qd ).count());
01009       if ( invisibleIncidences > 0 ) {
01010         const QString warningMsg = QString( "%1 (%2)" ).arg( downArrow ).arg( invisibleIncidences );
01011         QFontMetrics fm( p.font() );
01012         QRect msgRect = fm.boundingRect( warningMsg );
01013         msgRect.setRect( box.right() - msgRect.width() - 2, box.bottom() - msgRect.height() - 2, msgRect.width(), msgRect.height() );
01014 
01015         p.save();
01016         p.setPen( Qt::red );
01017         p.drawText( msgRect, Qt::AlignLeft, warningMsg );
01018         p.restore();
01019       }
01020     }
01021   }
01022 
01023   if ( textY < maxHeight ) {
01024     Todo::List todos = mCalendar->todos( qd );
01025     Todo::List::ConstIterator it2;
01026     for ( it2 = todos.begin(); it2 != todos.end() && textY < maxHeight; ++it2 ) {
01027       Todo *todo = *it2;
01028       if ( ( !printRecurDaily  && todo->recurrenceType() == Recurrence::rDaily  ) ||
01029            ( !printRecurWeekly && todo->recurrenceType() == Recurrence::rWeekly ) ) {
01030         continue;
01031       }
01032       if ( todo->hasStartDate() && !todo->doesFloat() ) {
01033         timeText = KGlobal::locale()->formatTime( todo->dtStart().time() ) + ' ';
01034       } else {
01035         timeText = "";
01036       }
01037       p.save();
01038       setCategoryColors( p, todo );
01039       QString summaryStr;
01040       if ( !todo->location().isEmpty() ) {
01041         summaryStr = i18n( "summary, location", "%1, %2" ).
01042                      arg( todo->summary() ).arg( todo->location() );
01043       } else {
01044         summaryStr = todo->summary();
01045       }
01046 
01047       QString str;
01048       if ( todo->hasDueDate() ) {
01049         if ( !todo->doesFloat() ) {
01050           str = i18n( "%1 (Due: %2)" ).
01051                 arg( summaryStr ).
01052                 arg( KGlobal::locale()->formatDateTime( todo->dtDue() ) );
01053         } else {
01054           str = i18n( "%1 (Due: %2)" ).
01055                 arg( summaryStr ).
01056                 arg( KGlobal::locale()->formatDate( todo->dtDue().date(), true ) );
01057         }
01058       } else {
01059         str = summaryStr;
01060       }
01061       drawIncidence( p, box, timeText,
01062                      i18n( "To-do: %1" ).arg( str ), todo->description(),
01063                      textY, singleLineLimit );
01064       p.restore();
01065     }
01066   }
01067 
01068   p.setFont( oldFont );
01069 }
01070 
01071 void CalPrintPluginBase::drawIncidence( QPainter &p, const QRect &dayBox,
01072                                         const QString &time,
01073                                         const QString &summary,
01074                                         const QString &description,
01075                                         int &textY, bool singleLineLimit )
01076 {
01077   int flags = Qt::AlignLeft | Qt::OpaqueMode;
01078   QFontMetrics fm = p.fontMetrics();
01079   const int borderWidth = p.pen().width() + 1;
01080   QRect timeBound = p.boundingRect( dayBox.x() + borderWidth,
01081                                     dayBox.y() + textY,
01082                                     dayBox.width(), fm.lineSpacing(),
01083                                     flags, time );
01084 
01085   int summaryWidth = time.isEmpty() ? 0 : timeBound.width() + 3;
01086   QRect summaryBound = QRect( dayBox.x() + borderWidth + summaryWidth,
01087                               dayBox.y() + textY + 1,
01088                               dayBox.width() - summaryWidth - ( borderWidth * 2 ),
01089                               dayBox.height() - textY );
01090 
01091   QString summaryText = summary;
01092   bool boxOverflow = false;
01093 
01094   if ( singleLineLimit ) {
01095     int totalHeight = fm.lineSpacing() + borderWidth;
01096     int textBoxHeight = ( totalHeight > ( dayBox.height() - textY ) ) ?
01097                         dayBox.height() - textY : totalHeight;
01098     summaryBound.setHeight(textBoxHeight);
01099     QRect lineRect( dayBox.x() + borderWidth, dayBox.y() + textY,
01100                     dayBox.width() - ( borderWidth * 2 ), textBoxHeight );
01101     drawBox( p, 1, lineRect );
01102     if ( !time.isEmpty() ) {
01103       p.drawText( timeBound, flags, time );
01104     }
01105     p.drawText( summaryBound, flags, summaryText );
01106   } else {
01107     int textBoxHeight = dayBox.height() - textY - borderWidth;
01108     QRect clipBox( 0, 0, dayBox.width() - ( borderWidth * 2 ), textBoxHeight );
01109     if ( !time.isEmpty() ) {
01110       summaryText = time + summary;
01111     }
01112     KWordWrap *ww = KWordWrap::formatText( fm, clipBox, 0, summaryText, -1 );
01113     QRect dayBound = QRect( dayBox.x() + borderWidth,
01114                             dayBox.y() + textY + 1,
01115                             dayBox.width() - ( borderWidth * 2 ),
01116                             dayBox.height() - textY );
01117     p.save();
01118     QRect backBox( dayBound.x(), dayBound.y(),
01119                    dayBound.width(), ww->boundingRect().height() );
01120     drawBox( p, 1, backBox );
01121     ww->drawText( &p, dayBound.x(), dayBound.y(), flags );
01122     summaryBound.setHeight( ww->boundingRect().height() );
01123     p.restore();
01124   }
01125   if ( summaryBound.bottom() < dayBox.bottom() ) {
01126     QPen oldPen( p.pen() );
01127     p.setPen( QPen() );
01128     p.drawLine( dayBox.x(), summaryBound.bottom(),
01129                 dayBox.x() + dayBox.width(), summaryBound.bottom() );
01130     p.setPen( oldPen );
01131   }
01132   textY += summaryBound.height();
01133 }
01134 
01136 
01137 void CalPrintPluginBase::drawWeek(QPainter &p, const QDate &qd,
01138                                   const QRect &box, bool singleLineLimit )
01139 {
01140   QDate weekDate = qd;
01141   bool portrait = ( box.height() > box.width() );
01142   int cellWidth, cellHeight;
01143   int vcells;
01144   if (portrait) {
01145     cellWidth = box.width()/2;
01146     vcells=3;
01147   } else {
01148     cellWidth = box.width()/6;
01149     vcells=1;
01150   }
01151   cellHeight = box.height()/vcells;
01152 
01153   // correct begin of week
01154   int weekdayCol = weekdayColumn( qd.dayOfWeek() );
01155   weekDate = qd.addDays( -weekdayCol );
01156 
01157   for (int i = 0; i < 7; i++, weekDate = weekDate.addDays(1)) {
01158     // Saturday and sunday share a cell, so we have to special-case sunday
01159     int hpos = ((i<6)?i:(i-1)) / vcells;
01160     int vpos = ((i<6)?i:(i-1)) % vcells;
01161     QRect dayBox( box.left()+cellWidth*hpos, box.top()+cellHeight*vpos + ((i==6)?(cellHeight/2):0),
01162         cellWidth, (i<5)?(cellHeight):(cellHeight/2) );
01163     drawDayBox(p, weekDate, dayBox, true, singleLineLimit );
01164   } // for i through all weekdays
01165 }
01166 
01167 
01168 void CalPrintPluginBase::drawTimeTable(QPainter &p,
01169     const QDate &fromDate, const QDate &toDate,
01170     QTime &fromTime, QTime &toTime,
01171     const QRect &box)
01172 {
01173   // timeline is 1 hour:
01174   int alldayHeight = (int)( 3600.*box.height()/(fromTime.secsTo(toTime)+3600.) );
01175   int timelineWidth = TIMELINE_WIDTH;
01176 
01177   QRect dowBox( box );
01178   dowBox.setLeft( box.left() + timelineWidth );
01179   dowBox.setHeight( mSubHeaderHeight );
01180   drawDaysOfWeek( p, fromDate, toDate, dowBox );
01181 
01182   QRect tlBox( box );
01183   tlBox.setWidth( timelineWidth );
01184   tlBox.setTop( dowBox.bottom() + BOX_BORDER_WIDTH + alldayHeight );
01185   drawTimeLine( p, fromTime, toTime, tlBox );
01186 
01187   // draw each day
01188   QDate curDate(fromDate);
01189   int i=0;
01190   double cellWidth = double(dowBox.width()) / double(fromDate.daysTo(toDate)+1);
01191   while (curDate<=toDate) {
01192     QRect allDayBox( dowBox.left()+int(i*cellWidth), dowBox.bottom() + BOX_BORDER_WIDTH,
01193                      int((i+1)*cellWidth)-int(i*cellWidth), alldayHeight );
01194     QRect dayBox( allDayBox );
01195     dayBox.setTop( tlBox.top() );
01196     dayBox.setBottom( box.bottom() );
01197     Event::List eventList = mCalendar->events(curDate,
01198                                               EventSortStartDate,
01199                                               SortDirectionAscending);
01200     alldayHeight = drawAllDayBox( p, eventList, curDate, false, allDayBox );
01201     drawAgendaDayBox( p, eventList, curDate, false, fromTime, toTime, dayBox );
01202     i++;
01203     curDate=curDate.addDays(1);
01204   }
01205 
01206 }
01207 
01208 
01210 
01211 class MonthEventStruct
01212 {
01213   public:
01214     MonthEventStruct() : event(0) {}
01215     MonthEventStruct( const QDateTime &s, const QDateTime &e, Event *ev)
01216     {
01217       event = ev;
01218       start = s;
01219       end = e;
01220       if ( event->doesFloat() ) {
01221         start = QDateTime( start.date(), QTime(0,0,0) );
01222         end = QDateTime( end.date().addDays(1), QTime(0,0,0) ).addSecs(-1);
01223       }
01224     }
01225     bool operator<(const MonthEventStruct &mes) { return start < mes.start; }
01226     QDateTime start;
01227     QDateTime end;
01228     Event *event;
01229 };
01230 
01231 void CalPrintPluginBase::drawMonth( QPainter &p, const QDate &dt, const QRect &box, int maxdays, int subDailyFlags, int holidaysFlags )
01232 {
01233   const KCalendarSystem *calsys = calendarSystem();
01234   QRect subheaderBox( box );
01235   subheaderBox.setHeight( subHeaderHeight() );
01236   QRect borderBox( box );
01237   borderBox.setTop( subheaderBox.bottom()+1 );
01238   drawSubHeaderBox( p, calsys->monthName(dt), subheaderBox );
01239   // correct for half the border width
01240   int correction = (BOX_BORDER_WIDTH/*-1*/)/2;
01241   QRect daysBox( borderBox );
01242   daysBox.addCoords( correction, correction, -correction, -correction );
01243 
01244   int daysinmonth = calsys->daysInMonth( dt );
01245   if ( maxdays <= 0 ) maxdays = daysinmonth;
01246 
01247   int d;
01248   float dayheight = float(daysBox.height()) / float( maxdays );
01249 
01250   QColor holidayColor( 240, 240, 240 );
01251   QColor workdayColor( 255, 255, 255 );
01252   int dayNrWidth = p.fontMetrics().width( "99" );
01253 
01254   // Fill the remaining space (if a month has less days than others) with a crossed-out pattern
01255   if ( daysinmonth<maxdays ) {
01256     QRect dayBox( box.left(), daysBox.top() + round(dayheight*daysinmonth), box.width(), 0 );
01257     dayBox.setBottom( daysBox.bottom() );
01258     p.fillRect( dayBox, Qt::DiagCrossPattern );
01259   }
01260   // Backgrounded boxes for each day, plus day numbers
01261   QBrush oldbrush( p.brush() );
01262   for ( d = 0; d < daysinmonth; ++d ) {
01263     QDate day;
01264     calsys->setYMD( day, dt.year(), dt.month(), d+1 );
01265     QRect dayBox( daysBox.left()/*+rand()%50*/, daysBox.top() + round(dayheight*d), daysBox.width()/*-rand()%50*/, 0 );
01266     // 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!
01267     dayBox.setBottom( daysBox.top()+round(dayheight*(d+1)) - 1 );
01268 
01269     p.setBrush( isWorkingDay( day )?workdayColor:holidayColor );
01270     p.drawRect( dayBox );
01271     QRect dateBox( dayBox );
01272     dateBox.setWidth( dayNrWidth+3 );
01273     p.drawText( dateBox, Qt::AlignRight | Qt::AlignVCenter | Qt::SingleLine,
01274                 QString::number(d+1) );
01275   }
01276   p.setBrush( oldbrush );
01277   int xstartcont = box.left() + dayNrWidth + 5;
01278 
01279   QDate start, end;
01280   calsys->setYMD( start, dt.year(), dt.month(), 1 );
01281   end = calsys->addMonths( start, 1 );
01282   end = calsys->addDays( end, -1 );
01283 
01284   Event::List events = mCalendar->events( start, end );
01285   QMap<int, QStringList> textEvents;
01286   QPtrList<KOrg::CellItem> timeboxItems;
01287   timeboxItems.setAutoDelete( true );
01288 
01289 
01290   // 1) For multi-day events, show boxes spanning several cells, use CellItem
01291   //    print the summary vertically
01292   // 2) For sub-day events, print the concated summaries into the remaining
01293   //    space of the box (optional, depending on the given flags)
01294   // 3) Draw some kind of timeline showing free and busy times
01295 
01296   // Holidays
01297   Event::List holidays;
01298   holidays.setAutoDelete( true );
01299   for ( QDate d(start); d <= end; d = d.addDays(1) ) {
01300     Event *e = holiday( d );
01301     if ( e ) {
01302       holidays.append( e );
01303       if ( holidaysFlags & TimeBoxes ) {
01304         timeboxItems.append( new PrintCellItem( e, QDateTime(d, QTime(0,0,0) ),
01305             QDateTime( d.addDays(1), QTime(0,0,0) ) ) );
01306       }
01307       if ( holidaysFlags & Text ) {
01308         textEvents[ d.day() ] << e->summary();
01309       }
01310     }
01311   }
01312 
01313   QValueList<MonthEventStruct> monthentries;
01314 
01315   for ( Event::List::ConstIterator evit = events.begin();
01316         evit != events.end(); ++evit ) {
01317     Event *e = (*evit);
01318     if (!e) continue;
01319     if ( e->doesRecur() ) {
01320       if ( e->recursOn( start ) ) {
01321         // This occurrence has possibly started before the beginning of the
01322         // month, so obtain the start date before the beginning of the month
01323         QValueList<QDateTime> starttimes = e->startDateTimesForDate( start );
01324         QValueList<QDateTime>::ConstIterator it = starttimes.begin();
01325         for ( ; it != starttimes.end(); ++it ) {
01326           monthentries.append( MonthEventStruct( *it, e->endDateForStart( *it ), e ) );
01327         }
01328       }
01329       // Loop through all remaining days of the month and check if the event
01330       // begins on that day (don't use Event::recursOn, as that will
01331       // also return events that have started earlier. These start dates
01332       // however, have already been treated!
01333       Recurrence *recur = e->recurrence();
01334       QDate d1( start.addDays(1) );
01335       while ( d1 <= end ) {
01336         if ( recur->recursOn(d1) ) {
01337           TimeList times( recur->recurTimesOn( d1 ) );
01338           for ( TimeList::ConstIterator it = times.begin();
01339                 it != times.end(); ++it ) {
01340             QDateTime d1start( d1, *it );
01341             monthentries.append( MonthEventStruct( d1start, e->endDateForStart( d1start ), e ) );
01342           }
01343         }
01344         d1 = d1.addDays(1);
01345       }
01346     } else {
01347       monthentries.append( MonthEventStruct( e->dtStart(), e->dtEnd(), e ) );
01348     }
01349   }
01350   qHeapSort( monthentries );
01351 
01352   QValueList<MonthEventStruct>::ConstIterator mit = monthentries.begin();
01353   QDateTime endofmonth( end, QTime(0,0,0) );
01354   endofmonth = endofmonth.addDays(1);
01355   for ( ; mit != monthentries.end(); ++mit ) {
01356     if ( (*mit).start.date() == (*mit).end.date() ) {
01357       // Show also single-day events as time line boxes
01358       if ( subDailyFlags & TimeBoxes ) {
01359         timeboxItems.append( new PrintCellItem( (*mit).event, (*mit).start, (*mit).end ) );
01360       }
01361       // Show as text in the box
01362       if ( subDailyFlags & Text ) {
01363         textEvents[ (*mit).start.date().day() ] << (*mit).event->summary();
01364       }
01365     } else {
01366       // Multi-day events are always shown as time line boxes
01367       QDateTime thisstart( (*mit).start );
01368       QDateTime thisend( (*mit).end );
01369       if ( thisstart.date()<start ) thisstart = start;
01370       if ( thisend>endofmonth ) thisend = endofmonth;
01371       timeboxItems.append( new PrintCellItem( (*mit).event, thisstart, thisend ) );
01372     }
01373   }
01374 
01375   // For Multi-day events, line them up nicely so that the boxes don't overlap
01376   QPtrListIterator<KOrg::CellItem> it1( timeboxItems );
01377   for( it1.toFirst(); it1.current(); ++it1 ) {
01378     KOrg::CellItem *placeItem = it1.current();
01379     KOrg::CellItem::placeItem( timeboxItems, placeItem );
01380   }
01381   QDateTime starttime( start, QTime( 0, 0, 0 ) );
01382   int newxstartcont = xstartcont;
01383 
01384   QFont oldfont( p.font() );
01385   p.setFont( QFont( "sans-serif", 7 ) );
01386   for( it1.toFirst(); it1.current(); ++it1 ) {
01387     PrintCellItem *placeItem = static_cast<PrintCellItem *>( it1.current() );
01388     int minsToStart = starttime.secsTo( placeItem->start() )/60;
01389     int minsToEnd = starttime.secsTo( placeItem->end() )/60;
01390 
01391     QRect eventBox( xstartcont + placeItem->subCell()*17,
01392            daysBox.top() + round( double( minsToStart*daysBox.height()) / double(maxdays*24*60) ),
01393            14, 0 );
01394     eventBox.setBottom( daysBox.top() + round( double( minsToEnd*daysBox.height()) / double(maxdays*24*60) ) );
01395     drawVerticalBox( p, 0, eventBox, placeItem->event()->summary() );
01396     newxstartcont = QMAX( newxstartcont, eventBox.right() );
01397   }
01398   xstartcont = newxstartcont;
01399 
01400   // For Single-day events, simply print their summaries into the remaining
01401   // space of the day's cell
01402   for ( int d=0; d<daysinmonth; ++d ) {
01403     QStringList dayEvents( textEvents[d+1] );
01404     QString txt = dayEvents.join(", ");
01405     QRect dayBox( xstartcont, daysBox.top()+round(dayheight*d), 0, 0 );
01406     dayBox.setRight( box.right() );
01407     dayBox.setBottom( daysBox.top()+round(dayheight*(d+1)) );
01408     printEventString(p, dayBox, txt, Qt::AlignTop | Qt::AlignLeft | Qt::BreakAnywhere );
01409   }
01410   p.setFont( oldfont );
01411 //   p.setBrush( Qt::NoBrush );
01412   drawBox( p, BOX_BORDER_WIDTH, borderBox );
01413   p.restore();
01414 }
01415 
01417 
01418 void CalPrintPluginBase::drawMonthTable(QPainter &p, const QDate &qd,
01419                                         bool weeknumbers, bool recurDaily,
01420                                         bool recurWeekly, bool singleLineLimit,
01421                                         const QRect &box )
01422 {
01423   int yoffset = mSubHeaderHeight;
01424   int xoffset = 0;
01425   QDate monthDate(QDate(qd.year(), qd.month(), 1));
01426   QDate monthFirst(monthDate);
01427   QDate monthLast(monthDate.addMonths(1).addDays(-1));
01428 
01429 
01430   int weekdayCol = weekdayColumn( monthDate.dayOfWeek() );
01431   monthDate = monthDate.addDays(-weekdayCol);
01432 
01433   if (weeknumbers) {
01434     xoffset += 14;
01435   }
01436 
01437   int rows=(weekdayCol + qd.daysInMonth() - 1)/7 +1;
01438   double cellHeight = ( box.height() - yoffset ) / (1.*rows);
01439   double cellWidth = ( box.width() - xoffset ) / 7.;
01440 
01441   // Precalculate the grid...
01442   // rows is at most 6, so using 8 entries in the array is fine, too!
01443   int coledges[8], rowedges[8];
01444   for ( int i = 0; i <= 7; i++ ) {
01445     rowedges[i] = int( box.top() + yoffset + i*cellHeight );
01446     coledges[i] = int( box.left() + xoffset + i*cellWidth );
01447   }
01448 
01449   if (weeknumbers) {
01450     QFont oldFont(p.font());
01451     QFont newFont(p.font());
01452     newFont.setPointSize(6);
01453     p.setFont(newFont);
01454     QDate weekDate(monthDate);
01455     for (int row = 0; row<rows; ++row ) {
01456       int calWeek = weekDate.weekNumber();
01457       QRect rc( box.left(), rowedges[row], coledges[0] - 3 - box.left(), rowedges[row+1]-rowedges[row] );
01458       p.drawText( rc, Qt::AlignRight | Qt::AlignVCenter, QString::number( calWeek ) );
01459       weekDate = weekDate.addDays( 7 );
01460     }
01461     p.setFont( oldFont );
01462   }
01463 
01464   QRect daysOfWeekBox( box );
01465   daysOfWeekBox.setHeight( mSubHeaderHeight );
01466   daysOfWeekBox.setLeft( box.left()+xoffset );
01467   drawDaysOfWeek( p, monthDate, monthDate.addDays( 6 ), daysOfWeekBox );
01468 
01469   QColor back = p.backgroundColor();
01470   bool darkbg = false;
01471   for ( int row = 0; row < rows; ++row ) {
01472     for ( int col = 0; col < 7; ++col ) {
01473       // show days from previous/next month with a grayed background
01474       if ( (monthDate < monthFirst) || (monthDate > monthLast) ) {
01475         p.setBackgroundColor( back.dark( 120 ) );
01476         darkbg = true;
01477       }
01478       QRect dayBox( coledges[col], rowedges[row], coledges[col+1]-coledges[col], rowedges[row+1]-rowedges[row] );
01479       drawDayBox(p, monthDate, dayBox, false, recurDaily, recurWeekly, singleLineLimit );
01480       if ( darkbg ) {
01481         p.setBackgroundColor( back );
01482         darkbg = false;
01483       }
01484       monthDate = monthDate.addDays(1);
01485     }
01486   }
01487 }
01488 
01489 
01491 
01492 void CalPrintPluginBase::drawTodo( int &count, Todo *todo, QPainter &p,
01493                                TodoSortField sortField, SortDirection sortDir,
01494                                bool connectSubTodos, bool strikeoutCompleted,
01495                                bool desc, int posPriority, int posSummary,
01496                                int posDueDt, int posPercentComplete,
01497                                int level, int x, int &y, int width,
01498                                int pageHeight, const Todo::List &todoList,
01499                                TodoParentStart *r )
01500 {
01501   QString outStr;
01502   const KLocale *local = KGlobal::locale();
01503   QRect rect;
01504   TodoParentStart startpt;
01505 
01506   // This list keeps all starting points of the parent to-dos so the connection
01507   // lines of the tree can easily be drawn (needed if a new page is started)
01508   static QPtrList<TodoParentStart> startPoints;
01509   if ( level < 1 ) {
01510     startPoints.clear();
01511   }
01512 
01513   // Compute the right hand side of the to-do box
01514   int rhs = posPercentComplete;
01515   if ( rhs < 0 ) rhs = posDueDt; //not printing percent completed
01516   if ( rhs < 0 ) rhs = x+width;  //not printing due dates either
01517 
01518   // size of to-do
01519   outStr=todo->summary();
01520   int left = posSummary + ( level*10 );
01521   rect = p.boundingRect( left, y, ( rhs-left-5 ), -1, Qt::WordBreak, outStr );
01522   if ( !todo->description().isEmpty() && desc ) {
01523     outStr = todo->description();
01524     rect = p.boundingRect( left+20, rect.bottom()+5, width-(left+10-x), -1,
01525                            Qt::WordBreak, outStr );
01526   }
01527   // if too big make new page
01528   if ( rect.bottom() > pageHeight ) {
01529     // first draw the connection lines from parent to-dos:
01530     if ( level > 0 && connectSubTodos ) {
01531       TodoParentStart *rct;
01532       for ( rct = startPoints.first(); rct; rct = startPoints.next() ) {
01533         int start;
01534         int center = rct->mRect.left() + (rct->mRect.width()/2);
01535         int to = p.viewport().bottom();
01536 
01537         // draw either from start point of parent or from top of the page
01538         if ( rct->mSamePage )
01539           start = rct->mRect.bottom() + 1;
01540         else
01541           start = p.viewport().top();
01542         p.moveTo( center, start );
01543         p.lineTo( center, to );
01544         rct->mSamePage = false;
01545       }
01546     }
01547     y=0;
01548     mPrinter->newPage();
01549   }
01550 
01551   // If this is a sub-to-do, r will not be 0, and we want the LH side
01552   // of the priority line up to the RH side of the parent to-do's priority
01553   bool showPriority = posPriority>=0;
01554   int lhs = posPriority;
01555   if ( r ) {
01556     lhs = r->mRect.right() + 1;
01557   }
01558 
01559   outStr.setNum( todo->priority() );
01560   rect = p.boundingRect( lhs, y + 10, 5, -1, Qt::AlignCenter, outStr );
01561   // Make it a more reasonable size
01562   rect.setWidth(18);
01563   rect.setHeight(18);
01564 
01565   // Draw a checkbox
01566   p.setBrush( QBrush( Qt::NoBrush ) );
01567   p.drawRect( rect );
01568   if ( todo->isCompleted() ) {
01569     // cross out the rectangle for completed to-dos
01570     p.drawLine( rect.topLeft(), rect.bottomRight() );
01571     p.drawLine( rect.topRight(), rect.bottomLeft() );
01572   }
01573   lhs = rect.right() + 3;
01574 
01575   // Priority
01576   if ( todo->priority() > 0 && showPriority ) {
01577     p.drawText( rect, Qt::AlignCenter, outStr );
01578   }
01579   startpt.mRect = rect; //save for later
01580 
01581   // Connect the dots
01582   if ( level > 0 && connectSubTodos ) {
01583     int bottom;
01584     int center( r->mRect.left() + (r->mRect.width()/2) );
01585     if ( r->mSamePage )
01586       bottom = r->mRect.bottom() + 1;
01587     else
01588       bottom = 0;
01589     int to( rect.top() + (rect.height()/2) );
01590     int endx( rect.left() );
01591     p.moveTo( center, bottom );
01592     p.lineTo( center, to );
01593     p.lineTo( endx, to );
01594   }
01595 
01596   // summary
01597   outStr=todo->summary();
01598   rect = p.boundingRect( lhs, rect.top(), (rhs-(left + rect.width() + 5)),
01599                          -1, Qt::WordBreak, outStr );
01600 
01601   QRect newrect;
01602   //FIXME: the following code prints underline rather than strikeout text
01603 #if 0
01604   QFont f( p.font() );
01605   if ( todo->isCompleted() && strikeoutCompleted ) {
01606     f.setStrikeOut( true );
01607     p.setFont( f );
01608   }
01609   p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
01610   f.setStrikeOut( false );
01611   p.setFont( f );
01612 #endif
01613   //TODO: Remove this section when the code above is fixed
01614   p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
01615   if ( todo->isCompleted() && strikeoutCompleted ) {
01616     // strike out the summary text if to-do is complete
01617     // Note: we tried to use a strike-out font and for unknown reasons the
01618     // result was underline instead of strike-out, so draw the lines ourselves.
01619     int delta = p.fontMetrics().lineSpacing();
01620     int lines = ( rect.height() / delta ) + 1;
01621     for ( int i=0; i<lines; i++ ) {
01622       p.moveTo( rect.left(),  rect.top() + ( delta/2 ) + ( i*delta ) );
01623       p.lineTo( rect.right(), rect.top() + ( delta/2 ) + ( i*delta ) );
01624     }
01625   }
01626 
01627   // due date
01628   if ( todo->hasDueDate() && posDueDt>=0 ) {
01629     outStr = local->formatDate( todo->dtDue().date(), true );
01630     rect = p.boundingRect( posDueDt, y, x + width, -1,
01631                            Qt::AlignTop | Qt::AlignLeft, outStr );
01632     p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr );
01633   }
01634 
01635   // percentage completed
01636   bool showPercentComplete = posPercentComplete>=0;
01637   if ( showPercentComplete ) {
01638     int lwidth = 24;
01639     int lheight = 12;
01640     //first, draw the progress bar
01641     int progress = (int)(( lwidth*todo->percentComplete())/100.0 + 0.5);
01642 
01643     p.setBrush( QBrush( Qt::NoBrush ) );
01644     p.drawRect( posPercentComplete, y+3, lwidth, lheight );
01645     if ( progress > 0 ) {
01646       p.setBrush( QColor( 128, 128, 128 ) );
01647       p.drawRect( posPercentComplete, y+3, progress, lheight );
01648     }
01649 
01650     //now, write the percentage
01651     outStr = i18n( "%1%" ).arg( todo->percentComplete() );
01652     rect = p.boundingRect( posPercentComplete+lwidth+3, y, x + width, -1,
01653                            Qt::AlignTop | Qt::AlignLeft, outStr );
01654     p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr );
01655   }
01656 
01657   // description
01658   if ( !todo->description().isEmpty() && desc ) {
01659     y = newrect.bottom() + 5;
01660     outStr = todo->description();
01661     rect = p.boundingRect( left+20, y, x+width-(left+10), -1,
01662                            Qt::WordBreak, outStr );
01663     p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
01664   }
01665 
01666   // Set the new line position
01667   y = newrect.bottom() + 10; //set the line position
01668 
01669   // If the to-do has sub-to-dos, we need to call ourselves recursively
01670 #if 0
01671   Incidence::List l = todo->relations();
01672   Incidence::List::ConstIterator it;
01673   startPoints.append( &startpt );
01674   for( it = l.begin(); it != l.end(); ++it ) {
01675     count++;
01676     // In the future, to-dos might also be related to events
01677     // Manually check if the sub-to-do is in the list of to-dos to print
01678     // The problem is that relations() does not apply filters, so
01679     // we need to compare manually with the complete filtered list!
01680     Todo* subtodo = dynamic_cast<Todo *>( *it );
01681     if (subtodo && todoList.contains( subtodo ) ) {
01682       drawTodo( count, subtodo, p, connectSubTodos, strikeoutCompleted,
01683                 desc, posPriority, posSummary, posDueDt, posPercentComplete,
01684                 level+1, x, y, width, pageHeight, todoList, &startpt );
01685     }
01686   }
01687 #endif
01688   // Make a list of all the sub-to-dos related to this to-do.
01689   Todo::List t;
01690   Incidence::List l = todo->relations();
01691   Incidence::List::ConstIterator it;
01692   for( it=l.begin(); it!=l.end(); ++it ) {
01693     // In the future, to-dos might also be related to events
01694     // Manually check if the sub-to-do is in the list of to-dos to print
01695     // The problem is that relations() does not apply filters, so
01696     // we need to compare manually with the complete filtered list!
01697     Todo* subtodo = dynamic_cast<Todo *>( *it );
01698     if ( subtodo && todoList.contains( subtodo ) ) {
01699       t.append( subtodo );
01700     }
01701   }
01702 
01703   // Sort the sub-to-dos and then print them
01704   Todo::List sl = mCalendar->sortTodos( &t, sortField, sortDir );
01705   Todo::List::ConstIterator isl;
01706   startPoints.append( &startpt );
01707   for( isl = sl.begin(); isl != sl.end(); ++isl ) {
01708     count++;
01709     drawTodo( count, ( *isl ), p, sortField, sortDir,
01710               connectSubTodos, strikeoutCompleted,
01711               desc, posPriority, posSummary, posDueDt, posPercentComplete,
01712               level+1, x, y, width, pageHeight, todoList, &startpt );
01713   }
01714   startPoints.remove( &startpt );
01715 }
01716 
01717 int CalPrintPluginBase::weekdayColumn( int weekday )
01718 {
01719   return ( weekday + 7 - KGlobal::locale()->weekStartDay() ) % 7;
01720 }
01721 
01722 void CalPrintPluginBase::drawJournalField( QPainter &p, QString field, QString text,
01723                                        int x, int &y, int width, int pageHeight )
01724 {
01725   if ( text.isEmpty() ) return;
01726 
01727   QString entry( field.arg( text ) );
01728 
01729   QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, entry) );
01730   if ( rect.bottom() > pageHeight) {
01731     // Start new page...
01732     // FIXME: If it's a multi-line text, draw a few lines on this page, and the
01733     // remaining lines on the next page.
01734     y=0;
01735     mPrinter->newPage();
01736     rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, entry);
01737   }
01738   QRect newrect;
01739   p.drawText( rect, Qt::WordBreak, entry, -1, &newrect );
01740   y = newrect.bottom() + 7;
01741 }
01742 
01743 void CalPrintPluginBase::drawJournal( Journal * journal, QPainter &p, int x, int &y,
01744                                   int width, int pageHeight )
01745 {
01746   QFont oldFont( p.font() );
01747   p.setFont( QFont( "sans-serif", 15 ) );
01748   QString headerText;
01749   QString dateText( KGlobal::locale()->
01750         formatDate( journal->dtStart().date(), false ) );
01751 
01752   if ( journal->summary().isEmpty() ) {
01753     headerText = dateText;
01754   } else {
01755     headerText = i18n("Description - date", "%1 - %2")
01756                      .arg( journal->summary() )
01757                      .arg( dateText );
01758   }
01759 
01760   QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText) );
01761   if ( rect.bottom() > pageHeight) {
01762     // Start new page...
01763     y=0;
01764     mPrinter->newPage();
01765     rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText );
01766   }
01767   QRect newrect;
01768   p.drawText( rect, Qt::WordBreak, headerText, -1, &newrect );
01769   p.setFont( oldFont );
01770 
01771   y = newrect.bottom() + 4;
01772 
01773   p.drawLine( x + 3, y, x + width - 6, y );
01774   y += 5;
01775 
01776   drawJournalField( p, i18n("Person: %1"), journal->organizer().fullName(), x, y, width, pageHeight );
01777   drawJournalField( p, i18n("%1"), journal->description(), x, y, width, pageHeight );
01778   y += 10;
01779 }
01780 
01781 
01782 void CalPrintPluginBase::drawSplitHeaderRight( QPainter &p, const QDate &fd,
01783                                            const QDate &td,
01784                                            const QDate &,
01785                                            int width, int )
01786 {
01787   QFont oldFont( p.font() );
01788 
01789   QPen oldPen( p.pen() );
01790   QPen pen( Qt::black, 4 );
01791 
01792   QString title;
01793   if ( mCalSys ) {
01794     if ( fd.month() == td.month() ) {
01795       title = i18n("Date range: Month dayStart - dayEnd", "%1 %2 - %3")
01796         .arg( mCalSys->monthName( fd.month(), false ) )
01797         .arg( mCalSys->dayString( fd, false ) )
01798         .arg( mCalSys->dayString( td, false ) );
01799     } else {
01800       title = i18n("Date range: monthStart dayStart - monthEnd dayEnd", "%1 %2 - %3 %4")
01801         .arg( mCalSys->monthName( fd.month(), false ) )
01802         .arg( mCalSys->dayString( fd, false ) )
01803         .arg( mCalSys->monthName( td.month(), false ) )
01804         .arg( mCalSys->dayString( td, false ) );
01805     }
01806   }
01807 
01808   QFont serifFont("Times", 30);
01809   p.setFont(serifFont);
01810 
01811   int lineSpacing = p.fontMetrics().lineSpacing();
01812   p.drawText( 0, lineSpacing * 0, width, lineSpacing,
01813               Qt::AlignRight | Qt::AlignTop, title );
01814 
01815   title.truncate(0);
01816 
01817   p.setPen( pen );
01818   p.drawLine(300, lineSpacing * 1, width, lineSpacing * 1);
01819   p.setPen( oldPen );
01820 
01821   p.setFont(QFont("Times", 20, QFont::Bold, TRUE));
01822   int newlineSpacing = p.fontMetrics().lineSpacing();
01823   title += QString::number(fd.year());
01824   p.drawText( 0, lineSpacing * 1 + 4, width, newlineSpacing,
01825               Qt::AlignRight | Qt::AlignTop, title );
01826 
01827   p.setFont( oldFont );
01828 }
01829 
01830 #endif
KDE Home | KDE Accessibility Home | Description of Access Keys