korganizer

kodaymatrix.cpp
00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 2001 Eitzenberger Thomas <thomas.eitzenberger@siemens.at>
00005     Parts of the source code have been copied from kdpdatebutton.cpp
00006 
00007     Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
00008     Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00018     GNU General Public License for more details.
00019 
00020     You should have received a copy of the GNU General Public License
00021     along with this program; if not, write to the Free Software
00022     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00023 
00024     As a special exception, permission is given to link this program
00025     with any edition of TQt, and distribute the resulting executable,
00026     without including the source code for TQt in the source distribution.
00027 */
00028 
00029 #include <tqevent.h>
00030 #include <tqpainter.h>
00031 #include <tqptrlist.h>
00032 
00033 #include <tdeglobal.h>
00034 #include <kdebug.h>
00035 #include <tdelocale.h>
00036 #include <kiconloader.h>
00037 
00038 #include <libkcal/vcaldrag.h>
00039 #include <libkcal/icaldrag.h>
00040 #include <libkcal/dndfactory.h>
00041 #include <libkcal/calendarresources.h>
00042 #include <libkcal/resourcecalendar.h>
00043 
00044 #include <kcalendarsystem.h>
00045 
00046 #include "koprefs.h"
00047 #include "koglobals.h"
00048 #include "kodialogmanager.h"
00049 
00050 #include "kodaymatrix.h"
00051 #include "kodaymatrix.moc"
00052 
00053 #ifndef NODND
00054 #include <tqcursor.h>
00055 #include <tdepopupmenu.h>
00056 #include <X11/Xlib.h>
00057 #undef FocusIn
00058 #undef KeyPress
00059 #undef None
00060 #undef Status
00061 #endif
00062 
00063 // ============================================================================
00064 //  D Y N A M I C   T I P
00065 // ============================================================================
00066 
00067 DynamicTip::DynamicTip( TQWidget * parent )
00068     : TQToolTip( parent )
00069 {
00070   mMatrix = static_cast<KODayMatrix *>( parent );
00071 }
00072 
00073 
00074 void DynamicTip::maybeTip( const TQPoint &pos )
00075 {
00076   //calculate which cell of the matrix the mouse is in
00077   TQRect sz = mMatrix->frameRect();
00078   int dheight = sz.height() * 7 / 42;
00079   int dwidth = sz.width() / 7;
00080   int row = pos.y() / dheight;
00081   int col = pos.x() / dwidth;
00082 
00083   TQRect rct( col * dwidth, row * dheight, dwidth, dheight );
00084 
00085 //  kdDebug(5850) << "DynamicTip::maybeTip matrix cell index [" <<
00086 //                col << "][" << row << "] => " <<(col+row*7) << endl;
00087 
00088   //show holiday names only
00089   TQString str = mMatrix->getHolidayLabel( col + row * 7 );
00090   if ( str.isEmpty() ) return;
00091   tip( rct, str );
00092 }
00093 
00094 
00095 // ============================================================================
00096 //  K O D A Y M A T R I X
00097 // ============================================================================
00098 
00099 const int KODayMatrix::NOSELECTION = -1000;
00100 const int KODayMatrix::NUMDAYS = 42;
00101 
00102 KODayMatrix::KODayMatrix( TQWidget *parent, const char *name )
00103   : TQFrame( parent, name ), mCalendar( 0 ), mStartDate(), mPendingChanges( false )
00104 {
00105   // initialize dynamic arrays
00106   mDays = new TQDate[ NUMDAYS ];
00107   mDayLabels = new TQString[ NUMDAYS ];
00108   mEvents = new int[ NUMDAYS ];
00109   mToolTip = new DynamicTip( this );
00110 
00111   mTodayMarginWidth = 2;
00112   mSelEnd = mSelStart = NOSELECTION;
00113   setBackgroundMode( NoBackground );
00114   recalculateToday();
00115 }
00116 
00117 void KODayMatrix::setCalendar( Calendar *cal )
00118 {
00119   if ( mCalendar ) {
00120     mCalendar->unregisterObserver( this );
00121     mCalendar->disconnect( this );
00122   }
00123 
00124   mCalendar = cal;
00125   mCalendar->registerObserver( this );
00126   CalendarResources *calres = dynamic_cast<CalendarResources*>( cal );
00127   if ( calres ) {
00128     connect( calres, TQT_SIGNAL(signalResourceAdded(ResourceCalendar *)), TQT_SLOT(resourcesChanged()) );
00129     connect( calres, TQT_SIGNAL(signalResourceModified( ResourceCalendar *)), TQT_SLOT(resourcesChanged()) );
00130     connect( calres, TQT_SIGNAL(signalResourceDeleted(ResourceCalendar *)), TQT_SLOT(resourcesChanged()) );
00131   }
00132 
00133   setAcceptDrops( mCalendar );
00134 
00135   updateEvents();
00136 }
00137 
00138 TQColor KODayMatrix::getShadedColor( const TQColor &color )
00139 {
00140   TQColor shaded;
00141   int h = 0;
00142   int s = 0;
00143   int v = 0;
00144   color.hsv( &h, &s, &v );
00145   s = s / 4;
00146   v = 192 + v / 4;
00147   shaded.setHsv( h, s, v );
00148 
00149   return shaded;
00150 }
00151 
00152 KODayMatrix::~KODayMatrix()
00153 {
00154   if ( mCalendar )
00155     mCalendar->unregisterObserver( this );
00156   delete [] mDays;
00157   delete [] mDayLabels;
00158   delete [] mEvents;
00159   delete mToolTip;
00160 }
00161 
00162 void KODayMatrix::addSelectedDaysTo( DateList &selDays )
00163 {
00164   kdDebug(5850) << "KODayMatrix::addSelectedDaysTo() - " << "mSelStart:" << mSelStart << endl;
00165 
00166   if ( mSelStart == NOSELECTION ) {
00167     return;
00168   }
00169 
00170   // cope with selection being out of matrix limits at top (< 0)
00171   int i0 = mSelStart;
00172   if ( i0 < 0 ) {
00173     for ( int i = i0; i < 0; i++ ) {
00174       selDays.append( mDays[ 0 ].addDays( i ) );
00175     }
00176     i0 = 0;
00177   }
00178 
00179   // cope with selection being out of matrix limits at bottom (> NUMDAYS-1)
00180   if ( mSelEnd > NUMDAYS-1 ) {
00181     for ( int i = i0; i <= NUMDAYS - 1; i++ ) {
00182       selDays.append( mDays[ i ] );
00183     }
00184     for ( int i = NUMDAYS; i < mSelEnd; i++ ) {
00185       selDays.append( mDays[ 0 ].addDays( i ) );
00186     }
00187   } else {
00188     // apply normal routine to selection being entirely within matrix limits
00189     for ( int i = i0; i <= mSelEnd; i++ ) {
00190       selDays.append( mDays[ i ] );
00191     }
00192   }
00193 }
00194 
00195 void KODayMatrix::setSelectedDaysFrom( const TQDate &start, const TQDate &end )
00196 {
00197   if ( mStartDate.isValid() ) {
00198     mSelStart = mStartDate.daysTo( start );
00199     mSelEnd = mStartDate.daysTo( end );
00200   }
00201 }
00202 
00203 void KODayMatrix::clearSelection()
00204 {
00205   mSelEnd = mSelStart = NOSELECTION;
00206 }
00207 
00208 void KODayMatrix::recalculateToday()
00209 {
00210   if ( !mStartDate.isValid() ) return;
00211   mToday = -1;
00212   for ( int i = 0; i < NUMDAYS; i++ ) {
00213     mDays[ i ] = mStartDate.addDays( i );
00214     mDayLabels[ i ] = TQString::number( KOGlobals::self()->calendarSystem()->day( mDays[i] ));
00215 
00216     // if today is in the currently displayed month, hilight today
00217     if ( mDays[ i ].year() == TQDate::currentDate().year() &&
00218          mDays[ i ].month() == TQDate::currentDate().month() &&
00219          mDays[ i ].day() == TQDate::currentDate().day() ) {
00220       mToday = i;
00221     }
00222   }
00223   // kdDegug(5850) << "Today is visible at "<< today << "." << endl;
00224 }
00225 
00226 /* slot */ void KODayMatrix::updateView()
00227 {
00228   updateView( mStartDate );
00229 }
00230 
00231 void KODayMatrix::setUpdateNeeded()
00232 {
00233   mPendingChanges = true;
00234 }
00235 
00236 void KODayMatrix::updateView( const TQDate &actdate )
00237 {
00238  kdDebug(5850) << "KODayMatrix::updateView() " << actdate << ", day start="<<mStartDate<< endl;
00239  if ( !actdate.isValid() ) return;
00240   //flag to indicate if the starting day of the matrix has changed by this call
00241   bool daychanged = false;
00242 
00243   // if a new startdate is to be set then apply Cornelius's calculation
00244   // of the first day to be shown
00245   if ( actdate != mStartDate ) {
00246     // reset index of selection according to shift of starting date from startdate to actdate
00247     if ( mSelStart != NOSELECTION ) {
00248       int tmp = actdate.daysTo( mStartDate );
00249       //kdDebug(5850) << "Shift of Selection1: " << mSelStart << " - " << mSelEnd << " -> " << tmp << "(" << offset << ")" << endl;
00250       // shift selection if new one would be visible at least partly !
00251 
00252       if ( mSelStart + tmp < NUMDAYS && mSelEnd + tmp >= 0 ) {
00253         // nested if is required for next X display pushed from a different month - correction required
00254         // otherwise, for month forward and backward, it must be avoided
00255         if( mSelStart > NUMDAYS || mSelStart < 0 )
00256           mSelStart = mSelStart + tmp;
00257         if( mSelEnd > NUMDAYS || mSelEnd < 0 )
00258           mSelEnd = mSelEnd + tmp;
00259       }
00260     }
00261 
00262     mStartDate = actdate;
00263     daychanged = true;
00264   }
00265 
00266   if ( daychanged ) {
00267     recalculateToday();
00268   }
00269 
00270   // the calendar hasn't changed in the meantime and the selected range is still the same
00271   // so we can safe the expensive updateEvents() call
00272   if ( !daychanged && !mPendingChanges )
00273     return;
00274 
00275   // TODO_Recurrence: If we just change the selection, but not the data, there's
00276   // no need to update the whole list of events... This is just a waste of
00277   // computational power (and it takes forever!)
00278   updateEvents();
00279   for( int i = 0; i < NUMDAYS; i++ ) {
00280     //if it is a holy day then draw it red. Sundays are consider holidays, too
00281     TQStringList holidays = KOGlobals::self()->holiday( mDays[ i ] );
00282     TQString holiStr = TQString();
00283 
00284     if ( ( KOGlobals::self()->calendarSystem()->dayOfWeek( mDays[ i ] ) ==
00285            KOGlobals::self()->calendarSystem()->weekDayOfPray() ) ||
00286          !holidays.isEmpty() ) {
00287       if ( !holidays.isEmpty() ) holiStr = holidays.join( i18n("delimiter for joining holiday names", ", " ) );
00288       if ( holiStr.isNull() ) holiStr = "";
00289     }
00290     mHolidays[ i ] = holiStr;
00291   }
00292 }
00293 
00294 void KODayMatrix::updateEvents()
00295 {
00296   kdDebug( 5850 ) << k_funcinfo << endl;
00297   if ( !mCalendar ) return;
00298 
00299   for( int i = 0; i < NUMDAYS; i++ ) {
00300     // if events are set for the day then remember to draw it bold
00301     Event::List eventlist = mCalendar->events( mDays[ i ] );
00302     int numEvents = eventlist.count();
00303     Event::List::ConstIterator it;
00304     for( it = eventlist.begin(); it != eventlist.end(); ++it ) {
00305       Event *event = *it;
00306       ushort recurType = event->recurrenceType();
00307       if ( ( recurType == Recurrence::rDaily &&
00308              !KOPrefs::instance()->mDailyRecur ) ||
00309            ( recurType == Recurrence::rWeekly &&
00310              !KOPrefs::instance()->mWeeklyRecur ) ) {
00311         numEvents--;
00312       }
00313     }
00314     mEvents[ i ] = numEvents;
00315   }
00316 
00317   mPendingChanges = false;
00318 }
00319 
00320 const TQDate& KODayMatrix::getDate( int offset )
00321 {
00322   if ( offset < 0 || offset > NUMDAYS - 1 ) {
00323     kdDebug(5850) << "Wrong offset (" << offset << ") in KODayMatrix::getDate(int)" << endl;
00324     return mDays[ 0 ];
00325   }
00326   return mDays[ offset ];
00327 }
00328 
00329 TQString KODayMatrix::getHolidayLabel( int offset )
00330 {
00331   if ( offset < 0 || offset > NUMDAYS - 1 ) {
00332     kdDebug(5850) << "Wrong offset (" << offset << ") in KODayMatrix::getHolidayLabel(int)" << endl;
00333     return 0;
00334   }
00335   return mHolidays[ offset ];
00336 }
00337 
00338 int KODayMatrix::getDayIndexFrom( int x, int y )
00339 {
00340   return 7 * ( y / mDaySize.height() ) +
00341          ( KOGlobals::self()->reverseLayout() ?
00342            6 - x / mDaySize.width() : x / mDaySize.width() );
00343 }
00344 
00345 void KODayMatrix::calendarIncidenceAdded(Incidence * incidence)
00346 {
00347   Q_UNUSED( incidence );
00348   mPendingChanges = true;
00349 }
00350 
00351 void KODayMatrix::calendarIncidenceChanged(Incidence * incidence)
00352 {
00353   Q_UNUSED( incidence );
00354   mPendingChanges = true;
00355 }
00356 
00357 void KODayMatrix::calendarIncidenceDeleted(Incidence * incidence)
00358 {
00359   Q_UNUSED( incidence );
00360   mPendingChanges = true;
00361 }
00362 
00363 void KODayMatrix::resourcesChanged()
00364 {
00365   mPendingChanges = true;
00366 }
00367 
00368 
00369 // ----------------------------------------------------------------------------
00370 //  M O U S E   E V E N T   H A N D L I N G
00371 // ----------------------------------------------------------------------------
00372 
00373 void KODayMatrix::mousePressEvent( TQMouseEvent *e )
00374 {
00375   mSelStart = getDayIndexFrom(e->x(), e->y());
00376   if (mSelStart > NUMDAYS-1) mSelStart=NUMDAYS-1;
00377   mSelInit = mSelStart;
00378 }
00379 
00380 void KODayMatrix::mouseReleaseEvent( TQMouseEvent *e )
00381 {
00382   int tmp = getDayIndexFrom(e->x(), e->y());
00383   if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
00384 
00385   if (mSelInit > tmp) {
00386     mSelEnd = mSelInit;
00387     if (tmp != mSelStart) {
00388       mSelStart = tmp;
00389       repaint();
00390     }
00391   } else {
00392     mSelStart = mSelInit;
00393 
00394     //repaint only if selection has changed
00395     if (tmp != mSelEnd) {
00396       mSelEnd = tmp;
00397       repaint();
00398     }
00399   }
00400 
00401   DateList daylist;
00402   if ( mSelStart < 0 ) mSelStart = 0;
00403   for ( int i = mSelStart; i <= mSelEnd; ++i ) {
00404     daylist.append( mDays[i] );
00405   }
00406   emit selected((const DateList)daylist);
00407 }
00408 
00409 void KODayMatrix::mouseMoveEvent( TQMouseEvent *e )
00410 {
00411   int tmp = getDayIndexFrom(e->x(), e->y());
00412   if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
00413 
00414   if (mSelInit > tmp) {
00415     mSelEnd = mSelInit;
00416     if ( tmp != mSelStart ) {
00417       mSelStart = tmp;
00418       repaint();
00419     }
00420   } else {
00421     mSelStart = mSelInit;
00422 
00423     //repaint only if selection has changed
00424     if ( tmp != mSelEnd ) {
00425       mSelEnd = tmp;
00426       repaint();
00427     }
00428   }
00429 }
00430 
00431 // ----------------------------------------------------------------------------
00432 //  D R A G ' N   D R O P   H A N D L I N G
00433 // ----------------------------------------------------------------------------
00434 
00435 //-----------------------------------------------------------------------------
00436 // Drag and Drop handling -- based on the Troll Tech dirview example
00437 
00438 enum {
00439   DRAG_COPY = 0,
00440   DRAG_MOVE = 1,
00441   DRAG_CANCEL = 2
00442 };
00443 
00444 void KODayMatrix::dragEnterEvent( TQDragEnterEvent *e )
00445 {
00446 #ifndef KORG_NODND
00447   if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
00448     e->ignore();
00449     return;
00450   }
00451 
00452   // some visual feedback
00453 //  oldPalette = palette();
00454 //  setPalette(my_HilitePalette);
00455 //  update();
00456 #endif
00457 }
00458 
00459 void KODayMatrix::dragMoveEvent( TQDragMoveEvent *e )
00460 {
00461 #ifndef KORG_NODND
00462   if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
00463     e->ignore();
00464     return;
00465   }
00466 
00467   e->accept();
00468 #endif
00469 }
00470 
00471 void KODayMatrix::dragLeaveEvent( TQDragLeaveEvent * /*dl*/ )
00472 {
00473 #ifndef KORG_NODND
00474 //  setPalette(oldPalette);
00475 //  update();
00476 #endif
00477 }
00478 
00479 void KODayMatrix::dropEvent( TQDropEvent *e )
00480 {
00481 #ifndef KORG_NODND
00482   kdDebug(5850) << "KODayMatrix::dropEvent(e) begin" << endl;
00483 
00484   if ( !mCalendar ||
00485        ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) ) {
00486     e->ignore();
00487     return;
00488   }
00489 
00490   DndFactory factory( mCalendar );
00491   Event *event = factory.createDrop( e );
00492   Todo *todo = factory.createDropTodo( e );
00493   if ( !event && !todo ) {
00494     e->ignore();
00495     return;
00496   }
00497 
00498   Todo *existingTodo = 0;
00499   Event *existingEvent = 0;
00500 
00501   // Find the incidence in the calendar, then we don't need the drag object any more
00502   if ( event ) existingEvent = mCalendar->event( event->uid() );
00503   if ( todo ) existingTodo = mCalendar->todo( todo->uid() );
00504 
00505   int action = DRAG_CANCEL;
00506 
00507   int root_x, root_y, win_x, win_y;
00508   uint keybstate;
00509   Window rootw, childw;
00510   XQueryPointer( tqt_xdisplay(), tqt_xrootwin(), &rootw, &childw,
00511                  &root_x, &root_y, &win_x, &win_y, &keybstate );
00512 
00513   if ( keybstate & ControlMask ) {
00514     action = DRAG_COPY;
00515   } else if ( keybstate & ShiftMask ) {
00516     action = DRAG_MOVE;
00517   } else {
00518     TDEPopupMenu *menu = new TDEPopupMenu( this );
00519     if ( existingEvent || existingTodo ) {
00520       menu->insertItem( i18n("Move"), DRAG_MOVE, 0 );
00521       if (existingEvent)
00522         menu->insertItem( KOGlobals::self()->smallIcon("edit-copy"), i18n("Copy"), DRAG_COPY, 1 );
00523     } else {
00524       menu->insertItem( i18n("Add"), DRAG_MOVE, 0 );
00525     }
00526     menu->insertSeparator();
00527     menu->insertItem( KOGlobals::self()->smallIcon("cancel"), i18n("Cancel"), DRAG_CANCEL, 3 );
00528     action = menu->exec( TQCursor::pos(), 0 );
00529   }
00530 
00531   if ( action == DRAG_COPY  || action == DRAG_MOVE ) {
00532     e->accept();
00533     int idx = getDayIndexFrom( e->pos().x(), e->pos().y() );
00534 
00535     if ( action == DRAG_COPY ) {
00536       if ( event ) emit incidenceDropped( event, mDays[idx] );
00537       if ( todo )  emit incidenceDropped( todo, mDays[idx] );
00538     } else if ( action == DRAG_MOVE ) {
00539       if ( event ) emit incidenceDroppedMove( event, mDays[idx] );
00540       if ( todo )  emit incidenceDroppedMove( todo, mDays[idx] );
00541     }
00542   }
00543   delete event;
00544   delete todo;
00545 #endif
00546 }
00547 
00548 // ----------------------------------------------------------------------------
00549 //  P A I N T   E V E N T   H A N D L I N G
00550 // ----------------------------------------------------------------------------
00551 
00552 void KODayMatrix::paintEvent( TQPaintEvent * )
00553 {
00554 // kdDebug(5850) << "KODayMatrix::paintEvent() BEGIN" << endl;
00555 
00556   TQPainter p;
00557   TQRect sz = frameRect();
00558   TQPixmap pm( sz.size() );
00559   int dheight = mDaySize.height();
00560   int dwidth = mDaySize.width();
00561   int row,col;
00562   int selw, selh;
00563   bool isRTL = KOGlobals::self()->reverseLayout();
00564 
00565   TQColorGroup cg = palette().active();
00566 
00567   p.begin(  &pm, this );
00568   pm.fill( cg.base() );
00569 
00570   // draw topleft frame
00571   p.setPen( cg.mid() );
00572   p.drawRect(0, 0, sz.width()-1, sz.height()-1);
00573   // don't paint over borders
00574   p.translate(1,1);
00575 
00576   // draw selected days with highlighted background color
00577   if (mSelStart != NOSELECTION) {
00578 
00579     row = mSelStart/7;
00580     // fix larger selections starting in the previous month
00581     if ( row < 0 && mSelEnd > 0 ) row = 0;
00582     col = mSelStart -row*7;
00583     TQColor selcol = KOPrefs::instance()->mHighlightColor;
00584 
00585     if ( row < 6 && row >= 0 ) {
00586       if (row == mSelEnd/7) {
00587         // Single row selection
00588         p.fillRect(isRTL ? (7 - (mSelEnd-mSelStart+1) - col)*dwidth : col*dwidth,
00589                     row*dheight, (mSelEnd-mSelStart+1)*dwidth, dheight, selcol);
00590       } else {
00591         // draw first row to the right
00592         p.fillRect(isRTL ? 0 : col*dwidth, row*dheight, (7-col)*dwidth,
00593                    dheight, selcol);
00594         // draw full block till last line
00595         selh = mSelEnd/7-row;
00596         if ( selh + row >= 6 ) selh = 6-row;
00597         if ( selh > 1 ) {
00598           p.fillRect(0, (row+1)*dheight, 7*dwidth, (selh-1)*dheight,selcol);
00599         }
00600         // draw last block from left to mSelEnd
00601         if ( mSelEnd/7 < 6 ) {
00602           selw = mSelEnd-7*(mSelEnd/7)+1;
00603           p.fillRect(isRTL ? (7-selw)*dwidth : 0, (row+selh)*dheight,
00604                      selw*dwidth, dheight, selcol);
00605         }
00606       }
00607     }
00608   }
00609 
00610   // iterate over all days in the matrix and draw the day label in appropriate colors
00611   TQColor textColor = cg.text();
00612   TQColor textColorShaded = getShadedColor( textColor );
00613   TQColor actcol = textColorShaded;
00614   p.setPen(actcol);
00615   TQPen tmppen;
00616   for ( int i = 0; i < NUMDAYS; ++i ) {
00617     row = i/7;
00618     col = isRTL ? 6-(i-row*7) : i-row*7;
00619 
00620     // if it is the first day of a month switch color from normal to shaded and vice versa
00621     if ( KOGlobals::self()->calendarSystem()->day( mDays[i] ) == 1) {
00622       if (actcol == textColorShaded) {
00623         actcol = textColor;
00624       } else {
00625         actcol = textColorShaded;
00626       }
00627       p.setPen(actcol);
00628     }
00629 
00630     //Reset pen color after selected days block
00631     if (i == mSelEnd+1) {
00632       p.setPen(actcol);
00633     }
00634 
00635     bool holiday = ! KOGlobals::self()->isWorkDay( mDays[ i ] );
00636 
00637     TQColor holidayColorShaded = getShadedColor( KOPrefs::instance()->mHolidayColor );
00638     // if today then draw rectangle around day
00639     if (mToday == i) {
00640       tmppen = p.pen();
00641       TQPen mTodayPen(p.pen());
00642 
00643       mTodayPen.setWidth(mTodayMarginWidth);
00644       //draw red rectangle for holidays
00645       if (holiday) {
00646         if (actcol == textColor) {
00647           mTodayPen.setColor(KOPrefs::instance()->mHolidayColor);
00648         } else {
00649           mTodayPen.setColor(holidayColorShaded);
00650         }
00651       }
00652       //draw gray rectangle for today if in selection
00653       if (i >= mSelStart && i <= mSelEnd) {
00654         TQColor grey("grey");
00655         mTodayPen.setColor(grey);
00656       }
00657       p.setPen(mTodayPen);
00658       p.drawRect(col*dwidth, row*dheight, dwidth, dheight);
00659       p.setPen(tmppen);
00660     }
00661 
00662     // if any events are on that day then draw it using a bold font
00663     if (mEvents[i] > 0) {
00664       TQFont myFont = font();
00665       myFont.setBold(true);
00666       p.setFont(myFont);
00667     }
00668 
00669     // if it is a holiday then use the default holiday color
00670     if (holiday) {
00671       if (actcol == textColor) {
00672         p.setPen(KOPrefs::instance()->mHolidayColor);
00673       } else {
00674         p.setPen(holidayColorShaded);
00675       }
00676     }
00677 
00678     // draw selected days with special color
00679     if ( i >= mSelStart && i <= mSelEnd && !holiday ) {
00680       p.setPen( TQColor( "white" ) );
00681     }
00682 
00683     p.drawText(col*dwidth, row*dheight, dwidth, dheight,
00684               TQt::AlignHCenter | TQt::AlignVCenter,  mDayLabels[i]);
00685 
00686     // reset color to actual color
00687     if ( holiday ) {
00688       p.setPen(actcol);
00689     }
00690     // reset bold font to plain font
00691     if (mEvents[i] > 0) {
00692       TQFont myFont = font();
00693       myFont.setBold(false);
00694       p.setFont(myFont);
00695     }
00696   }
00697   p.end();
00698   bitBlt( this, 0, 0, &pm );
00699 }
00700 
00701 // ----------------------------------------------------------------------------
00702 //  R E SI Z E   E V E N T   H A N D L I N G
00703 // ----------------------------------------------------------------------------
00704 
00705 void KODayMatrix::resizeEvent( TQResizeEvent * )
00706 {
00707   TQRect sz = frameRect();
00708   mDaySize.setHeight( sz.height() * 7 / NUMDAYS );
00709   mDaySize.setWidth( sz.width() / 7 );
00710 }
00711 
00712 /* static */
00713 TQPair<TQDate,TQDate> KODayMatrix::matrixLimits( const TQDate &month )
00714 {
00715   const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
00716   TQDate d = month;
00717   calSys->setYMD( d, calSys->year( month ), calSys->month( month ), 1 );
00718 
00719   const int dayOfWeek = calSys->dayOfWeek( d );
00720   const int weekstart = TDEGlobal::locale()->weekStartDay();
00721 
00722   d = d.addDays( weekstart - dayOfWeek );
00723 
00724   if ( dayOfWeek == weekstart ) {
00725     d = d.addDays( -7 ); // Start on the second line
00726   }
00727 
00728   return tqMakePair( d, d.addDays( NUMDAYS-1 ) );
00729 }