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