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