korganizer

komonthview.cpp
00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
00005     Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020 
00021     As a special exception, permission is given to link this program
00022     with any edition of TQt, and distribute the resulting executable,
00023     without including the source code for TQt in the source distribution.
00024 */
00025 
00026 #include <tqpopupmenu.h>
00027 #include <tqfont.h>
00028 #include <tqfontmetrics.h>
00029 #include <tqkeycode.h>
00030 #include <tqhbox.h>
00031 #include <tqvbox.h>
00032 #include <tqpushbutton.h>
00033 #include <tqtooltip.h>
00034 #include <tqpainter.h>
00035 #include <tqcursor.h>
00036 #include <tqlistbox.h>
00037 #include <tqlayout.h>
00038 #include <tqlabel.h>
00039 
00040 #include <kdebug.h>
00041 #include <tdelocale.h>
00042 #include <tdeglobal.h>
00043 #include <tdeconfig.h>
00044 #include <kiconloader.h>
00045 #include <kwordwrap.h>
00046 
00047 #include <kcalendarsystem.h>
00048 #include <libkcal/calfilter.h>
00049 #include <libkcal/calendar.h>
00050 #include <libkcal/incidenceformatter.h>
00051 #include <libkcal/calendarresources.h>
00052 
00053 #include "koprefs.h"
00054 #include "koglobals.h"
00055 #include "koincidencetooltip.h"
00056 #include "koeventpopupmenu.h"
00057 #include "kohelper.h"
00058 
00059 #include "komonthview.h"
00060 #include "komonthview.moc"
00061 
00062 //--------------------------------------------------------------------------
00063 
00064 KOMonthCellToolTip::KOMonthCellToolTip( TQWidget *parent,
00065                                         Calendar *calendar,
00066                                         const TQDate &date,
00067                                         KNoScrollListBox *lv )
00068   : TQToolTip( parent ), mCalendar( calendar ), mDate( date )
00069 {
00070   eventlist = lv;
00071 }
00072 
00073 void KOMonthCellToolTip::maybeTip( const TQPoint &pos )
00074 {
00075   TQRect r;
00076   TQListBoxItem *it = eventlist->itemAt( pos );
00077   MonthViewItem *i = static_cast<MonthViewItem*>( it );
00078 
00079   if( i && KOPrefs::instance()->mEnableToolTips ) {
00080     /* Calculate the rectangle. */
00081     r=eventlist->itemRect( it );
00082     /* Show the tip */
00083     TQString tipText( IncidenceFormatter::toolTipStr( mCalendar, i->incidence(), mDate ) );
00084     if ( !tipText.isEmpty() ) {
00085       tip( r, tipText );
00086     }
00087   }
00088 }
00089 
00090 KNoScrollListBox::KNoScrollListBox( TQWidget *parent, const char *name )
00091   : TQListBox( parent, name ),
00092     mSqueezing( false )
00093 {
00094   TQPalette pal = palette();
00095   pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) );
00096   pal.setColor( TQColorGroup::Base, KOPrefs::instance()->agendaBgColor() );
00097   setPalette( pal );
00098 }
00099 
00100 void KNoScrollListBox::setBackground( bool primary, bool workDay )
00101 {
00102   TQColor color;
00103   if ( workDay ) {
00104     color = KOPrefs::instance()->workingHoursColor();
00105   } else {
00106     color = KOPrefs::instance()->agendaBgColor();
00107   }
00108 
00109   TQPalette pal = palette();
00110   if ( primary ) {
00111     pal.setColor( TQColorGroup::Base, color );
00112   } else {
00113     pal.setColor( TQColorGroup::Base, color.dark( 115 ) );
00114   }
00115   setPalette( pal );
00116 }
00117 
00118 void KNoScrollListBox::keyPressEvent( TQKeyEvent *e )
00119 {
00120   switch( e->key() ) {
00121     case Key_Right:
00122       scrollBy( 4, 0 );
00123       break;
00124     case Key_Left:
00125       scrollBy( -4, 0 );
00126       break;
00127     case Key_Up:
00128       if ( !count() ) break;
00129       setCurrentItem( ( currentItem() + count() - 1 ) % count() );
00130       if ( !itemVisible( currentItem() ) ) {
00131         if ( (unsigned int)currentItem() == ( count() - 1 ) ) {
00132           setTopItem( currentItem() - numItemsVisible() + 1 );
00133         } else {
00134           setTopItem( topItem() - 1 );
00135         }
00136       }
00137       break;
00138     case Key_Down:
00139       if ( !count() ) break;
00140       setCurrentItem( ( currentItem() + 1 ) % count() );
00141       if( !itemVisible( currentItem() ) ) {
00142         if( currentItem() == 0 ) {
00143           setTopItem( 0 );
00144         } else {
00145           setTopItem( topItem() + 1 );
00146         }
00147       }
00148     case Key_Shift:
00149       emit shiftDown();
00150       break;
00151     default:
00152       break;
00153   }
00154 }
00155 
00156 void KNoScrollListBox::keyReleaseEvent( TQKeyEvent *e )
00157 {
00158   switch( e->key() ) {
00159     case Key_Shift:
00160       emit shiftUp();
00161       break;
00162     default:
00163       break;
00164   }
00165 }
00166 
00167 void KNoScrollListBox::mousePressEvent( TQMouseEvent *e )
00168 {
00169   TQListBox::mousePressEvent( e );
00170 
00171   if ( e->button() == Qt::RightButton ) {
00172     emit rightClick();
00173   }
00174 }
00175 
00176 void KNoScrollListBox::contentsMouseDoubleClickEvent ( TQMouseEvent * e )
00177 {
00178   TQListBox::contentsMouseDoubleClickEvent( e );
00179   TQListBoxItem *item = itemAt( e->pos() );
00180   if ( !item ) {
00181     emit doubleClicked( item );
00182   }
00183 }
00184 
00185 void KNoScrollListBox::resizeEvent( TQResizeEvent *e )
00186 {
00187   bool s = count() && ( maxItemWidth() > e->size().width() );
00188   if ( mSqueezing || s )
00189     triggerUpdate( false );
00190 
00191   mSqueezing = s;
00192   TQListBox::resizeEvent( e );
00193 }
00194 
00195 MonthViewItem::MonthViewItem( Incidence *incidence, const TQDateTime &qd,
00196                               const TQString & s ) : TQListBoxItem()
00197 {
00198   setText( s );
00199 
00200   mIncidence = incidence;
00201   mDateTime = qd;
00202 
00203   mEventPixmap     = KOGlobals::self()->smallIcon( "appointment" );
00204   mBirthdayPixmap  = KOGlobals::self()->smallIcon( "calendarbirthday" );
00205   mAnniversaryPixmap= KOGlobals::self()->smallIcon( "calendaranniversary" );
00206   mTodoPixmap      = KOGlobals::self()->smallIcon( "todo" );
00207   mTodoDonePixmap  = KOGlobals::self()->smallIcon( "checkedbox" );
00208   mAlarmPixmap     = KOGlobals::self()->smallIcon( "bell" );
00209   mRecurPixmap     = KOGlobals::self()->smallIcon( "recur" );
00210   mReplyPixmap     = KOGlobals::self()->smallIcon( "mail-reply-sender" );
00211 
00212   mEvent     = false;
00213   mTodo      = false;
00214   mTodoDone  = false;
00215   mRecur     = false;
00216   mAlarm     = false;
00217   mReply     = false;
00218 }
00219 
00220 TQColor MonthViewItem::catColor() const
00221 {
00222   TQColor retColor;
00223   if ( !mIncidence ) {
00224     return retColor;
00225   }
00226 
00227   TQStringList categories = mIncidence->categories();
00228   TQString cat;
00229   if ( !categories.isEmpty() ) {
00230     cat = categories.first();
00231   }
00232   if ( cat.isEmpty() ) {
00233     retColor = KOPrefs::instance()->unsetCategoryColor();
00234   } else {
00235     retColor = *( KOPrefs::instance()->categoryColor( cat ) );
00236   }
00237   return retColor;
00238 }
00239 
00240 void MonthViewItem::paint( TQPainter *p )
00241 {
00242   bool sel = isSelected();
00243 
00244   TQColor bgColor = TQColor(); // Default invalid color;
00245   if ( mIncidence && mTodo ) {
00246     if ( static_cast<Todo*>( mIncidence )->isOverdue() ) {
00247       bgColor = KOPrefs::instance()->todoOverdueColor();
00248     } else if ( static_cast<Todo*>( mIncidence )->dtDue().date() == TQDate::currentDate() ) {
00249       bgColor = KOPrefs::instance()->todoDueTodayColor();
00250     }
00251   }
00252 
00253   if ( !bgColor.isValid() ) {
00254     if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly ||
00255          KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) {
00256       bgColor = resourceColor();
00257     } else {
00258       bgColor = catColor();
00259     }
00260 
00261     if ( !bgColor.isValid() ) {
00262       bgColor = palette().color( TQPalette::Normal,
00263                                  sel ? TQColorGroup::Highlight :
00264                                        TQColorGroup::Background );
00265     }
00266   }
00267 
00268   TQColor frameColor;
00269   if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly ||
00270        KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
00271     frameColor = resourceColor();
00272   } else {
00273     frameColor = catColor();
00274   }
00275 
00276   if ( mIncidence ) {
00277     if ( mIncidence->categories().isEmpty() &&
00278          KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) {
00279       frameColor = bgColor;
00280     }
00281 
00282     if ( mIncidence->categories().isEmpty() &&
00283          KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
00284       bgColor = frameColor;
00285     }
00286   }
00287 
00288   if ( !frameColor.isValid() ) {
00289     frameColor = palette().color( TQPalette::Normal,
00290                                   sel ? TQColorGroup::Highlight :
00291                                         TQColorGroup::Foreground );
00292   } else {
00293     frameColor = frameColor.dark( 115 );
00294   }
00295 
00296   // draw the box for the item
00297   p->setBackgroundColor( frameColor );
00298   p->eraseRect( 0, 0, listBox()->maxItemWidth(), height( listBox() ) );
00299   int offset = 2;
00300   p->setBackgroundColor( bgColor );
00301   p->eraseRect( offset, offset, listBox()->maxItemWidth()-2*offset, height( listBox() )-2*offset );
00302 
00303   int x = 3;
00304 
00305   bool specialEvent = false;
00306   if ( mEvent ) {
00307     if ( mIncidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
00308       specialEvent = true;
00309       if ( mIncidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
00310         p->drawPixmap( x, 0, mAnniversaryPixmap );
00311         x += mAnniversaryPixmap.width() + 2;
00312       } else {
00313         p->drawPixmap( x, 0, mBirthdayPixmap );
00314         x += mBirthdayPixmap.width() + 2;
00315       }
00316     // Do NOT put on the event pixmap because it takes up too much space
00317     //} else {
00318     //  p->drawPixmap( x, 0, mEventPixmap );
00319     //  x += mEventPixmap.width() + 2;
00320     //
00321     }
00322   }
00323 
00324   if ( mTodo ) {
00325     p->drawPixmap( x, 0, mTodoPixmap );
00326     x += mTodoPixmap.width() + 2;
00327   }
00328   if ( mTodoDone ) {
00329     p->drawPixmap( x, 0, mTodoDonePixmap );
00330     x += mTodoPixmap.width() + 2;
00331   }
00332   if ( mRecur && !specialEvent ) {
00333     p->drawPixmap( x, 0, mRecurPixmap );
00334     x += mRecurPixmap.width() + 2;
00335   }
00336   if ( mAlarm && !specialEvent ) {
00337     p->drawPixmap( x, 0, mAlarmPixmap );
00338     x += mAlarmPixmap.width() + 2;
00339   }
00340   if ( mReply ) {
00341     p->drawPixmap(x, 0, mReplyPixmap );
00342     x += mReplyPixmap.width() + 2;
00343   }
00344   TQFontMetrics fm = p->fontMetrics();
00345   int yPos;
00346   int pmheight = TQMAX( mRecurPixmap.height(),
00347                        TQMAX( mAlarmPixmap.height(), mReplyPixmap.height() ) );
00348   if( pmheight < fm.height() )
00349     yPos = fm.ascent() + fm.leading()/2;
00350   else
00351     yPos = pmheight/2 - fm.height()/2  + fm.ascent();
00352   TQColor textColor = getTextColor( bgColor );
00353   p->setPen( textColor );
00354 
00355   KWordWrap::drawFadeoutText( p, x, yPos, listBox()->width() - x, text() );
00356 }
00357 
00358 int MonthViewItem::height( const TQListBox *lb ) const
00359 {
00360   return TQMAX( TQMAX( mRecurPixmap.height(), mReplyPixmap.height() ),
00361                TQMAX( mAlarmPixmap.height(), lb->fontMetrics().lineSpacing()+1) );
00362 }
00363 
00364 int MonthViewItem::width( const TQListBox *lb ) const
00365 {
00366   int x = 3;
00367   if( mRecur ) {
00368     x += mRecurPixmap.width()+2;
00369   }
00370   if( mAlarm ) {
00371     x += mAlarmPixmap.width()+2;
00372   }
00373   if( mReply ) {
00374     x += mReplyPixmap.width()+2;
00375   }
00376 
00377   return( x + lb->fontMetrics().boundingRect( text() ).width() + 1 );
00378 }
00379 
00380 
00381 MonthViewCell::MonthViewCell( KOMonthView *parent)
00382   : TQWidget( parent ),
00383     mMonthView( parent ), mPrimary( false ), mHoliday( false ),
00384     isSelected( false )
00385 {
00386   TQVBoxLayout *topLayout = new TQVBoxLayout( this );
00387 
00388   mLabel = new TQLabel( this );
00389   mLabel->setFrameStyle( TQFrame::Panel | TQFrame::Plain );
00390   mLabel->setLineWidth( 1 );
00391   mLabel->setAlignment( AlignCenter );
00392 
00393   mItemList = new KNoScrollListBox( this );
00394   mItemList->setMinimumSize( 10, 10 );
00395   mItemList->setFrameStyle( TQFrame::Panel | TQFrame::Plain );
00396   mItemList->setLineWidth( 1 );
00397 
00398   topLayout->addWidget( mItemList );
00399 
00400   mLabel->raise();
00401 
00402   mStandardPalette = palette();
00403 
00404   enableScrollBars( false );
00405 
00406   updateConfig();
00407 
00408   connect( mItemList, TQT_SIGNAL( doubleClicked( TQListBoxItem *) ),
00409            TQT_SLOT( defaultAction( TQListBoxItem * ) ) );
00410   connect( mItemList, TQT_SIGNAL( rightButtonPressed( TQListBoxItem *,
00411                                                   const TQPoint &) ),
00412            TQT_SLOT( contextMenu( TQListBoxItem * ) ) );
00413   connect( mItemList, TQT_SIGNAL( clicked( TQListBoxItem * ) ),
00414            TQT_SLOT( select() ) );
00415 }
00416 
00417 void MonthViewCell::setDate( const TQDate &date )
00418 {
00419 //  kdDebug(5850) << "MonthViewCell::setDate(): " << date.toString() << endl;
00420 
00421   mDate = date;
00422 
00423   setFrameWidth();
00424 
00425   TQString text;
00426   if ( KOGlobals::self()->calendarSystem()->day( date ) == 1 ) {
00427     text = i18n("'Month day' for month view cells", "%1 %2")
00428         .arg( KOGlobals::self()->calendarSystem()->monthName( date, true ) )
00429         .arg( KOGlobals::self()->calendarSystem()->day(mDate) );
00430     TQFontMetrics fm( mLabel->font() );
00431     mLabel->resize( mLabelSize + TQSize( fm.width( text ), 0 ) );
00432   } else {
00433     mLabel->resize( mLabelSize );
00434     text = TQString::number( KOGlobals::self()->calendarSystem()->day(mDate) );
00435   }
00436   mLabel->setText( text );
00437 
00438   new KOMonthCellToolTip( mItemList->viewport(),
00439                           monthView()->calendar(),
00440                           mDate,
00441                           static_cast<KNoScrollListBox *>( mItemList ) );
00442 
00443   resizeEvent( 0 );
00444 }
00445 
00446 TQDate MonthViewCell::date() const
00447 {
00448   return mDate;
00449 }
00450 
00451 void MonthViewCell::setFrameWidth()
00452 {
00453   // show current day with a thicker frame
00454   if ( mDate == TQDate::currentDate() ) {
00455     mItemList->setLineWidth( 3 );
00456   } else if ( !isSelected ) {
00457     mItemList->setLineWidth( 1 );
00458   }
00459 }
00460 
00461 void MonthViewCell::setPrimary( bool primary )
00462 {
00463   mPrimary = primary;
00464 
00465   if ( mPrimary ) {
00466     mLabel->setBackgroundMode( PaletteBase );
00467   } else {
00468     mLabel->setBackgroundMode( PaletteBackground );
00469   }
00470 
00471   mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) );
00472 }
00473 
00474 bool MonthViewCell::isPrimary() const
00475 {
00476   return mPrimary;
00477 }
00478 
00479 void MonthViewCell::setHoliday( bool holiday )
00480 {
00481   mHoliday = holiday;
00482 
00483   if ( holiday ) {
00484     setPalette( mHolidayPalette );
00485   } else {
00486     setPalette( mStandardPalette );
00487   }
00488 }
00489 
00490 void MonthViewCell::setHolidayString( const TQString &holiday )
00491 {
00492   mHolidayString = holiday;
00493 }
00494 
00495 void MonthViewCell::updateCell()
00496 {
00497   setFrameWidth();
00498 
00499   if ( mDate == TQDate::currentDate() ) {
00500     setPalette( mTodayPalette );
00501 
00502     TQPalette pal = mItemList->palette();
00503     pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->highlightColor() );
00504     mItemList->setPalette( pal );
00505   }
00506   else {
00507     if ( mHoliday )
00508       setPalette( mHolidayPalette );
00509     else
00510       setPalette( mStandardPalette );
00511 
00512     TQPalette pal = mItemList->palette();
00513     pal.setColor( TQColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) );
00514     mItemList->setPalette( pal );
00515   }
00516 
00517   mItemList->clear();
00518 
00519   if ( !mHolidayString.isEmpty() ) {
00520     MonthViewItem *item = new MonthViewItem( 0, TQDateTime( mDate ), mHolidayString );
00521     item->setPalette( mHolidayPalette );
00522     mItemList->insertItem( item );
00523   }
00524 }
00525 
00526 class MonthViewCell::CreateItemVisitor :
00527       public IncidenceBase::Visitor
00528 {
00529   public:
00530     CreateItemVisitor() : mItem(0) { emails = KOPrefs::instance()->allEmails(); }
00531 
00532     bool act( IncidenceBase *incidence, TQDate date, TQPalette stdPal, int multiDay )
00533     {
00534       mItem = 0;
00535       mDate = date;
00536       mStandardPalette = stdPal;
00537       mMultiDay = multiDay;
00538       return incidence->accept( *this );
00539     }
00540     MonthViewItem *item() const { return mItem; }
00541     TQStringList emails;
00542 
00543   protected:
00544     bool visit( Event *event ) {
00545       TQString text;
00546       TQDateTime dt( mDate );
00547       // take the time 0:00 into account, which is non-inclusive
00548       TQDate dtEnd = event->dtEnd().addSecs( event->doesFloat() ? 0 : -1).date();
00549       int length = event->dtStart().daysTo( TQDateTime(dtEnd) );
00550       if ( event->isMultiDay() ) {
00551         if (  mDate == event->dtStart().date()
00552            || ( mMultiDay == 0 && event->recursOn( mDate ) ) ) {
00553           text = "(-- " + event->summary();
00554           dt = event->dtStart();
00555         } else if ( !event->doesRecur() && mDate == dtEnd
00556                  // last day of a recurring multi-day event?
00557                  || ( mMultiDay == length && event->recursOn( mDate.addDays( -length ) ) ) ) {
00558           text = event->summary() + " --)";
00559         } else if (!(event->dtStart().date().daysTo(mDate) % 7) && length > 7 ) {
00560           text = "-- " + event->summary() + " --";
00561         } else {
00562           text = "----------------";
00563           dt = TQDateTime( mDate );
00564         }
00565       } else {
00566         if (event->doesFloat())
00567           text = event->summary();
00568         else {
00569           text = TDEGlobal::locale()->formatTime(event->dtStart().time());
00570           dt.setTime( event->dtStart().time() );
00571           text += ' ' + event->summary();
00572         }
00573       }
00574 
00575       mItem = new MonthViewItem( event, dt, text );
00576       mItem->setEvent( true );
00577       if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryOnly ||
00578            KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
00579         TQStringList categories = event->categories();
00580         TQString cat = categories.first();
00581         if (cat.isEmpty()) {
00582           mItem->setPalette(TQPalette(KOPrefs::instance()->unsetCategoryColor(),
00583                                      KOPrefs::instance()->unsetCategoryColor()) );
00584         } else {
00585           mItem->setPalette(TQPalette(*(KOPrefs::instance()->categoryColor(cat)),
00586                                      *(KOPrefs::instance()->categoryColor(cat))));
00587         }
00588       } else {
00589         mItem->setPalette( mStandardPalette );
00590       }
00591 
00592       Attendee *me = event->attendeeByMails( emails );
00593       if ( me != 0 ) {
00594         mItem->setReply( me->status() == Attendee::NeedsAction && me->RSVP() );
00595       } else
00596         mItem->setReply(false);
00597       return true;
00598     }
00599     bool visit( Todo *todo ) {
00600       TQString text;
00601       if ( !KOPrefs::instance()->showAllDayTodo() )
00602         return false;
00603       TQDateTime dt( mDate );
00604       if ( todo->hasDueDate() && !todo->doesFloat() &&
00605            todo->dtDue().time() != TQTime( 0,0 ) && todo->dtDue().time().isValid() ) {
00606         text += TDEGlobal::locale()->formatTime( todo->dtDue().time() );
00607         text += ' ';
00608         dt.setTime( todo->dtDue().time() );
00609       }
00610       text += todo->summary();
00611 
00612       mItem = new MonthViewItem( todo, dt, text );
00613       if ( todo->doesRecur() ) {
00614         mDate < todo->dtDue().date() ?
00615         mItem->setTodoDone( true ) : mItem->setTodo( true );
00616       }
00617       else
00618         todo->isCompleted() ? mItem->setTodoDone( true ) : mItem->setTodo( true );
00619       mItem->setPalette( mStandardPalette );
00620       return true;
00621     }
00622   protected:
00623     MonthViewItem *mItem;
00624     TQDate mDate;
00625     TQPalette mStandardPalette;
00626     int mMultiDay;
00627 };
00628 
00629 
00630 void MonthViewCell::addIncidence( Incidence *incidence, CreateItemVisitor& v, int multiDay )
00631 {
00632   if ( v.act( incidence, mDate, mStandardPalette, multiDay ) ) {
00633     MonthViewItem *item = v.item();
00634     if ( item ) {
00635       item->setAlarm( incidence->isAlarmEnabled() );
00636       item->setRecur( incidence->recurrenceType() );
00637 
00638       TQColor resourceColor = KOHelper::resourceColor( monthView()->calendar(), incidence );
00639       if ( !resourceColor.isValid() )
00640         resourceColor = KOPrefs::instance()->unsetCategoryColor();
00641       item->setResourceColor( resourceColor );
00642 
00643       // FIXME: Find the correct position (time-wise) to insert the item.
00644       //        Currently, the items are displayed in "random" order instead of
00645       //        chronologically sorted.
00646       uint i = 0;
00647       int pos = -1;
00648       TQDateTime dt( item->incidenceDateTime() );
00649 
00650       while ( i < mItemList->count() && pos<0 ) {
00651         TQListBoxItem *item = mItemList->item( i );
00652         MonthViewItem *mvitem = dynamic_cast<MonthViewItem*>( item );
00653         if ( mvitem && mvitem->incidenceDateTime()>dt ) {
00654           pos = i;
00655         }
00656         ++i;
00657       }
00658       mItemList->insertItem( item, pos );
00659     }
00660   }
00661 }
00662 
00663 void MonthViewCell::removeIncidence( Incidence *incidence )
00664 {
00665   for ( uint i = 0; i < mItemList->count(); ++i ) {
00666     MonthViewItem *item = static_cast<MonthViewItem *>(mItemList->item( i ) );
00667     if ( item && item->incidence() &&
00668          item->incidence()->uid() == incidence->uid() ) {
00669       mItemList->removeItem( i );
00670       --i;
00671     }
00672   }
00673 }
00674 
00675 void MonthViewCell::updateConfig()
00676 {
00677   setFont( KOPrefs::instance()->mMonthViewFont );
00678 
00679   TQFontMetrics fm( font() );
00680   mLabelSize = fm.size( 0, "30" ) +
00681                TQSize( mLabel->frameWidth() * 2, mLabel->frameWidth() * 2 ) +
00682                TQSize( 2, 2 );
00683 //  mStandardPalette = mOriginalPalette;
00684   TQColor bg = mStandardPalette.color( TQPalette::Active, TQColorGroup::Background );
00685   int h,s,v;
00686   bg.getHsv( &h, &s, &v );
00687   if ( date().month() %2 == 0 ) {
00688     if ( v < 128 ) {
00689       bg = bg.light( 125 );
00690     } else {
00691       bg = bg.dark( 125 );
00692     }
00693   }
00694   setPaletteBackgroundColor( bg );
00695 //  mStandardPalette.setColor( TQColorGroup::Background, bg);*/
00696 
00697   mHolidayPalette = mStandardPalette;
00698   mHolidayPalette.setColor( TQColorGroup::Foreground,
00699                             KOPrefs::instance()->holidayColor() );
00700   mHolidayPalette.setColor( TQColorGroup::Text,
00701                             KOPrefs::instance()->holidayColor() );
00702   mTodayPalette = mStandardPalette;
00703   mTodayPalette.setColor( TQColorGroup::Foreground,
00704                           KOPrefs::instance()->highlightColor() );
00705   mTodayPalette.setColor( TQColorGroup::Text,
00706                           KOPrefs::instance()->highlightColor() );
00707   updateCell();
00708 
00709   mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) );
00710 }
00711 
00712 void MonthViewCell::enableScrollBars( bool enabled )
00713 {
00714   if ( enabled ) {
00715     mItemList->setVScrollBarMode( TQScrollView::Auto );
00716     mItemList->setHScrollBarMode( TQScrollView::Auto );
00717   } else {
00718     mItemList->setVScrollBarMode( TQScrollView::AlwaysOff );
00719     mItemList->setHScrollBarMode( TQScrollView::AlwaysOff );
00720   }
00721 }
00722 
00723 Incidence *MonthViewCell::selectedIncidence()
00724 {
00725   int index = mItemList->currentItem();
00726   if ( index < 0 ) return 0;
00727 
00728   MonthViewItem *item =
00729       static_cast<MonthViewItem *>( mItemList->item( index ) );
00730 
00731   if ( !item ) return 0;
00732 
00733   return item->incidence();
00734 }
00735 
00736 TQDate MonthViewCell::selectedIncidenceDate()
00737 {
00738   TQDate qd;
00739   int index = mItemList->currentItem();
00740   if ( index < 0 ) return qd;
00741 
00742   MonthViewItem *item =
00743       static_cast<MonthViewItem *>( mItemList->item( index ) );
00744 
00745   if ( !item ) return qd;
00746 
00747   return item->incidenceDateTime().date();
00748 }
00749 
00750 void MonthViewCell::select()
00751 {
00752 
00753   isSelected = true;
00754 
00755   // setSelectedCell will deselect currently selected cells
00756   mMonthView->setSelectedCell( this );
00757 
00758   if( KOPrefs::instance()->enableMonthScroll() )
00759     enableScrollBars( true );
00760 
00761   // don't mess up the cell when it represents today
00762   if( mDate != TQDate::currentDate() ) {
00763     mItemList->setFrameStyle( TQFrame::Sunken | TQFrame::Panel );
00764     mItemList->setLineWidth( 3 );
00765   }
00766 }
00767 
00768 void MonthViewCell::deselect()
00769 {
00770   isSelected = false;
00771 
00772   mItemList->clearSelection();
00773   mItemList->setFrameStyle( TQFrame::Plain | TQFrame::Panel );
00774   setFrameWidth();
00775 
00776   enableScrollBars( false );
00777 }
00778 
00779 void MonthViewCell::resizeEvent ( TQResizeEvent * )
00780 {
00781   mLabel->move( width() - mLabel->width(), height() - mLabel->height() );
00782 }
00783 
00784 void MonthViewCell::defaultAction( TQListBoxItem *item )
00785 {
00786   select();
00787 
00788   if ( !item ) {
00789     emit newEventSignal( 0/*ResourceCalendar*/, TQString()/*subResource*/, date() );
00790   } else {
00791     MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
00792     Incidence *incidence = eventItem->incidence();
00793     if ( incidence ) mMonthView->defaultAction( incidence );
00794   }
00795 }
00796 
00797 void MonthViewCell::contextMenu( TQListBoxItem *item )
00798 {
00799   select();
00800 
00801   if ( item ) {
00802     MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
00803     Incidence *incidence = eventItem->incidence();
00804     if ( incidence ) {
00805       mMonthView->showEventContextMenu( monthView()->calendar(), incidence, mDate );
00806     }
00807   }  else {
00808     mMonthView->showGeneralContextMenu();
00809   }
00810 }
00811 
00812 
00813 KOMonthView::KOMonthView( Calendar *calendar, TQWidget *parent, const char *name )
00814     : KOEventView( calendar, parent, name ),
00815       mDaysPerWeek( 7 ), mNumWeeks( 6 ), mNumCells( mDaysPerWeek * mNumWeeks ),
00816       mShortDayLabels( false ), mWidthLongDayLabel( 0 ), mSelectedCell( 0 )
00817 {
00818   mCells.setAutoDelete( true );
00819 
00820   TQGridLayout *dayLayout = new TQGridLayout( this );
00821 
00822   TQFont bfont = font();
00823   bfont.setBold( true );
00824 
00825   TQFont mfont = bfont;
00826   mfont.setPointSize( 20 );
00827 
00828   // month name on top
00829   mLabel = new TQLabel( this );
00830   mLabel->setFont( mfont );
00831   mLabel->setAlignment( AlignCenter );
00832   mLabel->setLineWidth( 0 );
00833   mLabel->setFrameStyle( TQFrame::Plain );
00834 
00835   dayLayout->addMultiCellWidget( mLabel, 0, 0, 0, mDaysPerWeek );
00836 
00837   // create the day of the week labels (Sun, Mon, etc) and add them to
00838   // the layout.
00839   mDayLabels.resize( mDaysPerWeek );
00840   int i;
00841   for( i = 0; i < mDaysPerWeek; i++ ) {
00842     TQLabel *label = new TQLabel( this );
00843     label->setFont( bfont );
00844     label->setFrameStyle( TQFrame::Panel | TQFrame::Raised );
00845     label->setLineWidth( 1 );
00846     label->setAlignment( AlignCenter );
00847 
00848     mDayLabels.insert( i, label );
00849 
00850     dayLayout->addWidget( label, 1, i );
00851     dayLayout->addColSpacing( i, 10 );
00852     dayLayout->setColStretch( i, 1 );
00853   }
00854 
00855   int row, col;
00856 
00857   mCells.resize( mNumCells );
00858   for( row = 0; row < mNumWeeks; ++row ) {
00859     for( col = 0; col < mDaysPerWeek; ++col ) {
00860       MonthViewCell *cell = new MonthViewCell( this );
00861       mCells.insert( row * mDaysPerWeek + col, cell );
00862       dayLayout->addWidget( cell, row + 2, col );
00863 
00864       connect( cell, TQT_SIGNAL(defaultAction(Incidence *)),
00865                TQT_SLOT(defaultAction(Incidence *)) );
00866       connect( cell, TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)),
00867                TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)) );
00868     }
00869     dayLayout->setRowStretch( row + 2, 1 );
00870   }
00871 
00872   mEventContextMenu = eventPopup();
00873 
00874   updateConfig();
00875 
00876   emit incidenceSelected( 0, TQDate() );
00877 }
00878 
00879 KOMonthView::~KOMonthView()
00880 {
00881   delete mEventContextMenu;
00882 }
00883 
00884 int KOMonthView::maxDatesHint()
00885 {
00886   return mNumCells;
00887 }
00888 
00889 int KOMonthView::currentDateCount()
00890 {
00891   return mNumCells;
00892 }
00893 
00894 Incidence::List KOMonthView::selectedIncidences()
00895 {
00896   Incidence::List selected;
00897 
00898   if ( mSelectedCell ) {
00899     Incidence *incidence = mSelectedCell->selectedIncidence();
00900     if ( incidence ) selected.append( incidence );
00901   }
00902 
00903   return selected;
00904 }
00905 
00906 DateList KOMonthView::selectedIncidenceDates()
00907 {
00908   DateList selected;
00909 
00910   if ( mSelectedCell ) {
00911     TQDate qd = mSelectedCell->selectedIncidenceDate();
00912     if ( qd.isValid() ) selected.append( qd );
00913   }
00914 
00915   return selected;
00916 }
00917 
00918 bool KOMonthView::eventDurationHint( TQDateTime &startDt, TQDateTime &endDt, bool &allDay )
00919 {
00920   if ( mSelectedCell ) {
00921     startDt.setDate( mSelectedCell->date() );
00922     endDt.setDate( mSelectedCell->date() );
00923     allDay = true;
00924     return true;
00925   }
00926   return false;
00927 }
00928 
00929 void KOMonthView::updateConfig()
00930 {
00931   mWeekStartDay = TDEGlobal::locale()->weekStartDay();
00932 
00933   TQFontMetrics fontmetric( mDayLabels[0]->font() );
00934   mWidthLongDayLabel = 0;
00935 
00936   for ( int i = 0; i < 7; ++i ) {
00937     int width =
00938         fontmetric.width( KOGlobals::self()->calendarSystem()->weekDayName( i + 1 ) );
00939     if ( width > mWidthLongDayLabel ) mWidthLongDayLabel = width;
00940   }
00941 
00942   updateDayLabels();
00943 
00944   for ( uint i = 0; i < mCells.count(); ++i ) {
00945     mCells[i]->updateConfig();
00946   }
00947 
00948   showLabel( !KOPrefs::instance()->fullViewMonth() );
00949 }
00950 
00951 void KOMonthView::updateDayLabels()
00952 {
00953   kdDebug(5850) << "KOMonthView::updateDayLabels()" << endl;
00954 
00955   const KCalendarSystem*calsys=KOGlobals::self()->calendarSystem();
00956   int currDay;
00957   for ( int i = 0; i < 7; i++ ) {
00958     currDay = i+mWeekStartDay;
00959     if ( currDay > 7 ) currDay -= 7;
00960     mDayLabels[i]->setText( calsys->weekDayName( currDay, mShortDayLabels ) );
00961   }
00962 }
00963 
00964 void KOMonthView::showDates( const TQDate &start, const TQDate & )
00965 {
00966 //  kdDebug(5850) << "KOMonthView::showDates(): " << start.toString() << endl;
00967 
00968   const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
00969 
00970   mDateToCell.clear();
00971 
00972   // show first day of month on top for readability issues
00973   mStartDate = start.addDays( -start.day() + 1 );
00974   // correct begin of week
00975   int weekdayCol=( mStartDate.dayOfWeek() + 7 - mWeekStartDay ) % 7;
00976   mStartDate = mStartDate.addDays( -weekdayCol );
00977 
00978   mLabel->setText( i18n( "monthname year", "%1 %2" )
00979                    .arg( calSys->monthName( start ) )
00980                    .arg( calSys->year( start ) ) );
00981 
00982   showLabel( !KOPrefs::instance()->fullViewMonth() );
00983 
00984   bool primary = false;
00985   uint i;
00986   for( i = 0; i < mCells.size(); ++i ) {
00987     TQDate date = mStartDate.addDays( i );
00988     if ( calSys->day( date ) == 1 ) {
00989       primary = !primary;
00990     }
00991 
00992     mCells[i]->setDate( date );
00993     mDateToCell[ date ] = mCells[ i ];
00994     if( date == start ) {
00995       mCells[i]->select();
00996     }
00997 
00998     mCells[i]->setPrimary( primary );
00999 
01000     bool isHoliday = calSys->dayOfWeek( date ) == calSys->weekDayOfPray()
01001                   || !KOGlobals::self()->isWorkDay( date );
01002     mCells[i]->setHoliday( isHoliday );
01003 
01004     // add holiday, if present
01005     TQStringList holidays( KOGlobals::self()->holiday( date ) );
01006     mCells[i]->setHolidayString( holidays.join( i18n("delimiter for joining holiday names", ", " ) ) );
01007   }
01008 
01009   updateView();
01010 }
01011 
01012 TQDateTime KOMonthView::selectionStart()
01013 {
01014   if ( mSelectedCell) {
01015     return TQDateTime( mSelectedCell->date() );
01016   } else {
01017     return TQDateTime();
01018   }
01019 }
01020 
01021 TQDateTime KOMonthView::selectionEnd()
01022 {
01023   // Only one cell can be selected (for now)
01024   return selectionStart();
01025 }
01026 
01027 void KOMonthView::showIncidences( const Incidence::List &, const TQDate & )
01028 {
01029   kdDebug(5850) << "KOMonthView::showIncidences( const Incidence::List & ) is not implemented yet." << endl;
01030 }
01031 
01032 class KOMonthView::GetDateVisitor : public IncidenceBase::Visitor
01033 {
01034   public:
01035     GetDateVisitor() {}
01036 
01037     bool act( IncidenceBase *incidence )
01038     {
01039       return incidence->accept( *this );
01040     }
01041     TQDateTime startDate() const { return mStartDate; }
01042     TQDateTime endDate() const { return mEndDate; }
01043 
01044   protected:
01045     bool visit( Event *event ) {
01046       mStartDate = event->dtStart();
01047       mEndDate = event->dtEnd();
01048       return true;
01049     }
01050     bool visit( Todo *todo ) {
01051       if ( todo->hasDueDate() ) {
01052         if ( todo->dtDue().time() != TQTime( 0, 0 ) &&
01053              todo->dtDue().time().isValid() ) {
01054           mStartDate = todo->dtDue();
01055           mEndDate = todo->dtDue();
01056         } else {
01057           mStartDate = TQDateTime( todo->dtDue().date(), TQTime( 23,59 ) );
01058           mEndDate = mStartDate;
01059         }
01060       }// else
01061 //         return false;
01062       return true;
01063     }
01064     bool visit( Journal *journal ) {
01065       mStartDate = journal->dtStart();
01066       mEndDate = journal->dtStart();
01067       return true;
01068     }
01069   protected:
01070     TQDateTime mStartDate;
01071     TQDateTime mEndDate;
01072 };
01073 
01074 void KOMonthView::changeIncidenceDisplayAdded( Incidence *incidence, MonthViewCell::CreateItemVisitor& v)
01075 {
01076   GetDateVisitor gdv;
01077 
01078   if ( !gdv.act( incidence ) ) {
01079     kdDebug(5850) << "Visiting GetDateVisitor failed." << endl;
01080     return;
01081   }
01082 
01083   bool floats = incidence->doesFloat();
01084 
01085   if ( incidence->doesRecur() ) {
01086     for ( uint i = 0; i < mCells.count(); ++i ) {
01087       if ( incidence->recursOn( mCells[i]->date(), calendar() ) ) {
01088 
01089         // handle multiday events
01090         int length = gdv.startDate().daysTo( TQDateTime(gdv.endDate().addSecs( floats ? 0 : -1 ).date()) );
01091         for ( int j = 0; j <= length && i+j < mCells.count(); ++j ) {
01092           mCells[i+j]->addIncidence( incidence, v, j );
01093         }
01094       }
01095     }
01096   } else {
01097     // addSecs(-1) is added to handle 0:00 cases (because it's non-inclusive according to rfc)
01098     if ( gdv.endDate().isValid() ) {
01099       TQDate endDate = gdv.endDate().addSecs( floats ? 0 : -1).date();
01100       for ( TQDate date = gdv.startDate().date();
01101             date <= endDate; date = date.addDays( 1 ) ) {
01102         MonthViewCell *mvc = mDateToCell[ date ];
01103         if ( mvc ) mvc->addIncidence( incidence, v );
01104       }
01105     }
01106   }
01107 }
01108 
01109 void KOMonthView::changeIncidenceDisplay( Incidence *incidence, int action )
01110 {
01111   MonthViewCell::CreateItemVisitor v;
01112   switch ( action ) {
01113     case KOGlobals::INCIDENCEADDED:
01114       changeIncidenceDisplayAdded( incidence, v );
01115       break;
01116     case KOGlobals::INCIDENCEEDITED:
01117       for( uint i = 0; i < mCells.count(); i++ )
01118         mCells[i]->removeIncidence( incidence );
01119       changeIncidenceDisplayAdded( incidence, v );
01120       break;
01121     case KOGlobals::INCIDENCEDELETED:
01122       for( uint i = 0; i < mCells.count(); i++ )
01123         mCells[i]->removeIncidence( incidence );
01124       break;
01125     default:
01126       return;
01127   }
01128 }
01129 
01130 void KOMonthView::updateView()
01131 {
01132   for( uint i = 0; i < mCells.count(); ++i ) {
01133     mCells[i]->updateCell();
01134   }
01135 
01136   Incidence::List incidences = calendar()->incidences();
01137   Incidence::List::ConstIterator it;
01138 
01139   MonthViewCell::CreateItemVisitor v;
01140   for ( it = incidences.begin(); it != incidences.end(); ++it )
01141     changeIncidenceDisplayAdded( *it, v );
01142 
01143   processSelectionChange();
01144 }
01145 
01146 void KOMonthView::resizeEvent( TQResizeEvent * )
01147 {
01148   // select the appropriate heading string size. E.g. "Wednesday" or "Wed".
01149   // note this only changes the text if the requested size crosses the
01150   // threshold between big enough to support the full name and not big
01151   // enough.
01152   if( mDayLabels[0]->width() < mWidthLongDayLabel ) {
01153     if ( !mShortDayLabels ) {
01154       mShortDayLabels = true;
01155       updateDayLabels();
01156     }
01157   } else {
01158     if ( mShortDayLabels ) {
01159       mShortDayLabels = false;
01160       updateDayLabels();
01161     }
01162   }
01163 }
01164 
01165 void KOMonthView::showEventContextMenu( Calendar *cal, Incidence *incidence, const TQDate &qd )
01166 {
01167   mEventContextMenu->showIncidencePopup( cal, incidence, qd );
01168 }
01169 
01170 void KOMonthView::showGeneralContextMenu()
01171 {
01172   showNewEventPopup();
01173 }
01174 
01175 void KOMonthView::setSelectedCell( MonthViewCell *cell )
01176 {
01177   if ( mSelectedCell && cell != mSelectedCell )
01178     mSelectedCell->deselect();
01179 
01180   mSelectedCell = cell;
01181 
01182   if ( !mSelectedCell )
01183     emit incidenceSelected( 0, TQDate() );
01184   else
01185     if ( selectedIncidenceDates().isEmpty() ) {
01186       emit incidenceSelected( mSelectedCell->selectedIncidence(), TQDate() );
01187     } else {
01188       emit incidenceSelected( mSelectedCell->selectedIncidence(), selectedIncidenceDates().first() );
01189     }
01190 }
01191 
01192 void KOMonthView::processSelectionChange()
01193 {
01194   Incidence::List incidences = selectedIncidences();
01195   if (incidences.count() > 0) {
01196     if ( selectedIncidenceDates().isEmpty() ) {
01197       emit incidenceSelected( incidences.first(), TQDate() );
01198     } else {
01199       emit incidenceSelected( incidences.first(), selectedIncidenceDates().first() );
01200     }
01201   } else {
01202     emit incidenceSelected( 0, TQDate() );
01203   }
01204 }
01205 
01206 void KOMonthView::clearSelection()
01207 {
01208   if ( mSelectedCell ) {
01209     mSelectedCell->deselect();
01210     mSelectedCell = 0;
01211   }
01212 }
01213 
01214 void KOMonthView::showLabel( bool show )
01215 {
01216   if ( show ) {
01217     mLabel->show();
01218   } else {
01219     mLabel->hide();
01220   }
01221 }