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