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 Qt, and distribute the resulting executable,
00023     without including the source code for Qt in the source distribution.
00024 */
00025 
00026 #include <qpopupmenu.h>
00027 #include <qfont.h>
00028 #include <qfontmetrics.h>
00029 #include <qkeycode.h>
00030 #include <qhbox.h>
00031 #include <qvbox.h>
00032 #include <qpushbutton.h>
00033 #include <qtooltip.h>
00034 #include <qpainter.h>
00035 #include <qcursor.h>
00036 #include <qlistbox.h>
00037 #include <qlayout.h>
00038 #include <qlabel.h>
00039 
00040 #include <kdebug.h>
00041 #include <klocale.h>
00042 #include <kglobal.h>
00043 #include <kconfig.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( QWidget *parent,
00065                                         Calendar *calendar,
00066                                         const QDate &date,
00067                                         KNoScrollListBox *lv )
00068   : QToolTip( parent ), mCalendar( calendar ), mDate( date )
00069 {
00070   eventlist = lv;
00071 }
00072 
00073 void KOMonthCellToolTip::maybeTip( const QPoint &pos )
00074 {
00075   QRect r;
00076   QListBoxItem *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     QString tipText( IncidenceFormatter::toolTipStr( mCalendar, i->incidence(), mDate ) );
00084     if ( !tipText.isEmpty() ) {
00085       tip( r, tipText );
00086     }
00087   }
00088 }
00089 
00090 KNoScrollListBox::KNoScrollListBox( QWidget *parent, const char *name )
00091   : QListBox( parent, name ),
00092     mSqueezing( false )
00093 {
00094   QPalette pal = palette();
00095   pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) );
00096   pal.setColor( QColorGroup::Base, KOPrefs::instance()->agendaBgColor() );
00097   setPalette( pal );
00098 }
00099 
00100 void KNoScrollListBox::setBackground( bool primary, bool workDay )
00101 {
00102   QColor color;
00103   if ( workDay ) {
00104     color = KOPrefs::instance()->workingHoursColor();
00105   } else {
00106     color = KOPrefs::instance()->agendaBgColor();
00107   }
00108 
00109   QPalette pal = palette();
00110   if ( primary ) {
00111     pal.setColor( QColorGroup::Base, color );
00112   } else {
00113     pal.setColor( QColorGroup::Base, color.dark( 115 ) );
00114   }
00115   setPalette( pal );
00116 }
00117 
00118 void KNoScrollListBox::keyPressEvent( QKeyEvent *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( QKeyEvent *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( QMouseEvent *e )
00168 {
00169   QListBox::mousePressEvent( e );
00170 
00171   if ( e->button() == RightButton ) {
00172     emit rightClick();
00173   }
00174 }
00175 
00176 void KNoScrollListBox::contentsMouseDoubleClickEvent ( QMouseEvent * e )
00177 {
00178   QListBox::contentsMouseDoubleClickEvent( e );
00179   QListBoxItem *item = itemAt( e->pos() );
00180   if ( !item ) {
00181     emit doubleClicked( item );
00182   }
00183 }
00184 
00185 void KNoScrollListBox::resizeEvent( QResizeEvent *e )
00186 {
00187   bool s = count() && ( maxItemWidth() > e->size().width() );
00188   if ( mSqueezing || s )
00189     triggerUpdate( false );
00190 
00191   mSqueezing = s;
00192   QListBox::resizeEvent( e );
00193 }
00194 
00195 MonthViewItem::MonthViewItem( Incidence *incidence, const QDateTime &qd,
00196                               const QString & s ) : QListBoxItem()
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" );
00211 
00212   mEvent     = false;
00213   mTodo      = false;
00214   mTodoDone  = false;
00215   mRecur     = false;
00216   mAlarm     = false;
00217   mReply     = false;
00218 }
00219 
00220 QColor MonthViewItem::catColor() const
00221 {
00222   QColor retColor;
00223   if ( !mIncidence ) {
00224     return retColor;
00225   }
00226 
00227   QStringList categories = mIncidence->categories();
00228   QString 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( QPainter *p )
00241 {
00242 #if QT_VERSION >= 0x030000
00243   bool sel = isSelected();
00244 #else
00245   bool sel = selected();
00246 #endif
00247 
00248   QColor bgColor = QColor(); // Default invalid color;
00249   if ( mIncidence && mTodo ) {
00250     if ( static_cast<Todo*>( mIncidence )->isOverdue() ) {
00251       bgColor = KOPrefs::instance()->todoOverdueColor();
00252     } else if ( static_cast<Todo*>( mIncidence )->dtDue().date() == QDate::currentDate() ) {
00253       bgColor = KOPrefs::instance()->todoDueTodayColor();
00254     }
00255   }
00256 
00257   if ( !bgColor.isValid() ) {
00258     if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly ||
00259          KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) {
00260       bgColor = resourceColor();
00261     } else {
00262       bgColor = catColor();
00263     }
00264 
00265     if ( !bgColor.isValid() ) {
00266       bgColor = palette().color( QPalette::Normal,
00267                                  sel ? QColorGroup::Highlight :
00268                                        QColorGroup::Background );
00269     }
00270   }
00271 
00272   QColor frameColor;
00273   if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly ||
00274        KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
00275     frameColor = resourceColor();
00276   } else {
00277     frameColor = catColor();
00278   }
00279 
00280   if ( mIncidence ) {
00281     if ( mIncidence->categories().isEmpty() &&
00282          KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) {
00283       frameColor = bgColor;
00284     }
00285 
00286     if ( mIncidence->categories().isEmpty() &&
00287          KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
00288       bgColor = frameColor;
00289     }
00290   }
00291 
00292   if ( !frameColor.isValid() ) {
00293     frameColor = palette().color( QPalette::Normal,
00294                                   sel ? QColorGroup::Highlight :
00295                                         QColorGroup::Foreground );
00296   } else {
00297     frameColor = frameColor.dark( 115 );
00298   }
00299 
00300   // draw the box for the item
00301   p->setBackgroundColor( frameColor );
00302   p->eraseRect( 0, 0, listBox()->maxItemWidth(), height( listBox() ) );
00303   int offset = 2;
00304   p->setBackgroundColor( bgColor );
00305   p->eraseRect( offset, offset, listBox()->maxItemWidth()-2*offset, height( listBox() )-2*offset );
00306 
00307   int x = 3;
00308 
00309   bool specialEvent = false;
00310   if ( mEvent ) {
00311     if ( mIncidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
00312       specialEvent = true;
00313       if ( mIncidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
00314         p->drawPixmap( x, 0, mAnniversaryPixmap );
00315         x += mAnniversaryPixmap.width() + 2;
00316       } else {
00317         p->drawPixmap( x, 0, mBirthdayPixmap );
00318         x += mBirthdayPixmap.width() + 2;
00319       }
00320     // Do NOT put on the event pixmap because it takes up too much space
00321     //} else {
00322     //  p->drawPixmap( x, 0, mEventPixmap );
00323     //  x += mEventPixmap.width() + 2;
00324     //
00325     }
00326   }
00327 
00328   if ( mTodo ) {
00329     p->drawPixmap( x, 0, mTodoPixmap );
00330     x += mTodoPixmap.width() + 2;
00331   }
00332   if ( mTodoDone ) {
00333     p->drawPixmap( x, 0, mTodoDonePixmap );
00334     x += mTodoPixmap.width() + 2;
00335   }
00336   if ( mRecur && !specialEvent ) {
00337     p->drawPixmap( x, 0, mRecurPixmap );
00338     x += mRecurPixmap.width() + 2;
00339   }
00340   if ( mAlarm && !specialEvent ) {
00341     p->drawPixmap( x, 0, mAlarmPixmap );
00342     x += mAlarmPixmap.width() + 2;
00343   }
00344   if ( mReply ) {
00345     p->drawPixmap(x, 0, mReplyPixmap );
00346     x += mReplyPixmap.width() + 2;
00347   }
00348   QFontMetrics fm = p->fontMetrics();
00349   int yPos;
00350   int pmheight = QMAX( mRecurPixmap.height(),
00351                        QMAX( mAlarmPixmap.height(), mReplyPixmap.height() ) );
00352   if( pmheight < fm.height() )
00353     yPos = fm.ascent() + fm.leading()/2;
00354   else
00355     yPos = pmheight/2 - fm.height()/2  + fm.ascent();
00356   QColor textColor = getTextColor( bgColor );
00357   p->setPen( textColor );
00358 
00359   KWordWrap::drawFadeoutText( p, x, yPos, listBox()->width() - x, text() );
00360 }
00361 
00362 int MonthViewItem::height( const QListBox *lb ) const
00363 {
00364   return QMAX( QMAX( mRecurPixmap.height(), mReplyPixmap.height() ),
00365                QMAX( mAlarmPixmap.height(), lb->fontMetrics().lineSpacing()+1) );
00366 }
00367 
00368 int MonthViewItem::width( const QListBox *lb ) const
00369 {
00370   int x = 3;
00371   if( mRecur ) {
00372     x += mRecurPixmap.width()+2;
00373   }
00374   if( mAlarm ) {
00375     x += mAlarmPixmap.width()+2;
00376   }
00377   if( mReply ) {
00378     x += mReplyPixmap.width()+2;
00379   }
00380 
00381   return( x + lb->fontMetrics().boundingRect( text() ).width() + 1 );
00382 }
00383 
00384 
00385 MonthViewCell::MonthViewCell( KOMonthView *parent)
00386   : QWidget( parent ),
00387     mMonthView( parent ), mPrimary( false ), mHoliday( false )
00388 {
00389   QVBoxLayout *topLayout = new QVBoxLayout( this );
00390 
00391   mLabel = new QLabel( this );
00392   mLabel->setFrameStyle( QFrame::Panel | QFrame::Plain );
00393   mLabel->setLineWidth( 1 );
00394   mLabel->setAlignment( AlignCenter );
00395 
00396   mItemList = new KNoScrollListBox( this );
00397   mItemList->setMinimumSize( 10, 10 );
00398   mItemList->setFrameStyle( QFrame::Panel | QFrame::Plain );
00399   mItemList->setLineWidth( 1 );
00400 
00401   topLayout->addWidget( mItemList );
00402 
00403   mLabel->raise();
00404 
00405   mStandardPalette = palette();
00406 
00407   enableScrollBars( false );
00408 
00409   updateConfig();
00410 
00411   connect( mItemList, SIGNAL( doubleClicked( QListBoxItem *) ),
00412            SLOT( defaultAction( QListBoxItem * ) ) );
00413   connect( mItemList, SIGNAL( rightButtonPressed( QListBoxItem *,
00414                                                   const QPoint &) ),
00415            SLOT( contextMenu( QListBoxItem * ) ) );
00416   connect( mItemList, SIGNAL( clicked( QListBoxItem * ) ),
00417            SLOT( select() ) );
00418 }
00419 
00420 void MonthViewCell::setDate( const QDate &date )
00421 {
00422 //  kdDebug(5850) << "MonthViewCell::setDate(): " << date.toString() << endl;
00423 
00424   mDate = date;
00425 
00426   setFrameWidth();
00427 
00428   QString text;
00429   if ( KOGlobals::self()->calendarSystem()->day( date ) == 1 ) {
00430     text = i18n("'Month day' for month view cells", "%1 %2")
00431         .arg( KOGlobals::self()->calendarSystem()->monthName( date, true ) )
00432         .arg( KOGlobals::self()->calendarSystem()->day(mDate) );
00433     QFontMetrics fm( mLabel->font() );
00434     mLabel->resize( mLabelSize + QSize( fm.width( text ), 0 ) );
00435   } else {
00436     mLabel->resize( mLabelSize );
00437     text = QString::number( KOGlobals::self()->calendarSystem()->day(mDate) );
00438   }
00439   mLabel->setText( text );
00440 
00441   new KOMonthCellToolTip( mItemList->viewport(),
00442                           monthView()->calendar(),
00443                           mDate,
00444                           static_cast<KNoScrollListBox *>( mItemList ) );
00445 
00446   resizeEvent( 0 );
00447 }
00448 
00449 QDate MonthViewCell::date() const
00450 {
00451   return mDate;
00452 }
00453 
00454 void MonthViewCell::setFrameWidth()
00455 {
00456   // show current day with a thicker frame
00457   if ( mDate == QDate::currentDate() )
00458     mItemList->setLineWidth( 3 );
00459   else
00460     mItemList->setLineWidth( 1 );
00461 }
00462 
00463 void MonthViewCell::setPrimary( bool primary )
00464 {
00465   mPrimary = primary;
00466 
00467   if ( mPrimary ) {
00468     mLabel->setBackgroundMode( PaletteBase );
00469   } else {
00470     mLabel->setBackgroundMode( PaletteBackground );
00471   }
00472 
00473   mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) );
00474 }
00475 
00476 bool MonthViewCell::isPrimary() const
00477 {
00478   return mPrimary;
00479 }
00480 
00481 void MonthViewCell::setHoliday( bool holiday )
00482 {
00483   mHoliday = holiday;
00484 
00485   if ( holiday ) {
00486     setPalette( mHolidayPalette );
00487   } else {
00488     setPalette( mStandardPalette );
00489   }
00490 }
00491 
00492 void MonthViewCell::setHolidayString( const QString &holiday )
00493 {
00494   mHolidayString = holiday;
00495 }
00496 
00497 void MonthViewCell::updateCell()
00498 {
00499   setFrameWidth();
00500 
00501   if ( mDate == QDate::currentDate() ) {
00502     setPalette( mTodayPalette );
00503 
00504     QPalette pal = mItemList->palette();
00505     pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->highlightColor() );
00506     mItemList->setPalette( pal );
00507   }
00508   else {
00509     if ( mHoliday )
00510       setPalette( mHolidayPalette );
00511     else
00512       setPalette( mStandardPalette );
00513 
00514     QPalette pal = mItemList->palette();
00515     pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) );
00516     mItemList->setPalette( pal );
00517   }
00518 
00519   mItemList->clear();
00520 
00521   if ( !mHolidayString.isEmpty() ) {
00522     MonthViewItem *item = new MonthViewItem( 0, QDateTime( mDate ), mHolidayString );
00523     item->setPalette( mHolidayPalette );
00524     mItemList->insertItem( item );
00525   }
00526 }
00527 
00528 class MonthViewCell::CreateItemVisitor :
00529       public IncidenceBase::Visitor
00530 {
00531   public:
00532     CreateItemVisitor() : mItem(0) { emails = KOPrefs::instance()->allEmails(); }
00533 
00534     bool act( IncidenceBase *incidence, QDate date, QPalette stdPal, int multiDay )
00535     {
00536       mItem = 0;
00537       mDate = date;
00538       mStandardPalette = stdPal;
00539       mMultiDay = multiDay;
00540       return incidence->accept( *this );
00541     }
00542     MonthViewItem *item() const { return mItem; }
00543     QStringList emails;
00544 
00545   protected:
00546     bool visit( Event *event ) {
00547       QString text;
00548       QDateTime dt( mDate );
00549       // take the time 0:00 into account, which is non-inclusive
00550       QDate dtEnd = event->dtEnd().addSecs( event->doesFloat() ? 0 : -1).date();
00551       int length = event->dtStart().daysTo( dtEnd );
00552       if ( event->isMultiDay() ) {
00553         if (  mDate == event->dtStart().date()
00554            || ( mMultiDay == 0 && event->recursOn( mDate ) ) ) {
00555           text = "(-- " + event->summary();
00556           dt = event->dtStart();
00557         } else if ( !event->doesRecur() && mDate == dtEnd
00558                  // last day of a recurring multi-day event?
00559                  || ( mMultiDay == length && event->recursOn( mDate.addDays( -length ) ) ) ) {
00560           text = event->summary() + " --)";
00561         } else if (!(event->dtStart().date().daysTo(mDate) % 7) && length > 7 ) {
00562           text = "-- " + event->summary() + " --";
00563         } else {
00564           text = "----------------";
00565           dt = QDateTime( mDate );
00566         }
00567       } else {
00568         if (event->doesFloat())
00569           text = event->summary();
00570         else {
00571           text = KGlobal::locale()->formatTime(event->dtStart().time());
00572           dt.setTime( event->dtStart().time() );
00573           text += ' ' + event->summary();
00574         }
00575       }
00576 
00577       mItem = new MonthViewItem( event, dt, text );
00578       mItem->setEvent( true );
00579       if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryOnly ||
00580            KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
00581         QStringList categories = event->categories();
00582         QString cat = categories.first();
00583         if (cat.isEmpty()) {
00584           mItem->setPalette(QPalette(KOPrefs::instance()->unsetCategoryColor(),
00585                                      KOPrefs::instance()->unsetCategoryColor()) );
00586         } else {
00587           mItem->setPalette(QPalette(*(KOPrefs::instance()->categoryColor(cat)),
00588                                      *(KOPrefs::instance()->categoryColor(cat))));
00589         }
00590       } else {
00591         mItem->setPalette( mStandardPalette );
00592       }
00593 
00594       Attendee *me = event->attendeeByMails( emails );
00595       if ( me != 0 ) {
00596         mItem->setReply( me->status() == Attendee::NeedsAction && me->RSVP() );
00597       } else
00598         mItem->setReply(false);
00599       return true;
00600     }
00601     bool visit( Todo *todo ) {
00602       QString text;
00603       if ( !KOPrefs::instance()->showAllDayTodo() )
00604         return false;
00605       QDateTime dt( mDate );
00606       if ( todo->hasDueDate() && !todo->doesFloat() &&
00607            todo->dtDue().time() != QTime( 0,0 ) && todo->dtDue().time().isValid() ) {
00608         text += KGlobal::locale()->formatTime( todo->dtDue().time() );
00609         text += ' ';
00610         dt.setTime( todo->dtDue().time() );
00611       }
00612       text += todo->summary();
00613 
00614       mItem = new MonthViewItem( todo, dt, text );
00615       if ( todo->doesRecur() ) {
00616         mDate < todo->dtDue().date() ?
00617         mItem->setTodoDone( true ) : mItem->setTodo( true );
00618       }
00619       else
00620         todo->isCompleted() ? mItem->setTodoDone( true ) : mItem->setTodo( true );
00621       mItem->setPalette( mStandardPalette );
00622       return true;
00623     }
00624   protected:
00625     MonthViewItem *mItem;
00626     QDate mDate;
00627     QPalette mStandardPalette;
00628     int mMultiDay;
00629 };
00630 
00631 
00632 void MonthViewCell::addIncidence( Incidence *incidence, CreateItemVisitor& v, int multiDay )
00633 {
00634   if ( v.act( incidence, mDate, mStandardPalette, multiDay ) ) {
00635     MonthViewItem *item = v.item();
00636     if ( item ) {
00637       item->setAlarm( incidence->isAlarmEnabled() );
00638       item->setRecur( incidence->recurrenceType() );
00639 
00640       QColor resourceColor = KOHelper::resourceColor( monthView()->calendar(), incidence );
00641       if ( !resourceColor.isValid() )
00642         resourceColor = KOPrefs::instance()->unsetCategoryColor();
00643       item->setResourceColor( resourceColor );
00644 
00645       // FIXME: Find the correct position (time-wise) to insert the item.
00646       //        Currently, the items are displayed in "random" order instead of
00647       //        chronologically sorted.
00648       uint i = 0;
00649       int pos = -1;
00650       QDateTime dt( item->incidenceDateTime() );
00651 
00652       while ( i < mItemList->count() && pos<0 ) {
00653         QListBoxItem *item = mItemList->item( i );
00654         MonthViewItem *mvitem = dynamic_cast<MonthViewItem*>( item );
00655         if ( mvitem && mvitem->incidenceDateTime()>dt ) {
00656           pos = i;
00657         }
00658         ++i;
00659       }
00660       mItemList->insertItem( item, pos );
00661     }
00662   }
00663 }
00664 
00665 void MonthViewCell::removeIncidence( Incidence *incidence )
00666 {
00667   for ( uint i = 0; i < mItemList->count(); ++i ) {
00668     MonthViewItem *item = static_cast<MonthViewItem *>(mItemList->item( i ) );
00669     if ( item && item->incidence() &&
00670          item->incidence()->uid() == incidence->uid() ) {
00671       mItemList->removeItem( i );
00672       --i;
00673     }
00674   }
00675 }
00676 
00677 void MonthViewCell::updateConfig()
00678 {
00679   setFont( KOPrefs::instance()->mMonthViewFont );
00680 
00681   QFontMetrics fm( font() );
00682   mLabelSize = fm.size( 0, "30" ) +
00683                QSize( mLabel->frameWidth() * 2, mLabel->frameWidth() * 2 ) +
00684                QSize( 2, 2 );
00685 //  mStandardPalette = mOriginalPalette;
00686   QColor bg = mStandardPalette.color( QPalette::Active, QColorGroup::Background );
00687   int h,s,v;
00688   bg.getHsv( &h, &s, &v );
00689   if ( date().month() %2 == 0 ) {
00690     if ( v < 128 ) {
00691       bg = bg.light( 125 );
00692     } else {
00693       bg = bg.dark( 125 );
00694     }
00695   }
00696   setPaletteBackgroundColor( bg );
00697 //  mStandardPalette.setColor( QColorGroup::Background, bg);*/
00698 
00699   mHolidayPalette = mStandardPalette;
00700   mHolidayPalette.setColor( QColorGroup::Foreground,
00701                             KOPrefs::instance()->holidayColor() );
00702   mHolidayPalette.setColor( QColorGroup::Text,
00703                             KOPrefs::instance()->holidayColor() );
00704   mTodayPalette = mStandardPalette;
00705   mTodayPalette.setColor( QColorGroup::Foreground,
00706                           KOPrefs::instance()->highlightColor() );
00707   mTodayPalette.setColor( QColorGroup::Text,
00708                           KOPrefs::instance()->highlightColor() );
00709   updateCell();
00710 
00711   mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) );
00712 }
00713 
00714 void MonthViewCell::enableScrollBars( bool enabled )
00715 {
00716   if ( enabled ) {
00717     mItemList->setVScrollBarMode( QScrollView::Auto );
00718     mItemList->setHScrollBarMode( QScrollView::Auto );
00719   } else {
00720     mItemList->setVScrollBarMode( QScrollView::AlwaysOff );
00721     mItemList->setHScrollBarMode( QScrollView::AlwaysOff );
00722   }
00723 }
00724 
00725 Incidence *MonthViewCell::selectedIncidence()
00726 {
00727   int index = mItemList->currentItem();
00728   if ( index < 0 ) return 0;
00729 
00730   MonthViewItem *item =
00731       static_cast<MonthViewItem *>( mItemList->item( index ) );
00732 
00733   if ( !item ) return 0;
00734 
00735   return item->incidence();
00736 }
00737 
00738 QDate MonthViewCell::selectedIncidenceDate()
00739 {
00740   QDate qd;
00741   int index = mItemList->currentItem();
00742   if ( index < 0 ) return qd;
00743 
00744   MonthViewItem *item =
00745       static_cast<MonthViewItem *>( mItemList->item( index ) );
00746 
00747   if ( !item ) return qd;
00748 
00749   return item->incidenceDateTime().date();
00750 }
00751 
00752 void MonthViewCell::select()
00753 {
00754   // setSelectedCell will deselect currently selected cells
00755   mMonthView->setSelectedCell( this );
00756 
00757   if( KOPrefs::instance()->enableMonthScroll() )
00758     enableScrollBars( true );
00759 
00760   // don't mess up the cell when it represents today
00761   if( mDate != QDate::currentDate() ) {
00762     mItemList->setFrameStyle( QFrame::Sunken | QFrame::Panel );
00763     mItemList->setLineWidth( 3 );
00764   }
00765 }
00766 
00767 void MonthViewCell::deselect()
00768 {
00769   mItemList->clearSelection();
00770   mItemList->setFrameStyle( QFrame::Plain | QFrame::Panel );
00771   setFrameWidth();
00772 
00773   enableScrollBars( false );
00774 }
00775 
00776 void MonthViewCell::resizeEvent ( QResizeEvent * )
00777 {
00778   mLabel->move( width() - mLabel->width(), height() - mLabel->height() );
00779 }
00780 
00781 void MonthViewCell::defaultAction( QListBoxItem *item )
00782 {
00783   select();
00784 
00785   if ( !item ) {
00786     emit newEventSignal( 0/*ResourceCalendar*/, QString()/*subResource*/, date() );
00787   } else {
00788     MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
00789     Incidence *incidence = eventItem->incidence();
00790     if ( incidence ) mMonthView->defaultAction( incidence );
00791   }
00792 }
00793 
00794 void MonthViewCell::contextMenu( QListBoxItem *item )
00795 {
00796   select();
00797 
00798   if ( item ) {
00799     MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
00800     Incidence *incidence = eventItem->incidence();
00801     if ( incidence ) mMonthView->showEventContextMenu( monthView()->calendar(), incidence, date() );
00802   }
00803   else {
00804     mMonthView->showGeneralContextMenu();
00805   }
00806 }
00807 
00808 
00809 KOMonthView::KOMonthView( Calendar *calendar, QWidget *parent, const char *name )
00810     : KOEventView( calendar, parent, name ),
00811       mDaysPerWeek( 7 ), mNumWeeks( 6 ), mNumCells( mDaysPerWeek * mNumWeeks ),
00812       mShortDayLabels( false ), mWidthLongDayLabel( 0 ), mSelectedCell( 0 )
00813 {
00814   mCells.setAutoDelete( true );
00815 
00816   QGridLayout *dayLayout = new QGridLayout( this );
00817 
00818   QFont bfont = font();
00819   bfont.setBold( true );
00820 
00821   QFont mfont = bfont;
00822   mfont.setPointSize( 20 );
00823 
00824   // month name on top
00825   mLabel = new QLabel( this );
00826   mLabel->setFont( mfont );
00827   mLabel->setAlignment( AlignCenter );
00828   mLabel->setLineWidth( 0 );
00829   mLabel->setFrameStyle( QFrame::Plain );
00830 
00831   dayLayout->addMultiCellWidget( mLabel, 0, 0, 0, mDaysPerWeek );
00832 
00833   // create the day of the week labels (Sun, Mon, etc) and add them to
00834   // the layout.
00835   mDayLabels.resize( mDaysPerWeek );
00836   int i;
00837   for( i = 0; i < mDaysPerWeek; i++ ) {
00838     QLabel *label = new QLabel( this );
00839     label->setFont( bfont );
00840     label->setFrameStyle( QFrame::Panel | QFrame::Raised );
00841     label->setLineWidth( 1 );
00842     label->setAlignment( AlignCenter );
00843 
00844     mDayLabels.insert( i, label );
00845 
00846     dayLayout->addWidget( label, 1, i );
00847     dayLayout->addColSpacing( i, 10 );
00848     dayLayout->setColStretch( i, 1 );
00849   }
00850 
00851   int row, col;
00852 
00853   mCells.resize( mNumCells );
00854   for( row = 0; row < mNumWeeks; ++row ) {
00855     for( col = 0; col < mDaysPerWeek; ++col ) {
00856       MonthViewCell *cell = new MonthViewCell( this );
00857       mCells.insert( row * mDaysPerWeek + col, cell );
00858       dayLayout->addWidget( cell, row + 2, col );
00859 
00860       connect( cell, SIGNAL(defaultAction(Incidence *)),
00861                SLOT(defaultAction(Incidence *)) );
00862       connect( cell, SIGNAL(newEventSignal(ResourceCalendar *,const QString &,const QDate &)),
00863                SIGNAL(newEventSignal(ResourceCalendar *,const QString &,const QDate &)) );
00864     }
00865     dayLayout->setRowStretch( row + 2, 1 );
00866   }
00867 
00868   mEventContextMenu = eventPopup();
00869 
00870   updateConfig();
00871 
00872   emit incidenceSelected( 0, QDate() );
00873 }
00874 
00875 KOMonthView::~KOMonthView()
00876 {
00877   delete mEventContextMenu;
00878 }
00879 
00880 int KOMonthView::maxDatesHint()
00881 {
00882   return mNumCells;
00883 }
00884 
00885 int KOMonthView::currentDateCount()
00886 {
00887   return mNumCells;
00888 }
00889 
00890 Incidence::List KOMonthView::selectedIncidences()
00891 {
00892   Incidence::List selected;
00893 
00894   if ( mSelectedCell ) {
00895     Incidence *incidence = mSelectedCell->selectedIncidence();
00896     if ( incidence ) selected.append( incidence );
00897   }
00898 
00899   return selected;
00900 }
00901 
00902 DateList KOMonthView::selectedDates()
00903 {
00904   DateList selected;
00905 
00906   if ( mSelectedCell ) {
00907     QDate qd = mSelectedCell->selectedIncidenceDate();
00908     if ( qd.isValid() ) selected.append( qd );
00909   }
00910 
00911   return selected;
00912 }
00913 
00914 bool KOMonthView::eventDurationHint( QDateTime &startDt, QDateTime &endDt, bool &allDay )
00915 {
00916   if ( mSelectedCell ) {
00917     startDt.setDate( mSelectedCell->date() );
00918     endDt.setDate( mSelectedCell->date() );
00919     allDay = true;
00920     return true;
00921   }
00922   return false;
00923 }
00924 
00925 void KOMonthView::updateConfig()
00926 {
00927   mWeekStartDay = KGlobal::locale()->weekStartDay();
00928 
00929   QFontMetrics fontmetric( mDayLabels[0]->font() );
00930   mWidthLongDayLabel = 0;
00931 
00932   for ( int i = 0; i < 7; ++i ) {
00933     int width =
00934         fontmetric.width( KOGlobals::self()->calendarSystem()->weekDayName( i + 1 ) );
00935     if ( width > mWidthLongDayLabel ) mWidthLongDayLabel = width;
00936   }
00937 
00938   updateDayLabels();
00939 
00940   for ( uint i = 0; i < mCells.count(); ++i ) {
00941     mCells[i]->updateConfig();
00942   }
00943 }
00944 
00945 void KOMonthView::updateDayLabels()
00946 {
00947   kdDebug(5850) << "KOMonthView::updateDayLabels()" << endl;
00948 
00949   const KCalendarSystem*calsys=KOGlobals::self()->calendarSystem();
00950   int currDay;
00951   for ( int i = 0; i < 7; i++ ) {
00952     currDay = i+mWeekStartDay;
00953     if ( currDay > 7 ) currDay -= 7;
00954     mDayLabels[i]->setText( calsys->weekDayName( currDay, mShortDayLabels ) );
00955   }
00956 }
00957 
00958 void KOMonthView::showDates( const QDate &start, const QDate & )
00959 {
00960 //  kdDebug(5850) << "KOMonthView::showDates(): " << start.toString() << endl;
00961 
00962   const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
00963 
00964   mDateToCell.clear();
00965 
00966   // show first day of month on top for readability issues
00967   mStartDate = start.addDays( -start.day() + 1 );
00968   // correct begin of week
00969   int weekdayCol=( mStartDate.dayOfWeek() + 7 - mWeekStartDay ) % 7;
00970   mStartDate = mStartDate.addDays( -weekdayCol );
00971 
00972   mLabel->setText( i18n( "monthname year", "%1 %2" )
00973                    .arg( calSys->monthName( start ) )
00974                    .arg( calSys->year( start ) ) );
00975   if ( !KOPrefs::instance()->fullViewMonth() ) {
00976     mLabel->show();
00977   } else {
00978     mLabel->hide();
00979   }
00980 
00981   bool primary = false;
00982   uint i;
00983   for( i = 0; i < mCells.size(); ++i ) {
00984     QDate date = mStartDate.addDays( i );
00985     if ( calSys->day( date ) == 1 ) {
00986       primary = !primary;
00987     }
00988 
00989     mCells[i]->setDate( date );
00990     mDateToCell[ date ] = mCells[ i ];
00991     if( date == start )
00992       mCells[i]->select();
00993 
00994     mCells[i]->setPrimary( primary );
00995 
00996     bool isHoliday = calSys->dayOfWeek( date ) == calSys->weekDayOfPray()
00997                   || !KOGlobals::self()->isWorkDay( date );
00998     mCells[i]->setHoliday( isHoliday );
00999 
01000     // add holiday, if present
01001     QStringList holidays( KOGlobals::self()->holiday( date ) );
01002     mCells[i]->setHolidayString( holidays.join( i18n("delimiter for joining holiday names", ", " ) ) );
01003   }
01004 
01005   updateView();
01006 }
01007 
01008 void KOMonthView::showIncidences( const Incidence::List &, const QDate & )
01009 {
01010   kdDebug(5850) << "KOMonthView::showIncidences( const Incidence::List & ) is not implemented yet." << endl;
01011 }
01012 
01013 class KOMonthView::GetDateVisitor : public IncidenceBase::Visitor
01014 {
01015   public:
01016     GetDateVisitor() {}
01017 
01018     bool act( IncidenceBase *incidence )
01019     {
01020       return incidence->accept( *this );
01021     }
01022     QDateTime startDate() const { return mStartDate; }
01023     QDateTime endDate() const { return mEndDate; }
01024 
01025   protected:
01026     bool visit( Event *event ) {
01027       mStartDate = event->dtStart();
01028       mEndDate = event->dtEnd();
01029       return true;
01030     }
01031     bool visit( Todo *todo ) {
01032       if ( todo->hasDueDate() ) {
01033         if ( todo->dtDue().time() != QTime( 0, 0 ) &&
01034              todo->dtDue().time().isValid() ) {
01035           mStartDate = todo->dtDue();
01036           mEndDate = todo->dtDue();
01037         } else {
01038           mStartDate = QDateTime( todo->dtDue().date(), QTime( 23,59 ) );
01039           mEndDate = mStartDate;
01040         }
01041       }// else
01042 //         return false;
01043       return true;
01044     }
01045     bool visit( Journal *journal ) {
01046       mStartDate = journal->dtStart();
01047       mEndDate = journal->dtStart();
01048       return true;
01049     }
01050   protected:
01051     QDateTime mStartDate;
01052     QDateTime mEndDate;
01053 };
01054 
01055 void KOMonthView::changeIncidenceDisplayAdded( Incidence *incidence, MonthViewCell::CreateItemVisitor& v)
01056 {
01057   GetDateVisitor gdv;
01058 
01059   if ( !gdv.act( incidence ) ) {
01060     kdDebug(5850) << "Visiting GetDateVisitor failed." << endl;
01061     return;
01062   }
01063 
01064   bool floats = incidence->doesFloat();
01065 
01066   if ( incidence->doesRecur() ) {
01067     for ( uint i = 0; i < mCells.count(); ++i ) {
01068       if ( incidence->recursOn( mCells[i]->date() ) ) {
01069 
01070         // handle multiday events
01071         int length = gdv.startDate().daysTo( gdv.endDate().addSecs( floats ? 0 : -1 ).date() );
01072         for ( int j = 0; j <= length && i+j < mCells.count(); ++j ) {
01073           mCells[i+j]->addIncidence( incidence, v, j );
01074         }
01075       }
01076     }
01077   } else {
01078     // addSecs(-1) is added to handle 0:00 cases (because it's non-inclusive according to rfc)
01079     if ( gdv.endDate().isValid() ) {
01080       QDate endDate = gdv.endDate().addSecs( floats ? 0 : -1).date();
01081       for ( QDate date = gdv.startDate().date();
01082             date <= endDate; date = date.addDays( 1 ) ) {
01083         MonthViewCell *mvc = mDateToCell[ date ];
01084         if ( mvc ) mvc->addIncidence( incidence, v );
01085       }
01086     }
01087   }
01088 }
01089 
01090 void KOMonthView::changeIncidenceDisplay( Incidence *incidence, int action )
01091 {
01092   MonthViewCell::CreateItemVisitor v;
01093   switch ( action ) {
01094     case KOGlobals::INCIDENCEADDED:
01095       changeIncidenceDisplayAdded( incidence, v );
01096       break;
01097     case KOGlobals::INCIDENCEEDITED:
01098       for( uint i = 0; i < mCells.count(); i++ )
01099         mCells[i]->removeIncidence( incidence );
01100       changeIncidenceDisplayAdded( incidence, v );
01101       break;
01102     case KOGlobals::INCIDENCEDELETED:
01103       for( uint i = 0; i < mCells.count(); i++ )
01104         mCells[i]->removeIncidence( incidence );
01105       break;
01106     default:
01107       return;
01108   }
01109 }
01110 
01111 void KOMonthView::updateView()
01112 {
01113   for( uint i = 0; i < mCells.count(); ++i ) {
01114     mCells[i]->updateCell();
01115   }
01116 
01117   Incidence::List incidences = calendar()->incidences();
01118   Incidence::List::ConstIterator it;
01119 
01120   MonthViewCell::CreateItemVisitor v;
01121   for ( it = incidences.begin(); it != incidences.end(); ++it )
01122     changeIncidenceDisplayAdded( *it, v );
01123 
01124   processSelectionChange();
01125 }
01126 
01127 void KOMonthView::resizeEvent( QResizeEvent * )
01128 {
01129   // select the appropriate heading string size. E.g. "Wednesday" or "Wed".
01130   // note this only changes the text if the requested size crosses the
01131   // threshold between big enough to support the full name and not big
01132   // enough.
01133   if( mDayLabels[0]->width() < mWidthLongDayLabel ) {
01134     if ( !mShortDayLabels ) {
01135       mShortDayLabels = true;
01136       updateDayLabels();
01137     }
01138   } else {
01139     if ( mShortDayLabels ) {
01140       mShortDayLabels = false;
01141       updateDayLabels();
01142     }
01143   }
01144 }
01145 
01146 void KOMonthView::showEventContextMenu( Calendar *cal, Incidence *incidence, const QDate &qd )
01147 {
01148   mEventContextMenu->showIncidencePopup( cal, incidence, qd );
01149 }
01150 
01151 void KOMonthView::showGeneralContextMenu()
01152 {
01153   showNewEventPopup();
01154 }
01155 
01156 void KOMonthView::setSelectedCell( MonthViewCell *cell )
01157 {
01158   if ( mSelectedCell && cell != mSelectedCell )
01159     mSelectedCell->deselect();
01160 
01161   mSelectedCell = cell;
01162 
01163   if ( !mSelectedCell )
01164     emit incidenceSelected( 0, QDate() );
01165   else
01166     if ( selectedDates().isEmpty() ) {
01167       emit incidenceSelected( mSelectedCell->selectedIncidence(), QDate() );
01168     } else {
01169       emit incidenceSelected( mSelectedCell->selectedIncidence(), selectedDates().first() );
01170     }
01171 }
01172 
01173 void KOMonthView::processSelectionChange()
01174 {
01175   Incidence::List incidences = selectedIncidences();
01176   if (incidences.count() > 0) {
01177     if ( selectedDates().isEmpty() ) {
01178       emit incidenceSelected( incidences.first(), QDate() );
01179     } else {
01180       emit incidenceSelected( incidences.first(), selectedDates().first() );
01181     }
01182   } else {
01183     emit incidenceSelected( 0, QDate() );
01184   }
01185 }
01186 
01187 void KOMonthView::clearSelection()
01188 {
01189   if ( mSelectedCell ) {
01190     mSelectedCell->deselect();
01191     mSelectedCell = 0;
01192   }
01193 }
KDE Home | KDE Accessibility Home | Description of Access Keys