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, const QRect &box, Incidence *incidence, const QString &str, int flags )
00395 {
00396   QPen oldpen( p.pen() );
00397   QBrush oldbrush( p.brush() );
00398   QColor bgColor( categoryBgColor( incidence ) );
00399   if ( mUseColors & bgColor.isValid() ) {
00400     p.setBrush( bgColor );
00401   } else {
00402     p.setBrush( QColor( 232, 232, 232 ) );
00403   }
00404   drawBox( p, EVENT_BORDER_WIDTH, box );
00405 
00406   if ( mUseColors && bgColor.isValid() ) {
00407     p.setPen( textColor( bgColor ) );
00408   }
00409   printEventString( p, box, str, flags );
00410   p.setPen( oldpen );
00411   p.setBrush( oldbrush );
00412 }
00413 
00414 
00415 void CalPrintPluginBase::drawSubHeaderBox(QPainter &p, const QString &str, const QRect &box )
00416 {
00417   drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), box );
00418   QFont oldfont( p.font() );
00419   p.setFont( QFont( "sans-serif", 10, QFont::Bold ) );
00420   p.drawText( box, Qt::AlignCenter | Qt::AlignVCenter, str );
00421   p.setFont( oldfont );
00422 }
00423 
00424 void CalPrintPluginBase::drawVerticalBox( QPainter &p, const QRect &box, const QString &str,
00425                                           int flags )
00426 {
00427   p.save();
00428   p.rotate( -90 );
00429   QRect rotatedBox( -box.top()-box.height(), box.left(), box.height(), box.width() );
00430   showEventBox( p, rotatedBox, 0, str,
00431                 ( flags == -1 ) ? Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine : flags );
00432 
00433   p.restore();
00434 }
00435 
00436 
00437 
00439 // Return value: If expand, bottom of the printed box, otherwise vertical end
00440 // of the printed contents inside the box.
00441 
00442 int CalPrintPluginBase::drawBoxWithCaption( QPainter &p, const QRect &allbox,
00443         const QString &caption, const QString &contents, bool sameLine, bool expand, const QFont &captionFont, const QFont &textFont )
00444 {
00445   QFont oldFont( p.font() );
00446 //   QFont captionFont( "sans-serif", 11, QFont::Bold );
00447 //   QFont textFont( "sans-serif", 11, QFont::Normal );
00448 //   QFont captionFont( "Tahoma", 11, QFont::Bold );
00449 //   QFont textFont( "Tahoma", 11, QFont::Normal );
00450 
00451 
00452   QRect box( allbox );
00453 
00454   // Bounding rectangle for caption, single-line, clip on the right
00455   QRect captionBox( box.left() + padding(), box.top() + padding(), 0, 0 );
00456   p.setFont( captionFont );
00457   captionBox = p.boundingRect( captionBox, Qt::AlignLeft | Qt::AlignTop | Qt::SingleLine, caption );
00458   p.setFont( oldFont );
00459   if ( captionBox.right() > box.right() )
00460     captionBox.setRight( box.right() );
00461   if ( expand && captionBox.bottom() + padding() > box.bottom() )
00462     box.setBottom( captionBox.bottom() + padding() );
00463 
00464   // Bounding rectangle for the contents (if any), word break, clip on the bottom
00465   QRect textBox( captionBox );
00466   if ( !contents.isEmpty() ) {
00467     if ( sameLine ) {
00468       textBox.setLeft( captionBox.right() + padding() );
00469     } else {
00470       textBox.setTop( captionBox.bottom() + padding() );
00471     }
00472     textBox.setRight( box.right() );
00473     textBox.setHeight( 0 );
00474     p.setFont( textFont );
00475     textBox = p.boundingRect( textBox, Qt::WordBreak | Qt::AlignTop | Qt::AlignLeft, contents );
00476     p.setFont( oldFont );
00477     if ( textBox.bottom() + padding() > box.bottom() ) {
00478       if ( expand ) {
00479         box.setBottom( textBox.bottom() + padding() );
00480       } else {
00481         textBox.setBottom( box.bottom() );
00482       }
00483     }
00484   }
00485 
00486   drawBox( p, BOX_BORDER_WIDTH, box );
00487   p.setFont( captionFont );
00488   p.drawText( captionBox, Qt::AlignLeft | Qt::AlignTop | Qt::SingleLine, caption );
00489   if ( !contents.isEmpty() ) {
00490     p.setFont( textFont );
00491     p.drawText( textBox, Qt::WordBreak | Qt::AlignTop | Qt::AlignLeft, contents );
00492   }
00493   p.setFont( oldFont );
00494 
00495   if ( expand ) {
00496     return box.bottom();
00497   } else {
00498     return textBox.bottom();
00499   }
00500 }
00501 
00502 
00504 
00505 int CalPrintPluginBase::drawHeader( QPainter &p, QString title,
00506     const QDate &month1, const QDate &month2, const QRect &allbox, bool expand )
00507 {
00508   // print previous month for month view, print current for to-do, day and week
00509   int smallMonthWidth = (allbox.width()/4) - 10;
00510   if (smallMonthWidth>100) smallMonthWidth=100;
00511 
00512   int right = allbox.right();
00513   if ( month1.isValid() ) right -= (20+smallMonthWidth);
00514   if ( month2.isValid() ) right -= (20+smallMonthWidth);
00515   QRect box( allbox );
00516   QRect textRect( allbox );
00517   textRect.addCoords( 5, 0, 0, 0 );
00518   textRect.setRight( right );
00519 
00520 
00521   QFont oldFont( p.font() );
00522   QFont newFont("sans-serif", (textRect.height()<60)?16:18, QFont::Bold);
00523   if ( expand ) {
00524     p.setFont( newFont );
00525     QRect boundingR = p.boundingRect( textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::WordBreak, title );
00526     p.setFont( oldFont );
00527     int h = boundingR.height();
00528     if ( h > allbox.height() ) {
00529       box.setHeight( h );
00530       textRect.setHeight( h );
00531     }
00532   }
00533 
00534   drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), box );
00535 
00536   QRect monthbox( box.right()-10-smallMonthWidth, box.top(), smallMonthWidth, box.height() );
00537   if (month2.isValid()) {
00538     drawSmallMonth( p, QDate(month2.year(), month2.month(), 1), monthbox );
00539     monthbox.moveBy( -20 - smallMonthWidth, 0 );
00540   }
00541   if (month1.isValid()) {
00542     drawSmallMonth( p, QDate(month1.year(), month1.month(), 1), monthbox );
00543     monthbox.moveBy( -20 - smallMonthWidth, 0 );
00544   }
00545 
00546   // Set the margins
00547   p.setFont( newFont );
00548   p.drawText( textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::WordBreak, title );
00549   p.setFont( oldFont );
00550 
00551   return textRect.bottom();
00552 }
00553 
00554 
00555 int CalPrintPluginBase::drawFooter( QPainter &p, QRect &footbox )
00556 {
00557   QFont oldfont( p.font() );
00558   p.setFont( QFont( "sans-serif", 6 ) );
00559   QFontMetrics fm( p.font() );
00560   QString dateStr = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(), false );
00561   p.drawText( footbox, Qt::AlignCenter | Qt::AlignVCenter | Qt::SingleLine,
00562               i18n( "print date: formatted-datetime", "printed: %1" ).arg( dateStr ) );
00563   p.setFont( oldfont );
00564 
00565   return footbox.bottom();
00566 }
00567 
00568 void CalPrintPluginBase::drawSmallMonth(QPainter &p, const QDate &qd,
00569     const QRect &box )
00570 {
00571 
00572   int weekdayCol = weekdayColumn( qd.dayOfWeek() );
00573   int month = qd.month();
00574   QDate monthDate(QDate(qd.year(), qd.month(), 1));
00575   // correct begin of week
00576   QDate monthDate2( monthDate.addDays( -weekdayCol ) );
00577 
00578   double cellWidth = double(box.width())/double(7);
00579   int rownr = 3 + ( qd.daysInMonth() + weekdayCol - 1 ) / 7;
00580   // 3 Pixel after month name, 2 after day names, 1 after the calendar
00581   double cellHeight = (box.height() - 5) / rownr;
00582   QFont oldFont( p.font() );
00583   p.setFont(QFont("sans-serif", int(cellHeight-1), QFont::Normal));
00584 
00585   // draw the title
00586   if ( mCalSys ) {
00587     QRect titleBox( box );
00588     titleBox.setHeight( int(cellHeight+1) );
00589     p.drawText( titleBox, Qt::AlignTop | Qt::AlignHCenter, mCalSys->monthName( qd ) );
00590   }
00591 
00592   // draw days of week
00593   QRect wdayBox( box );
00594   wdayBox.setTop( int( box.top() + 3 + cellHeight ) );
00595   wdayBox.setHeight( int(2*cellHeight)-int(cellHeight) );
00596 
00597   if ( mCalSys ) {
00598     for (int col = 0; col < 7; ++col) {
00599       QString tmpStr = mCalSys->weekDayName( monthDate2 )[0].upper();
00600       wdayBox.setLeft( int(box.left() + col*cellWidth) );
00601       wdayBox.setRight( int(box.left() + (col+1)*cellWidth) );
00602       p.drawText( wdayBox, Qt::AlignCenter, tmpStr );
00603       monthDate2 = monthDate2.addDays( 1 );
00604     }
00605   }
00606 
00607   // draw separator line
00608   int calStartY = wdayBox.bottom() + 2;
00609   p.drawLine( box.left(), calStartY, box.right(), calStartY );
00610   monthDate = monthDate.addDays( -weekdayCol );
00611 
00612   for ( int row = 0; row < (rownr-2); row++ ) {
00613     for ( int col = 0; col < 7; col++ ) {
00614       if ( monthDate.month() == month ) {
00615         QRect dayRect( int( box.left() + col*cellWidth ), int( calStartY + row*cellHeight ), 0, 0 );
00616         dayRect.setRight( int( box.left() + (col+1)*cellWidth ) );
00617         dayRect.setBottom( int( calStartY + (row+1)*cellHeight ) );
00618         p.drawText( dayRect, Qt::AlignCenter, QString::number( monthDate.day() ) );
00619       }
00620       monthDate = monthDate.addDays(1);
00621     }
00622   }
00623   p.setFont( oldFont );
00624 }
00625 
00626 
00627 
00628 
00629 
00631 
00632 /*
00633  * This routine draws a header box over the main part of the calendar
00634  * containing the days of the week.
00635  */
00636 void CalPrintPluginBase::drawDaysOfWeek(QPainter &p,
00637     const QDate &fromDate, const QDate &toDate, const QRect &box )
00638 {
00639   double cellWidth = double(box.width()) / double(fromDate.daysTo( toDate )+1);
00640   QDate cellDate( fromDate );
00641   QRect dateBox( box );
00642   int i = 0;
00643 
00644   while ( cellDate <= toDate ) {
00645     dateBox.setLeft( box.left() + int(i*cellWidth) );
00646     dateBox.setRight( box.left() + int((i+1)*cellWidth) );
00647     drawDaysOfWeekBox(p, cellDate, dateBox );
00648     cellDate = cellDate.addDays(1);
00649     i++;
00650   }
00651 }
00652 
00653 
00654 void CalPrintPluginBase::drawDaysOfWeekBox(QPainter &p, const QDate &qd,
00655     const QRect &box )
00656 {
00657   drawSubHeaderBox( p, (mCalSys)?(mCalSys->weekDayName( qd )):(QString::null), box );
00658 }
00659 
00660 
00661 void CalPrintPluginBase::drawTimeLine( QPainter &p, const QTime &fromTime,
00662                                        const QTime &toTime, const QRect &box )
00663 {
00664   drawBox( p, BOX_BORDER_WIDTH, box );
00665 
00666   int totalsecs = fromTime.secsTo( toTime );
00667   float minlen = (float)box.height() * 60. / (float)totalsecs;
00668   float cellHeight = ( 60. * (float)minlen );
00669   float currY = box.top();
00670   // TODO: Don't use half of the width, but less, for the minutes!
00671   int xcenter = box.left() + box.width() / 2;
00672 
00673   QTime curTime( fromTime );
00674   QTime endTime( toTime );
00675   if ( fromTime.minute() > 30 ) {
00676     curTime = QTime( fromTime.hour()+1, 0, 0 );
00677   } else if ( fromTime.minute() > 0 ) {
00678     curTime = QTime( fromTime.hour(), 30, 0 );
00679     float yy = currY + minlen * (float)fromTime.secsTo( curTime ) / 60.;
00680     p.drawLine( xcenter, (int)yy, box.right(), (int)yy );
00681     curTime = QTime( fromTime.hour() + 1, 0, 0 );
00682   }
00683   currY += ( float( fromTime.secsTo( curTime ) * minlen ) / 60. );
00684 
00685   while ( curTime < endTime ) {
00686     p.drawLine( box.left(), (int)currY, box.right(), (int)currY );
00687     int newY = (int)( currY + cellHeight / 2. );
00688     QString numStr;
00689     if ( newY < box.bottom() ) {
00690       QFont oldFont( p.font() );
00691       // draw the time:
00692       if ( !KGlobal::locale()->use12Clock() ) {
00693         p.drawLine( xcenter, (int)newY, box.right(), (int)newY );
00694         numStr.setNum( curTime.hour() );
00695         if  ( cellHeight > 30 ) {
00696           p.setFont( QFont( "sans-serif", 14, QFont::Bold ) );
00697         } else {
00698           p.setFont( QFont( "sans-serif", 12, QFont::Bold ) );
00699         }
00700         p.drawText( box.left() + 4, (int)currY + 2, box.width() / 2 - 2, (int)cellHeight,
00701                     Qt::AlignTop | Qt::AlignRight, numStr );
00702         p.setFont( QFont ( "helvetica", 10, QFont::Normal ) );
00703         p.drawText( xcenter + 4, (int)currY + 2, box.width() / 2 + 2, (int)(cellHeight / 2 ) - 3,
00704                     Qt::AlignTop | Qt::AlignLeft, "00" );
00705       } else {
00706         p.drawLine( box.left(), (int)newY, box.right(), (int)newY );
00707         QTime time( curTime.hour(), 0 );
00708         numStr = KGlobal::locale()->formatTime( time );
00709         if ( box.width() < 60 ) {
00710           p.setFont( QFont( "sans-serif", 7, QFont::Bold ) ); // for weekprint
00711         } else {
00712           p.setFont( QFont( "sans-serif", 12, QFont::Bold ) ); // for dayprint
00713         }
00714         p.drawText( box.left() + 2, (int)currY + 2, box.width() - 4, (int)cellHeight / 2 - 3,
00715                     Qt::AlignTop|Qt::AlignLeft, numStr );
00716       }
00717       currY += cellHeight;
00718       p.setFont( oldFont );
00719     } // enough space for half-hour line and time
00720     if ( curTime.secsTo( endTime ) > 3600 ) {
00721       curTime = curTime.addSecs( 3600 );
00722     } else {
00723       curTime = endTime;
00724     }
00725   } // currTime<endTime
00726 }
00727 
00734 int CalPrintPluginBase::drawAllDayBox(QPainter &p, Event::List &eventList,
00735     const QDate &qd, bool expandable, const QRect &box )
00736 {
00737   Event::List::Iterator it, itold;
00738 
00739   int offset=box.top();
00740 
00741   QString multiDayStr;
00742 
00743   Event*hd = holiday( qd );
00744   if ( hd ) eventList.prepend( hd );
00745 
00746   it = eventList.begin();
00747   Event *currEvent = 0;
00748   // First, print all floating events
00749   while( it!=eventList.end() ) {
00750     currEvent=*it;
00751     itold=it;
00752     ++it;
00753     if ( currEvent && currEvent->doesFloat() ) {
00754       // set the colors according to the categories
00755       if ( expandable ) {
00756         QRect eventBox( box );
00757         eventBox.setTop( offset );
00758         showEventBox( p, eventBox, currEvent, currEvent->summary() );
00759         offset += box.height();
00760       } else {
00761         if ( !multiDayStr.isEmpty() ) multiDayStr += ", ";
00762         multiDayStr += currEvent->summary();
00763       }
00764       eventList.remove( itold );
00765     }
00766   }
00767   if ( hd ) delete hd;
00768 
00769   int ret = box.height();
00770   QRect eventBox( box );
00771   if (!expandable) {
00772     if (!multiDayStr.isEmpty()) {
00773       drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 128, 128, 128 ), eventBox );
00774       printEventString( p, eventBox, multiDayStr );
00775     } else {
00776       drawBox( p, BOX_BORDER_WIDTH, eventBox );
00777     }
00778   } else {
00779     ret = offset - box.top();
00780     eventBox.setBottom( ret );
00781     drawBox( p, BOX_BORDER_WIDTH, eventBox );
00782   }
00783   return ret;
00784 }
00785 
00786 
00787 void CalPrintPluginBase::drawAgendaDayBox( QPainter &p, Event::List &events,
00788                                      const QDate &qd, bool expandable,
00789                                      QTime &fromTime, QTime &toTime,
00790                                      const QRect &oldbox )
00791 {
00792   if ( !isWorkingDay( qd ) ) {
00793     drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), oldbox );
00794   } else {
00795     drawBox( p, BOX_BORDER_WIDTH, oldbox );
00796   }
00797   QRect box( oldbox );
00798   // Account for the border with and cut away that margin from the interior
00799 //   box.setRight( box.right()-BOX_BORDER_WIDTH );
00800 
00801   Event *event;
00802 
00803   if ( expandable ) {
00804     // Adapt start/end times to include complete events
00805     Event::List::ConstIterator it;
00806     for ( it = events.begin(); it != events.end(); ++it ) {
00807       event = *it;
00808       if ( event->dtStart().time() < fromTime )
00809         fromTime = event->dtStart().time();
00810       if ( event->dtEnd().time() > toTime )
00811         toTime = event->dtEnd().time();
00812     }
00813   }
00814 
00815   // Show at least one hour
00816 //   if ( fromTime.secsTo( toTime ) < 3600 ) {
00817 //     fromTime = QTime( fromTime.hour(), 0, 0 );
00818 //     toTime = fromTime.addSecs( 3600 );
00819 //   }
00820 
00821   // calculate the height of a cell and of a minute
00822   int totalsecs = fromTime.secsTo( toTime );
00823   float minlen = box.height() * 60. / totalsecs;
00824   float cellHeight = 60. * minlen;
00825   float currY = box.top();
00826 
00827   // print grid:
00828   QTime curTime( QTime( fromTime.hour(), 0, 0 ) );
00829   currY += fromTime.secsTo( curTime ) * minlen / 60;
00830 
00831   while ( curTime < toTime && curTime.isValid() ) {
00832     if ( currY > box.top() )
00833       p.drawLine( box.left(), int( currY ), box.right(), int( currY ) );
00834     currY += cellHeight / 2;
00835     if ( ( currY > box.top() ) && ( currY < box.bottom() ) ) {
00836       // enough space for half-hour line
00837       QPen oldPen( p.pen() );
00838       p.setPen( QColor( 192, 192, 192 ) );
00839       p.drawLine( box.left(), int( currY ), box.right(), int( currY ) );
00840       p.setPen( oldPen );
00841     }
00842     if ( curTime.secsTo( toTime ) > 3600 )
00843       curTime = curTime.addSecs( 3600 );
00844     else curTime = toTime;
00845     currY += cellHeight / 2;
00846   }
00847 
00848   QDateTime startPrintDate = QDateTime( qd, fromTime );
00849   QDateTime endPrintDate = QDateTime( qd, toTime );
00850 
00851   // Calculate horizontal positions and widths of events taking into account
00852   // overlapping events
00853 
00854   QPtrList<KOrg::CellItem> cells;
00855   cells.setAutoDelete( true );
00856 
00857   Event::List::ConstIterator itEvents;
00858   for( itEvents = events.begin(); itEvents != events.end(); ++itEvents ) {
00859     QValueList<QDateTime> times = (*itEvents)->startDateTimesForDate( qd );
00860     for ( QValueList<QDateTime>::ConstIterator it = times.begin();
00861           it != times.end(); ++it ) {
00862       cells.append( new PrintCellItem( *itEvents, (*it), (*itEvents)->endDateForStart( *it ) ) );
00863     }
00864   }
00865 
00866   QPtrListIterator<KOrg::CellItem> it1( cells );
00867   for( it1.toFirst(); it1.current(); ++it1 ) {
00868     KOrg::CellItem *placeItem = it1.current();
00869     KOrg::CellItem::placeItem( cells, placeItem );
00870   }
00871 
00872 //   p.setFont( QFont( "sans-serif", 10 ) );
00873 
00874   for( it1.toFirst(); it1.current(); ++it1 ) {
00875     PrintCellItem *placeItem = static_cast<PrintCellItem *>( it1.current() );
00876     drawAgendaItem( placeItem, p, startPrintDate, endPrintDate, minlen, box );
00877   }
00878 //   p.setFont( oldFont );
00879 }
00880 
00881 
00882 
00883 void CalPrintPluginBase::drawAgendaItem( PrintCellItem *item, QPainter &p,
00884                                    const QDateTime &startPrintDate,
00885                                    const QDateTime &endPrintDate,
00886                                    float minlen, const QRect &box )
00887 {
00888   Event *event = item->event();
00889 
00890   // start/end of print area for event
00891   QDateTime startTime = item->start();
00892   QDateTime endTime = item->end();
00893   if ( ( startTime < endPrintDate && endTime > startPrintDate ) ||
00894        ( endTime > startPrintDate && startTime < endPrintDate ) ) {
00895     if ( startTime < startPrintDate ) startTime = startPrintDate;
00896     if ( endTime > endPrintDate ) endTime = endPrintDate;
00897     int currentWidth = box.width() / item->subCells();
00898     int currentX = box.left() + item->subCell() * currentWidth;
00899     int currentYPos = int( box.top() + startPrintDate.secsTo( startTime ) *
00900                            minlen / 60. );
00901     int currentHeight = int( box.top() + startPrintDate.secsTo( endTime ) * minlen / 60. ) - currentYPos;
00902 
00903     QRect eventBox( currentX, currentYPos, currentWidth, currentHeight );
00904     QString str;
00905     if ( event->location().isEmpty() ) {
00906       str = i18n( "starttime - endtime summary",
00907                   "%1-%2 %3" ).
00908             arg( KGlobal::locale()->formatTime( startTime.time() ) ).
00909             arg( KGlobal::locale()->formatTime( endTime.time() ) ).
00910             arg( cleanStr( event->summary() ) );
00911     } else {
00912       str = i18n( "starttime - endtime summary, location",
00913                   "%1-%2 %3, %4" ).
00914             arg( KGlobal::locale()->formatTime( startTime.time() ) ).
00915             arg( KGlobal::locale()->formatTime( endTime.time() ) ).
00916             arg( cleanStr( event->summary() ) ).
00917             arg( cleanStr( event->location() ) );
00918     }
00919     showEventBox( p, eventBox, event, str );
00920   }
00921 }
00922 
00923 //TODO TODO TODO
00924 void CalPrintPluginBase::drawDayBox( QPainter &p, const QDate &qd,
00925     const QRect &box,
00926     bool fullDate, bool printRecurDaily, bool printRecurWeekly )
00927 {
00928   QString dayNumStr;
00929   const KLocale*local = KGlobal::locale();
00930 
00931   // This has to be localized
00932   if ( fullDate && mCalSys ) {
00933 
00934     dayNumStr = i18n("weekday month date", "%1 %2 %3")
00935         .arg( mCalSys->weekDayName( qd ) )
00936         .arg( mCalSys->monthName( qd ) )
00937         .arg( qd.day() );
00938 //    dayNumStr = local->formatDate(qd);
00939   } else {
00940     dayNumStr = QString::number( qd.day() );
00941   }
00942 
00943   QRect subHeaderBox( box );
00944   subHeaderBox.setHeight( mSubHeaderHeight );
00945   drawShadedBox( p, BOX_BORDER_WIDTH, p.backgroundColor(), box );
00946   drawShadedBox( p, 0, QColor( 232, 232, 232 ), subHeaderBox );
00947   drawBox( p, BOX_BORDER_WIDTH, box );
00948   QString hstring( holidayString( qd ) );
00949   QFont oldFont( p.font() );
00950 
00951   QRect headerTextBox( subHeaderBox );
00952   headerTextBox.setLeft( subHeaderBox.left()+5 );
00953   headerTextBox.setRight( subHeaderBox.right()-5 );
00954   if (!hstring.isEmpty()) {
00955     p.setFont( QFont( "sans-serif", 8, QFont::Bold, true ) );
00956 
00957     p.drawText( headerTextBox, Qt::AlignLeft | Qt::AlignVCenter, hstring );
00958   }
00959   p.setFont(QFont("sans-serif", 10, QFont::Bold));
00960   p.drawText( headerTextBox, Qt::AlignRight | Qt::AlignVCenter, dayNumStr);
00961 
00962   Event::List eventList = mCalendar->events( qd,
00963                                              EventSortStartDate,
00964                                              SortDirectionAscending );
00965   QString timeText;
00966   p.setFont( QFont( "sans-serif", 8 ) );
00967 
00968   int textY=mSubHeaderHeight+3; // gives the relative y-coord of the next printed entry
00969   Event::List::ConstIterator it;
00970 
00971   for( it = eventList.begin(); it != eventList.end() && textY<box.height(); ++it ) {
00972     Event *currEvent = *it;
00973     if ( ( !printRecurDaily  && currEvent->recurrenceType() == Recurrence::rDaily  ) ||
00974          ( !printRecurWeekly && currEvent->recurrenceType() == Recurrence::rWeekly ) ) {
00975       continue;
00976     }
00977     if ( currEvent->doesFloat() || currEvent->isMultiDay() ) {
00978       timeText = "";
00979     } else {
00980       timeText = local->formatTime( currEvent->dtStart().time() );
00981     }
00982 
00983     QString str;
00984     if ( !currEvent->location().isEmpty() ) {
00985       str = i18n( "summary, location", "%1, %2" ).
00986             arg( currEvent->summary() ).arg( currEvent->location() );
00987     } else {
00988       str = currEvent->summary();
00989     }
00990     drawIncidence( p, box, timeText, str, textY );
00991   }
00992 
00993   if ( textY < box.height() ) {
00994     Todo::List todos = mCalendar->todos( qd );
00995     Todo::List::ConstIterator it2;
00996     for ( it2 = todos.begin(); it2 != todos.end() && textY <box.height(); ++it2 ) {
00997       Todo *todo = *it2;
00998       if ( ( !printRecurDaily  && todo->recurrenceType() == Recurrence::rDaily  ) ||
00999            ( !printRecurWeekly && todo->recurrenceType() == Recurrence::rWeekly ) ) {
01000         continue;
01001       }
01002       if ( todo->hasStartDate() && !todo->doesFloat() ) {
01003         timeText = KGlobal::locale()->formatTime( todo->dtStart().time() ) + " ";
01004       } else {
01005         timeText = "";
01006       }
01007       QString summaryStr;
01008       if ( !todo->location().isEmpty() ) {
01009         summaryStr = i18n( "summary, location", "%1, %2" ).
01010                      arg( todo->summary() ).arg( todo->location() );
01011       } else {
01012         summaryStr = todo->summary();
01013       }
01014       QString str;
01015       if ( todo->hasDueDate() ) {
01016         if ( !todo->doesFloat() ) {
01017           str = i18n( "%1 (Due: %2)" ).
01018                 arg( summaryStr ).
01019                 arg( KGlobal::locale()->formatDateTime( todo->dtDue() ) );
01020         } else {
01021           str = i18n( "%1 (Due: %2)" ).
01022                 arg( summaryStr ).
01023                 arg( KGlobal::locale()->formatDate( todo->dtDue().date(), true ) );
01024         }
01025       } else {
01026         str = summaryStr;
01027       }
01028       drawIncidence( p, box, timeText, i18n("To-do: %1").arg( str ), textY );
01029     }
01030   }
01031 
01032   p.setFont( oldFont );
01033 }
01034 
01035 // TODO TODO TODO
01036 void CalPrintPluginBase::drawIncidence( QPainter &p, const QRect &dayBox, const QString &time, const QString &summary, int &textY )
01037 {
01038   kdDebug(5850) << "summary = " << summary << endl;
01039 
01040   int flags = Qt::AlignLeft;
01041   QFontMetrics fm = p.fontMetrics();
01042   QRect timeBound = p.boundingRect( dayBox.x() + 5, dayBox.y() + textY,
01043                                     dayBox.width() - 10, fm.lineSpacing(),
01044                                     flags, time );
01045   p.drawText( timeBound, flags, time );
01046 
01047   int summaryWidth = time.isEmpty() ? 0 : timeBound.width() + 4;
01048   QRect summaryBound = QRect( dayBox.x() + 5 + summaryWidth, dayBox.y() + textY,
01049                               dayBox.width() - summaryWidth -5, dayBox.height() );
01050 
01051   KWordWrap *ww = KWordWrap::formatText( fm, summaryBound, flags, summary );
01052   ww->drawText( &p, dayBox.x() + 5 + summaryWidth, dayBox.y() + textY, flags );
01053 
01054   textY += ww->boundingRect().height();
01055 
01056   delete ww;
01057 }
01058 
01059 
01061 
01062 void CalPrintPluginBase::drawWeek(QPainter &p, const QDate &qd, const QRect &box )
01063 {
01064   QDate weekDate = qd;
01065   bool portrait = ( box.height() > box.width() );
01066   int cellWidth, cellHeight;
01067   int vcells;
01068   if (portrait) {
01069     cellWidth = box.width()/2;
01070     vcells=3;
01071   } else {
01072     cellWidth = box.width()/6;
01073     vcells=1;
01074   }
01075   cellHeight = box.height()/vcells;
01076 
01077   // correct begin of week
01078   int weekdayCol = weekdayColumn( qd.dayOfWeek() );
01079   weekDate = qd.addDays( -weekdayCol );
01080 
01081   for (int i = 0; i < 7; i++, weekDate = weekDate.addDays(1)) {
01082     // Saturday and sunday share a cell, so we have to special-case sunday
01083     int hpos = ((i<6)?i:(i-1)) / vcells;
01084     int vpos = ((i<6)?i:(i-1)) % vcells;
01085     QRect dayBox( box.left()+cellWidth*hpos, box.top()+cellHeight*vpos + ((i==6)?(cellHeight/2):0),
01086         cellWidth, (i<5)?(cellHeight):(cellHeight/2) );
01087     drawDayBox(p, weekDate, dayBox, true);
01088   } // for i through all weekdays
01089 }
01090 
01091 
01092 void CalPrintPluginBase::drawTimeTable(QPainter &p,
01093     const QDate &fromDate, const QDate &toDate,
01094     QTime &fromTime, QTime &toTime,
01095     const QRect &box)
01096 {
01097   // timeline is 1 hour:
01098   int alldayHeight = (int)( 3600.*box.height()/(fromTime.secsTo(toTime)+3600.) );
01099   int timelineWidth = TIMELINE_WIDTH;
01100 
01101   QRect dowBox( box );
01102   dowBox.setLeft( box.left() + timelineWidth );
01103   dowBox.setHeight( mSubHeaderHeight );
01104   drawDaysOfWeek( p, fromDate, toDate, dowBox );
01105 
01106   QRect tlBox( box );
01107   tlBox.setWidth( timelineWidth );
01108   tlBox.setTop( dowBox.bottom() + BOX_BORDER_WIDTH + alldayHeight );
01109   drawTimeLine( p, fromTime, toTime, tlBox );
01110 
01111   // draw each day
01112   QDate curDate(fromDate);
01113   int i=0;
01114   double cellWidth = double(dowBox.width()) / double(fromDate.daysTo(toDate)+1);
01115   while (curDate<=toDate) {
01116     QRect allDayBox( dowBox.left()+int(i*cellWidth), dowBox.bottom() + BOX_BORDER_WIDTH,
01117                      int((i+1)*cellWidth)-int(i*cellWidth), alldayHeight );
01118     QRect dayBox( allDayBox );
01119     dayBox.setTop( tlBox.top() );
01120     dayBox.setBottom( box.bottom() );
01121     Event::List eventList = mCalendar->events(curDate,
01122                                               EventSortStartDate,
01123                                               SortDirectionAscending);
01124     alldayHeight = drawAllDayBox( p, eventList, curDate, false, allDayBox );
01125     drawAgendaDayBox( p, eventList, curDate, false, fromTime, toTime, dayBox );
01126     i++;
01127     curDate=curDate.addDays(1);
01128   }
01129 
01130 }
01131 
01132 
01134 
01135 class MonthEventStruct
01136 {
01137   public:
01138     MonthEventStruct() : event(0) {}
01139     MonthEventStruct( const QDateTime &s, const QDateTime &e, Event *ev)
01140     {
01141       event = ev;
01142       start = s;
01143       end = e;
01144       if ( event->doesFloat() ) {
01145         start = QDateTime( start.date(), QTime(0,0,0) );
01146         end = QDateTime( end.date().addDays(1), QTime(0,0,0) ).addSecs(-1);
01147       }
01148     }
01149     bool operator<(const MonthEventStruct &mes) { return start < mes.start; }
01150     QDateTime start;
01151     QDateTime end;
01152     Event *event;
01153 };
01154 
01155 void CalPrintPluginBase::drawMonth( QPainter &p, const QDate &dt, const QRect &box, int maxdays, int subDailyFlags, int holidaysFlags )
01156 {
01157   const KCalendarSystem *calsys = calendarSystem();
01158   QRect subheaderBox( box );
01159   subheaderBox.setHeight( subHeaderHeight() );
01160   QRect borderBox( box );
01161   borderBox.setTop( subheaderBox.bottom()+1 );
01162   drawSubHeaderBox( p, calsys->monthName(dt), subheaderBox );
01163   // correct for half the border width
01164   int correction = (BOX_BORDER_WIDTH/*-1*/)/2;
01165   QRect daysBox( borderBox );
01166   daysBox.addCoords( correction, correction, -correction, -correction );
01167 
01168   int daysinmonth = calsys->daysInMonth( dt );
01169   if ( maxdays <= 0 ) maxdays = daysinmonth;
01170 
01171   int d;
01172   float dayheight = float(daysBox.height()) / float( maxdays );
01173 
01174   QColor holidayColor( 240, 240, 240 );
01175   QColor workdayColor( 255, 255, 255 );
01176   int dayNrWidth = p.fontMetrics().width( "99" );
01177 
01178   // Fill the remaining space (if a month has less days than others) with a crossed-out pattern
01179   if ( daysinmonth<maxdays ) {
01180     QRect dayBox( box.left(), daysBox.top() + round(dayheight*daysinmonth), box.width(), 0 );
01181     dayBox.setBottom( daysBox.bottom() );
01182     p.fillRect( dayBox, Qt::DiagCrossPattern );
01183   }
01184   // Backgrounded boxes for each day, plus day numbers
01185   QBrush oldbrush( p.brush() );
01186   for ( d = 0; d < daysinmonth; ++d ) {
01187     QDate day;
01188     calsys->setYMD( day, dt.year(), dt.month(), d+1 );
01189     QRect dayBox( daysBox.left()/*+rand()%50*/, daysBox.top() + round(dayheight*d), daysBox.width()/*-rand()%50*/, 0 );
01190     // 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!
01191     dayBox.setBottom( daysBox.top()+round(dayheight*(d+1)) - 1 );
01192 
01193     p.setBrush( isWorkingDay( day )?workdayColor:holidayColor );
01194     p.drawRect( dayBox );
01195     QRect dateBox( dayBox );
01196     dateBox.setWidth( dayNrWidth+3 );
01197     p.drawText( dateBox, Qt::AlignRight | Qt::AlignVCenter | Qt::SingleLine,
01198                 QString::number(d+1) );
01199   }
01200   p.setBrush( oldbrush );
01201   int xstartcont = box.left() + dayNrWidth + 5;
01202 
01203   QDate start, end;
01204   calsys->setYMD( start, dt.year(), dt.month(), 1 );
01205   end = calsys->addMonths( start, 1 );
01206   end = calsys->addDays( end, -1 );
01207 
01208   Event::List events = mCalendar->events( start, end );
01209   QMap<int, QStringList> textEvents;
01210   QPtrList<KOrg::CellItem> timeboxItems;
01211   timeboxItems.setAutoDelete( true );
01212 
01213 
01214   // 1) For multi-day events, show boxes spanning several cells, use CellItem
01215   //    print the summary vertically
01216   // 2) For sub-day events, print the concated summaries into the remaining
01217   //    space of the box (optional, depending on the given flags)
01218   // 3) Draw some kind of timeline showing free and busy times
01219 
01220   // Holidays
01221   Event::List holidays;
01222   holidays.setAutoDelete( true );
01223   for ( QDate d(start); d <= end; d = d.addDays(1) ) {
01224     Event *e = holiday( d );
01225     if ( e ) {
01226       holidays.append( e );
01227       if ( holidaysFlags & TimeBoxes ) {
01228         timeboxItems.append( new PrintCellItem( e, QDateTime(d, QTime(0,0,0) ),
01229             QDateTime( d.addDays(1), QTime(0,0,0) ) ) );
01230       }
01231       if ( holidaysFlags & Text ) {
01232         textEvents[ d.day() ] << e->summary();
01233       }
01234     }
01235   }
01236 
01237   QValueList<MonthEventStruct> monthentries;
01238 
01239   for ( Event::List::ConstIterator evit = events.begin();
01240         evit != events.end(); ++evit ) {
01241     Event *e = (*evit);
01242     if (!e) continue;
01243     if ( e->doesRecur() ) {
01244       if ( e->recursOn( start ) ) {
01245         // This occurrence has possibly started before the beginning of the
01246         // month, so obtain the start date before the beginning of the month
01247         QValueList<QDateTime> starttimes = e->startDateTimesForDate( start );
01248         QValueList<QDateTime>::ConstIterator it = starttimes.begin();
01249         for ( ; it != starttimes.end(); ++it ) {
01250           monthentries.append( MonthEventStruct( *it, e->endDateForStart( *it ), e ) );
01251         }
01252       }
01253       // Loop through all remaining days of the month and check if the event
01254       // begins on that day (don't use Event::recursOn, as that will
01255       // also return events that have started earlier. These start dates
01256       // however, have already been treated!
01257       Recurrence *recur = e->recurrence();
01258       QDate d1( start.addDays(1) );
01259       while ( d1 <= end ) {
01260         if ( recur->recursOn(d1) ) {
01261           TimeList times( recur->recurTimesOn( d1 ) );
01262           for ( TimeList::ConstIterator it = times.begin();
01263                 it != times.end(); ++it ) {
01264             QDateTime d1start( d1, *it );
01265             monthentries.append( MonthEventStruct( d1start, e->endDateForStart( d1start ), e ) );
01266           }
01267         }
01268         d1 = d1.addDays(1);
01269       }
01270     } else {
01271       monthentries.append( MonthEventStruct( e->dtStart(), e->dtEnd(), e ) );
01272     }
01273   }
01274   qHeapSort( monthentries );
01275 
01276   QValueList<MonthEventStruct>::ConstIterator mit = monthentries.begin();
01277   QDateTime endofmonth( end, QTime(0,0,0) );
01278   endofmonth = endofmonth.addDays(1);
01279   for ( ; mit != monthentries.end(); ++mit ) {
01280     if ( (*mit).start.date() == (*mit).end.date() ) {
01281       // Show also single-day events as time line boxes
01282       if ( subDailyFlags & TimeBoxes ) {
01283         timeboxItems.append( new PrintCellItem( (*mit).event, (*mit).start, (*mit).end ) );
01284       }
01285       // Show as text in the box
01286       if ( subDailyFlags & Text ) {
01287         textEvents[ (*mit).start.date().day() ] << (*mit).event->summary();
01288       }
01289     } else {
01290       // Multi-day events are always shown as time line boxes
01291       QDateTime thisstart( (*mit).start );
01292       QDateTime thisend( (*mit).end );
01293       if ( thisstart.date()<start ) thisstart = start;
01294       if ( thisend>endofmonth ) thisend = endofmonth;
01295       timeboxItems.append( new PrintCellItem( (*mit).event, thisstart, thisend ) );
01296     }
01297   }
01298 
01299   // For Multi-day events, line them up nicely so that the boxes don't overlap
01300   QPtrListIterator<KOrg::CellItem> it1( timeboxItems );
01301   for( it1.toFirst(); it1.current(); ++it1 ) {
01302     KOrg::CellItem *placeItem = it1.current();
01303     KOrg::CellItem::placeItem( timeboxItems, placeItem );
01304   }
01305   QDateTime starttime( start, QTime( 0, 0, 0 ) );
01306   int newxstartcont = xstartcont;
01307 
01308   QFont oldfont( p.font() );
01309   p.setFont( QFont( "sans-serif", 7 ) );
01310   for( it1.toFirst(); it1.current(); ++it1 ) {
01311     PrintCellItem *placeItem = static_cast<PrintCellItem *>( it1.current() );
01312     int minsToStart = starttime.secsTo( placeItem->start() )/60;
01313     int minsToEnd = starttime.secsTo( placeItem->end() )/60;
01314 
01315     QRect eventBox( xstartcont + placeItem->subCell()*17,
01316            daysBox.top() + round( double( minsToStart*daysBox.height()) / double(maxdays*24*60) ),
01317            14, 0 );
01318     eventBox.setBottom( daysBox.top() + round( double( minsToEnd*daysBox.height()) / double(maxdays*24*60) ) );
01319     drawVerticalBox( p, eventBox, placeItem->event()->summary() );
01320     newxstartcont = QMAX( newxstartcont, eventBox.right() );
01321   }
01322   xstartcont = newxstartcont;
01323 
01324   // For Single-day events, simply print their summaries into the remaining
01325   // space of the day's cell
01326   for ( int d=0; d<daysinmonth; ++d ) {
01327     QStringList dayEvents( textEvents[d+1] );
01328     QString txt = dayEvents.join(", ");
01329     QRect dayBox( xstartcont, daysBox.top()+round(dayheight*d), 0, 0 );
01330     dayBox.setRight( box.right() );
01331     dayBox.setBottom( daysBox.top()+round(dayheight*(d+1)) );
01332     printEventString(p, dayBox, txt, Qt::AlignTop | Qt::AlignLeft | Qt::BreakAnywhere );
01333   }
01334   p.setFont( oldfont );
01335 //   p.setBrush( Qt::NoBrush );
01336   drawBox( p, BOX_BORDER_WIDTH, borderBox );
01337   p.restore();
01338 }
01339 
01341 
01342 void CalPrintPluginBase::drawMonthTable(QPainter &p, const QDate &qd, bool weeknumbers,
01343                                bool recurDaily, bool recurWeekly,
01344                                const QRect &box)
01345 {
01346   int yoffset = mSubHeaderHeight;
01347   int xoffset = 0;
01348   QDate monthDate(QDate(qd.year(), qd.month(), 1));
01349   QDate monthFirst(monthDate);
01350   QDate monthLast(monthDate.addMonths(1).addDays(-1));
01351 
01352 
01353   int weekdayCol = weekdayColumn( monthDate.dayOfWeek() );
01354   monthDate = monthDate.addDays(-weekdayCol);
01355 
01356   if (weeknumbers) {
01357     xoffset += 14;
01358   }
01359 
01360   int rows=(weekdayCol + qd.daysInMonth() - 1)/7 +1;
01361   double cellHeight = ( box.height() - yoffset ) / (1.*rows);
01362   double cellWidth = ( box.width() - xoffset ) / 7.;
01363 
01364   // Precalculate the grid...
01365   // rows is at most 6, so using 8 entries in the array is fine, too!
01366   int coledges[8], rowedges[8];
01367   for ( int i = 0; i <= 7; i++ ) {
01368     rowedges[i] = int( box.top() + yoffset + i*cellHeight );
01369     coledges[i] = int( box.left() + xoffset + i*cellWidth );
01370   }
01371 
01372   if (weeknumbers) {
01373     QFont oldFont(p.font());
01374     QFont newFont(p.font());
01375     newFont.setPointSize(6);
01376     p.setFont(newFont);
01377     QDate weekDate(monthDate);
01378     for (int row = 0; row<rows; ++row ) {
01379       int calWeek = weekDate.weekNumber();
01380       QRect rc( box.left(), rowedges[row], coledges[0] - 3 - box.left(), rowedges[row+1]-rowedges[row] );
01381       p.drawText( rc, Qt::AlignRight | Qt::AlignVCenter, QString::number( calWeek ) );
01382       weekDate = weekDate.addDays( 7 );
01383     }
01384     p.setFont( oldFont );
01385   }
01386 
01387   QRect daysOfWeekBox( box );
01388   daysOfWeekBox.setHeight( mSubHeaderHeight );
01389   daysOfWeekBox.setLeft( box.left()+xoffset );
01390   drawDaysOfWeek( p, monthDate, monthDate.addDays( 6 ), daysOfWeekBox );
01391 
01392   QColor back = p.backgroundColor();
01393   bool darkbg = false;
01394   for ( int row = 0; row < rows; ++row ) {
01395     for ( int col = 0; col < 7; ++col ) {
01396       // show days from previous/next month with a grayed background
01397       if ( (monthDate < monthFirst) || (monthDate > monthLast) ) {
01398         p.setBackgroundColor( back.dark( 120 ) );
01399         darkbg = true;
01400       }
01401       QRect dayBox( coledges[col], rowedges[row], coledges[col+1]-coledges[col], rowedges[row+1]-rowedges[row] );
01402       drawDayBox(p, monthDate, dayBox, false, recurDaily, recurWeekly );
01403       if ( darkbg ) {
01404         p.setBackgroundColor( back );
01405         darkbg = false;
01406       }
01407       monthDate = monthDate.addDays(1);
01408     }
01409   }
01410 }
01411 
01412 
01414 
01415 void CalPrintPluginBase::drawTodo( int &count, Todo *todo, QPainter &p,
01416                                TodoSortField sortField, SortDirection sortDir,
01417                                bool connectSubTodos, bool strikeoutCompleted,
01418                                bool desc, int posPriority, int posSummary,
01419                                int posDueDt, int posPercentComplete,
01420                                int level, int x, int &y, int width,
01421                                int pageHeight, const Todo::List &todoList,
01422                                TodoParentStart *r )
01423 {
01424   QString outStr;
01425   const KLocale *local = KGlobal::locale();
01426   QRect rect;
01427   TodoParentStart startpt;
01428 
01429   // This list keeps all starting points of the parent to-dos so the connection
01430   // lines of the tree can easily be drawn (needed if a new page is started)
01431   static QPtrList<TodoParentStart> startPoints;
01432   if ( level < 1 ) {
01433     startPoints.clear();
01434   }
01435 
01436   // Compute the right hand side of the to-do box
01437   int rhs = posPercentComplete;
01438   if ( rhs < 0 ) rhs = posDueDt; //not printing percent completed
01439   if ( rhs < 0 ) rhs = x+width;  //not printing due dates either
01440 
01441   // size of to-do
01442   outStr=todo->summary();
01443   int left = posSummary + ( level*10 );
01444   rect = p.boundingRect( left, y, ( rhs-left-5 ), -1, Qt::WordBreak, outStr );
01445   if ( !todo->description().isEmpty() && desc ) {
01446     outStr = todo->description();
01447     rect = p.boundingRect( left+20, rect.bottom()+5, width-(left+10-x), -1,
01448                            Qt::WordBreak, outStr );
01449   }
01450   // if too big make new page
01451   if ( rect.bottom() > pageHeight ) {
01452     // first draw the connection lines from parent to-dos:
01453     if ( level > 0 && connectSubTodos ) {
01454       TodoParentStart *rct;
01455       for ( rct = startPoints.first(); rct; rct = startPoints.next() ) {
01456         int start;
01457         int center = rct->mRect.left() + (rct->mRect.width()/2);
01458         int to = p.viewport().bottom();
01459 
01460         // draw either from start point of parent or from top of the page
01461         if ( rct->mSamePage )
01462           start = rct->mRect.bottom() + 1;
01463         else
01464           start = p.viewport().top();
01465         p.moveTo( center, start );
01466         p.lineTo( center, to );
01467         rct->mSamePage = false;
01468       }
01469     }
01470     y=0;
01471     mPrinter->newPage();
01472   }
01473 
01474   // If this is a sub-to-do, r will not be 0, and we want the LH side
01475   // of the priority line up to the RH side of the parent to-do's priority
01476   bool showPriority = posPriority>=0;
01477   int lhs = posPriority;
01478   if ( r ) {
01479     lhs = r->mRect.right() + 1;
01480   }
01481 
01482   outStr.setNum( todo->priority() );
01483   rect = p.boundingRect( lhs, y + 10, 5, -1, Qt::AlignCenter, outStr );
01484   // Make it a more reasonable size
01485   rect.setWidth(18);
01486   rect.setHeight(18);
01487 
01488   // Draw a checkbox
01489   p.setBrush( QBrush( Qt::NoBrush ) );
01490   p.drawRect( rect );
01491   if ( todo->isCompleted() ) {
01492     // cross out the rectangle for completed to-dos
01493     p.drawLine( rect.topLeft(), rect.bottomRight() );
01494     p.drawLine( rect.topRight(), rect.bottomLeft() );
01495   }
01496   lhs = rect.right() + 3;
01497 
01498   // Priority
01499   if ( todo->priority() > 0 && showPriority ) {
01500     p.drawText( rect, Qt::AlignCenter, outStr );
01501   }
01502   startpt.mRect = rect; //save for later
01503 
01504   // Connect the dots
01505   if ( level > 0 && connectSubTodos ) {
01506     int bottom;
01507     int center( r->mRect.left() + (r->mRect.width()/2) );
01508     if ( r->mSamePage )
01509       bottom = r->mRect.bottom() + 1;
01510     else
01511       bottom = 0;
01512     int to( rect.top() + (rect.height()/2) );
01513     int endx( rect.left() );
01514     p.moveTo( center, bottom );
01515     p.lineTo( center, to );
01516     p.lineTo( endx, to );
01517   }
01518 
01519   // summary
01520   outStr=todo->summary();
01521   rect = p.boundingRect( lhs, rect.top(), (rhs-(left + rect.width() + 5)),
01522                          -1, Qt::WordBreak, outStr );
01523 
01524   QRect newrect;
01525   //FIXME: the following code prints underline rather than strikeout text
01526 #if 0
01527   QFont f( p.font() );
01528   if ( todo->isCompleted() && strikeoutCompleted ) {
01529     f.setStrikeOut( true );
01530     p.setFont( f );
01531   }
01532   p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
01533   f.setStrikeOut( false );
01534   p.setFont( f );
01535 #endif
01536   //TODO: Remove this section when the code above is fixed
01537   p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
01538   if ( todo->isCompleted() && strikeoutCompleted ) {
01539     // strike out the summary text if to-do is complete
01540     // Note: we tried to use a strike-out font and for unknown reasons the
01541     // result was underline instead of strike-out, so draw the lines ourselves.
01542     int delta = p.fontMetrics().lineSpacing();
01543     int lines = ( rect.height() / delta ) + 1;
01544     for ( int i=0; i<lines; i++ ) {
01545       p.moveTo( rect.left(),  rect.top() + ( delta/2 ) + ( i*delta ) );
01546       p.lineTo( rect.right(), rect.top() + ( delta/2 ) + ( i*delta ) );
01547     }
01548   }
01549 
01550   // due date
01551   if ( todo->hasDueDate() && posDueDt>=0 ) {
01552     outStr = local->formatDate( todo->dtDue().date(), true );
01553     rect = p.boundingRect( posDueDt, y, x + width, -1,
01554                            Qt::AlignTop | Qt::AlignLeft, outStr );
01555     p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr );
01556   }
01557 
01558   // percentage completed
01559   bool showPercentComplete = posPercentComplete>=0;
01560   if ( showPercentComplete ) {
01561     int lwidth = 24;
01562     int lheight = 12;
01563     //first, draw the progress bar
01564     int progress = (int)(( lwidth*todo->percentComplete())/100.0 + 0.5);
01565 
01566     p.setBrush( QBrush( Qt::NoBrush ) );
01567     p.drawRect( posPercentComplete, y+3, lwidth, lheight );
01568     if ( progress > 0 ) {
01569       p.setBrush( QColor( 128, 128, 128 ) );
01570       p.drawRect( posPercentComplete, y+3, progress, lheight );
01571     }
01572 
01573     //now, write the percentage
01574     outStr = i18n( "%1%" ).arg( todo->percentComplete() );
01575     rect = p.boundingRect( posPercentComplete+lwidth+3, y, x + width, -1,
01576                            Qt::AlignTop | Qt::AlignLeft, outStr );
01577     p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr );
01578   }
01579 
01580   // description
01581   if ( !todo->description().isEmpty() && desc ) {
01582     y = newrect.bottom() + 5;
01583     outStr = todo->description();
01584     rect = p.boundingRect( left+20, y, x+width-(left+10), -1,
01585                            Qt::WordBreak, outStr );
01586     p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
01587   }
01588 
01589   // Set the new line position
01590   y = newrect.bottom() + 10; //set the line position
01591 
01592   // If the to-do has sub-to-dos, we need to call ourselves recursively
01593 #if 0
01594   Incidence::List l = todo->relations();
01595   Incidence::List::ConstIterator it;
01596   startPoints.append( &startpt );
01597   for( it = l.begin(); it != l.end(); ++it ) {
01598     count++;
01599     // In the future, to-dos might also be related to events
01600     // Manually check if the sub-to-do is in the list of to-dos to print
01601     // The problem is that relations() does not apply filters, so
01602     // we need to compare manually with the complete filtered list!
01603     Todo* subtodo = dynamic_cast<Todo *>( *it );
01604     if (subtodo && todoList.contains( subtodo ) ) {
01605       drawTodo( count, subtodo, p, connectSubTodos, strikeoutCompleted,
01606                 desc, posPriority, posSummary, posDueDt, posPercentComplete,
01607                 level+1, x, y, width, pageHeight, todoList, &startpt );
01608     }
01609   }
01610 #endif
01611   // Make a list of all the sub-to-dos related to this to-do.
01612   Todo::List t;
01613   Incidence::List l = todo->relations();
01614   Incidence::List::ConstIterator it;
01615   for( it=l.begin(); it!=l.end(); ++it ) {
01616     // In the future, to-dos might also be related to events
01617     // Manually check if the sub-to-do is in the list of to-dos to print
01618     // The problem is that relations() does not apply filters, so
01619     // we need to compare manually with the complete filtered list!
01620     Todo* subtodo = dynamic_cast<Todo *>( *it );
01621     if ( subtodo && todoList.contains( subtodo ) ) {
01622       t.append( subtodo );
01623     }
01624   }
01625 
01626   // Sort the sub-to-dos and then print them
01627   Todo::List sl = mCalendar->sortTodos( &t, sortField, sortDir );
01628   Todo::List::ConstIterator isl;
01629   startPoints.append( &startpt );
01630   for( isl = sl.begin(); isl != sl.end(); ++isl ) {
01631     count++;
01632     drawTodo( count, ( *isl ), p, sortField, sortDir,
01633               connectSubTodos, strikeoutCompleted,
01634               desc, posPriority, posSummary, posDueDt, posPercentComplete,
01635               level+1, x, y, width, pageHeight, todoList, &startpt );
01636   }
01637   startPoints.remove( &startpt );
01638 }
01639 
01640 int CalPrintPluginBase::weekdayColumn( int weekday )
01641 {
01642   return ( weekday + 7 - KGlobal::locale()->weekStartDay() ) % 7;
01643 }
01644 
01645 void CalPrintPluginBase::drawJournalField( QPainter &p, QString field, QString text,
01646                                        int x, int &y, int width, int pageHeight )
01647 {
01648   if ( text.isEmpty() ) return;
01649 
01650   QString entry( field.arg( text ) );
01651 
01652   QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, entry) );
01653   if ( rect.bottom() > pageHeight) {
01654     // Start new page...
01655     // FIXME: If it's a multi-line text, draw a few lines on this page, and the
01656     // remaining lines on the next page.
01657     y=0;
01658     mPrinter->newPage();
01659     rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, entry);
01660   }
01661   QRect newrect;
01662   p.drawText( rect, Qt::WordBreak, entry, -1, &newrect );
01663   y = newrect.bottom() + 7;
01664 }
01665 
01666 void CalPrintPluginBase::drawJournal( Journal * journal, QPainter &p, int x, int &y,
01667                                   int width, int pageHeight )
01668 {
01669   QFont oldFont( p.font() );
01670   p.setFont( QFont( "sans-serif", 15 ) );
01671   QString headerText;
01672   QString dateText( KGlobal::locale()->
01673         formatDate( journal->dtStart().date(), false ) );
01674 
01675   if ( journal->summary().isEmpty() ) {
01676     headerText = dateText;
01677   } else {
01678     headerText = i18n("Description - date", "%1 - %2")
01679                      .arg( journal->summary() )
01680                      .arg( dateText );
01681   }
01682 
01683   QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText) );
01684   if ( rect.bottom() > pageHeight) {
01685     // Start new page...
01686     y=0;
01687     mPrinter->newPage();
01688     rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText );
01689   }
01690   QRect newrect;
01691   p.drawText( rect, Qt::WordBreak, headerText, -1, &newrect );
01692   p.setFont( oldFont );
01693 
01694   y = newrect.bottom() + 4;
01695 
01696   p.drawLine( x + 3, y, x + width - 6, y );
01697   y += 5;
01698 
01699   drawJournalField( p, i18n("Person: %1"), journal->organizer().fullName(), x, y, width, pageHeight );
01700   drawJournalField( p, i18n("%1"), journal->description(), x, y, width, pageHeight );
01701   y += 10;
01702 }
01703 
01704 
01705 void CalPrintPluginBase::drawSplitHeaderRight( QPainter &p, const QDate &fd,
01706                                            const QDate &td,
01707                                            const QDate &,
01708                                            int width, int )
01709 {
01710   QFont oldFont( p.font() );
01711 
01712   QPen oldPen( p.pen() );
01713   QPen pen( Qt::black, 4 );
01714 
01715   QString title;
01716   if ( mCalSys ) {
01717     if ( fd.month() == td.month() ) {
01718       title = i18n("Date range: Month dayStart - dayEnd", "%1 %2 - %3")
01719         .arg( mCalSys->monthName( fd.month(), false ) )
01720         .arg( mCalSys->dayString( fd, false ) )
01721         .arg( mCalSys->dayString( td, false ) );
01722     } else {
01723       title = i18n("Date range: monthStart dayStart - monthEnd dayEnd", "%1 %2 - %3 %4")
01724         .arg( mCalSys->monthName( fd.month(), false ) )
01725         .arg( mCalSys->dayString( fd, false ) )
01726         .arg( mCalSys->monthName( td.month(), false ) )
01727         .arg( mCalSys->dayString( td, false ) );
01728     }
01729   }
01730 
01731   QFont serifFont("Times", 30);
01732   p.setFont(serifFont);
01733 
01734   int lineSpacing = p.fontMetrics().lineSpacing();
01735   p.drawText( 0, lineSpacing * 0, width, lineSpacing,
01736               Qt::AlignRight | Qt::AlignTop, title );
01737 
01738   title.truncate(0);
01739 
01740   p.setPen( pen );
01741   p.drawLine(300, lineSpacing * 1, width, lineSpacing * 1);
01742   p.setPen( oldPen );
01743 
01744   p.setFont(QFont("Times", 20, QFont::Bold, TRUE));
01745   int newlineSpacing = p.fontMetrics().lineSpacing();
01746   title += QString::number(fd.year());
01747   p.drawText( 0, lineSpacing * 1 + 4, width, newlineSpacing,
01748               Qt::AlignRight | Qt::AlignTop, title );
01749 
01750   p.setFont( oldFont );
01751 }
01752 
01753 #endif
KDE Home | KDE Accessibility Home | Description of Access Keys