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