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