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 TQt, and distribute the resulting executable,
00025     without including the source code for TQt in the source distribution.
00026 */
00027 
00028 #ifndef KORG_NOPRINTER
00029 
00030 #include <tqpainter.h>
00031 #include <tqdatetimeedit.h>
00032 #include <tqcheckbox.h>
00033 #include <tqlineedit.h>
00034 #include <tqbuttongroup.h>
00035 
00036 #include <kdebug.h>
00037 #include <tdeconfig.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 "calprintweetdeconfig_base.h"
00049 #include "calprintmonthconfig_base.h"
00050 #include "calprinttodoconfig_base.h"
00051 
00052 static TQString cleanString( const TQString &instr )
00053 {
00054   TQString 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 TQWidget *CalPrintIncidence::createConfigWidget( TQWidget *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     TQString mStartCaption, mStartString;
00136     TQString mEndCaption, mEndString;
00137     TQString 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 = TQString();
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 = TQString();
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 = TQString();
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 = TQString();
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 = TQString();
00194       mEndString = TQString();
00195       return true;
00196     }
00197 };
00198 
00199 int CalPrintIncidence::printCaptionAndText( TQPainter &p, const TQRect &box, const TQString &caption, const TQString &text, TQFont captionFont, TQFont textFont )
00200 {
00201   TQFontMetrics captionFM( captionFont );
00202   int textWd = captionFM.width( caption );
00203   TQRect textRect( box );
00204 
00205   TQFont oldFont( p.font() );
00206   p.setFont( captionFont );
00207   p.drawText( box, TQt::AlignLeft|TQt::AlignTop|TQt::SingleLine, caption );
00208 
00209   if ( !text.isEmpty() ) {
00210     textRect.setLeft( textRect.left() + textWd );
00211     p.setFont( textFont );
00212     p.drawText( textRect, TQt::AlignLeft|TQt::AlignTop|TQt::SingleLine, text );
00213   }
00214   p.setFont( oldFont );
00215   return textRect.bottom();
00216 }
00217 
00218 #include <tqfontdatabase.h>
00219 void CalPrintIncidence::print( TQPainter &p, int width, int height )
00220 {
00221   TQFont oldFont(p.font());
00222   TQFont textFont( "sans-serif", 11, TQFont::Normal );
00223   TQFont captionFont( "sans-serif", 11, TQFont::Bold );
00224   p.setFont( textFont );
00225   int lineHeight = p.fontMetrics().lineSpacing();
00226   TQString 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     TQRect box( 0, 0, width, height );
00267     TQRect 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(), TQDate(), TQDate(), titleBox, true );
00271     titleBox.setBottom( titleBottom );
00272 
00273     TQRect 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       TQRect 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 = TQMAX( printCaptionAndText( p, textRect, stringVis.mEndCaption, stringVis.mEndString, captionFont, textFont ), h );
00287     }
00288 
00289     // Convert recurrence to a string
00290     if ( (*it)->doesRecur() ) {
00291       TQRect recurBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight );
00292       KCal::Recurrence *recurs = (*it)->recurrence();
00293 
00294       TQString displayString = IncidenceFormatter::recurrenceString((*it));
00295       // exception dates
00296       TQString 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( TDEGlobal::locale()->formatDate(recurs->exDates()[i],
00302                                true) );
00303         }
00304       }
00305       displayString.append(exceptString);
00306       h = TQMAX( printCaptionAndText( p, recurBox, i18n( "Repeats: "), displayString, captionFont, textFont ), h );
00307     }
00308 
00309     // Alarms Printing
00310     TQRect 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 = TQString();
00315     } else {
00316       cap = i18n("Reminder: ", "%n reminders: ", alarms.count() );
00317 
00318       TQStringList 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         TQString 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 = TQMAX( printCaptionAndText( p, alarmBox, cap, txt, captionFont, textFont ), h );
00363 
00364 
00365     TQRect organizerBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight );
00366     h = TQMAX( printCaptionAndText( p, organizerBox, i18n("Organizer: "), (*it)->organizer().fullName(), captionFont, textFont ), h );
00367 
00368     // Finally, draw the frame around the time information...
00369     timesBox.setBottom( TQMAX( timesBox.bottom(), h+padding() ) );
00370     drawBox( p, BOX_BORDER_WIDTH, timesBox );
00371 
00372 
00373     TQRect 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     TQRect footerBox( locationBox );
00383     footerBox.setBottom( box.bottom() );
00384     footerBox.setTop( footerBox.bottom() - lineHeight - 2*padding() );
00385 
00386     TQRect categoriesBox( footerBox );
00387     categoriesBox.setBottom( footerBox.top() );
00388     categoriesBox.setTop( categoriesBox.bottom() - lineHeight - 2*padding() );
00389 
00390     TQRect attendeesBox( box.left(), categoriesBox.top()-padding()-box.height()/9, box.width(), box.height()/9 );
00391 
00392     TQRect attachmentsBox( box.left(), attendeesBox.top()-padding()-box.height()/9, box.width()*3/4 - padding(), box.height()/9 );
00393     TQRect optionsBox( attachmentsBox.right() + padding(), attachmentsBox.top(), 0, 0 );
00394     optionsBox.setRight( box.right() );
00395     optionsBox.setBottom( attachmentsBox.bottom() );
00396     TQRect notesBox( optionsBox.left(), locationBox.bottom() + padding(), optionsBox.width(), 0 );
00397     notesBox.setBottom( optionsBox.top() - padding() );
00398 
00399     TQRect 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                          TQString(), /*sameLine=*/false, /*expand=*/false,
00443                          captionFont, textFont );
00444         TQPen oldPen( p.pen() );
00445         p.setPen( TQt::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         TQString 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         TQString subitemString;
00463         TQString statusString;
00464         TQString 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                 TDEGlobal::locale()->formatDate( (*rit)->dtStart().date(),
00486                                 true ) );
00487             if ( !(*rit)->doesFloat() ) {
00488                 datesString += i18n(
00489                 "Start Time: %1\n").arg(
00490                 TDEGlobal::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                 TDEGlobal::locale()->formatDate( (*rit)->dtEnd().date(),
00498                                 true ) );
00499             if ( !(*rit)->doesFloat() ) {
00500               subitemString += i18n(
00501                   "subitem due time", "Due Time: %1\n").arg(
00502                   TDEGlobal::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       TQString attachmentCaption;
00531       if ( attachments.count() == 0 ) {
00532         attachmentCaption = i18n( "No Attachments" );
00533         txt = TQString();
00534       } else {
00535         attachmentCaption = i18n( "1 Attachment:", "%1 Attachments:", attachments.count() );
00536       }
00537       TQString 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       TQString attendeeCaption;
00554       if ( attendees.count() == 0 )
00555         attendeeCaption = i18n("No Attendees");
00556       else
00557         attendeeCaption = i18n("1 Attendee:", "%n Attendees:", attendees.count() );
00558       TQString 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       TQString 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 TQWidget *CalPrintDay::createConfigWidget( TQWidget *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     TQDate dt;
00667     TQTime tm1( dayStart() );
00668     TQDateTime startTm( dt, tm1 );
00669     TQDateTime 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", TQDateTime( TQDate(), mStartTime ) );
00683     mConfig->writeEntry( "End time", TQDateTime( TQDate(), mEndTime ) );
00684     mConfig->writeEntry( "Include todos", mIncludeTodos );
00685     mConfig->writeEntry( "Include all events", mIncludeAllEvents );
00686   }
00687 }
00688 
00689 void CalPrintDay::setDateRange( const TQDate& from, const TQDate& 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( TQPainter &p, int width, int height )
00701 {
00702   TQDate curDay( mFromDate );
00703 
00704   TQRect headerBox( 0, 0, width, headerHeight() );
00705   TQRect footerBox( 0, height - footerHeight(), width, footerHeight() );
00706   height -= footerHeight();
00707 
00708   TDELocale *local = TDEGlobal::locale();
00709 
00710   do {
00711     TQTime curStartTime( mStartTime );
00712     TQTime 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 = TQTime( curStartTime.hour(), 0, 0 );
00718       curEndTime = curStartTime.addSecs( 3600 );
00719     }
00720 
00721     drawHeader( p, local->formatDate( curDay ), curDay, TQDate(), 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     TQFont textFont( "sans-serif", fontSize, TQFont::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 = TQMIN( alldayEvents.count(), maxAllDayEvents ) * lineSpacing;
00744     allDayHeight = TQMAX( allDayHeight, ( 5 * lineSpacing ) ) + ( 2 * padding() );
00745     TQRect 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       TQFont oldFont( p.font() );
00750       p.setFont( TQFont( "sans-serif", 9, TQFont::Normal ) );
00751       drawVerticalBox( p,
00752                        BOX_BORDER_WIDTH,
00753                        TQRect( 0, headerBox.bottom() + padding(), TIMELINE_WIDTH, allDayHeight ),
00754                        i18n( "Today's Events" ),
00755                        TQt::AlignHCenter | TQt::AlignVCenter | TQt::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       TQRect 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         TQString str;
00773         if ( (*it)->location().isEmpty() ) {
00774           str = cleanString( (*it)->summary() );
00775         } else {
00776           str = i18n( "summary, location", "%1, %2" ).
00777                 arg( cleanString( (*it)->summary() ), cleanString( (*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     TQRect dayBox( allDayBox );
00788     dayBox.setTop( allDayBox.bottom() + padding() );
00789     dayBox.setBottom( height );
00790     drawAgendaDayBox( p, timedEvents, curDay, mIncludeAllEvents,
00791                       curStartTime, curEndTime, dayBox );
00792 
00793     TQRect 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 TQWidget *CalPrintWeek::createConfigWidget( TQWidget *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     mIncludeTodos = cfg->mIncludeTodos->isChecked();
00841     mUseColors = cfg->mColors->isChecked();
00842   }
00843 }
00844 
00845 void CalPrintWeek::setSettingsWidget()
00846 {
00847   CalPrintWeekConfig_Base *cfg =
00848       dynamic_cast<CalPrintWeekConfig_Base*>( mConfigWidget );
00849   if ( cfg ) {
00850     cfg->mFromDate->setDate( mFromDate );
00851     cfg->mToDate->setDate( mToDate );
00852 
00853     cfg->mPrintType->setButton( mWeekPrintType );
00854 
00855     cfg->mFromTime->setTime( mStartTime );
00856     cfg->mToTime->setTime( mEndTime );
00857 
00858     cfg->mIncludeTodos->setChecked( mIncludeTodos );
00859     cfg->mColors->setChecked( mUseColors );
00860   }
00861 }
00862 
00863 void CalPrintWeek::loadConfig()
00864 {
00865   if ( mConfig ) {
00866     TQDate dt;
00867     TQTime tm1( dayStart() );
00868     TQDateTime startTm( dt, tm1  );
00869     TQDateTime endTm( dt, tm1.addSecs( 43200 ) );
00870     mStartTime = mConfig->readDateTimeEntry( "Start time", &startTm ).time();
00871     mEndTime = mConfig->readDateTimeEntry( "End time", &endTm ).time();
00872     mIncludeTodos = mConfig->readBoolEntry( "Include todos", false );
00873     mWeekPrintType =(eWeekPrintType)( mConfig->readNumEntry( "Print type", (int)Filofax ) );
00874   }
00875   setSettingsWidget();
00876 }
00877 
00878 void CalPrintWeek::saveConfig()
00879 {
00880   readSettingsWidget();
00881   if ( mConfig ) {
00882     mConfig->writeEntry( "Start time", TQDateTime( TQDate(), mStartTime ) );
00883     mConfig->writeEntry( "End time", TQDateTime( TQDate(), mEndTime ) );
00884     mConfig->writeEntry( "Include todos", mIncludeTodos );
00885     mConfig->writeEntry( "Print type", int( mWeekPrintType ) );
00886   }
00887 }
00888 
00889 KPrinter::Orientation CalPrintWeek::defaultOrientation()
00890 {
00891   if ( mWeekPrintType == Filofax ) return KPrinter::Portrait;
00892   else if ( mWeekPrintType == SplitWeek ) return KPrinter::Portrait;
00893   else return KPrinter::Landscape;
00894 }
00895 
00896 void CalPrintWeek::setDateRange( const TQDate &from, const TQDate &to )
00897 {
00898   CalPrintPluginBase::setDateRange( from, to );
00899   CalPrintWeekConfig_Base *cfg =
00900       dynamic_cast<CalPrintWeekConfig_Base*>( mConfigWidget );
00901   if ( cfg ) {
00902     cfg->mFromDate->setDate( from );
00903     cfg->mToDate->setDate( to );
00904   }
00905 }
00906 
00907 void CalPrintWeek::print( TQPainter &p, int width, int height )
00908 {
00909   TQDate curWeek, fromWeek, toWeek;
00910 
00911   // correct begin and end to first and last day of week
00912   int weekdayCol = weekdayColumn( mFromDate.dayOfWeek() );
00913   fromWeek = mFromDate.addDays( -weekdayCol );
00914   weekdayCol = weekdayColumn( mFromDate.dayOfWeek() );
00915   toWeek = mToDate.addDays( 6 - weekdayCol );
00916 
00917   curWeek = fromWeek.addDays( 6 );
00918   TDELocale *local = TDEGlobal::locale();
00919 
00920   TQString line1, line2, title;
00921   TQRect headerBox( 0, 0, width, headerHeight() );
00922   TQRect footerBox( 0, height - footerHeight(), width, footerHeight() );
00923   height -= footerHeight();
00924 
00925   TQRect weekBox( headerBox );
00926   weekBox.setTop( headerBox.bottom() + padding() );
00927   weekBox.setBottom( height );
00928 
00929   switch ( mWeekPrintType ) {
00930     case Filofax:
00931       do {
00932         line1 = local->formatDate( curWeek.addDays( -6 ) );
00933         line2 = local->formatDate( curWeek );
00934         if ( orientation() == KPrinter::Landscape ) {
00935           title = i18n("date from-to", "%1 - %2");
00936         } else {
00937           title = i18n("date from-\nto", "%1 -\n%2");;
00938         }
00939         title = title.arg( line1 ).arg( line2 );
00940         drawHeader( p, title, curWeek.addDays( -6 ), TQDate(), headerBox );
00941 
00942         drawWeek( p, curWeek, weekBox );
00943 
00944         drawFooter( p, footerBox );
00945 
00946         curWeek = curWeek.addDays( 7 );
00947         if ( curWeek <= toWeek )
00948           mPrinter->newPage();
00949       } while ( curWeek <= toWeek );
00950       break;
00951 
00952     case Timetable:
00953     default:
00954       do {
00955         line1 = local->formatDate( curWeek.addDays( -6 ) );
00956         line2 = local->formatDate( curWeek );
00957         if ( orientation() == KPrinter::Landscape ) {
00958           title = i18n("date from - to (week number)", "%1 - %2 (Week %3)");
00959         } else {
00960           title = i18n("date from -\nto (week number)", "%1 -\n%2 (Week %3)");
00961         }
00962         title = title.arg( line1 ).arg( line2 ).arg( curWeek.weekNumber() );
00963         drawHeader( p, title, curWeek, TQDate(), headerBox );
00964 
00965         TQRect weekBox( headerBox );
00966         weekBox.setTop( headerBox.bottom() + padding() );
00967         weekBox.setBottom( height );
00968         drawTimeTable( p, fromWeek, curWeek, mStartTime, mEndTime, weekBox );
00969 
00970         drawFooter( p, footerBox );
00971 
00972         fromWeek = fromWeek.addDays( 7 );
00973         curWeek = fromWeek.addDays( 6 );
00974         if ( curWeek <= toWeek )
00975           mPrinter->newPage();
00976       } while ( curWeek <= toWeek );
00977       break;
00978 
00979     case SplitWeek: {
00980       TQRect weekBox1( weekBox );
00981       // On the left side there are four days (mo-th) plus the timeline,
00982       // on the right there are only three days (fr-su) plus the timeline. Don't
00983       // use the whole width, but rather give them the same width as on the left.
00984       weekBox1.setRight( int( ( width - TIMELINE_WIDTH ) * 3. / 4. + TIMELINE_WIDTH ) );
00985       do {
00986         TQDate endLeft( fromWeek.addDays( 3 ) );
00987         int hh = headerHeight();
00988 
00989         drawTimeTable( p, fromWeek, endLeft,
00990                        mStartTime, mEndTime, weekBox );
00991         mPrinter->newPage();
00992         drawSplitHeaderRight( p, fromWeek, curWeek, TQDate(), width, hh );
00993         drawTimeTable( p, endLeft.addDays( 1 ), curWeek,
00994                        mStartTime, mEndTime, weekBox1 );
00995 
00996         drawFooter( p, footerBox );
00997 
00998         fromWeek = fromWeek.addDays( 7 );
00999         curWeek = fromWeek.addDays( 6 );
01000         if ( curWeek <= toWeek )
01001           mPrinter->newPage();
01002       } while ( curWeek <= toWeek );
01003       }
01004       break;
01005   }
01006 }
01007 
01008 
01009 
01010 
01011 /**************************************************************
01012  *           Print Month
01013  **************************************************************/
01014 
01015 CalPrintMonth::CalPrintMonth() : CalPrintPluginBase()
01016 {
01017 }
01018 
01019 CalPrintMonth::~CalPrintMonth()
01020 {
01021 }
01022 
01023 TQWidget *CalPrintMonth::createConfigWidget( TQWidget *w )
01024 {
01025   return new CalPrintMonthConfig_Base( w );
01026 }
01027 
01028 void CalPrintMonth::readSettingsWidget()
01029 {
01030   CalPrintMonthConfig_Base *cfg =
01031       dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget );
01032   if ( cfg ) {
01033     mFromDate = TQDate( cfg->mFromYear->value(), cfg->mFromMonth->currentItem()+1, 1 );
01034     mToDate = TQDate( cfg->mToYear->value(), cfg->mToMonth->currentItem()+1, 1 );
01035 
01036     mWeekNumbers =  cfg->mWeekNumbers->isChecked();
01037     mRecurDaily = cfg->mRecurDaily->isChecked();
01038     mRecurWeekly = cfg->mRecurWeekly->isChecked();
01039     mIncludeTodos = cfg->mIncludeTodos->isChecked();
01040 //    mUseColors = cfg->mColors->isChecked();
01041   }
01042 }
01043 
01044 void CalPrintMonth::setSettingsWidget()
01045 {
01046   CalPrintMonthConfig_Base *cfg =
01047       dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget );
01048   setDateRange( mFromDate, mToDate );
01049   if ( cfg ) {
01050     cfg->mWeekNumbers->setChecked( mWeekNumbers );
01051     cfg->mRecurDaily->setChecked( mRecurDaily );
01052     cfg->mRecurWeekly->setChecked( mRecurWeekly );
01053     cfg->mIncludeTodos->setChecked( mIncludeTodos );
01054 //    cfg->mColors->setChecked( mUseColors );
01055   }
01056 }
01057 
01058 void CalPrintMonth::loadConfig()
01059 {
01060   if ( mConfig ) {
01061     mWeekNumbers = mConfig->readBoolEntry( "Print week numbers", true );
01062     mRecurDaily = mConfig->readBoolEntry( "Print daily incidences", true );
01063     mRecurWeekly = mConfig->readBoolEntry( "Print weekly incidences", true );
01064     mIncludeTodos = mConfig->readBoolEntry( "Include todos", false );
01065   }
01066   setSettingsWidget();
01067 }
01068 
01069 void CalPrintMonth::saveConfig()
01070 {
01071   readSettingsWidget();
01072   if ( mConfig ) {
01073     mConfig->writeEntry( "Print week numbers", mWeekNumbers );
01074     mConfig->writeEntry( "Print daily incidences", mRecurDaily );
01075     mConfig->writeEntry( "Print weekly incidences", mRecurWeekly );
01076     mConfig->writeEntry( "Include todos", mIncludeTodos );
01077   }
01078 }
01079 
01080 void CalPrintMonth::setDateRange( const TQDate &from, const TQDate &to )
01081 {
01082   CalPrintPluginBase::setDateRange( from, to );
01083   CalPrintMonthConfig_Base *cfg =
01084       dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget );
01085   const KCalendarSystem *calSys = calendarSystem();
01086   if ( cfg && calSys ) {
01087     cfg->mFromMonth->clear();
01088     for ( int i=0; i<calSys->monthsInYear( mFromDate ); ++i ) {
01089       cfg->mFromMonth->insertItem( calSys->monthName( i+1, mFromDate.year() ) );
01090     }
01091     cfg->mToMonth->clear();
01092     for ( int i=0; i<calSys->monthsInYear( mToDate ); ++i ) {
01093       cfg->mToMonth->insertItem( calSys->monthName( i+1, mToDate.year() ) );
01094     }
01095   }
01096   if ( cfg ) {
01097     cfg->mFromMonth->setCurrentItem( from.month()-1 );
01098     cfg->mFromYear->setValue( to.year() );
01099     cfg->mToMonth->setCurrentItem( mToDate.month()-1 );
01100     cfg->mToYear->setValue( mToDate.year() );
01101   }
01102 }
01103 
01104 void CalPrintMonth::print( TQPainter &p, int width, int height )
01105 {
01106   TQDate curMonth, fromMonth, toMonth;
01107 
01108   fromMonth = mFromDate.addDays( -( mFromDate.day() - 1 ) );
01109   toMonth = mToDate.addDays( mToDate.daysInMonth() - mToDate.day() );
01110 
01111   curMonth = fromMonth;
01112   const KCalendarSystem *calSys = calendarSystem();
01113   if ( !calSys ) return;
01114 
01115   TQRect headerBox( 0, 0, width, headerHeight() );
01116   TQRect footerBox( 0, height - footerHeight(), width, footerHeight() );
01117   height -= footerHeight();
01118 
01119   TQRect monthBox( 0, 0, width, height );
01120   monthBox.setTop( headerBox.bottom() + padding() );
01121 
01122   do {
01123     TQString title( i18n("monthname year", "%1 %2") );
01124     title = title.arg( calSys->monthName( curMonth ) )
01125                  .arg( curMonth.year() );
01126     TQDate tmp( fromMonth );
01127     int weekdayCol = weekdayColumn( tmp.dayOfWeek() );
01128     tmp = tmp.addDays( -weekdayCol );
01129 
01130     drawHeader( p, title, curMonth.addMonths( -1 ), curMonth.addMonths( 1 ),
01131                 headerBox );
01132     drawMonthTable( p, curMonth, mWeekNumbers, mRecurDaily, mRecurWeekly, monthBox );
01133 
01134     drawFooter( p, footerBox );
01135 
01136     curMonth = curMonth.addDays( curMonth.daysInMonth() );
01137     if ( curMonth <= toMonth ) mPrinter->newPage();
01138   } while ( curMonth <= toMonth );
01139 
01140 }
01141 
01142 
01143 
01144 
01145 /**************************************************************
01146  *           Print Todos
01147  **************************************************************/
01148 
01149 CalPrintTodos::CalPrintTodos() : CalPrintPluginBase()
01150 {
01151   mTodoSortField = TodoFieldUnset;
01152   mTodoSortDirection = TodoDirectionUnset;
01153 }
01154 
01155 CalPrintTodos::~CalPrintTodos()
01156 {
01157 }
01158 
01159 TQWidget *CalPrintTodos::createConfigWidget( TQWidget *w )
01160 {
01161   return new CalPrintTodoConfig_Base( w );
01162 }
01163 
01164 void CalPrintTodos::readSettingsWidget()
01165 {
01166   CalPrintTodoConfig_Base *cfg =
01167       dynamic_cast<CalPrintTodoConfig_Base *>( mConfigWidget );
01168   if ( cfg ) {
01169     mPageTitle = cfg->mTitle->text();
01170 
01171     mTodoPrintType = (eTodoPrintType)( cfg->mPrintType->id(
01172       cfg->mPrintType->selected() ) );
01173 
01174     mFromDate = cfg->mFromDate->date();
01175     mToDate = cfg->mToDate->date();
01176 
01177     mIncludeDescription = cfg->mDescription->isChecked();
01178     mIncludePriority = cfg->mPriority->isChecked();
01179     mIncludeDueDate = cfg->mDueDate->isChecked();
01180     mIncludePercentComplete = cfg->mPercentComplete->isChecked();
01181     mConnectSubTodos = cfg->mConnectSubTodos->isChecked();
01182     mStrikeOutCompleted = cfg->mStrikeOutCompleted->isChecked();
01183 
01184     mTodoSortField = (eTodoSortField)cfg->mSortField->currentItem();
01185     mTodoSortDirection = (eTodoSortDirection)cfg->mSortDirection->currentItem();
01186   }
01187 }
01188 
01189 void CalPrintTodos::setSettingsWidget()
01190 {
01191 //   kdDebug(5850) << "CalPrintTodos::setSettingsWidget" << endl;
01192 
01193   CalPrintTodoConfig_Base *cfg =
01194       dynamic_cast<CalPrintTodoConfig_Base *>( mConfigWidget );
01195   if ( cfg ) {
01196     cfg->mTitle->setText( mPageTitle );
01197 
01198     cfg->mPrintType->setButton( mTodoPrintType );
01199 
01200     cfg->mFromDate->setDate( mFromDate );
01201     cfg->mToDate->setDate( mToDate );
01202 
01203     cfg->mDescription->setChecked( mIncludeDescription );
01204     cfg->mPriority->setChecked( mIncludePriority );
01205     cfg->mDueDate->setChecked( mIncludeDueDate );
01206     cfg->mPercentComplete->setChecked( mIncludePercentComplete );
01207     cfg->mConnectSubTodos->setChecked( mConnectSubTodos );
01208     cfg->mStrikeOutCompleted->setChecked( mStrikeOutCompleted );
01209 
01210     if ( mTodoSortField != TodoFieldUnset ) {
01211       // do not insert if already done so.
01212       cfg->mSortField->insertItem( i18n("Summary") );
01213       cfg->mSortField->insertItem( i18n("Start Date") );
01214       cfg->mSortField->insertItem( i18n("Due Date") );
01215       cfg->mSortField->insertItem( i18n("Priority") );
01216       cfg->mSortField->insertItem( i18n("Percent Complete") );
01217       cfg->mSortField->setCurrentItem( (int)mTodoSortField );
01218     }
01219 
01220     if ( mTodoSortDirection != TodoDirectionUnset ) {
01221       // do not insert if already done so.
01222       cfg->mSortDirection->insertItem( i18n("Ascending") );
01223       cfg->mSortDirection->insertItem( i18n("Descending") );
01224       cfg->mSortDirection->setCurrentItem( (int)mTodoSortDirection );
01225     }
01226   }
01227 }
01228 
01229 void CalPrintTodos::loadConfig()
01230 {
01231   if ( mConfig ) {
01232     mPageTitle = mConfig->readEntry( "Page title", i18n("To-do list") );
01233     mTodoPrintType = (eTodoPrintType)mConfig->readNumEntry( "Print type", (int)TodosAll );
01234     mIncludeDescription = mConfig->readBoolEntry( "Include description", true );
01235     mIncludePriority = mConfig->readBoolEntry( "Include priority", true );
01236     mIncludeDueDate = mConfig->readBoolEntry( "Include due date", true );
01237     mIncludePercentComplete = mConfig->readBoolEntry( "Include percentage completed", true );
01238     mConnectSubTodos = mConfig->readBoolEntry( "Connect subtodos", true );
01239     mStrikeOutCompleted = mConfig->readBoolEntry( "Strike out completed summaries",  true );
01240     mTodoSortField = (eTodoSortField)mConfig->readNumEntry( "Sort field", (int)TodoFieldSummary );
01241     mTodoSortDirection = (eTodoSortDirection)mConfig->readNumEntry( "Sort direction", (int)TodoDirectionAscending );
01242   }
01243   setSettingsWidget();
01244 }
01245 
01246 void CalPrintTodos::saveConfig()
01247 {
01248   readSettingsWidget();
01249   if ( mConfig ) {
01250     mConfig->writeEntry( "Page title", mPageTitle );
01251     mConfig->writeEntry( "Print type", int( mTodoPrintType ) );
01252     mConfig->writeEntry( "Include description", mIncludeDescription );
01253     mConfig->writeEntry( "Include priority", mIncludePriority );
01254     mConfig->writeEntry( "Include due date", mIncludeDueDate );
01255     mConfig->writeEntry( "Include percentage completed", mIncludePercentComplete );
01256     mConfig->writeEntry( "Connect subtodos", mConnectSubTodos );
01257     mConfig->writeEntry( "Strike out completed summaries", mStrikeOutCompleted );
01258     mConfig->writeEntry( "Sort field", mTodoSortField );
01259     mConfig->writeEntry( "Sort direction", mTodoSortDirection );
01260   }
01261 }
01262 
01263 void CalPrintTodos::print( TQPainter &p, int width, int height )
01264 {
01265   // TODO: Find a good way to guarantee a nicely designed output
01266   int pospriority = 0;
01267   int possummary = 100;
01268   int posdue = width - 65;
01269   int poscomplete = posdue - 70; //Complete column is to right of the Due column
01270   int lineSpacing = 15;
01271   int fontHeight = 10;
01272 
01273   TQRect headerBox( 0, 0, width, headerHeight() );
01274   TQRect footerBox( 0, height - footerHeight(), width, footerHeight() );
01275   height -= footerHeight();
01276 
01277   // Draw the First Page Header
01278   drawHeader( p, mPageTitle, mFromDate, TQDate(), headerBox );
01279 
01280   // Draw the Column Headers
01281   int mCurrentLinePos = headerHeight() + 5;
01282   TQString outStr;
01283   TQFont oldFont( p.font() );
01284 
01285   p.setFont( TQFont( "sans-serif", 9, TQFont::Bold ) );
01286   lineSpacing = p.fontMetrics().lineSpacing();
01287   mCurrentLinePos += lineSpacing;
01288   if ( mIncludePriority ) {
01289     outStr += i18n( "Priority" );
01290     p.drawText( pospriority, mCurrentLinePos - 2, outStr );
01291   } else {
01292     pospriority = -1;
01293   }
01294 
01295   outStr.truncate( 0 );
01296   outStr += i18n( "Summary" );
01297   p.drawText( possummary, mCurrentLinePos - 2, outStr );
01298 
01299   if ( mIncludePercentComplete ) {
01300     if ( !mIncludeDueDate ) //move Complete column to the right
01301       poscomplete = posdue; //if not print the Due Date column
01302     outStr.truncate( 0 );
01303     outStr += i18n( "Complete" );
01304     p.drawText( poscomplete, mCurrentLinePos - 2, outStr );
01305   } else {
01306     poscomplete = -1;
01307   }
01308 
01309   if ( mIncludeDueDate ) {
01310     outStr.truncate( 0 );
01311     outStr += i18n( "Due" );
01312     p.drawText( posdue, mCurrentLinePos - 2, outStr );
01313   } else {
01314     posdue = -1;
01315   }
01316 
01317   p.setFont( TQFont( "sans-serif", 10 ) );
01318   fontHeight = p.fontMetrics().height();
01319 
01320   Todo::List todoList;
01321   Todo::List tempList;
01322   Todo::List::ConstIterator it;
01323 
01324   // Convert sort options to the corresponding enums
01325   TodoSortField sortField = TodoSortSummary;
01326   switch( mTodoSortField ) {
01327   case TodoFieldSummary:
01328     sortField = TodoSortSummary; break;
01329   case TodoFieldStartDate:
01330     sortField = TodoSortStartDate; break;
01331   case TodoFieldDueDate:
01332     sortField = TodoSortDueDate; break;
01333   case TodoFieldPriority:
01334     sortField = TodoSortPriority; break;
01335   case TodoFieldPercentComplete:
01336     sortField = TodoSortPercentComplete; break;
01337   case TodoFieldUnset:
01338     break;
01339   }
01340 
01341   SortDirection sortDirection;
01342   switch( mTodoSortDirection ) {
01343   case TodoDirectionAscending:
01344     sortDirection = SortDirectionAscending; break;
01345   case TodoDirectionDescending:
01346     sortDirection = SortDirectionDescending; break;
01347   case TodoDirectionUnset:
01348     break;
01349   }
01350 
01351   // Create list of to-dos which will be printed
01352   todoList = mCalendar->todos( sortField,  sortDirection );
01353   switch( mTodoPrintType ) {
01354   case TodosAll:
01355     break;
01356   case TodosUnfinished:
01357     for( it = todoList.begin(); it!= todoList.end(); ++it ) {
01358       if ( !(*it)->isCompleted() )
01359         tempList.append( *it );
01360     }
01361     todoList = tempList;
01362     break;
01363   case TodosDueRange:
01364     for( it = todoList.begin(); it!= todoList.end(); ++it ) {
01365       if ( (*it)->hasDueDate() ) {
01366         if ( (*it)->dtDue().date() >= mFromDate &&
01367              (*it)->dtDue().date() <= mToDate )
01368           tempList.append( *it );
01369       } else {
01370         tempList.append( *it );
01371       }
01372     }
01373     todoList = tempList;
01374     break;
01375   }
01376 
01377   // Print to-dos
01378   int count = 0;
01379   for ( it=todoList.begin(); it!=todoList.end(); ++it ) {
01380     Todo *currEvent = *it;
01381 
01382     // Skip sub-to-dos. They will be printed recursively in drawTodo()
01383     if ( !currEvent->relatedTo() ) {
01384       count++;
01385       drawTodo( count, currEvent, p,
01386                          sortField, sortDirection,
01387                          mConnectSubTodos,
01388                          mStrikeOutCompleted, mIncludeDescription,
01389                          pospriority, possummary, posdue, poscomplete,
01390                          0, 0, mCurrentLinePos, width, height, todoList );
01391     }
01392   }
01393 
01394   drawFooter( p, footerBox );
01395   p.setFont( oldFont );
01396 }
01397 
01398 #endif