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