korganizer

calprintdefaultplugins.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     Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
00007     Copyright (c) 2008 Ron Goodheart <ron.goodheart@gmail.com>
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00017     GNU General Public License for more details.
00018 
00019     You should have received a copy of the GNU General Public License
00020     along with this program; if not, write to the Free Software
00021     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00022 
00023     As a special exception, permission is given to link this program
00024     with any edition of Qt, and distribute the resulting executable,
00025     without including the source code for Qt in the source distribution.
00026 */
00027 
00028 #ifndef KORG_NOPRINTER
00029 
00030 #include <qpainter.h>
00031 #include <qdatetimeedit.h>
00032 #include <qcheckbox.h>
00033 #include <qlineedit.h>
00034 #include <qbuttongroup.h>
00035 
00036 #include <kdebug.h>
00037 #include <kconfig.h>
00038 #include <kcalendarsystem.h>
00039 #include <knuminput.h>
00040 #include <kcombobox.h>
00041 
00042 #include <libkcal/incidenceformatter.h>
00043 
00044 #include "calprintdefaultplugins.h"
00045 
00046 #include "calprintincidenceconfig_base.h"
00047 #include "calprintdayconfig_base.h"
00048 #include "calprintweekconfig_base.h"
00049 #include "calprintmonthconfig_base.h"
00050 #include "calprinttodoconfig_base.h"
00051 
00052 static QString cleanStr( const QString &instr )
00053 {
00054   QString ret = instr;
00055   return ret.replace( '\n', ' ' );
00056 }
00057 
00058 /**************************************************************
00059  *           Print Incidence
00060  **************************************************************/
00061 
00062 CalPrintIncidence::CalPrintIncidence() : CalPrintPluginBase()
00063 {
00064 }
00065 
00066 CalPrintIncidence::~CalPrintIncidence()
00067 {
00068 }
00069 
00070 QWidget *CalPrintIncidence::createConfigWidget( QWidget *w )
00071 {
00072   return new CalPrintIncidenceConfig_Base( w );
00073 }
00074 
00075 void CalPrintIncidence::readSettingsWidget()
00076 {
00077   CalPrintIncidenceConfig_Base *cfg =
00078       dynamic_cast<CalPrintIncidenceConfig_Base*>( mConfigWidget );
00079   if ( cfg ) {
00080     mUseColors = cfg->mColors->isChecked();
00081     mShowOptions = cfg->mShowDetails->isChecked();
00082     mShowSubitemsNotes = cfg->mShowSubitemsNotes->isChecked();
00083     mShowAttendees = cfg->mShowAttendees->isChecked();
00084     mShowAttachments = cfg->mShowAttachments->isChecked();
00085   }
00086 }
00087 
00088 void CalPrintIncidence::setSettingsWidget()
00089 {
00090   CalPrintIncidenceConfig_Base *cfg =
00091       dynamic_cast<CalPrintIncidenceConfig_Base*>( mConfigWidget );
00092   if ( cfg ) {
00093     cfg->mColors->setChecked( mUseColors );
00094     cfg->mShowDetails->setChecked(mShowOptions);
00095     cfg->mShowSubitemsNotes->setChecked(mShowSubitemsNotes);
00096     cfg->mShowAttendees->setChecked(mShowAttendees);
00097     cfg->mShowAttachments->setChecked(mShowAttachments);
00098   }
00099 }
00100 
00101 void CalPrintIncidence::loadConfig()
00102 {
00103   if ( mConfig ) {
00104     mUseColors = mConfig->readBoolEntry( "Use Colors", false );
00105     mShowOptions = mConfig->readBoolEntry( "Show Options", false );
00106     mShowSubitemsNotes = mConfig->readBoolEntry( "Show Subitems and Notes", false );
00107     mShowAttendees = mConfig->readBoolEntry( "Use Attendees", false );
00108     mShowAttachments = mConfig->readBoolEntry( "Use Attachments", false );
00109   }
00110   setSettingsWidget();
00111 }
00112 
00113 void CalPrintIncidence::saveConfig()
00114 {
00115   readSettingsWidget();
00116   if ( mConfig ) {
00117     mConfig->writeEntry( "Use Colors", mUseColors );
00118     mConfig->writeEntry( "Show Options", mShowOptions );
00119     mConfig->writeEntry( "Show Subitems and Notes", mShowSubitemsNotes );
00120     mConfig->writeEntry( "Use Attendees", mShowAttendees );
00121     mConfig->writeEntry( "Use Attachments", mShowAttachments );
00122   }
00123 }
00124 
00125 
00126 class TimePrintStringsVisitor : public IncidenceBase::Visitor
00127 {
00128   public:
00129     TimePrintStringsVisitor() {}
00130 
00131     bool act( IncidenceBase *incidence )
00132     {
00133       return incidence->accept( *this );
00134     }
00135     QString mStartCaption, mStartString;
00136     QString mEndCaption, mEndString;
00137     QString mDurationCaption, mDurationString;
00138 
00139   protected:
00140     bool visit( Event *event ) {
00141       if ( event->dtStart().isValid() ) {
00142         mStartCaption =  i18n( "Start date: " );
00143         mStartString = IncidenceFormatter::dateTimeToString(
00144           event->dtStart(), event->doesFloat(), false );
00145       } else {
00146         mStartCaption = i18n( "No start date" );
00147         mStartString = QString::null;
00148       }
00149 
00150       if ( event->hasEndDate() ) {
00151         mEndCaption = i18n( "End date: " );
00152         mEndString = IncidenceFormatter::dateTimeToString(
00153           event->dtEnd(), event->doesFloat(), false );
00154       } else if ( event->hasDuration() ) {
00155         mEndCaption = i18n("Duration: ");
00156         int mins = event->duration() / 60;
00157         if ( mins >= 60 ) {
00158           mEndString += i18n( "1 hour ", "%n hours ", mins/60 );
00159         }
00160         if ( mins%60 > 0 ) {
00161           mEndString += i18n( "1 minute ", "%n minutes ",  mins%60 );
00162         }
00163       } else {
00164         mEndCaption = i18n("No end date");
00165         mEndString = QString::null;
00166       }
00167       return true;
00168     }
00169     bool visit( Todo *todo ) {
00170       if ( todo->hasStartDate() ) {
00171         mStartCaption =  i18n( "Start date: " );
00172         mStartString = IncidenceFormatter::dateTimeToString(
00173           todo->dtStart(), todo->doesFloat(), false );
00174       } else {
00175         mStartCaption = i18n( "No start date" );
00176         mStartString = QString::null;
00177       }
00178 
00179       if ( todo->hasDueDate() ) {
00180         mEndCaption = i18n( "Due date: " );
00181         mEndString = IncidenceFormatter::dateTimeToString(
00182           todo->dtDue(), todo->doesFloat(), false );
00183       } else {
00184         mEndCaption = i18n("No due date");
00185         mEndString = QString::null;
00186       }
00187       return true;
00188     }
00189     bool visit( Journal *journal ) {
00190       mStartCaption = i18n( "Start date: " );
00191       mStartString = IncidenceFormatter::dateTimeToString(
00192         journal->dtStart(), journal->doesFloat(), false );
00193       mEndCaption = QString::null;
00194       mEndString = QString::null;
00195       return true;
00196     }
00197 };
00198 
00199 int CalPrintIncidence::printCaptionAndText( QPainter &p, const QRect &box, const QString &caption, const QString &text, QFont captionFont, QFont textFont )
00200 {
00201   QFontMetrics captionFM( captionFont );
00202   int textWd = captionFM.width( caption );
00203   QRect textRect( box );
00204 
00205   QFont oldFont( p.font() );
00206   p.setFont( captionFont );
00207   p.drawText( box, Qt::AlignLeft|Qt::AlignTop|Qt::SingleLine, caption );
00208 
00209   if ( !text.isEmpty() ) {
00210     textRect.setLeft( textRect.left() + textWd );
00211     p.setFont( textFont );
00212     p.drawText( textRect, Qt::AlignLeft|Qt::AlignTop|Qt::SingleLine, text );
00213   }
00214   p.setFont( oldFont );
00215   return textRect.bottom();
00216 }
00217 
00218 #include <qfontdatabase.h>
00219 void CalPrintIncidence::print( QPainter &p, int width, int height )
00220 {
00221   QFont oldFont(p.font());
00222   QFont textFont( "sans-serif", 11, QFont::Normal );
00223   QFont captionFont( "sans-serif", 11, QFont::Bold );
00224   p.setFont( textFont );
00225   int lineHeight = p.fontMetrics().lineSpacing();
00226   QString cap, txt;
00227 
00228 
00229   Incidence::List::ConstIterator it;
00230   for ( it=mSelectedIncidences.begin(); it!=mSelectedIncidences.end(); ++it ) {
00231     // don't do anything on a 0-pointer!
00232     if ( !(*it) ) continue;
00233     if ( it != mSelectedIncidences.begin() ) mPrinter->newPage();
00234 
00235 
00236     // PAGE Layout (same for landscape and portrait! astonishingly, it looks good with both!):
00237     //  +-----------------------------------+
00238     //  | Header:  Summary                  |
00239     //  +===================================+
00240     //  | start: ______   end: _________    |
00241     //  | repeats: ___________________      |
00242     //  | reminder: __________________      |
00243     //  +-----------------------------------+
00244     //  | Location: ______________________  |
00245     //  +------------------------+----------+
00246     //  | Description:           | Notes or |
00247     //  |                        | Subitems |
00248     //  |                        |          |
00249     //  |                        |          |
00250     //  |                        |          |
00251     //  |                        |          |
00252     //  |                        |          |
00253     //  |                        |          |
00254     //  |                        |          |
00255     //  |                        |          |
00256     //  +------------------------+----------+
00257     //  | Attachments:           | Settings |
00258     //  |                        |          |
00259     //  +------------------------+----------+
00260     //  | Attendees:                        |
00261     //  |                                   |
00262     //  +-----------------------------------+
00263     //  | Categories: _____________________ |
00264     //  +-----------------------------------+
00265 
00266     QRect box( 0, 0, width, height );
00267     QRect titleBox( box );
00268     titleBox.setHeight( headerHeight() );
00269     // Draw summary as header, no small calendars in title bar, expand height if needed
00270     int titleBottom = drawHeader( p, (*it)->summary(), QDate(), QDate(), titleBox, true );
00271     titleBox.setBottom( titleBottom );
00272 
00273     QRect timesBox( titleBox );
00274     timesBox.setTop( titleBox.bottom() + padding() );
00275     timesBox.setHeight( height / 8 );
00276 
00277     TimePrintStringsVisitor stringVis;
00278     int h = timesBox.top();
00279     if ( stringVis.act(*it) ) {
00280       QRect textRect( timesBox.left()+padding(), timesBox.top()+padding(), 0, lineHeight );
00281       textRect.setRight( timesBox.center().x() );
00282       h = printCaptionAndText( p, textRect, stringVis.mStartCaption, stringVis.mStartString, captionFont, textFont );
00283 
00284       textRect.setLeft( textRect.right() );
00285       textRect.setRight( timesBox.right() - padding() );
00286       h = QMAX( printCaptionAndText( p, textRect, stringVis.mEndCaption, stringVis.mEndString, captionFont, textFont ), h );
00287     }
00288 
00289     // Convert recurrence to a string
00290     if ( (*it)->doesRecur() ) {
00291       QRect recurBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight );
00292       KCal::Recurrence *recurs = (*it)->recurrence();
00293 
00294       QString displayString = IncidenceFormatter::recurrenceString((*it));
00295       // exception dates
00296       QString exceptString;
00297       if ( !recurs->exDates().isEmpty() ) {
00298         exceptString = i18n("except for listed dates", " except");
00299         for ( uint i = 0; i < recurs->exDates().size(); i++ ) {
00300           exceptString.append(" ");
00301           exceptString.append( KGlobal::locale()->formatDate(recurs->exDates()[i],
00302                                true) );
00303         }
00304       }
00305       displayString.append(exceptString);
00306       h = QMAX( printCaptionAndText( p, recurBox, i18n( "Repeats: "), displayString, captionFont, textFont ), h );
00307     }
00308 
00309     // Alarms Printing
00310     QRect alarmBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight );
00311     Alarm::List alarms = (*it)->alarms();
00312     if ( alarms.count() == 0 ) {
00313       cap = i18n("No reminders");
00314       txt = QString();
00315     } else {
00316       cap = i18n("Reminder: ", "%n reminders: ", alarms.count() );
00317 
00318       QStringList alarmStrings;
00319       KCal::Alarm::List::ConstIterator it;
00320       for ( it = alarms.begin(); it != alarms.end(); ++it ) {
00321         Alarm *alarm = *it;
00322 
00323         // Alarm offset, copied from koeditoralarms.cpp:
00324         QString offsetstr;
00325         int offset = 0;
00326         if ( alarm->hasStartOffset() ) {
00327           offset = alarm->startOffset().asSeconds();
00328           if ( offset < 0 ) {
00329             offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 before the start");
00330             offset = -offset;
00331           } else {
00332             offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 after the start");
00333           }
00334         } else if ( alarm->hasEndOffset() ) {
00335           offset = alarm->endOffset().asSeconds();
00336           if ( offset < 0 ) {
00337             offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 before the end");
00338             offset = -offset;
00339           } else {
00340             offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 after the end");
00341           }
00342         }
00343 
00344         offset = offset / 60; // make minutes
00345         int useoffset = offset;
00346 
00347         if ( offset % (24*60) == 0 && offset>0 ) { // divides evenly into days?
00348           useoffset = offset / (24*60);
00349           offsetstr = offsetstr.arg( i18n("1 day", "%n days", useoffset ) );
00350         } else if (offset % 60 == 0 && offset>0 ) { // divides evenly into hours?
00351           useoffset = offset / 60;
00352           offsetstr = offsetstr.arg( i18n("1 hour", "%n hours", useoffset ) );
00353         } else {
00354           useoffset = offset;
00355           offsetstr = offsetstr.arg( i18n("1 minute", "%n minutes", useoffset ) );
00356         }
00357         alarmStrings << offsetstr;
00358       }
00359       txt = alarmStrings.join( i18n("Spacer for the joined list of categories", ", ") );
00360 
00361     }
00362     h = QMAX( printCaptionAndText( p, alarmBox, cap, txt, captionFont, textFont ), h );
00363 
00364 
00365     QRect organizerBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight );
00366     h = QMAX( printCaptionAndText( p, organizerBox, i18n("Organizer: "), (*it)->organizer().fullName(), captionFont, textFont ), h );
00367 
00368     // Finally, draw the frame around the time information...
00369     timesBox.setBottom( QMAX( timesBox.bottom(), h+padding() ) );
00370     drawBox( p, BOX_BORDER_WIDTH, timesBox );
00371 
00372 
00373     QRect locationBox( timesBox );
00374     locationBox.setTop( timesBox.bottom() + padding() );
00375     locationBox.setHeight( 0 );
00376     int locationBottom = drawBoxWithCaption( p, locationBox, i18n("Location: "),
00377          (*it)->location(), /*sameLine=*/true, /*expand=*/true, captionFont, textFont );
00378     locationBox.setBottom( locationBottom );
00379 
00380 
00381     // Now start constructing the boxes from the bottom:
00382     QRect footerBox( locationBox );
00383     footerBox.setBottom( box.bottom() );
00384     footerBox.setTop( footerBox.bottom() - lineHeight - 2*padding() );
00385 
00386     QRect categoriesBox( footerBox );
00387     categoriesBox.setBottom( footerBox.top() );
00388     categoriesBox.setTop( categoriesBox.bottom() - lineHeight - 2*padding() );
00389 
00390     QRect attendeesBox( box.left(), categoriesBox.top()-padding()-box.height()/9, box.width(), box.height()/9 );
00391 
00392     QRect attachmentsBox( box.left(), attendeesBox.top()-padding()-box.height()/9, box.width()*3/4 - padding(), box.height()/9 );
00393     QRect optionsBox( attachmentsBox.right() + padding(), attachmentsBox.top(), 0, 0 );
00394     optionsBox.setRight( box.right() );
00395     optionsBox.setBottom( attachmentsBox.bottom() );
00396     QRect notesBox( optionsBox.left(), locationBox.bottom() + padding(), optionsBox.width(), 0 );
00397     notesBox.setBottom( optionsBox.top() - padding() );
00398 
00399     QRect descriptionBox( notesBox );
00400     descriptionBox.setLeft( box.left() );
00401     descriptionBox.setRight( attachmentsBox.right() );
00402     // Adjust boxes depending on the show options...
00403     if (!mShowSubitemsNotes) {
00404       descriptionBox.setRight( box.right() );
00405     }
00406     if (!mShowAttachments || !mShowAttendees) {
00407         descriptionBox.setBottom( attachmentsBox.bottom() );
00408         optionsBox.setTop( attendeesBox.top() );
00409         optionsBox.setBottom( attendeesBox.bottom() );
00410         notesBox.setBottom( attachmentsBox.bottom() );
00411         if (mShowOptions) {
00412           attendeesBox.setRight( attachmentsBox.right() );
00413         }
00414       if (!mShowAttachments && !mShowAttendees) {
00415         if (mShowSubitemsNotes) {
00416           descriptionBox.setBottom( attendeesBox.bottom() );
00417         }
00418         if (!mShowOptions) {
00419           descriptionBox.setBottom( attendeesBox.bottom() );
00420           notesBox.setBottom( attendeesBox.bottom() );
00421         }
00422       }
00423     }
00424     if (mShowAttachments) {
00425       if (!mShowOptions) {
00426         attachmentsBox.setRight( box.right() );
00427         attachmentsBox.setRight( box.right() );
00428       }
00429       if (!mShowAttendees) {
00430         attachmentsBox.setTop( attendeesBox.top() );
00431         attachmentsBox.setBottom( attendeesBox.bottom() );
00432       }
00433     }
00434 
00435     drawBoxWithCaption( p, descriptionBox, i18n("Description:"),
00436                         (*it)->description(), /*sameLine=*/false,
00437                         /*expand=*/false, captionFont, textFont );
00438 
00439     if ( mShowSubitemsNotes ) {
00440       if ( (*it)->relations().isEmpty() || (*it)->type() != "Todo" ) {
00441         int notesPosition = drawBoxWithCaption( p, notesBox, i18n("Notes:"),
00442                          QString::null, /*sameLine=*/false, /*expand=*/false,
00443                          captionFont, textFont );
00444         QPen oldPen( p.pen() );
00445         p.setPen( Qt::DotLine );
00446         while ( (notesPosition += int(1.5*lineHeight)) < notesBox.bottom() ) {
00447           p.drawLine( notesBox.left()+padding(), notesPosition, notesBox.right()-padding(), notesPosition );
00448         }
00449         p.setPen( oldPen );
00450       } else {
00451         Incidence::List relations = (*it)->relations();
00452         QString subitemCaption;
00453         if ( relations.count() == 0 ) {
00454           subitemCaption = i18n( "No Subitems" );
00455           txt == "";
00456         } else {
00457           subitemCaption = i18n( "1 Subitem:",
00458                           "%1 Subitems:",
00459                           relations.count() );
00460         }
00461         Incidence::List::ConstIterator rit;
00462         QString subitemString;
00463         QString statusString;
00464         QString datesString;
00465         int count = 0;
00466         for ( rit = relations.begin(); rit != relations.end(); ++rit ) {
00467           ++count;
00468           if ( !(*rit) ) { // defensive, skip any zero pointers
00469             continue;
00470           }
00471           // format the status
00472           statusString = (*rit)->statusStr();
00473           if ( statusString.isEmpty() ) {
00474             if ( (*rit)->status() == Incidence::StatusNone ) {
00475               statusString = i18n( "no status", "none" );
00476             } else {
00477               statusString = i18n( "unknown status", "unknown" );
00478             }
00479           }
00480           // format the dates if provided
00481           datesString = "";
00482           if ( (*rit)->dtStart().isValid() ) {
00483                 datesString += i18n(
00484                 "Start Date: %1\n").arg(
00485                 KGlobal::locale()->formatDate( (*rit)->dtStart().date(),
00486                                 true ) );
00487             if ( !(*rit)->doesFloat() ) {
00488                 datesString += i18n(
00489                 "Start Time: %1\n").arg(
00490                 KGlobal::locale()->formatTime((*rit)->dtStart().time(),
00491                      false, false) );
00492             }
00493           }
00494           if ( (*rit)->dtEnd().isValid() ) {
00495             subitemString += i18n(
00496                 "Due Date: %1\n").arg(
00497                 KGlobal::locale()->formatDate( (*rit)->dtEnd().date(),
00498                                 true ) );
00499             if ( !(*rit)->doesFloat() ) {
00500               subitemString += i18n(
00501                   "subitem due time", "Due Time: %1\n").arg(
00502                   KGlobal::locale()->formatTime((*rit)->dtEnd().time(),
00503                       false, false) );
00504             }
00505           }
00506           subitemString += i18n("subitem counter", "%1: ", count);
00507           subitemString += (*rit)->summary();
00508           subitemString += "\n";
00509           if ( !datesString.isEmpty() ) {
00510             subitemString += datesString;
00511             subitemString += "\n";
00512           }
00513           subitemString += i18n( "subitem Status: statusString",
00514                                   "Status: %1\n").arg( statusString );
00515           subitemString += IncidenceFormatter::recurrenceString((*rit)) + "\n";
00516           subitemString += i18n( "subitem Priority: N",
00517                                   "Priority: %1\n").arg( (*rit)->priority() );
00518           subitemString += i18n( "subitem Secrecy: secrecyString",
00519                                   "Secrecy: %1\n").arg( (*rit)->secrecyStr() );
00520           subitemString += "\n";
00521         }
00522         drawBoxWithCaption( p, notesBox, i18n("Subitems:"),
00523                             (*it)->description(), /*sameLine=*/false,
00524                             /*expand=*/false, captionFont, textFont );
00525       }
00526     }
00527 
00528     if ( mShowAttachments ) {
00529       Attachment::List attachments = (*it)->attachments();
00530       QString attachmentCaption;
00531       if ( attachments.count() == 0 ) {
00532         attachmentCaption = i18n( "No Attachments" );
00533         txt = QString();
00534       } else {
00535         attachmentCaption = i18n( "1 Attachment:", "%1 Attachments:", attachments.count() );
00536       }
00537       QString attachmentString;
00538       Attachment::List::ConstIterator ait = attachments.begin();
00539       for ( ; ait != attachments.end(); ++ait ) {
00540         if (!attachmentString.isEmpty()) {
00541           attachmentString += i18n( "Spacer for list of attachments", "  " );
00542         }
00543         attachmentString.append((*ait)->label());
00544       }
00545       drawBoxWithCaption( p, attachmentsBox,
00546                         attachmentCaption, attachmentString,
00547                         /*sameLine=*/false, /*expand=*/false,
00548                         captionFont, textFont );
00549     }
00550 
00551     if ( mShowAttendees ) {
00552       Attendee::List attendees = (*it)->attendees();
00553       QString attendeeCaption;
00554       if ( attendees.count() == 0 )
00555         attendeeCaption = i18n("No Attendees");
00556       else
00557         attendeeCaption = i18n("1 Attendee:", "%n Attendees:", attendees.count() );
00558       QString attendeeString;
00559       for ( Attendee::List::ConstIterator ait = attendees.begin(); ait != attendees.end(); ++ait ) {
00560         if ( !attendeeString.isEmpty() ) attendeeString += "\n";
00561         attendeeString += i18n("Formatting of an attendee: "
00562                "'Name (Role): Status', e.g. 'Reinhold Kainhofer "
00563                "<reinhold@kainhofer.com> (Participant): Awaiting Response'",
00564                "%1 (%2): %3")
00565                        .arg( (*ait)->fullName() )
00566                        .arg( (*ait)->roleStr() ).arg( (*ait)->statusStr() );
00567       }
00568       drawBoxWithCaption( p, attendeesBox, i18n("Attendees:"), attendeeString,
00569                /*sameLine=*/false, /*expand=*/false, captionFont, textFont );
00570     }
00571 
00572     if ( mShowOptions ) {
00573       QString optionsString;
00574       if ( !(*it)->statusStr().isEmpty() ) {
00575         optionsString += i18n("Status: %1").arg( (*it)->statusStr() );
00576         optionsString += "\n";
00577       }
00578       if ( !(*it)->secrecyStr().isEmpty() ) {
00579         optionsString += i18n("Secrecy: %1").arg( (*it)->secrecyStr() );
00580         optionsString += "\n";
00581       }
00582       if ( (*it)->type() == "Event" ) {
00583         Event *e = static_cast<Event*>(*it);
00584         if ( e->transparency() == Event::Opaque ) {
00585           optionsString += i18n("Show as: Busy");
00586         } else {
00587           optionsString += i18n("Show as: Free");
00588         }
00589         optionsString += "\n";
00590       } else if ( (*it)->type() == "Todo" ) {
00591         Todo *t = static_cast<Todo*>(*it);
00592         if ( t->isOverdue() ) {
00593           optionsString += i18n("This task is overdue!");
00594           optionsString += "\n";
00595         }
00596       } else if ( (*it)->type() == "Journal" ) {
00597         //TODO: Anything Journal-specific?
00598       }
00599       drawBoxWithCaption( p, optionsBox, i18n("Settings: "),
00600              optionsString, /*sameLine=*/false, /*expand=*/false, captionFont, textFont );
00601     }
00602 
00603     drawBoxWithCaption( p, categoriesBox, i18n("Categories: "),
00604            (*it)->categories().join( i18n("Spacer for the joined list of categories", ", ") ),
00605            /*sameLine=*/true, /*expand=*/false, captionFont, textFont );
00606 
00607     drawFooter( p, footerBox );
00608   }
00609   p.setFont( oldFont );
00610 }
00611 
00612 /**************************************************************
00613  *           Print Day
00614  **************************************************************/
00615 
00616 CalPrintDay::CalPrintDay() : CalPrintPluginBase()
00617 {
00618 }
00619 
00620 CalPrintDay::~CalPrintDay()
00621 {
00622 }
00623 
00624 QWidget *CalPrintDay::createConfigWidget( QWidget *w )
00625 {
00626   return new CalPrintDayConfig_Base( w );
00627 }
00628 
00629 void CalPrintDay::readSettingsWidget()
00630 {
00631   CalPrintDayConfig_Base *cfg =
00632       dynamic_cast<CalPrintDayConfig_Base*>( mConfigWidget );
00633   if ( cfg ) {
00634     mFromDate = cfg->mFromDate->date();
00635     mToDate = cfg->mToDate->date();
00636 
00637     mStartTime = cfg->mFromTime->time();
00638     mEndTime = cfg->mToTime->time();
00639     mIncludeAllEvents = cfg->mIncludeAllEvents->isChecked();
00640 
00641     mIncludeTodos = cfg->mIncludeTodos->isChecked();
00642     mUseColors = cfg->mColors->isChecked();
00643   }
00644 }
00645 
00646 void CalPrintDay::setSettingsWidget()
00647 {
00648   CalPrintDayConfig_Base *cfg =
00649       dynamic_cast<CalPrintDayConfig_Base*>( mConfigWidget );
00650   if ( cfg ) {
00651     cfg->mFromDate->setDate( mFromDate );
00652     cfg->mToDate->setDate( mToDate );
00653 
00654     cfg->mFromTime->setTime( mStartTime );
00655     cfg->mToTime->setTime( mEndTime );
00656     cfg->mIncludeAllEvents->setChecked( mIncludeAllEvents );
00657 
00658     cfg->mIncludeTodos->setChecked( mIncludeTodos );
00659     cfg->mColors->setChecked( mUseColors );
00660   }
00661 }
00662 
00663 void CalPrintDay::loadConfig()
00664 {
00665   if ( mConfig ) {
00666     QDate dt;
00667     QTime tm1( dayStart() );
00668     QDateTime startTm( dt, tm1 );
00669     QDateTime endTm( dt, tm1.addSecs( 12 * 60 * 60 ) );
00670     mStartTime = mConfig->readDateTimeEntry( "Start time", &startTm ).time();
00671     mEndTime = mConfig->readDateTimeEntry( "End time", &endTm ).time();
00672     mIncludeTodos = mConfig->readBoolEntry( "Include todos", false );
00673     mIncludeAllEvents = mConfig->readBoolEntry( "Include all events", false );
00674   }
00675   setSettingsWidget();
00676 }
00677 
00678 void CalPrintDay::saveConfig()
00679 {
00680   readSettingsWidget();
00681   if ( mConfig ) {
00682     mConfig->writeEntry( "Start time", QDateTime( QDate(), mStartTime ) );
00683     mConfig->writeEntry( "End time", QDateTime( QDate(), mEndTime ) );
00684     mConfig->writeEntry( "Include todos", mIncludeTodos );
00685     mConfig->writeEntry( "Include all events", mIncludeAllEvents );
00686   }
00687 }
00688 
00689 void CalPrintDay::setDateRange( const QDate& from, const QDate& to )
00690 {
00691   CalPrintPluginBase::setDateRange( from, to );
00692   CalPrintDayConfig_Base *cfg =
00693       dynamic_cast<CalPrintDayConfig_Base*>( mConfigWidget );
00694   if ( cfg ) {
00695     cfg->mFromDate->setDate( from );
00696     cfg->mToDate->setDate( to );
00697   }
00698 }
00699 
00700 void CalPrintDay::print( QPainter &p, int width, int height )
00701 {
00702   QDate curDay( mFromDate );
00703 
00704   QRect headerBox( 0, 0, width, headerHeight() );
00705   QRect footerBox( 0, height - footerHeight(), width, footerHeight() );
00706   height -= footerHeight();
00707 
00708   KLocale *local = KGlobal::locale();
00709 
00710   do {
00711     QTime curStartTime( mStartTime );
00712     QTime curEndTime( mEndTime );
00713 
00714     // For an invalid time range, simply show one hour, starting at the hour
00715     // before the given start time
00716     if ( curEndTime <= curStartTime ) {
00717       curStartTime = QTime( curStartTime.hour(), 0, 0 );
00718       curEndTime = curStartTime.addSecs( 3600 );
00719     }
00720 
00721     drawHeader( p, local->formatDate( curDay ), curDay, QDate(), headerBox );
00722     Event::List eventList = mCalendar->events( curDay,
00723                                                EventSortStartDate,
00724                                                SortDirectionAscending );
00725 
00726     // split out the all day events as they will be printed in a separate box
00727     Event::List alldayEvents, timedEvents;
00728     Event::List::ConstIterator it;
00729     for ( it = eventList.begin(); it != eventList.end(); ++it ) {
00730       if ( (*it)->doesFloat() ) {
00731         alldayEvents.append( *it );
00732       } else {
00733         timedEvents.append( *it );
00734       }
00735     }
00736 
00737     int fontSize = 11;
00738     QFont textFont( "sans-serif", fontSize, QFont::Normal );
00739     p.setFont( textFont );
00740     uint lineSpacing = p.fontMetrics().lineSpacing();
00741 
00742     uint maxAllDayEvents = 8; // the max we allow to be printed, sorry.
00743     uint allDayHeight = QMIN( alldayEvents.count(), maxAllDayEvents ) * lineSpacing;
00744     allDayHeight = QMAX( allDayHeight, ( 5 * lineSpacing ) ) + ( 2 * padding() );
00745     QRect allDayBox( TIMELINE_WIDTH + padding(), headerBox.bottom() + padding(),
00746                      width - TIMELINE_WIDTH - padding(), allDayHeight );
00747     if ( alldayEvents.count() > 0 ) {
00748       // draw the side bar for all-day events
00749       QFont oldFont( p.font() );
00750       p.setFont( QFont( "sans-serif", 9, QFont::Normal ) );
00751       drawVerticalBox( p,
00752                        BOX_BORDER_WIDTH,
00753                        QRect( 0, headerBox.bottom() + padding(), TIMELINE_WIDTH, allDayHeight ),
00754                        i18n( "Today's Events" ),
00755                        Qt::AlignHCenter | Qt::AlignVCenter | Qt::WordBreak );
00756       p.setFont( oldFont );
00757 
00758       // now draw at most maxAllDayEvents in the all-day box
00759       drawBox( p, BOX_BORDER_WIDTH, allDayBox );
00760 
00761       Event::List::ConstIterator it;
00762       QRect eventBox( allDayBox );
00763       eventBox.setLeft( TIMELINE_WIDTH + ( 2 * padding() ) );
00764       eventBox.setTop( eventBox.top() + padding() );
00765       eventBox.setBottom( eventBox.top() + lineSpacing );
00766       uint count = 0;
00767       for ( it = alldayEvents.begin(); it != alldayEvents.end(); ++it ) {
00768         if ( count == maxAllDayEvents ) {
00769           break;
00770         }
00771         count++;
00772         QString str;
00773         if ( (*it)->location().isEmpty() ) {
00774           str = cleanStr( (*it)->summary() );
00775         } else {
00776           str = i18n( "summary, location", "%1, %2" ).
00777                 arg( cleanStr( (*it)->summary() ), cleanStr( (*it)->location() ) );
00778         }
00779         printEventString( p, eventBox, str );
00780         eventBox.setTop( eventBox.bottom() );
00781         eventBox.setBottom( eventBox.top() + lineSpacing );
00782       }
00783     } else {
00784       allDayBox.setBottom( headerBox.bottom() );
00785     }
00786 
00787     QRect dayBox( allDayBox );
00788     dayBox.setTop( allDayBox.bottom() + padding() );
00789     dayBox.setBottom( height );
00790     drawAgendaDayBox( p, timedEvents, curDay, mIncludeAllEvents,
00791                       curStartTime, curEndTime, dayBox );
00792 
00793     QRect tlBox( dayBox );
00794     tlBox.setLeft( 0 );
00795     tlBox.setWidth( TIMELINE_WIDTH );
00796     drawTimeLine( p, curStartTime, curEndTime, tlBox );
00797 
00798     drawFooter( p, footerBox );
00799 
00800     curDay = curDay.addDays( 1 );
00801     if ( curDay <= mToDate ) {
00802       mPrinter->newPage();
00803     }
00804   } while ( curDay <= mToDate );
00805 }
00806 
00807 
00808 
00809 /**************************************************************
00810  *           Print Week
00811  **************************************************************/
00812 
00813 CalPrintWeek::CalPrintWeek() : CalPrintPluginBase()
00814 {
00815 }
00816 
00817 CalPrintWeek::~CalPrintWeek()
00818 {
00819 }
00820 
00821 QWidget *CalPrintWeek::createConfigWidget( QWidget *w )
00822 {
00823   return new CalPrintWeekConfig_Base( w );
00824 }
00825 
00826 void CalPrintWeek::readSettingsWidget()
00827 {
00828   CalPrintWeekConfig_Base *cfg =
00829       dynamic_cast<CalPrintWeekConfig_Base*>( mConfigWidget );
00830   if ( cfg ) {
00831     mFromDate = cfg->mFromDate->date();
00832     mToDate = cfg->mToDate->date();
00833 
00834     mWeekPrintType = (eWeekPrintType)( cfg->mPrintType->id(
00835       cfg->mPrintType->selected() ) );
00836 
00837     mStartTime = cfg->mFromTime->time();
00838     mEndTime = cfg->mToTime->time();
00839 
00840     mSingleLineLimit = cfg->mSingleLineLimit->isChecked();
00841     mIncludeTodos = cfg->mIncludeTodos->isChecked();
00842     mUseColors = cfg->mColors->isChecked();
00843   }
00844 }
00845 
00846 void CalPrintWeek::setSettingsWidget()
00847 {
00848   CalPrintWeekConfig_Base *cfg =
00849       dynamic_cast<CalPrintWeekConfig_Base*>( mConfigWidget );
00850   if ( cfg ) {
00851     cfg->mFromDate->setDate( mFromDate );
00852     cfg->mToDate->setDate( mToDate );
00853 
00854     cfg->mPrintType->setButton( mWeekPrintType );
00855 
00856     cfg->mFromTime->setTime( mStartTime );
00857     cfg->mToTime->setTime( mEndTime );
00858 
00859     cfg->mSingleLineLimit->setChecked( mSingleLineLimit );
00860     cfg->mIncludeTodos->setChecked( mIncludeTodos );
00861     cfg->mColors->setChecked( mUseColors );
00862   }
00863 }
00864 
00865 void CalPrintWeek::loadConfig()
00866 {
00867   if ( mConfig ) {
00868     QDate dt;
00869     QTime tm1( dayStart() );
00870     QDateTime startTm( dt, tm1  );
00871     QDateTime endTm( dt, tm1.addSecs( 43200 ) );
00872     mStartTime = mConfig->readDateTimeEntry( "Start time", &startTm ).time();
00873     mEndTime = mConfig->readDateTimeEntry( "End time", &endTm ).time();
00874     mSingleLineLimit = mConfig->readBoolEntry( "Single line limit", false );
00875     mIncludeTodos = mConfig->readBoolEntry( "Include todos", false );
00876     mWeekPrintType =(eWeekPrintType)( mConfig->readNumEntry( "Print type", (int)Filofax ) );
00877   }
00878   setSettingsWidget();
00879 }
00880 
00881 void CalPrintWeek::saveConfig()
00882 {
00883   readSettingsWidget();
00884   if ( mConfig ) {
00885     mConfig->writeEntry( "Start time", QDateTime( QDate(), mStartTime ) );
00886     mConfig->writeEntry( "End time", QDateTime( QDate(), mEndTime ) );
00887     mConfig->writeEntry( "Single line limit", mSingleLineLimit );
00888     mConfig->writeEntry( "Include todos", mIncludeTodos );
00889     mConfig->writeEntry( "Print type", int( mWeekPrintType ) );
00890   }
00891 }
00892 
00893 KPrinter::Orientation CalPrintWeek::defaultOrientation()
00894 {
00895   if ( mWeekPrintType == Filofax ) return KPrinter::Portrait;
00896   else if ( mWeekPrintType == SplitWeek ) return KPrinter::Portrait;
00897   else return KPrinter::Landscape;
00898 }
00899 
00900 void CalPrintWeek::setDateRange( const QDate &from, const QDate &to )
00901 {
00902   CalPrintPluginBase::setDateRange( from, to );
00903   CalPrintWeekConfig_Base *cfg =
00904       dynamic_cast<CalPrintWeekConfig_Base*>( mConfigWidget );
00905   if ( cfg ) {
00906     cfg->mFromDate->setDate( from );
00907     cfg->mToDate->setDate( to );
00908   }
00909 }
00910 
00911 void CalPrintWeek::print( QPainter &p, int width, int height )
00912 {
00913   QDate curWeek, fromWeek, toWeek;
00914 
00915   // correct begin and end to first and last day of week
00916   int weekdayCol = weekdayColumn( mFromDate.dayOfWeek() );
00917   fromWeek = mFromDate.addDays( -weekdayCol );
00918   weekdayCol = weekdayColumn( mFromDate.dayOfWeek() );
00919   toWeek = mToDate.addDays( 6 - weekdayCol );
00920 
00921   curWeek = fromWeek.addDays( 6 );
00922   KLocale *local = KGlobal::locale();
00923 
00924   QString line1, line2, title;
00925   QRect headerBox( 0, 0, width, headerHeight() );
00926   QRect footerBox( 0, height - footerHeight(), width, footerHeight() );
00927   height -= footerHeight();
00928 
00929   QRect weekBox( headerBox );
00930   weekBox.setTop( headerBox.bottom() + padding() );
00931   weekBox.setBottom( height );
00932 
00933   switch ( mWeekPrintType ) {
00934     case Filofax:
00935       do {
00936         line1 = local->formatDate( curWeek.addDays( -6 ) );
00937         line2 = local->formatDate( curWeek );
00938         if ( orientation() == KPrinter::Landscape ) {
00939           title = i18n("date from-to", "%1 - %2");
00940         } else {
00941           title = i18n("date from-\nto", "%1 -\n%2");;
00942         }
00943         title = title.arg( line1 ).arg( line2 );
00944         drawHeader( p, title, curWeek.addDays( -6 ), QDate(), headerBox );
00945 
00946         drawWeek( p, curWeek, weekBox, mSingleLineLimit );
00947 
00948         drawFooter( p, footerBox );
00949 
00950         curWeek = curWeek.addDays( 7 );
00951         if ( curWeek <= toWeek )
00952           mPrinter->newPage();
00953       } while ( curWeek <= toWeek );
00954       break;
00955 
00956     case Timetable:
00957     default:
00958       do {
00959         line1 = local->formatDate( curWeek.addDays( -6 ) );
00960         line2 = local->formatDate( curWeek );
00961         if ( orientation() == KPrinter::Landscape ) {
00962           title = i18n("date from - to (week number)", "%1 - %2 (Week %3)");
00963         } else {
00964           title = i18n("date from -\nto (week number)", "%1 -\n%2 (Week %3)");
00965         }
00966         title = title.arg( line1 ).arg( line2 ).arg( curWeek.weekNumber() );
00967         drawHeader( p, title, curWeek, QDate(), headerBox );
00968 
00969         QRect weekBox( headerBox );
00970         weekBox.setTop( headerBox.bottom() + padding() );
00971         weekBox.setBottom( height );
00972         drawTimeTable( p, fromWeek, curWeek, mStartTime, mEndTime, weekBox );
00973 
00974         drawFooter( p, footerBox );
00975 
00976         fromWeek = fromWeek.addDays( 7 );
00977         curWeek = fromWeek.addDays( 6 );
00978         if ( curWeek <= toWeek )
00979           mPrinter->newPage();
00980       } while ( curWeek <= toWeek );
00981       break;
00982 
00983     case SplitWeek: {
00984       QRect weekBox1( weekBox );
00985       // On the left side there are four days (mo-th) plus the timeline,
00986       // on the right there are only three days (fr-su) plus the timeline. Don't
00987       // use the whole width, but rather give them the same width as on the left.
00988       weekBox1.setRight( int( ( width - TIMELINE_WIDTH ) * 3. / 4. + TIMELINE_WIDTH ) );
00989       do {
00990         QDate endLeft( fromWeek.addDays( 3 ) );
00991         int hh = headerHeight();
00992 
00993         drawTimeTable( p, fromWeek, endLeft,
00994                        mStartTime, mEndTime, weekBox );
00995         mPrinter->newPage();
00996         drawSplitHeaderRight( p, fromWeek, curWeek, QDate(), width, hh );
00997         drawTimeTable( p, endLeft.addDays( 1 ), curWeek,
00998                        mStartTime, mEndTime, weekBox1 );
00999 
01000         drawFooter( p, footerBox );
01001 
01002         fromWeek = fromWeek.addDays( 7 );
01003         curWeek = fromWeek.addDays( 6 );
01004         if ( curWeek <= toWeek )
01005           mPrinter->newPage();
01006       } while ( curWeek <= toWeek );
01007       }
01008       break;
01009   }
01010 }
01011 
01012 
01013 
01014 
01015 /**************************************************************
01016  *           Print Month
01017  **************************************************************/
01018 
01019 CalPrintMonth::CalPrintMonth() : CalPrintPluginBase()
01020 {
01021 }
01022 
01023 CalPrintMonth::~CalPrintMonth()
01024 {
01025 }
01026 
01027 QWidget *CalPrintMonth::createConfigWidget( QWidget *w )
01028 {
01029   return new CalPrintMonthConfig_Base( w );
01030 }
01031 
01032 void CalPrintMonth::readSettingsWidget()
01033 {
01034   CalPrintMonthConfig_Base *cfg =
01035       dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget );
01036   if ( cfg ) {
01037     mFromDate = QDate( cfg->mFromYear->value(), cfg->mFromMonth->currentItem()+1, 1 );
01038     mToDate = QDate( cfg->mToYear->value(), cfg->mToMonth->currentItem()+1, 1 );
01039 
01040     mWeekNumbers =  cfg->mWeekNumbers->isChecked();
01041     mRecurDaily = cfg->mRecurDaily->isChecked();
01042     mRecurWeekly = cfg->mRecurWeekly->isChecked();
01043     mSingleLineLimit = cfg->mSingleLineLimit->isChecked();
01044     mIncludeTodos = cfg->mIncludeTodos->isChecked();
01045     mUseColors = cfg->mColors->isChecked();
01046   }
01047 }
01048 
01049 void CalPrintMonth::setSettingsWidget()
01050 {
01051   CalPrintMonthConfig_Base *cfg =
01052       dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget );
01053   setDateRange( mFromDate, mToDate );
01054   if ( cfg ) {
01055     cfg->mWeekNumbers->setChecked( mWeekNumbers );
01056     cfg->mRecurDaily->setChecked( mRecurDaily );
01057     cfg->mRecurWeekly->setChecked( mRecurWeekly );
01058     cfg->mSingleLineLimit->setChecked( mSingleLineLimit );
01059     cfg->mIncludeTodos->setChecked( mIncludeTodos );
01060     cfg->mColors->setChecked( mUseColors );
01061   }
01062 }
01063 
01064 void CalPrintMonth::loadConfig()
01065 {
01066   if ( mConfig ) {
01067     mWeekNumbers = mConfig->readBoolEntry( "Print week numbers", true );
01068     mRecurDaily = mConfig->readBoolEntry( "Print daily incidences", true );
01069     mRecurWeekly = mConfig->readBoolEntry( "Print weekly incidences", true );
01070     mSingleLineLimit = mConfig->readBoolEntry( "Single line limit", false );
01071     mIncludeTodos = mConfig->readBoolEntry( "Include todos", false );
01072   }
01073   setSettingsWidget();
01074 }
01075 
01076 void CalPrintMonth::saveConfig()
01077 {
01078   readSettingsWidget();
01079   if ( mConfig ) {
01080     mConfig->writeEntry( "Print week numbers", mWeekNumbers );
01081     mConfig->writeEntry( "Print daily incidences", mRecurDaily );
01082     mConfig->writeEntry( "Print weekly incidences", mRecurWeekly );
01083     mConfig->writeEntry( "Single line limit", mSingleLineLimit );
01084     mConfig->writeEntry( "Include todos", mIncludeTodos );
01085   }
01086 }
01087 
01088 void CalPrintMonth::setDateRange( const QDate &from, const QDate &to )
01089 {
01090   CalPrintPluginBase::setDateRange( from, to );
01091   CalPrintMonthConfig_Base *cfg =
01092       dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget );
01093   const KCalendarSystem *calSys = calendarSystem();
01094   if ( cfg && calSys ) {
01095     cfg->mFromMonth->clear();
01096     for ( int i=0; i<calSys->monthsInYear( mFromDate ); ++i ) {
01097       cfg->mFromMonth->insertItem( calSys->monthName( i+1, mFromDate.year() ) );
01098     }
01099     cfg->mToMonth->clear();
01100     for ( int i=0; i<calSys->monthsInYear( mToDate ); ++i ) {
01101       cfg->mToMonth->insertItem( calSys->monthName( i+1, mToDate.year() ) );
01102     }
01103   }
01104   if ( cfg ) {
01105     cfg->mFromMonth->setCurrentItem( from.month()-1 );
01106     cfg->mFromYear->setValue( to.year() );
01107     cfg->mToMonth->setCurrentItem( mToDate.month()-1 );
01108     cfg->mToYear->setValue( mToDate.year() );
01109   }
01110 }
01111 
01112 void CalPrintMonth::print( QPainter &p, int width, int height )
01113 {
01114   QDate curMonth, fromMonth, toMonth;
01115 
01116   fromMonth = mFromDate.addDays( -( mFromDate.day() - 1 ) );
01117   toMonth = mToDate.addDays( mToDate.daysInMonth() - mToDate.day() );
01118 
01119   curMonth = fromMonth;
01120   const KCalendarSystem *calSys = calendarSystem();
01121   if ( !calSys ) return;
01122 
01123   QRect headerBox( 0, 0, width, headerHeight() );
01124   QRect footerBox( 0, height - footerHeight(), width, footerHeight() );
01125   height -= footerHeight();
01126 
01127   QRect monthBox( 0, 0, width, height );
01128   monthBox.setTop( headerBox.bottom() + padding() );
01129 
01130   do {
01131     QString title( i18n("monthname year", "%1 %2") );
01132     title = title.arg( calSys->monthName( curMonth ) )
01133                  .arg( curMonth.year() );
01134     QDate tmp( fromMonth );
01135     int weekdayCol = weekdayColumn( tmp.dayOfWeek() );
01136     tmp = tmp.addDays( -weekdayCol );
01137 
01138     drawHeader( p, title, curMonth.addMonths( -1 ), curMonth.addMonths( 1 ),
01139                 headerBox );
01140     drawMonthTable( p, curMonth, mWeekNumbers, mRecurDaily, mRecurWeekly,
01141                     mSingleLineLimit, monthBox );
01142 
01143     drawFooter( p, footerBox );
01144 
01145     curMonth = curMonth.addDays( curMonth.daysInMonth() );
01146     if ( curMonth <= toMonth ) mPrinter->newPage();
01147   } while ( curMonth <= toMonth );
01148 
01149 }
01150 
01151 
01152 
01153 
01154 /**************************************************************
01155  *           Print Todos
01156  **************************************************************/
01157 
01158 CalPrintTodos::CalPrintTodos() : CalPrintPluginBase()
01159 {
01160   mTodoSortField = TodoFieldUnset;
01161   mTodoSortDirection = TodoDirectionUnset;
01162 }
01163 
01164 CalPrintTodos::~CalPrintTodos()
01165 {
01166 }
01167 
01168 QWidget *CalPrintTodos::createConfigWidget( QWidget *w )
01169 {
01170   return new CalPrintTodoConfig_Base( w );
01171 }
01172 
01173 void CalPrintTodos::readSettingsWidget()
01174 {
01175   CalPrintTodoConfig_Base *cfg =
01176       dynamic_cast<CalPrintTodoConfig_Base *>( mConfigWidget );
01177   if ( cfg ) {
01178     mPageTitle = cfg->mTitle->text();
01179 
01180     mTodoPrintType = (eTodoPrintType)( cfg->mPrintType->id(
01181       cfg->mPrintType->selected() ) );
01182 
01183     mFromDate = cfg->mFromDate->date();
01184     mToDate = cfg->mToDate->date();
01185 
01186     mIncludeDescription = cfg->mDescription->isChecked();
01187     mIncludePriority = cfg->mPriority->isChecked();
01188     mIncludeDueDate = cfg->mDueDate->isChecked();
01189     mIncludePercentComplete = cfg->mPercentComplete->isChecked();
01190     mConnectSubTodos = cfg->mConnectSubTodos->isChecked();
01191     mStrikeOutCompleted = cfg->mStrikeOutCompleted->isChecked();
01192 
01193     mTodoSortField = (eTodoSortField)cfg->mSortField->currentItem();
01194     mTodoSortDirection = (eTodoSortDirection)cfg->mSortDirection->currentItem();
01195   }
01196 }
01197 
01198 void CalPrintTodos::setSettingsWidget()
01199 {
01200 //   kdDebug(5850) << "CalPrintTodos::setSettingsWidget" << endl;
01201 
01202   CalPrintTodoConfig_Base *cfg =
01203       dynamic_cast<CalPrintTodoConfig_Base *>( mConfigWidget );
01204   if ( cfg ) {
01205     cfg->mTitle->setText( mPageTitle );
01206 
01207     cfg->mPrintType->setButton( mTodoPrintType );
01208 
01209     cfg->mFromDate->setDate( mFromDate );
01210     cfg->mToDate->setDate( mToDate );
01211 
01212     cfg->mDescription->setChecked( mIncludeDescription );
01213     cfg->mPriority->setChecked( mIncludePriority );
01214     cfg->mDueDate->setChecked( mIncludeDueDate );
01215     cfg->mPercentComplete->setChecked( mIncludePercentComplete );
01216     cfg->mConnectSubTodos->setChecked( mConnectSubTodos );
01217     cfg->mStrikeOutCompleted->setChecked( mStrikeOutCompleted );
01218 
01219     if ( mTodoSortField != TodoFieldUnset ) {
01220       // do not insert if already done so.
01221       cfg->mSortField->insertItem( i18n("Summary") );
01222       cfg->mSortField->insertItem( i18n("Start Date") );
01223       cfg->mSortField->insertItem( i18n("Due Date") );
01224       cfg->mSortField->insertItem( i18n("Priority") );
01225       cfg->mSortField->insertItem( i18n("Percent Complete") );
01226       cfg->mSortField->setCurrentItem( (int)mTodoSortField );
01227     }
01228 
01229     if ( mTodoSortDirection != TodoDirectionUnset ) {
01230       // do not insert if already done so.
01231       cfg->mSortDirection->insertItem( i18n("Ascending") );
01232       cfg->mSortDirection->insertItem( i18n("Descending") );
01233       cfg->mSortDirection->setCurrentItem( (int)mTodoSortDirection );
01234     }
01235   }
01236 }
01237 
01238 void CalPrintTodos::loadConfig()
01239 {
01240   if ( mConfig ) {
01241     mPageTitle = mConfig->readEntry( "Page title", i18n("To-do list") );
01242     mTodoPrintType = (eTodoPrintType)mConfig->readNumEntry( "Print type", (int)TodosAll );
01243     mIncludeDescription = mConfig->readBoolEntry( "Include description", true );
01244     mIncludePriority = mConfig->readBoolEntry( "Include priority", true );
01245     mIncludeDueDate = mConfig->readBoolEntry( "Include due date", true );
01246     mIncludePercentComplete = mConfig->readBoolEntry( "Include percentage completed", true );
01247     mConnectSubTodos = mConfig->readBoolEntry( "Connect subtodos", true );
01248     mStrikeOutCompleted = mConfig->readBoolEntry( "Strike out completed summaries",  true );
01249     mTodoSortField = (eTodoSortField)mConfig->readNumEntry( "Sort field", (int)TodoFieldSummary );
01250     mTodoSortDirection = (eTodoSortDirection)mConfig->readNumEntry( "Sort direction", (int)TodoDirectionAscending );
01251   }
01252   setSettingsWidget();
01253 }
01254 
01255 void CalPrintTodos::saveConfig()
01256 {
01257   readSettingsWidget();
01258   if ( mConfig ) {
01259     mConfig->writeEntry( "Page title", mPageTitle );
01260     mConfig->writeEntry( "Print type", int( mTodoPrintType ) );
01261     mConfig->writeEntry( "Include description", mIncludeDescription );
01262     mConfig->writeEntry( "Include priority", mIncludePriority );
01263     mConfig->writeEntry( "Include due date", mIncludeDueDate );
01264     mConfig->writeEntry( "Include percentage completed", mIncludePercentComplete );
01265     mConfig->writeEntry( "Connect subtodos", mConnectSubTodos );
01266     mConfig->writeEntry( "Strike out completed summaries", mStrikeOutCompleted );
01267     mConfig->writeEntry( "Sort field", mTodoSortField );
01268     mConfig->writeEntry( "Sort direction", mTodoSortDirection );
01269   }
01270 }
01271 
01272 void CalPrintTodos::print( QPainter &p, int width, int height )
01273 {
01274   // TODO: Find a good way to guarantee a nicely designed output
01275   int pospriority = 0;
01276   int possummary = 100;
01277   int posdue = width - 65;
01278   int poscomplete = posdue - 70; //Complete column is to right of the Due column
01279   int lineSpacing = 15;
01280   //int fontHeight = 10;
01281 
01282   QRect headerBox( 0, 0, width, headerHeight() );
01283   QRect footerBox( 0, height - footerHeight(), width, footerHeight() );
01284   height -= footerHeight();
01285 
01286   // Draw the First Page Header
01287   drawHeader( p, mPageTitle, mFromDate, QDate(), headerBox );
01288 
01289   // Draw the Column Headers
01290   int mCurrentLinePos = headerHeight() + 5;
01291   QString outStr;
01292   QFont oldFont( p.font() );
01293 
01294   p.setFont( QFont( "sans-serif", 9, QFont::Bold ) );
01295   lineSpacing = p.fontMetrics().lineSpacing();
01296   mCurrentLinePos += lineSpacing;
01297   if ( mIncludePriority ) {
01298     outStr += i18n( "Priority" );
01299     p.drawText( pospriority, mCurrentLinePos - 2, outStr );
01300   } else {
01301     pospriority = -1;
01302   }
01303 
01304   outStr.truncate( 0 );
01305   outStr += i18n( "Summary" );
01306   p.drawText( possummary, mCurrentLinePos - 2, outStr );
01307 
01308   if ( mIncludePercentComplete ) {
01309     if ( !mIncludeDueDate ) //move Complete column to the right
01310       poscomplete = posdue; //if not print the Due Date column
01311     outStr.truncate( 0 );
01312     outStr += i18n( "Complete" );
01313     p.drawText( poscomplete, mCurrentLinePos - 2, outStr );
01314   } else {
01315     poscomplete = -1;
01316   }
01317 
01318   if ( mIncludeDueDate ) {
01319     outStr.truncate( 0 );
01320     outStr += i18n( "Due" );
01321     p.drawText( posdue, mCurrentLinePos - 2, outStr );
01322   } else {
01323     posdue = -1;
01324   }
01325 
01326   p.setFont( QFont( "sans-serif", 10 ) );
01327   //fontHeight = p.fontMetrics().height();
01328 
01329   Todo::List todoList;
01330   Todo::List tempList;
01331   Todo::List::ConstIterator it;
01332 
01333   // Convert sort options to the corresponding enums
01334   TodoSortField sortField = TodoSortSummary;
01335   switch( mTodoSortField ) {
01336   case TodoFieldSummary:
01337     sortField = TodoSortSummary; break;
01338   case TodoFieldStartDate:
01339     sortField = TodoSortStartDate; break;
01340   case TodoFieldDueDate:
01341     sortField = TodoSortDueDate; break;
01342   case TodoFieldPriority:
01343     sortField = TodoSortPriority; break;
01344   case TodoFieldPercentComplete:
01345     sortField = TodoSortPercentComplete; break;
01346   case TodoFieldUnset:
01347     break;
01348   }
01349 
01350   SortDirection sortDirection;
01351   switch( mTodoSortDirection ) {
01352   case TodoDirectionAscending:
01353     sortDirection = SortDirectionAscending; break;
01354   case TodoDirectionDescending:
01355     sortDirection = SortDirectionDescending; break;
01356   case TodoDirectionUnset:
01357     break;
01358   }
01359 
01360   // Create list of to-dos which will be printed
01361   todoList = mCalendar->todos( sortField,  sortDirection );
01362   switch( mTodoPrintType ) {
01363   case TodosAll:
01364     break;
01365   case TodosUnfinished:
01366     for( it = todoList.begin(); it!= todoList.end(); ++it ) {
01367       if ( !(*it)->isCompleted() )
01368         tempList.append( *it );
01369     }
01370     todoList = tempList;
01371     break;
01372   case TodosDueRange:
01373     for( it = todoList.begin(); it!= todoList.end(); ++it ) {
01374       if ( (*it)->hasDueDate() ) {
01375         if ( (*it)->dtDue().date() >= mFromDate &&
01376              (*it)->dtDue().date() <= mToDate )
01377           tempList.append( *it );
01378       } else {
01379         tempList.append( *it );
01380       }
01381     }
01382     todoList = tempList;
01383     break;
01384   }
01385 
01386   // Print to-dos
01387   int count = 0;
01388   for ( it=todoList.begin(); it!=todoList.end(); ++it ) {
01389     Todo *currEvent = *it;
01390 
01391     // Skip sub-to-dos. They will be printed recursively in drawTodo()
01392     if ( !currEvent->relatedTo() ) {
01393       count++;
01394       drawTodo( count, currEvent, p,
01395                          sortField, sortDirection,
01396                          mConnectSubTodos,
01397                          mStrikeOutCompleted, mIncludeDescription,
01398                          pospriority, possummary, posdue, poscomplete,
01399                          0, 0, mCurrentLinePos, width, height, todoList );
01400     }
01401   }
01402 
01403   drawFooter( p, footerBox );
01404   p.setFont( oldFont );
01405 }
01406 
01407 #endif
KDE Home | KDE Accessibility Home | Description of Access Keys