korganizer

calprinthelper.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 #include <qptrlist.h>
00031 #include <qintdict.h>
00032 
00033 #include <kglobal.h>
00034 #include <klocale.h>
00035 #include <kdebug.h>
00036 #include <kconfig.h>
00037 #include <kcalendarsystem.h>
00038 #include <kprinter.h>
00039 #include <kwordwrap.h>
00040 
00041 #include <libkcal/calendar.h>
00042 #include <libkcal/todo.h>
00043 #include <libkcal/event.h>
00044 
00045 #include "korganizer/corehelper.h"
00046 #include "cellitem.h"
00047 
00048 #include "calprinthelper.h"
00049 
00050 #ifndef KORG_NOPRINTER
00051 
00052 
00053 
00054 class CalPrintHelper::TodoParentStart
00055 {
00056   public:
00057     TodoParentStart( QRect pt = QRect(), bool page = true )
00058       : mRect( pt ), mSamePage( page ) {}
00059 
00060     QRect mRect;
00061     bool mSamePage;
00062 };
00063 
00064 class PrintCellItem : public KOrg::CellItem
00065 {
00066   public:
00067     PrintCellItem( Event *event, const QDateTime &start, const QDateTime &end )
00068       : mEvent( event ), mStart( start), mEnd( end )
00069     {
00070     }
00071 
00072     Event *event() const { return mEvent; }
00073 
00074     QString label() const { return mEvent->summary(); }
00075 
00076     QDateTime start() const { return mStart; }
00077     QDateTime end() const { return mEnd; }
00078 
00081     bool overlaps( KOrg::CellItem *o ) const
00082     {
00083       PrintCellItem *other = static_cast<PrintCellItem *>( o );
00084 
00085 #if 0
00086       kdDebug(5850) << "PrintCellItem::overlaps() " << event()->summary()
00087                     << " <-> " << other->event()->summary() << endl;
00088       kdDebug(5850) << "  start     : " << start.toString() << endl;
00089       kdDebug(5850) << "  end       : " << end.toString() << endl;
00090       kdDebug(5850) << "  otherStart: " << otherStart.toString() << endl;
00091       kdDebug(5850) << "  otherEnd  : " << otherEnd.toString() << endl;
00092 #endif
00093 
00094       return !( other->start() >= end() || other->end() <= start() );
00095     }
00096 
00097   private:
00098     Event *mEvent;
00099     QDateTime mStart, mEnd;
00100 };
00101 
00102 CalPrintHelper::CalPrintHelper( KPrinter *pr, Calendar *cal, KConfig *cfg,
00103                                 KOrg::CoreHelper *corehelper )
00104   : mPrinter( pr ), mCalendar( cal ), mConfig( cfg ),
00105     mCoreHelper( corehelper ),
00106     mHeaderHeight( 72 ), mSubHeaderHeight( 20 ), mMargin( 36 )
00107 {
00108   if ( corehelper )
00109     setCalendarSystem( mCoreHelper->calendarSystem() );
00110 }
00111 
00112 CalPrintHelper::~CalPrintHelper()
00113 {
00114 }
00115 
00116 
00117 
00118 void CalPrintHelper::setCategoryColors( QPainter &p, Incidence *incidence )
00119 {
00120   if ( mCoreHelper ) {
00121     QColor bgColor = mCoreHelper->categoryColor( incidence->categories() );
00122     QColor textColor = mCoreHelper->textColor( bgColor );
00123     p.setPen( textColor );
00124     p.setBrush( bgColor );
00125   }
00126 }
00127 
00128 
00129 
00131 
00132 void CalPrintHelper::drawHeader( QPainter &p, QString title,
00133     const QDate &month1, const QDate &month2,
00134     int x, int y, int width, int height )
00135 {
00136   p.drawRect( x, y, width, height );
00137   p.fillRect( x + 1, y + 1, width - 2, height - 2,
00138               QBrush( Qt::Dense7Pattern ) );
00139 
00140   int right=x+width;
00141 
00142   // print previous month for month view, print current for to-do, day and week
00143   int smallMonthWidth=width/4-10;
00144   if (smallMonthWidth>100) smallMonthWidth=100;
00145   if (month2.isValid()) {
00146     right -= (10+smallMonthWidth);
00147     drawSmallMonth(p, QDate(month2.year(), month2.month(), 1),
00148                    right, y+2, smallMonthWidth, height-4);
00149     right-=10;
00150   }
00151   if (month1.isValid()) {
00152     right -= (10+smallMonthWidth);
00153     drawSmallMonth(p, QDate(month1.year(), month1.month(), 1),
00154                    right, y+2, smallMonthWidth, height-4);
00155     right-=10;
00156   }
00157 
00158   // Print the titles...
00159   QFont oldFont(p.font());
00160   p.setFont( QFont("helvetica", 18, QFont::Bold) );
00161   QRect textRect( x+5, y+5, right-10-x, height-10 );
00162   p.drawText( textRect, Qt::AlignLeft | Qt::AlignTop | Qt::WordBreak, title );
00163   p.setFont(oldFont);
00164 }
00165 
00166 
00167 void CalPrintHelper::drawSmallMonth(QPainter &p, const QDate &qd,
00168     int x, int y, int width, int height)
00169 {
00170   bool firstCol = true;
00171   QDate monthDate(QDate(qd.year(), qd.month(), 1));
00172   QDate monthDate2;
00173   int month = monthDate.month();
00174 
00175   // draw the title
00176   QFont oldFont( p.font() );
00177   p.setFont(QFont("helvetica", 8, QFont::Bold));
00178   //  int lineSpacing = p.fontMetrics().lineSpacing();
00179   if ( mCalSys )
00180     p.drawText(x, y, width, height/4, Qt::AlignCenter,
00181       mCalSys->monthName( qd ) );
00182 
00183   int cellWidth = width/7;
00184   int cellHeight = height/8;
00185   QString tmpStr;
00186 
00187   // correct begin of week
00188   int weekdayCol = weekdayColumn( qd.dayOfWeek() );
00189   monthDate2 = monthDate.addDays( -weekdayCol );
00190 
00191   // draw days of week
00192   if ( mCalSys ) {
00193     for (int col = 0; col < 7; ++col) {
00194       // tmpStr.sprintf("%c",(const char*)monthDate2.dayName(monthDate2.dayOfWeek()));
00195       tmpStr=mCalSys->weekDayName( monthDate2 )[0].upper();
00196       p.drawText( x + col*cellWidth, y + height/4, cellWidth, cellHeight,
00197                  Qt::AlignCenter, tmpStr );
00198       monthDate2 = monthDate2.addDays( 1 );
00199     }
00200   }
00201 
00202   // draw separator line
00203   p.drawLine( x, y + height/4 + cellHeight, x + width,
00204       y + height/4 + cellHeight );
00205 
00206   for ( int row = 0; row < 5; row++ ) {
00207     for ( int col = 0; col < 7; col++ ) {
00208       if ( monthDate.month() != month )
00209         break;
00210       if (firstCol) {
00211         firstCol = true;
00212         col = weekdayColumn( monthDate.dayOfWeek() );
00213       }
00214       p.drawText( x+col*cellWidth,
00215                   y+height/4+cellHeight+(row*cellHeight),
00216                   cellWidth, cellHeight, Qt::AlignCenter,
00217                   tmpStr.setNum( monthDate.day() ) );
00218       monthDate = monthDate.addDays(1);
00219     }
00220   }
00221   p.setFont( oldFont );
00222 }
00223 
00224 
00226 
00227 /*
00228  * This routine draws a header box over the main part of the calendar
00229  * containing the days of the week.
00230  */
00231 void CalPrintHelper::drawDaysOfWeek(QPainter &p,
00232     const QDate &fromDate, const QDate &toDate,
00233     int x, int y, int width, int height)
00234 {
00235   int cellWidth = width/(fromDate.daysTo( toDate )+1);
00236   int currx=x;
00237   QDate cellDate(fromDate);
00238 
00239   while (cellDate<=toDate) {
00240     drawDaysOfWeekBox(p, cellDate, currx, y, cellWidth, height);
00241     currx+=cellWidth;
00242     cellDate = cellDate.addDays(1);
00243   }
00244 }
00245 
00246 
00247 void CalPrintHelper::drawDaysOfWeekBox(QPainter &p, const QDate &qd,
00248     int x, int y, int width, int height)
00249 {
00250   QFont oldFont( p.font() );
00251   p.setFont( QFont( "helvetica", 10, QFont::Bold ) );
00252   p.drawRect( x, y, width, height );
00253   p.fillRect( x+1, y+1,
00254               width-2, height-2,
00255               QBrush( Qt::Dense7Pattern ) );
00256   if ( mCalSys )
00257     p.drawText( x+5, y, width-10, height, Qt::AlignCenter | Qt::AlignVCenter,
00258              mCalSys->weekDayName( qd ) );
00259   p.setFont( oldFont );
00260 }
00261 
00262 
00263 void CalPrintHelper::drawTimeLine(QPainter &p,
00264     const QTime &fromTime, const QTime &toTime,
00265     int x, int y, int width, int height)
00266 {
00267   p.drawRect(x, y, width, height);
00268 
00269   int totalsecs=fromTime.secsTo(toTime);
00270   float minlen=(float)height*60./(float)totalsecs;
00271   float cellHeight=(60.*(float)minlen);
00272   float currY=y;
00273 
00274   QTime curTime( fromTime );
00275   QTime endTime( toTime );
00276   if ( fromTime.minute() > 30 )
00277     curTime = QTime( fromTime.hour()+1, 0, 0 );
00278   else if ( fromTime.minute() > 0 ) {
00279     curTime = QTime( fromTime.hour(), 30, 0 );
00280     float yy = currY + minlen*(float)fromTime.secsTo( curTime )/60.;
00281     p.drawLine( x+width/2, (int)yy, x+width, (int)yy );
00282     curTime = QTime( fromTime.hour()+1, 0, 0 );
00283   }
00284   currY += ( fromTime.secsTo(curTime)*minlen/60 );
00285 
00286   while ( curTime < endTime ) {
00287     p.drawLine( x, (int)currY, x+width, (int)currY );
00288     int newY=(int)(currY+cellHeight/2.);
00289     QString numStr;
00290     if (newY < y+height) {
00291       QFont oldFont( p.font() );
00292       p.drawLine(x+width/2, (int)newY, x+width, (int)newY);
00293       // draw the time:
00294       if ( !KGlobal::locale()->use12Clock() ) {
00295         numStr.setNum(curTime.hour());
00296         if (cellHeight > 30) {
00297           p.setFont(QFont("helvetica", 16, QFont::Bold));
00298         } else {
00299           p.setFont(QFont("helvetica", 12, QFont::Bold));
00300         }
00301         p.drawText(x+2, (int)currY+2, width/2-2, (int)cellHeight,
00302                   Qt::AlignTop | Qt::AlignRight, numStr);
00303         p.setFont(QFont("helvetica", 10, QFont::Normal));
00304         p.drawText(x+width/2, (int)currY+2, width/2+2, (int)(cellHeight/2)-3,
00305                   Qt::AlignTop | Qt::AlignLeft, "00");
00306       } else {
00307         QTime time( curTime.hour(), 0 );
00308         numStr = KGlobal::locale()->formatTime( time );
00309         p.setFont(QFont("helvetica", 14, QFont::Bold));
00310         p.drawText(x+2, (int)currY+2, width-4, (int)cellHeight/2-3,
00311                   Qt::AlignTop|Qt::AlignLeft, numStr);
00312       }
00313       currY+=cellHeight;
00314     p.setFont( oldFont );
00315     } // enough space for half-hour line and time
00316     if (curTime.secsTo(endTime)>3600)
00317       curTime=curTime.addSecs(3600);
00318     else curTime=endTime;
00319   } // currTime<endTime
00320 }
00321 
00322 Event *CalPrintHelper::holiday( const QDate &dt )
00323 {
00324 #ifndef KORG_NOPLUGINS
00325   if ( !mCoreHelper ) return 0;
00326   QString hstring( mCoreHelper->holidayString( dt ) );
00327   if ( !hstring.isEmpty() ) {
00328     Event*holiday=new Event();
00329     holiday->setDtStart( dt );
00330     holiday->setDtEnd( dt );
00331     holiday->setFloats( true );
00332     holiday->setCategories( i18n("Holiday") );
00333     return holiday;
00334   }
00335   return 0;
00336 #endif
00337 
00338 }
00339 
00341 
00347 void CalPrintHelper::drawAllDayBox(QPainter &p, Event::List &eventList,
00348     const QDate &qd, bool expandable,
00349     int x, int y, int width, int &height)
00350 {
00351   Event::List::Iterator it, itold;
00352 
00353   int offset=y;
00354 
00355   QPen oldPen( p.pen() );
00356   QColor oldBgColor( p.backgroundColor() );
00357   QBrush oldBrush( p.brush() );
00358   QString multiDayStr;
00359 
00360   Event*hd = holiday( qd );
00361   if ( hd ) eventList.prepend( hd );
00362 
00363   it = eventList.begin();
00364   Event *currEvent = 0;
00365   // First, print all floating events
00366   while( it!=eventList.end() ) {
00367     currEvent=*it;
00368     itold=it;
00369     ++it;
00370     if ( currEvent->doesFloat() ) {
00371       // set the colors according to the categories
00372       if ( expandable ) {
00373         if ( mUseColors )
00374           setCategoryColors( p, currEvent );
00375 
00376         p.drawRect( x, offset, width, height );
00377         p.drawText( x + 5, offset + 5, width - 10, height - 10,
00378                     Qt::AlignCenter | Qt::AlignVCenter | Qt::AlignJustify |
00379                     Qt::WordBreak,
00380                     currEvent->summary() );
00381         // reset the colors
00382         p.setBrush( oldBrush );
00383         p.setPen( oldPen );
00384         p.setBackgroundColor( oldBgColor );
00385 
00386         offset += height;
00387       } else {
00388         if ( !multiDayStr.isEmpty() ) multiDayStr += ", ";
00389         multiDayStr += currEvent->summary() + "\n";
00390       }
00391       eventList.remove( itold );
00392     }
00393   }
00394 
00395   if (!expandable) {
00396     p.drawRect(x, offset, width, height);
00397     if (!multiDayStr.isEmpty()) {
00398       p.fillRect( x + 1, offset + 1, width - 2, height - 2,
00399                   QBrush( Qt::Dense5Pattern ) );
00400       p.drawText( x + 5, offset + 5, width - 10, height - 10,
00401                   Qt::AlignCenter | Qt::AlignVCenter | Qt::AlignJustify |
00402                   Qt::WordBreak,
00403                   multiDayStr);
00404     }
00405   } else {
00406     height=offset-y;
00407   }
00408   p.setBrush( oldBrush );
00409 }
00410 
00411 
00412 void CalPrintHelper::drawAgendaDayBox( QPainter &p, Event::List &events,
00413                                      const QDate &qd, bool expandable,
00414                                      QTime &fromTime, QTime &toTime,
00415                                      int x, int y, int width, int height )
00416 {
00417   p.drawRect( x, y, width, height );
00418 
00419   Event *event;
00420 
00421   if ( expandable ) {
00422     // Adapt start/end times to include complete events
00423     Event::List::ConstIterator it;
00424     for ( it = events.begin(); it != events.end(); ++it ) {
00425       event = *it;
00426       if ( event->dtStart().time() < fromTime )
00427         fromTime = event->dtStart().time();
00428       if ( event->dtEnd().time() > toTime )
00429         toTime = event->dtEnd().time();
00430     }
00431   }
00432 
00433   // Show at least one hour
00434   if ( fromTime.secsTo( toTime ) < 3600 ) {
00435     fromTime = QTime( fromTime.hour(), 0, 0 );
00436     toTime = fromTime.addSecs( 3600 );
00437   }
00438 
00439   // calculate the height of a cell and of a minute
00440   int totalsecs = fromTime.secsTo( toTime );
00441   float minlen = height * 60. / totalsecs;
00442   float cellHeight = 60. * minlen;
00443   float currY = y;
00444 
00445   // print grid:
00446   QTime curTime( QTime( fromTime.hour(), 0, 0 ) );
00447   currY += fromTime.secsTo( curTime ) * minlen / 60;
00448 
00449   while ( curTime < toTime && curTime.isValid() ) {
00450     if ( currY > y ) p.drawLine( x, int( currY ), x + width, int( currY ) );
00451     currY += cellHeight / 2;
00452     if ( ( currY > y ) && ( currY < y + height ) ) {
00453       QPen oldPen( p.pen() );
00454       p.setPen( QColor( 192, 192, 192 ) );
00455       p.drawLine( x, int( currY ), x + width, int( currY ) );
00456       p.setPen( oldPen );
00457     } // enough space for half-hour line
00458     if ( curTime.secsTo( toTime ) > 3600 )
00459       curTime = curTime.addSecs( 3600 );
00460     else curTime = toTime;
00461     currY += cellHeight / 2;
00462   }
00463 
00464   QDateTime startPrintDate = QDateTime( qd, fromTime );
00465   QDateTime endPrintDate = QDateTime( qd, toTime );
00466 
00467   // Calculate horizontal positions and widths of events taking into account
00468   // overlapping events
00469 
00470   QPtrList<KOrg::CellItem> cells;
00471   cells.setAutoDelete( true );
00472 
00473   Event::List::ConstIterator itEvents;
00474   for( itEvents = events.begin(); itEvents != events.end(); ++itEvents ) {
00475     QValueList<QDateTime> times = (*itEvents)->startDateTimesForDate( qd );
00476     for ( QValueList<QDateTime>::ConstIterator it = times.begin();
00477           it != times.end(); ++it ) {
00478       cells.append( new PrintCellItem( *itEvents, (*it), (*itEvents)->endDateForStart( *it ) ) );
00479     }
00480   }
00481 
00482   QPtrListIterator<KOrg::CellItem> it1( cells );
00483   for( it1.toFirst(); it1.current(); ++it1 ) {
00484     KOrg::CellItem *placeItem = it1.current();
00485 
00486     KOrg::CellItem::placeItem( cells, placeItem );
00487   }
00488 
00489   QPen oldPen( p.pen() );
00490   QColor oldBgColor( p.backgroundColor() );
00491   QBrush oldBrush( p.brush() );
00492   QFont oldFont( p.font() );
00493 
00494   p.setFont( QFont( "helvetica", 10 ) );
00495   p.setBrush( QBrush( Qt::Dense7Pattern ) );
00496 
00497   for( it1.toFirst(); it1.current(); ++it1 ) {
00498     PrintCellItem *placeItem = static_cast<PrintCellItem *>( it1.current() );
00499 
00500     drawAgendaItem( placeItem, p, qd, startPrintDate, endPrintDate, minlen, x,
00501                     y, width );
00502 
00503     p.setBrush( oldBrush );
00504     p.setPen( oldPen );
00505     p.setBackgroundColor( oldBgColor );
00506   }
00507   p.setFont( oldFont );
00508 //  p.setBrush( QBrush( NoBrush ) );
00509 }
00510 
00511 
00512 void CalPrintHelper::drawAgendaItem( PrintCellItem *item, QPainter &p,
00513                                    const QDate &qd,
00514                                    const QDateTime &startPrintDate,
00515                                    const QDateTime &endPrintDate,
00516                                    float minlen, int x, int y, int width )
00517 {
00518   Event *event = item->event();
00519 
00520   // set the colors according to the categories
00521   if ( mUseColors ) setCategoryColors( p, event );
00522 
00523   // start/end of print area for event
00524   QDateTime startTime = item->start();
00525   QDateTime endTime = item->end();
00526   if ( ( startTime < endPrintDate && endTime > startPrintDate ) ||
00527        ( endTime > startPrintDate && startTime < endPrintDate ) ) {
00528     if ( startTime < startPrintDate ) startTime = startPrintDate;
00529     if ( endTime > endPrintDate ) endTime = endPrintDate;
00530     int currentHeight = int( startTime.secsTo( endTime ) / 60. * minlen );
00531     int currentYPos = int( y + startPrintDate.secsTo( startTime ) *
00532                            minlen / 60. );
00533     int currentWidth = width / item->subCells();
00534     int currentX = x + item->subCell() * currentWidth;
00535 
00536     p.drawRect( currentX, currentYPos, currentWidth, currentHeight );
00537     int offset = 4;
00538     // print the text vertically centered. If it doesn't fit inside the
00539     // box, align it at the top so the beginning is visible
00540     int flags = Qt::AlignLeft | Qt::WordBreak;
00541     QRect bound = p.boundingRect ( currentX + offset, currentYPos,
00542                                    currentWidth - 2 * offset, currentHeight,
00543                                    flags, event->summary() );
00544     flags |= Qt::AlignTop;
00545     p.drawText( currentX+offset, currentYPos+offset, currentWidth-2*offset,
00546                 currentHeight-2*offset, flags, event->summary() );
00547   }
00548 }
00549 
00550 void CalPrintHelper::drawDayBox( QPainter &p, const QDate &qd,
00551     int x, int y, int width, int height,
00552     bool fullDate, bool printRecurDaily, bool printRecurWeekly )
00553 {
00554   QString dayNumStr;
00555   QString ampm;
00556   const KLocale*local = KGlobal::locale();
00557 
00558 
00559   // This has to be localized
00560   if ( fullDate && mCalSys ) {
00561 
00562     dayNumStr = i18n("weekday month date", "%1 %2 %3")
00563         .arg( mCalSys->weekDayName( qd ) )
00564         .arg( mCalSys->monthName( qd ) )
00565         .arg( qd.day() );
00566 //    dayNumStr = local->formatDate(qd);
00567   } else {
00568     dayNumStr = QString::number( qd.day() );
00569   }
00570 
00571   p.eraseRect( x, y, width, height );
00572   QRect dayBox( x, y, width, height );
00573   p.drawRect( dayBox );
00574   p.drawRect( x, y, width, mSubHeaderHeight );
00575   p.fillRect( x + 1, y + 1, width - 2, mSubHeaderHeight - 2,
00576               QBrush( Qt::Dense7Pattern ) );
00577   QString hstring;
00578 #ifndef KORG_NOPLUGINS
00579   if ( mCoreHelper ) hstring = mCoreHelper->holidayString(qd);
00580 #endif
00581   QFont oldFont( p.font() );
00582 
00583   if (!hstring.isEmpty()) {
00584     p.setFont( QFont( "helvetica", 8, QFont::Bold, true ) );
00585 
00586     p.drawText( x+5, y, width-25, mSubHeaderHeight,
00587                 Qt::AlignLeft | Qt::AlignVCenter, hstring );
00588   }
00589   p.setFont(QFont("helvetica", 10, QFont::Bold));
00590   p.drawText( x + 5, y, width - 10, mSubHeaderHeight,
00591               Qt::AlignRight | Qt::AlignVCenter, dayNumStr);
00592 
00593   Event::List eventList = mCalendar->events( qd,
00594                                              EventSortStartDate,
00595                                              SortDirectionAscending );
00596   QString text;
00597   p.setFont( QFont( "helvetica", 8 ) );
00598 
00599   int textY=mSubHeaderHeight+3; // gives the relative y-coord of the next printed entry
00600   Event::List::ConstIterator it;
00601 
00602   for( it = eventList.begin(); it != eventList.end() && textY<height; ++it ) {
00603     Event *currEvent = *it;
00604     if ( ( !printRecurDaily  && currEvent->recurrenceType() == Recurrence::rDaily  ) ||
00605          ( !printRecurWeekly && currEvent->recurrenceType() == Recurrence::rWeekly ) ) {
00606       continue; }
00607     if ( currEvent->doesFloat() || currEvent->isMultiDay() )
00608       text = "";
00609     else
00610       text = local->formatTime( currEvent->dtStart().time() );
00611 
00612     drawIncidence( p, dayBox, text, currEvent->summary(), textY );
00613   }
00614 
00615   if ( textY<height ) {
00616     Todo::List todos = mCalendar->todos( qd );
00617     Todo::List::ConstIterator it2;
00618     for( it2 = todos.begin(); it2 != todos.end() && textY<height; ++it2 ) {
00619       Todo *todo = *it2;
00620       if ( ( !printRecurDaily  && todo->recurrenceType() == Recurrence::rDaily  ) ||
00621            ( !printRecurWeekly && todo->recurrenceType() == Recurrence::rWeekly ) )
00622         continue;
00623       if ( todo->hasDueDate() && !todo->doesFloat() )
00624         text += KGlobal::locale()->formatTime(todo->dtDue().time()) + " ";
00625       else
00626         text = "";
00627       drawIncidence( p, dayBox, text, i18n("To-do: %1").arg(todo->summary()), textY );
00628     }
00629   }
00630 
00631   p.setFont( oldFont );
00632 }
00633 
00634 void CalPrintHelper::drawIncidence( QPainter &p, QRect &dayBox, const QString &time, const QString &summary, int &textY )
00635 {
00636   kdDebug(5850) << "summary = " << summary << endl;
00637 
00638   int flags = Qt::AlignLeft;
00639   QFontMetrics fm = p.fontMetrics();
00640   QRect timeBound = p.boundingRect( dayBox.x() + 5, dayBox.y() + textY,
00641                                     dayBox.width() - 10, fm.lineSpacing(),
00642                                     flags, time );
00643   p.drawText( timeBound, flags, time );
00644 
00645   int summaryWidth = time.isEmpty() ? 0 : timeBound.width() + 4;
00646   QRect summaryBound = QRect( dayBox.x() + 5 + summaryWidth, dayBox.y() + textY,
00647                               dayBox.width() - summaryWidth -5, dayBox.height() );
00648 
00649   KWordWrap *ww = KWordWrap::formatText( fm, summaryBound, flags, summary );
00650   ww->drawText( &p, dayBox.x() + 5 + summaryWidth, dayBox.y() + textY, flags );
00651 
00652   textY += ww->boundingRect().height();
00653 
00654   delete ww;
00655 }
00656 
00657 
00659 
00660 void CalPrintHelper::drawWeek(QPainter &p, const QDate &qd,
00661     int x, int y, int width, int height)
00662 {
00663   QDate weekDate = qd;
00664   bool portrait = ( height > width );
00665   int cellWidth, cellHeight;
00666   int vcells;
00667   if (portrait) {
00668     cellWidth = width/2;
00669     vcells=3;
00670   } else {
00671     cellWidth = width/6;
00672     vcells=1;
00673   }
00674   cellHeight = height/vcells;
00675 
00676   // correct begin of week
00677   int weekdayCol = weekdayColumn( qd.dayOfWeek() );
00678   weekDate = qd.addDays( -weekdayCol );
00679 
00680   for (int i = 0; i < 7; i++, weekDate = weekDate.addDays(1)) {
00681     if (i<5) {
00682       drawDayBox(p, weekDate, x+cellWidth*(int)(i/vcells), y+cellHeight*(i%vcells),
00683         cellWidth, cellHeight, true);
00684     } else if (i==5) {
00685       drawDayBox(p, weekDate, x+cellWidth*(int)(i/vcells), y+cellHeight*(i%vcells),
00686         cellWidth, cellHeight/2, true);
00687     } else if (i==6) {
00688       drawDayBox(p, weekDate, x+cellWidth*(int)((i-1)/vcells),
00689         y+cellHeight*((i-1)%vcells)+cellHeight/2, cellWidth, cellHeight/2, true);
00690     }
00691   } // for i through all weekdays
00692 }
00693 
00694 
00695 void CalPrintHelper::drawTimeTable(QPainter &p,
00696     const QDate &fromDate, const QDate &toDate,
00697     QTime &fromTime, QTime &toTime,
00698     int x, int y, int width, int height)
00699 {
00700   // timeline is 1.5 hours:
00701   int alldayHeight = (int)( 3600.*height/(fromTime.secsTo(toTime)+3600.) );
00702   int timelineWidth = 50;
00703   int cellWidth = (int)( (width-timelineWidth)/(fromDate.daysTo(toDate)+1) );
00704   int currY=y;
00705   int currX=x;
00706 
00707   drawDaysOfWeek( p, fromDate, toDate, x+timelineWidth, currY, width-timelineWidth, mSubHeaderHeight);
00708   currY+=mSubHeaderHeight;
00709   drawTimeLine( p, fromTime, toTime, x, currY+alldayHeight,
00710     timelineWidth, height-mSubHeaderHeight-alldayHeight );
00711 
00712   currX=x+timelineWidth;
00713   // draw each day
00714   QDate curDate(fromDate);
00715   while (curDate<=toDate) {
00716     Event::List eventList = mCalendar->events(curDate,
00717                                               EventSortStartDate,
00718                                               SortDirectionAscending);
00719     drawAllDayBox( p, eventList, curDate, false, currX, currY, cellWidth, alldayHeight);
00720     drawAgendaDayBox( p, eventList, curDate, false, fromTime, toTime, currX,
00721       currY+alldayHeight, cellWidth, height-mSubHeaderHeight-alldayHeight );
00722     currX+=cellWidth;
00723     curDate=curDate.addDays(1);
00724   }
00725 
00726 }
00727 
00728 
00730 
00731 void CalPrintHelper::drawMonth(QPainter &p, const QDate &qd, bool weeknumbers,
00732                                bool recurDaily, bool recurWeekly, int x, int y,
00733                                int width, int height)
00734 {
00735   int yoffset = mSubHeaderHeight;
00736   int xoffset = 0;
00737   QDate monthDate(QDate(qd.year(), qd.month(), 1));
00738   QDate monthFirst(monthDate);
00739   QDate monthLast(monthDate.addMonths(1).addDays(-1));
00740 
00741 
00742   int weekdayCol = weekdayColumn( monthDate.dayOfWeek() );
00743   monthDate = monthDate.addDays(-weekdayCol);
00744 
00745   int rows=(weekdayCol + qd.daysInMonth() - 1)/7 +1;
00746   int cellHeight = (height-yoffset) / rows;
00747 
00748   if (weeknumbers) {
00749     QFont oldFont(p.font());
00750     QFont newFont(p.font());
00751     newFont.setPointSize(6);
00752     p.setFont(newFont);
00753     xoffset += 14;
00754     QDate weekDate(monthDate);
00755     for (int row = 0; row<rows; ++row ) {
00756       int calWeek = weekDate.weekNumber();
00757       QRect rc( x, y + yoffset + cellHeight*row, xoffset - 1, cellHeight );
00758       p.drawText( rc, Qt::AlignRight | Qt::AlignVCenter,
00759                   QString::number( calWeek ) );
00760       weekDate = weekDate.addDays( 7 );
00761     }
00762     p.setFont( oldFont );
00763   }
00764 
00765   drawDaysOfWeek( p, monthDate, monthDate.addDays( 6 ), x + xoffset,
00766                   y, width - xoffset, mSubHeaderHeight );
00767   int cellWidth = ( width - xoffset ) / 7;
00768 
00769   QColor back = p.backgroundColor();
00770   bool darkbg = false;
00771   for ( int row = 0; row < rows; ++row ) {
00772     for ( int col = 0; col < 7; ++col ) {
00773       // show days from previous/next month with a grayed background
00774       if ( (monthDate < monthFirst) || (monthDate > monthLast) ) {
00775         p.setBackgroundColor( back.dark( 120 ) );
00776         darkbg = true;
00777       }
00778       drawDayBox(p, monthDate, x+xoffset+col*cellWidth, y+yoffset+row*cellHeight,
00779                  cellWidth, cellHeight, false,  recurDaily, recurWeekly );
00780       if ( darkbg ) {
00781         p.setBackgroundColor( back );
00782         darkbg = false;
00783       }
00784       monthDate = monthDate.addDays(1);
00785     }
00786   }
00787 }
00788 
00789 
00791 
00792 void CalPrintHelper::drawTodo( int &count, Todo *todo, QPainter &p,
00793                                TodoSortField sortField, SortDirection sortDir,
00794                                bool connectSubTodos, bool strikeoutCompleted,
00795                                bool desc, int posPriority, int posSummary,
00796                                int posDueDt, int posPercentComplete,
00797                                int level, int x, int &y, int width,
00798                                int pageHeight, const Todo::List &todoList,
00799                                TodoParentStart *r )
00800 {
00801   QString outStr;
00802   const KLocale *local = KGlobal::locale();
00803   QRect rect;
00804   TodoParentStart startpt;
00805 
00806   // This list keeps all starting points of the parent to-dos so the connection
00807   // lines of the tree can easily be drawn (needed if a new page is started)
00808   static QPtrList<TodoParentStart> startPoints;
00809   if ( level < 1 ) {
00810     startPoints.clear();
00811   }
00812 
00813   // Compute the right hand side of the to-do box
00814   int rhs = posPercentComplete;
00815   if ( rhs < 0 ) rhs = posDueDt; //not printing percent completed
00816   if ( rhs < 0 ) rhs = x+width;  //not printing due dates either
00817 
00818   // size of to-do
00819   outStr=todo->summary();
00820   int left = posSummary + ( level*10 );
00821   rect = p.boundingRect( left, y, ( rhs-left-5 ), -1, Qt::WordBreak, outStr );
00822   if ( !todo->description().isEmpty() && desc ) {
00823     outStr = todo->description();
00824     rect = p.boundingRect( left+20, rect.bottom()+5, width-(left+10-x), -1,
00825                            Qt::WordBreak, outStr );
00826   }
00827   // if too big make new page
00828   if ( rect.bottom() > pageHeight ) {
00829     // first draw the connection lines from parent to-dos:
00830     if ( level > 0 && connectSubTodos ) {
00831       TodoParentStart *rct;
00832       for ( rct = startPoints.first(); rct; rct = startPoints.next() ) {
00833         int start;
00834         int center = rct->mRect.left() + (rct->mRect.width()/2);
00835         int to = p.viewport().bottom();
00836 
00837         // draw either from start point of parent or from top of the page
00838         if ( rct->mSamePage )
00839           start = rct->mRect.bottom() + 1;
00840         else
00841           start = p.viewport().top();
00842         p.moveTo( center, start );
00843         p.lineTo( center, to );
00844         rct->mSamePage = false;
00845       }
00846     }
00847     y=0;
00848     mPrinter->newPage();
00849   }
00850 
00851   // If this is a sub-to-do, r will not be 0, and we want the LH side
00852   // of the priority line up to the RH side of the parent to-do's priority
00853   bool showPriority = posPriority>=0;
00854   int lhs = posPriority;
00855   if ( r ) {
00856     lhs = r->mRect.right() + 1;
00857   }
00858 
00859   outStr.setNum( todo->priority() );
00860   rect = p.boundingRect( lhs, y + 10, 5, -1, Qt::AlignCenter, outStr );
00861   // Make it a more reasonable size
00862   rect.setWidth(18);
00863   rect.setHeight(18);
00864 
00865   // Draw a checkbox
00866   p.setBrush( QBrush( Qt::NoBrush ) );
00867   p.drawRect( rect );
00868   if ( todo->isCompleted() ) {
00869     // cross out the rectangle for completed to-dos
00870     p.drawLine( rect.topLeft(), rect.bottomRight() );
00871     p.drawLine( rect.topRight(), rect.bottomLeft() );
00872   }
00873   lhs = rect.right() + 3;
00874 
00875   // Priority
00876   if ( todo->priority() > 0 && showPriority ) {
00877     p.drawText( rect, Qt::AlignCenter, outStr );
00878   }
00879   startpt.mRect = rect; //save for later
00880 
00881   // Connect the dots
00882   if ( level > 0 && connectSubTodos ) {
00883     int bottom;
00884     int center( r->mRect.left() + (r->mRect.width()/2) );
00885     if ( r->mSamePage )
00886       bottom = r->mRect.bottom() + 1;
00887     else
00888       bottom = 0;
00889     int to( rect.top() + (rect.height()/2) );
00890     int endx( rect.left() );
00891     p.moveTo( center, bottom );
00892     p.lineTo( center, to );
00893     p.lineTo( endx, to );
00894   }
00895 
00896   // summary
00897   outStr=todo->summary();
00898   rect = p.boundingRect( lhs, rect.top(), (rhs-(left + rect.width() + 5)),
00899                          -1, Qt::WordBreak, outStr );
00900 
00901   QRect newrect;
00902   //FIXME: the following code prints underline rather than strikeout text
00903 #if 0
00904   QFont f( p.font() );
00905   if ( todo->isCompleted() && strikeoutCompleted ) {
00906     f.setStrikeOut( true );
00907     p.setFont( f );
00908   }
00909   p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
00910   f.setStrikeOut( false );
00911   p.setFont( f );
00912 #endif
00913   //TODO: Remove this section when the code above is fixed
00914   p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
00915   if ( todo->isCompleted() && strikeoutCompleted ) {
00916     // strike out the summary text if to-do is complete
00917     // Note: we tried to use a strike-out font and for unknown reasons the
00918     // result was underline instead of strike-out, so draw the lines ourselves.
00919     int delta = p.fontMetrics().lineSpacing();
00920     int lines = ( rect.height() / delta ) + 1;
00921     for ( int i=0; i<lines; i++ ) {
00922       p.moveTo( rect.left(),  rect.top() + ( delta/2 ) + ( i*delta ) );
00923       p.lineTo( rect.right(), rect.top() + ( delta/2 ) + ( i*delta ) );
00924     }
00925   }
00926 
00927   // due date
00928   if ( todo->hasDueDate() && posDueDt>=0 ) {
00929     outStr = local->formatDate( todo->dtDue().date(), true );
00930     rect = p.boundingRect( posDueDt, y, x + width, -1,
00931                            Qt::AlignTop | Qt::AlignLeft, outStr );
00932     p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr );
00933   }
00934 
00935   // percentage completed
00936   bool showPercentComplete = posPercentComplete>=0;
00937   if ( showPercentComplete ) {
00938     int lwidth = 24;
00939     int lheight = 12;
00940     //first, draw the progress bar
00941     int progress = (int)(( lwidth*todo->percentComplete())/100.0 + 0.5);
00942 
00943     p.setBrush( QBrush( Qt::NoBrush ) );
00944     p.drawRect( posPercentComplete, y+3, lwidth, lheight );
00945     if ( progress > 0 ) {
00946       p.setBrush( QBrush( Qt::Dense5Pattern ) );
00947       p.drawRect( posPercentComplete, y+3, progress, lheight );
00948     }
00949 
00950     //now, write the percentage
00951     outStr = i18n( "%1%" ).arg( todo->percentComplete() );
00952     rect = p.boundingRect( posPercentComplete+lwidth+3, y, x + width, -1,
00953                            Qt::AlignTop | Qt::AlignLeft, outStr );
00954     p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr );
00955   }
00956 
00957   // description
00958   if ( !todo->description().isEmpty() && desc ) {
00959     y = newrect.bottom() + 5;
00960     outStr = todo->description();
00961     rect = p.boundingRect( left+20, y, x+width-(left+10), -1,
00962                            Qt::WordBreak, outStr );
00963     p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect );
00964   }
00965 
00966   // Set the new line position
00967   y = newrect.bottom() + 10; //set the line position
00968 
00969   // If the to-do has sub-to-dos, we need to call ourselves recursively
00970 #if 0
00971   Incidence::List l = todo->relations();
00972   Incidence::List::ConstIterator it;
00973   startPoints.append( &startpt );
00974   for( it = l.begin(); it != l.end(); ++it ) {
00975     count++;
00976     // In the future, to-dos might also be related to events
00977     // Manually check if the sub-to-do is in the list of to-dos to print
00978     // The problem is that relations() does not apply filters, so
00979     // we need to compare manually with the complete filtered list!
00980     Todo* subtodo = dynamic_cast<Todo *>( *it );
00981     if (subtodo && todoList.contains( subtodo ) ) {
00982       drawTodo( count, subtodo, p, connectSubTodos, strikeoutCompleted,
00983                 desc, posPriority, posSummary, posDueDt, posPercentComplete,
00984                 level+1, x, y, width, pageHeight, todoList, &startpt );
00985     }
00986   }
00987 #endif
00988   // Make a list of all the sub-to-dos related to this to-do.
00989   Todo::List t;
00990   Incidence::List l = todo->relations();
00991   Incidence::List::ConstIterator it;
00992   for( it=l.begin(); it!=l.end(); ++it ) {
00993     // In the future, to-dos might also be related to events
00994     // Manually check if the sub-to-do is in the list of to-dos to print
00995     // The problem is that relations() does not apply filters, so
00996     // we need to compare manually with the complete filtered list!
00997     Todo* subtodo = dynamic_cast<Todo *>( *it );
00998     if ( subtodo && todoList.contains( subtodo ) ) {
00999       t.append( subtodo );
01000     }
01001   }
01002 
01003   // Sort the sub-to-dos and then print them
01004   Todo::List sl = mCalendar->sortTodos( &t, sortField, sortDir );
01005   Todo::List::ConstIterator isl;
01006   startPoints.append( &startpt );
01007   for( isl = sl.begin(); isl != sl.end(); ++isl ) {
01008     count++;
01009     drawTodo( count, ( *isl ), p, sortField,  sortDir,
01010               connectSubTodos, strikeoutCompleted,
01011               desc, posPriority, posSummary, posDueDt, posPercentComplete,
01012               level+1, x, y, width, pageHeight, todoList, &startpt );
01013   }
01014   startPoints.remove( &startpt );
01015 }
01016 
01017 int CalPrintHelper::weekdayColumn( int weekday )
01018 {
01019   return ( weekday + 7 - KGlobal::locale()->weekStartDay() ) % 7;
01020 }
01021 
01022 void CalPrintHelper::drawJournalField( QPainter &p, QString field, QString text,
01023                                        int x, int &y, int width, int pageHeight )
01024 {
01025   if ( text.isEmpty() ) return;
01026 
01027   QString entry( field.arg( text ) );
01028 
01029   QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, entry) );
01030   if ( rect.bottom() > pageHeight) {
01031     // Start new page...
01032     // FIXME: If it's a multi-line text, draw a few lines on this page, and the
01033     // remaining lines on the next page.
01034     y=0;
01035     mPrinter->newPage();
01036     rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, entry);
01037   }
01038   QRect newrect;
01039   p.drawText( rect, Qt::WordBreak, entry, -1, &newrect );
01040   y = newrect.bottom() + 7;
01041 }
01042 
01043 void CalPrintHelper::drawJournal( Journal * journal, QPainter &p, int x, int &y,
01044                                   int width, int pageHeight )
01045 {
01046   QFont oldFont( p.font() );
01047   p.setFont( QFont( "helvetica", 15 ) );
01048   QString headerText;
01049   QString dateText( KGlobal::locale()->
01050         formatDate( journal->dtStart().date(), false ) );
01051 
01052   if ( journal->summary().isEmpty() ) {
01053     headerText = dateText;
01054   } else {
01055     headerText = i18n("Description - date", "%1 - %2")
01056                      .arg( journal->summary() )
01057                      .arg( dateText );
01058   }
01059 
01060   QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText) );
01061   if ( rect.bottom() > pageHeight) {
01062     // Start new page...
01063     y=0;
01064     mPrinter->newPage();
01065     rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText );
01066   }
01067   QRect newrect;
01068   p.drawText( rect, Qt::WordBreak, headerText, -1, &newrect );
01069   p.setFont( oldFont );
01070 
01071   y = newrect.bottom() + 4;
01072 
01073   p.drawLine( x + 3, y, x + width - 6, y );
01074   y += 5;
01075 
01076   drawJournalField( p, i18n("Person: %1"), journal->organizer().fullName(), x, y, width, pageHeight );
01077   drawJournalField( p, i18n("%1"), journal->description(), x, y, width, pageHeight );
01078   y += 10;
01079 }
01080 
01081 
01082 void CalPrintHelper::drawSplitHeaderRight( QPainter &p, const QDate &fd,
01083                                            const QDate &td,
01084                                            const QDate &,
01085                                            int width, int )
01086 {
01087   QFont oldFont( p.font() );
01088 
01089   QPen oldPen( p.pen() );
01090   QPen pen( Qt::black, 4 );
01091 
01092   QString title;
01093   if ( mCalSys ) {
01094     if ( fd.month() == td.month() ) {
01095       title = i18n("Date range: Month dayStart - dayEnd", "%1 %2 - %3")
01096         .arg( mCalSys->monthName( fd.month(), false ) )
01097         .arg( mCalSys->dayString( fd, false ) )
01098         .arg( mCalSys->dayString( td, false ) );
01099     } else {
01100       title = i18n("Date range: monthStart dayStart - monthEnd dayEnd", "%1 %2 - %3 %4")
01101         .arg( mCalSys->monthName( fd.month(), false ) )
01102         .arg( mCalSys->dayString( fd, false ) )
01103         .arg( mCalSys->monthName( td.month(), false ) )
01104         .arg( mCalSys->dayString( td, false ) );
01105     }
01106   }
01107 
01108   QFont serifFont("Times", 30);
01109   p.setFont(serifFont);
01110 
01111   int lineSpacing = p.fontMetrics().lineSpacing();
01112   p.drawText( 0, lineSpacing * 0, width, lineSpacing,
01113               Qt::AlignRight | Qt::AlignTop, title );
01114 
01115   title.truncate(0);
01116 
01117   p.setPen( pen );
01118   p.drawLine(300, lineSpacing * 1, width, lineSpacing * 1);
01119   p.setPen( oldPen );
01120 
01121   p.setFont(QFont("Times", 20, QFont::Bold, TRUE));
01122   int newlineSpacing = p.fontMetrics().lineSpacing();
01123   title += QString::number(fd.year());
01124   p.drawText( 0, lineSpacing * 1 + 4, width, newlineSpacing,
01125               Qt::AlignRight | Qt::AlignTop, title );
01126 
01127   p.setFont( oldFont );
01128 }
01129 
01130 #endif
KDE Home | KDE Accessibility Home | Description of Access Keys