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