/* This file is part of KOrganizer. Copyright (c) 2000,2001 Cornelius Schumacher Copyright (C) 2003-2004 Reinhold Kainhofer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "koprefs.h" #include "koglobals.h" #include "koincidencetooltip.h" #include "koeventpopupmenu.h" #include "kohelper.h" #include "komonthview.h" #include "komonthview.moc" //-------------------------------------------------------------------------- KOMonthCellToolTip::KOMonthCellToolTip( QWidget *parent, KNoScrollListBox *lv ) : QToolTip( parent ) { eventlist = lv; } void KOMonthCellToolTip::maybeTip( const QPoint & pos ) { QRect r; QListBoxItem *it = eventlist->itemAt( pos ); MonthViewItem *i = static_cast( it ); if( i && KOPrefs::instance()->mEnableToolTips ) { /* Calculate the rectangle. */ r=eventlist->itemRect( it ); /* Show the tip */ QString tipText( IncidenceFormatter::toolTipString( i->incidence() ) ); if ( !tipText.isEmpty() ) { tip( r, tipText ); } } } KNoScrollListBox::KNoScrollListBox( QWidget *parent, const char *name ) : QListBox( parent, name ), mSqueezing( false ) { QPalette pal = palette(); pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) ); pal.setColor( QColorGroup::Base, KOPrefs::instance()->agendaBgColor() ); setPalette( pal ); } void KNoScrollListBox::setBackground( bool primary, bool workDay ) { QColor color; if ( workDay ) { color = KOPrefs::instance()->workingHoursColor(); } else { color = KOPrefs::instance()->agendaBgColor(); } QPalette pal = palette(); if ( primary ) { pal.setColor( QColorGroup::Base, color ); } else { pal.setColor( QColorGroup::Base, color.dark( 115 ) ); } setPalette( pal ); } void KNoScrollListBox::keyPressEvent( QKeyEvent *e ) { switch( e->key() ) { case Key_Right: scrollBy( 4, 0 ); break; case Key_Left: scrollBy( -4, 0 ); break; case Key_Up: if ( !count() ) break; setCurrentItem( ( currentItem() + count() - 1 ) % count() ); if ( !itemVisible( currentItem() ) ) { if ( (unsigned int)currentItem() == ( count() - 1 ) ) { setTopItem( currentItem() - numItemsVisible() + 1 ); } else { setTopItem( topItem() - 1 ); } } break; case Key_Down: if ( !count() ) break; setCurrentItem( ( currentItem() + 1 ) % count() ); if( !itemVisible( currentItem() ) ) { if( currentItem() == 0 ) { setTopItem( 0 ); } else { setTopItem( topItem() + 1 ); } } case Key_Shift: emit shiftDown(); break; default: break; } } void KNoScrollListBox::keyReleaseEvent( QKeyEvent *e ) { switch( e->key() ) { case Key_Shift: emit shiftUp(); break; default: break; } } void KNoScrollListBox::mousePressEvent( QMouseEvent *e ) { QListBox::mousePressEvent( e ); if ( e->button() == RightButton ) { emit rightClick(); } } void KNoScrollListBox::contentsMouseDoubleClickEvent ( QMouseEvent * e ) { QListBox::contentsMouseDoubleClickEvent( e ); QListBoxItem *item = itemAt( e->pos() ); if ( !item ) { emit doubleClicked( item ); } } void KNoScrollListBox::resizeEvent( QResizeEvent *e ) { bool s = count() && ( maxItemWidth() > e->size().width() ); if ( mSqueezing || s ) triggerUpdate( false ); mSqueezing = s; QListBox::resizeEvent( e ); } MonthViewItem::MonthViewItem( Incidence *incidence, const QDateTime &qd, const QString & s ) : QListBoxItem() { setText( s ); mIncidence = incidence; mDateTime = qd; mEventPixmap = KOGlobals::self()->smallIcon( "appointment" ); mTodoPixmap = KOGlobals::self()->smallIcon( "todo" ); mTodoDonePixmap = KOGlobals::self()->smallIcon( "checkedbox" ); mAlarmPixmap = KOGlobals::self()->smallIcon( "bell" ); mRecurPixmap = KOGlobals::self()->smallIcon( "recur" ); mReplyPixmap = KOGlobals::self()->smallIcon( "mail_reply" ); mResourceColor = QColor(); mEvent = false; mTodo = false; mTodoDone = false; mRecur = false; mAlarm = false; mReply = false; } void MonthViewItem::paint( QPainter *p ) { #if QT_VERSION >= 0x030000 bool sel = isSelected(); #else bool sel = selected(); #endif QColor bgColor = palette().color( QPalette::Normal, sel ? QColorGroup::Highlight : QColorGroup::Background ); int offset=0; if ( KOPrefs::instance()->monthViewUsesResourceColor() && mResourceColor.isValid() ) { p->setBackgroundColor( mResourceColor ); p->eraseRect( 0, 0, listBox()->maxItemWidth(), height( listBox() ) ); offset=2; } if ( KOPrefs::instance()->monthViewUsesCategoryColor() ) { p->setBackgroundColor( bgColor ); p->eraseRect( offset, offset, listBox()->maxItemWidth()-2*offset, height( listBox() )-2*offset ); } int x = 3; // Do NOT put on the event pixmap because it takes up too much space // if ( mEvent ) { // p->drawPixmap( x, 0, mEventPixmap ); // x += mEventPixmap.width() + 2; // } if ( mTodo ) { p->drawPixmap( x, 0, mTodoPixmap ); x += mTodoPixmap.width() + 2; } if ( mTodoDone ) { p->drawPixmap( x, 0, mTodoDonePixmap ); x += mTodoPixmap.width() + 2; } if ( mRecur ) { p->drawPixmap( x, 0, mRecurPixmap ); x += mRecurPixmap.width() + 2; } if ( mAlarm ) { p->drawPixmap( x, 0, mAlarmPixmap ); x += mAlarmPixmap.width() + 2; } if ( mReply ) { p->drawPixmap(x, 0, mReplyPixmap ); x += mReplyPixmap.width() + 2; } QFontMetrics fm = p->fontMetrics(); int yPos; int pmheight = QMAX( mRecurPixmap.height(), QMAX( mAlarmPixmap.height(), mReplyPixmap.height() ) ); if( pmheight < fm.height() ) yPos = fm.ascent() + fm.leading()/2; else yPos = pmheight/2 - fm.height()/2 + fm.ascent(); QColor textColor = getTextColor( bgColor ); p->setPen( textColor ); KWordWrap::drawFadeoutText( p, x, yPos, listBox()->width() - x, text() ); } int MonthViewItem::height( const QListBox *lb ) const { return QMAX( QMAX( mRecurPixmap.height(), mReplyPixmap.height() ), QMAX( mAlarmPixmap.height(), lb->fontMetrics().lineSpacing()+1) ); } int MonthViewItem::width( const QListBox *lb ) const { int x = 3; if( mRecur ) { x += mRecurPixmap.width()+2; } if( mAlarm ) { x += mAlarmPixmap.width()+2; } if( mReply ) { x += mReplyPixmap.width()+2; } return( x + lb->fontMetrics().boundingRect( text() ).width() + 1 ); } MonthViewCell::MonthViewCell( KOMonthView *parent) : QWidget( parent ), mMonthView( parent ), mPrimary( false ), mHoliday( false ) { QVBoxLayout *topLayout = new QVBoxLayout( this ); mLabel = new QLabel( this ); mLabel->setFrameStyle( QFrame::Panel | QFrame::Plain ); mLabel->setLineWidth( 1 ); mLabel->setAlignment( AlignCenter ); mItemList = new KNoScrollListBox( this ); mItemList->setMinimumSize( 10, 10 ); mItemList->setFrameStyle( QFrame::Panel | QFrame::Plain ); mItemList->setLineWidth( 1 ); new KOMonthCellToolTip( mItemList->viewport(), static_cast( mItemList ) ); topLayout->addWidget( mItemList ); mLabel->raise(); mStandardPalette = palette(); enableScrollBars( false ); updateConfig(); connect( mItemList, SIGNAL( doubleClicked( QListBoxItem *) ), SLOT( defaultAction( QListBoxItem * ) ) ); connect( mItemList, SIGNAL( rightButtonPressed( QListBoxItem *, const QPoint &) ), SLOT( contextMenu( QListBoxItem * ) ) ); connect( mItemList, SIGNAL( clicked( QListBoxItem * ) ), SLOT( select() ) ); } void MonthViewCell::setDate( const QDate &date ) { // kdDebug(5850) << "MonthViewCell::setDate(): " << date.toString() << endl; mDate = date; setFrameWidth(); QString text; if ( KOGlobals::self()->calendarSystem()->day( date ) == 1 ) { text = i18n("'Month day' for month view cells", "%1 %2") .arg( KOGlobals::self()->calendarSystem()->monthName( date, true ) ) .arg( KOGlobals::self()->calendarSystem()->day(mDate) ); QFontMetrics fm( mLabel->font() ); mLabel->resize( mLabelSize + QSize( fm.width( text ), 0 ) ); } else { mLabel->resize( mLabelSize ); text = QString::number( KOGlobals::self()->calendarSystem()->day(mDate) ); } mLabel->setText( text ); resizeEvent( 0 ); } QDate MonthViewCell::date() const { return mDate; } void MonthViewCell::setFrameWidth() { // show current day with a thicker frame if ( mDate == QDate::currentDate() ) mItemList->setLineWidth( 3 ); else mItemList->setLineWidth( 1 ); } void MonthViewCell::setPrimary( bool primary ) { mPrimary = primary; if ( mPrimary ) { mLabel->setBackgroundMode( PaletteBase ); } else { mLabel->setBackgroundMode( PaletteBackground ); } mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) ); } bool MonthViewCell::isPrimary() const { return mPrimary; } void MonthViewCell::setHoliday( bool holiday ) { mHoliday = holiday; if ( holiday ) { setPalette( mHolidayPalette ); } else { setPalette( mStandardPalette ); } } void MonthViewCell::setHolidayString( const QString &holiday ) { mHolidayString = holiday; } void MonthViewCell::updateCell() { setFrameWidth(); if ( mDate == QDate::currentDate() ) { setPalette( mTodayPalette ); QPalette pal = mItemList->palette(); pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->highlightColor() ); mItemList->setPalette( pal ); } else { if ( mHoliday ) setPalette( mHolidayPalette ); else setPalette( mStandardPalette ); QPalette pal = mItemList->palette(); pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) ); mItemList->setPalette( pal ); } mItemList->clear(); if ( !mHolidayString.isEmpty() ) { MonthViewItem *item = new MonthViewItem( 0, QDateTime( mDate ), mHolidayString ); item->setPalette( mHolidayPalette ); mItemList->insertItem( item ); } } class MonthViewCell::CreateItemVisitor : public IncidenceBase::Visitor { public: CreateItemVisitor() : mItem(0) { emails = KOPrefs::instance()->allEmails(); } bool act( IncidenceBase *incidence, QDate date, QPalette stdPal, int multiDay ) { mItem = 0; mDate = date; mStandardPalette = stdPal; mMultiDay = multiDay; return incidence->accept( *this ); } MonthViewItem *item() const { return mItem; } QStringList emails; protected: bool visit( Event *event ) { QString text; QDateTime dt( mDate ); // take the time 0:00 into account, which is non-inclusive QDate dtEnd = event->dtEnd().addSecs( event->doesFloat() ? 0 : -1).date(); int length = event->dtStart().daysTo( dtEnd ); if ( event->isMultiDay() ) { if ( mDate == event->dtStart().date() || ( mMultiDay == 0 && event->recursOn( mDate ) ) ) { text = "(-- " + event->summary(); dt = event->dtStart(); } else if ( !event->doesRecur() && mDate == dtEnd // last day of a recurring multi-day event? || ( mMultiDay == length && event->recursOn( mDate.addDays( -length ) ) ) ) { text = event->summary() + " --)"; } else if (!(event->dtStart().date().daysTo(mDate) % 7) && length > 7 ) { text = "-- " + event->summary() + " --"; } else { text = "----------------"; dt = QDateTime( mDate ); } } else { if (event->doesFloat()) text = event->summary(); else { text = KGlobal::locale()->formatTime(event->dtStart().time()); dt.setTime( event->dtStart().time() ); text += ' ' + event->summary(); } } mItem = new MonthViewItem( event, dt, text ); mItem->setEvent( true ); if (KOPrefs::instance()->monthViewUsesCategoryColor()) { QStringList categories = event->categories(); QString cat = categories.first(); if (cat.isEmpty()) { mItem->setPalette(QPalette(KOPrefs::instance()->mEventColor, KOPrefs::instance()->mEventColor)); } else { mItem->setPalette(QPalette(*(KOPrefs::instance()->categoryColor(cat)), *(KOPrefs::instance()->categoryColor(cat)))); } } else { mItem->setPalette( mStandardPalette ); } Attendee *me = event->attendeeByMails( emails ); if ( me != 0 ) { mItem->setReply( me->status() == Attendee::NeedsAction && me->RSVP() ); } else mItem->setReply(false); return true; } bool visit( Todo *todo ) { QString text; if ( !KOPrefs::instance()->showAllDayTodo() ) return false; QDateTime dt( mDate ); if ( todo->hasDueDate() && !todo->doesFloat() ) { text += KGlobal::locale()->formatTime( todo->dtDue().time() ); text += ' '; dt.setTime( todo->dtDue().time() ); } text += todo->summary(); mItem = new MonthViewItem( todo, dt, text ); if ( todo->doesRecur() ) { mDate < todo->dtDue().date() ? mItem->setTodoDone( true ) : mItem->setTodo( true ); } else todo->isCompleted() ? mItem->setTodoDone( true ) : mItem->setTodo( true ); mItem->setPalette( mStandardPalette ); return true; } protected: MonthViewItem *mItem; QDate mDate; QPalette mStandardPalette; int mMultiDay; }; void MonthViewCell::addIncidence( Incidence *incidence, CreateItemVisitor& v, int multiDay ) { if ( v.act( incidence, mDate, mStandardPalette, multiDay ) ) { MonthViewItem *item = v.item(); if ( item ) { item->setAlarm( incidence->isAlarmEnabled() ); item->setRecur( incidence->recurrenceType() ); QColor resourceColor = KOHelper::resourceColor( mCalendar, incidence ); if ( !resourceColor.isValid() ) resourceColor = KOPrefs::instance()->mEventColor; item->setResourceColor( resourceColor ); // FIXME: Find the correct position (time-wise) to insert the item. // Currently, the items are displayed in "random" order instead of // chronologically sorted. uint i = 0; int pos = -1; QDateTime dt( item->incidenceDateTime() ); while ( i < mItemList->count() && pos<0 ) { QListBoxItem *item = mItemList->item( i ); MonthViewItem *mvitem = dynamic_cast( item ); if ( mvitem && mvitem->incidenceDateTime()>dt ) { pos = i; } ++i; } mItemList->insertItem( item, pos ); } } } void MonthViewCell::removeIncidence( Incidence *incidence ) { for ( uint i = 0; i < mItemList->count(); ++i ) { MonthViewItem *item = static_cast(mItemList->item( i ) ); if ( item && item->incidence() && item->incidence()->uid() == incidence->uid() ) { mItemList->removeItem( i ); --i; } } } void MonthViewCell::updateConfig() { setFont( KOPrefs::instance()->mMonthViewFont ); QFontMetrics fm( font() ); mLabelSize = fm.size( 0, "30" ) + QSize( mLabel->frameWidth() * 2, mLabel->frameWidth() * 2 ) + QSize( 2, 2 ); // mStandardPalette = mOriginalPalette; QColor bg = mStandardPalette.color( QPalette::Active, QColorGroup::Background ); int h,s,v; bg.getHsv( &h, &s, &v ); if ( date().month() %2 == 0 ) { if ( v < 128 ) { bg = bg.light( 125 ); } else { bg = bg.dark( 125 ); } } setPaletteBackgroundColor( bg ); // mStandardPalette.setColor( QColorGroup::Background, bg);*/ mHolidayPalette = mStandardPalette; mHolidayPalette.setColor( QColorGroup::Foreground, KOPrefs::instance()->holidayColor() ); mHolidayPalette.setColor( QColorGroup::Text, KOPrefs::instance()->holidayColor() ); mTodayPalette = mStandardPalette; mTodayPalette.setColor( QColorGroup::Foreground, KOPrefs::instance()->highlightColor() ); mTodayPalette.setColor( QColorGroup::Text, KOPrefs::instance()->highlightColor() ); updateCell(); mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) ); } void MonthViewCell::enableScrollBars( bool enabled ) { if ( enabled ) { mItemList->setVScrollBarMode( QScrollView::Auto ); mItemList->setHScrollBarMode( QScrollView::Auto ); } else { mItemList->setVScrollBarMode( QScrollView::AlwaysOff ); mItemList->setHScrollBarMode( QScrollView::AlwaysOff ); } } Incidence *MonthViewCell::selectedIncidence() { int index = mItemList->currentItem(); if ( index < 0 ) return 0; MonthViewItem *item = static_cast( mItemList->item( index ) ); if ( !item ) return 0; return item->incidence(); } QDate MonthViewCell::selectedIncidenceDate() { QDate qd; int index = mItemList->currentItem(); if ( index < 0 ) return qd; MonthViewItem *item = static_cast( mItemList->item( index ) ); if ( !item ) return qd; return item->incidenceDateTime().date(); } void MonthViewCell::select() { // setSelectedCell will deselect currently selected cells mMonthView->setSelectedCell( this ); if( KOPrefs::instance()->enableMonthScroll() ) enableScrollBars( true ); // don't mess up the cell when it represents today if( mDate != QDate::currentDate() ) { mItemList->setFrameStyle( QFrame::Sunken | QFrame::Panel ); mItemList->setLineWidth( 3 ); } } void MonthViewCell::deselect() { mItemList->clearSelection(); mItemList->setFrameStyle( QFrame::Plain | QFrame::Panel ); setFrameWidth(); enableScrollBars( false ); } void MonthViewCell::resizeEvent ( QResizeEvent * ) { mLabel->move( width() - mLabel->width(), height() - mLabel->height() ); } void MonthViewCell::defaultAction( QListBoxItem *item ) { select(); if ( !item ) { emit newEventSignal( date() ); } else { MonthViewItem *eventItem = static_cast( item ); Incidence *incidence = eventItem->incidence(); if ( incidence ) mMonthView->defaultAction( incidence ); } } void MonthViewCell::contextMenu( QListBoxItem *item ) { select(); if ( item ) { MonthViewItem *eventItem = static_cast( item ); Incidence *incidence = eventItem->incidence(); if ( incidence ) mMonthView->showEventContextMenu( incidence, date() ); } else { mMonthView->showGeneralContextMenu(); } } KOMonthView::KOMonthView( Calendar *calendar, QWidget *parent, const char *name ) : KOEventView( calendar, parent, name ), mDaysPerWeek( 7 ), mNumWeeks( 6 ), mNumCells( mDaysPerWeek * mNumWeeks ), mShortDayLabels( false ), mWidthLongDayLabel( 0 ), mSelectedCell( 0 ) { mCells.setAutoDelete( true ); QGridLayout *dayLayout = new QGridLayout( this ); QFont bfont = font(); bfont.setBold( true ); QFont mfont = bfont; mfont.setPointSize( 20 ); // month name on top mLabel = new QLabel( this ); mLabel->setFont( mfont ); mLabel->setAlignment( AlignCenter ); mLabel->setLineWidth( 0 ); mLabel->setFrameStyle( QFrame::Plain ); dayLayout->addMultiCellWidget( mLabel, 0, 0, 0, mDaysPerWeek ); // create the day of the week labels (Sun, Mon, etc) and add them to // the layout. mDayLabels.resize( mDaysPerWeek ); int i; for( i = 0; i < mDaysPerWeek; i++ ) { QLabel *label = new QLabel( this ); label->setFont( bfont ); label->setFrameStyle( QFrame::Panel | QFrame::Raised ); label->setLineWidth( 1 ); label->setAlignment( AlignCenter ); mDayLabels.insert( i, label ); dayLayout->addWidget( label, 1, i ); dayLayout->addColSpacing( i, 10 ); dayLayout->setColStretch( i, 1 ); } int row, col; mCells.resize( mNumCells ); for( row = 0; row < mNumWeeks; ++row ) { for( col = 0; col < mDaysPerWeek; ++col ) { MonthViewCell *cell = new MonthViewCell( this ); cell->setCalendar(calendar); mCells.insert( row * mDaysPerWeek + col, cell ); dayLayout->addWidget( cell, row + 2, col ); connect( cell, SIGNAL( defaultAction( Incidence * ) ), SLOT( defaultAction( Incidence * ) ) ); connect( cell, SIGNAL( newEventSignal( const QDate & ) ), SIGNAL( newEventSignal( const QDate & ) ) ); } dayLayout->setRowStretch( row + 2, 1 ); } mEventContextMenu = eventPopup(); updateConfig(); emit incidenceSelected( 0 ); } KOMonthView::~KOMonthView() { delete mEventContextMenu; } int KOMonthView::maxDatesHint() { return mNumCells; } int KOMonthView::currentDateCount() { return mNumCells; } Incidence::List KOMonthView::selectedIncidences() { Incidence::List selected; if ( mSelectedCell ) { Incidence *incidence = mSelectedCell->selectedIncidence(); if ( incidence ) selected.append( incidence ); } return selected; } DateList KOMonthView::selectedDates() { DateList selected; if ( mSelectedCell ) { QDate qd = mSelectedCell->selectedIncidenceDate(); if ( qd.isValid() ) selected.append( qd ); } return selected; } bool KOMonthView::eventDurationHint( QDateTime &startDt, QDateTime &endDt, bool &allDay ) { if ( mSelectedCell ) { startDt.setDate( mSelectedCell->date() ); endDt.setDate( mSelectedCell->date() ); allDay = true; return true; } return false; } void KOMonthView::updateConfig() { mWeekStartDay = KGlobal::locale()->weekStartDay(); QFontMetrics fontmetric( mDayLabels[0]->font() ); mWidthLongDayLabel = 0; for ( int i = 0; i < 7; ++i ) { int width = fontmetric.width( KOGlobals::self()->calendarSystem()->weekDayName( i + 1 ) ); if ( width > mWidthLongDayLabel ) mWidthLongDayLabel = width; } updateDayLabels(); for ( uint i = 0; i < mCells.count(); ++i ) { mCells[i]->updateConfig(); } } void KOMonthView::updateDayLabels() { kdDebug(5850) << "KOMonthView::updateDayLabels()" << endl; const KCalendarSystem*calsys=KOGlobals::self()->calendarSystem(); int currDay; for ( int i = 0; i < 7; i++ ) { currDay = i+mWeekStartDay; if ( currDay > 7 ) currDay -= 7; mDayLabels[i]->setText( calsys->weekDayName( currDay, mShortDayLabels ) ); } } void KOMonthView::showDates( const QDate &start, const QDate & ) { // kdDebug(5850) << "KOMonthView::showDates(): " << start.toString() << endl; const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem(); mDateToCell.clear(); // show first day of month on top for readability issues mStartDate = start.addDays( -start.day() + 1 ); // correct begin of week int weekdayCol=( mStartDate.dayOfWeek() + 7 - mWeekStartDay ) % 7; mStartDate = mStartDate.addDays( -weekdayCol ); mLabel->setText( i18n( "monthname year", "%1 %2" ) .arg( calSys->monthName( start ) ) .arg( calSys->year( start ) ) ); if ( !KOPrefs::instance()->fullViewMonth() ) { mLabel->show(); } else { mLabel->hide(); } bool primary = false; uint i; for( i = 0; i < mCells.size(); ++i ) { QDate date = mStartDate.addDays( i ); if ( calSys->day( date ) == 1 ) { primary = !primary; } mCells[i]->setDate( date ); mDateToCell[ date ] = mCells[ i ]; if( date == start ) mCells[i]->select(); mCells[i]->setPrimary( primary ); bool isHoliday = calSys->dayOfWeek( date ) == calSys->weekDayOfPray() || !KOGlobals::self()->isWorkDay( date ); mCells[i]->setHoliday( isHoliday ); // add holiday, if present QStringList holidays( KOGlobals::self()->holiday( date ) ); mCells[i]->setHolidayString( holidays.join( i18n("delimiter for joining holiday names", ", " ) ) ); } updateView(); } void KOMonthView::showIncidences( const Incidence::List & ) { kdDebug(5850) << "KOMonthView::showIncidences( const Incidence::List & ) is not implemented yet." << endl; } class KOMonthView::GetDateVisitor : public IncidenceBase::Visitor { public: GetDateVisitor() {} bool act( IncidenceBase *incidence ) { return incidence->accept( *this ); } QDateTime startDate() const { return mStartDate; } QDateTime endDate() const { return mEndDate; } protected: bool visit( Event *event ) { mStartDate = event->dtStart(); mEndDate = event->dtEnd(); return true; } bool visit( Todo *todo ) { if ( todo->hasDueDate() ) { mStartDate = todo->dtDue(); mEndDate = todo->dtDue(); }// else // return false; return true; } bool visit( Journal *journal ) { mStartDate = journal->dtStart(); mEndDate = journal->dtStart(); return true; } protected: QDateTime mStartDate; QDateTime mEndDate; }; void KOMonthView::changeIncidenceDisplayAdded( Incidence *incidence, MonthViewCell::CreateItemVisitor& v) { GetDateVisitor gdv; if ( !gdv.act( incidence ) ) { kdDebug(5850) << "Visiting GetDateVisitor failed." << endl; return; } bool floats = incidence->doesFloat(); if ( incidence->doesRecur() ) { for ( uint i = 0; i < mCells.count(); ++i ) { if ( incidence->recursOn( mCells[i]->date() ) ) { // handle multiday events int length = gdv.startDate().daysTo( gdv.endDate().addSecs( floats ? 0 : -1 ).date() ); for ( int j = 0; j <= length && i+j < mCells.count(); ++j ) { mCells[i+j]->addIncidence( incidence, v, j ); } } } } else { // addSecs(-1) is added to handle 0:00 cases (because it's non-inclusive according to rfc) if ( gdv.endDate().isValid() ) { QDate endDate = gdv.endDate().addSecs( floats ? 0 : -1).date(); for ( QDate date = gdv.startDate().date(); date <= endDate; date = date.addDays( 1 ) ) { MonthViewCell *mvc = mDateToCell[ date ]; if ( mvc ) mvc->addIncidence( incidence, v ); } } } } void KOMonthView::changeIncidenceDisplay( Incidence *incidence, int action ) { MonthViewCell::CreateItemVisitor v; switch ( action ) { case KOGlobals::INCIDENCEADDED: changeIncidenceDisplayAdded( incidence, v ); break; case KOGlobals::INCIDENCEEDITED: for( uint i = 0; i < mCells.count(); i++ ) mCells[i]->removeIncidence( incidence ); changeIncidenceDisplayAdded( incidence, v ); break; case KOGlobals::INCIDENCEDELETED: for( uint i = 0; i < mCells.count(); i++ ) mCells[i]->removeIncidence( incidence ); break; default: return; } } void KOMonthView::updateView() { for( uint i = 0; i < mCells.count(); ++i ) { mCells[i]->updateCell(); } Incidence::List incidences = calendar()->incidences(); Incidence::List::ConstIterator it; MonthViewCell::CreateItemVisitor v; for ( it = incidences.begin(); it != incidences.end(); ++it ) changeIncidenceDisplayAdded( *it, v ); processSelectionChange(); } void KOMonthView::resizeEvent( QResizeEvent * ) { // select the appropriate heading string size. E.g. "Wednesday" or "Wed". // note this only changes the text if the requested size crosses the // threshold between big enough to support the full name and not big // enough. if( mDayLabels[0]->width() < mWidthLongDayLabel ) { if ( !mShortDayLabels ) { mShortDayLabels = true; updateDayLabels(); } } else { if ( mShortDayLabels ) { mShortDayLabels = false; updateDayLabels(); } } } void KOMonthView::showEventContextMenu( Incidence *incidence, const QDate &qd ) { mEventContextMenu->showIncidencePopup( incidence, qd ); } void KOMonthView::showGeneralContextMenu() { showNewEventPopup(); } void KOMonthView::setSelectedCell( MonthViewCell *cell ) { if ( mSelectedCell && cell != mSelectedCell ) mSelectedCell->deselect(); mSelectedCell = cell; if ( !mSelectedCell ) emit incidenceSelected( 0 ); else emit incidenceSelected( mSelectedCell->selectedIncidence() ); } void KOMonthView::processSelectionChange() { Incidence::List incidences = selectedIncidences(); if (incidences.count() > 0) { emit incidenceSelected( incidences.first() ); } else { emit incidenceSelected( 0 ); } } void KOMonthView::clearSelection() { if ( mSelectedCell ) { mSelectedCell->deselect(); mSelectedCell = 0; } }