diff --git a/korganizer/koagendaview.cpp b/korganizer/koagendaview.cpp index cc5dec93e5..a540efda3b 100644 --- a/korganizer/koagendaview.cpp +++ b/korganizer/koagendaview.cpp @@ -1,1630 +1,1630 @@ /* This file is part of KOrganizer. Copyright (c) 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 #ifndef KORG_NOSPLITTER #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "koglobals.h" #ifndef KORG_NOPLUGINS #include "kocore.h" #endif #include "koprefs.h" #include "koagenda.h" #include "koagendaitem.h" #include "timelabels.h" #include "koincidencetooltip.h" #include "kogroupware.h" #include "kodialogmanager.h" #include "koeventpopupmenu.h" #include "koagendaview.h" #include "koagendaview.moc" using namespace KOrg; EventIndicator::EventIndicator(Location loc,QWidget *parent,const char *name) : QFrame(parent,name) { mColumns = 1; mEnabled.resize( mColumns ); mLocation = loc; if (mLocation == Top) mPixmap = KOGlobals::self()->smallIcon("upindicator"); else mPixmap = KOGlobals::self()->smallIcon("downindicator"); setMinimumHeight(mPixmap.height()); } EventIndicator::~EventIndicator() { } void EventIndicator::drawContents(QPainter *p) { // kdDebug(5850) << "======== top: " << contentsRect().top() << " bottom " // << contentsRect().bottom() << " left " << contentsRect().left() // << " right " << contentsRect().right() << endl; int i; for(i=0;ireverseLayout() ? (mColumns - 1 - i)*cellWidth + cellWidth/2 -mPixmap.width()/2 : i*cellWidth + cellWidth/2 -mPixmap.width()/2; p->drawPixmap(QPoint(xOffset,0),mPixmap); } } } void EventIndicator::changeColumns(int columns) { mColumns = columns; mEnabled.resize(mColumns); update(); } void EventIndicator::enableColumn(int column, bool enable) { mEnabled[column] = enable; } #include //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// KOAlternateLabel::KOAlternateLabel(const QString &shortlabel, const QString &longlabel, const QString &extensivelabel, QWidget *parent, const char *name ) : QLabel(parent, name), mTextTypeFixed(false), mShortText(shortlabel), mLongText(longlabel), mExtensiveText(extensivelabel) { setSizePolicy(QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed )); if (mExtensiveText.isEmpty()) mExtensiveText = mLongText; squeezeTextToLabel(); } KOAlternateLabel::~KOAlternateLabel() { } void KOAlternateLabel::useShortText() { mTextTypeFixed = true; QLabel::setText( mShortText ); QToolTip::remove( this ); QToolTip::add( this, mExtensiveText ); } void KOAlternateLabel::useLongText() { mTextTypeFixed = true; QLabel::setText( mLongText ); QToolTip::remove( this ); QToolTip::add( this, mExtensiveText ); } void KOAlternateLabel::useExtensiveText() { mTextTypeFixed = true; QLabel::setText( mExtensiveText ); QToolTip::remove( this ); QToolTip::hide(); } void KOAlternateLabel::useDefaultText() { mTextTypeFixed = false; squeezeTextToLabel(); } void KOAlternateLabel::squeezeTextToLabel() { if (mTextTypeFixed) return; QFontMetrics fm(fontMetrics()); int labelWidth = size().width(); int textWidth = fm.width(mLongText); int longTextWidth = fm.width(mExtensiveText); if (longTextWidth <= labelWidth) { QLabel::setText( mExtensiveText ); QToolTip::remove( this ); QToolTip::hide(); } else if (textWidth <= labelWidth) { QLabel::setText( mLongText ); QToolTip::remove( this ); QToolTip::add( this, mExtensiveText ); } else { QLabel::setText( mShortText ); QToolTip::remove( this ); QToolTip::add( this, mExtensiveText ); } } void KOAlternateLabel::resizeEvent( QResizeEvent * ) { squeezeTextToLabel(); } QSize KOAlternateLabel::minimumSizeHint() const { QSize sh = QLabel::minimumSizeHint(); sh.setWidth(-1); return sh; } void KOAlternateLabel::setText( const QString &text ) { mLongText = text; squeezeTextToLabel(); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// KOAgendaView::KOAgendaView(Calendar *cal,QWidget *parent,const char *name, bool isSideBySide ) : KOrg::AgendaView (cal,parent,name), mExpandButton( 0 ), mAllowAgendaUpdate( true ), mUpdateItem( 0 ), mResource( 0 ), mIsSideBySide( isSideBySide ), mPendingChanges( true ) { mSelectedDates.append(QDate::currentDate()); mLayoutDayLabels = 0; mDayLabelsFrame = 0; mDayLabels = 0; bool isRTL = KOGlobals::self()->reverseLayout(); if ( KOPrefs::instance()->compactDialogs() ) { if ( KOPrefs::instance()->mVerticalScreen ) { mExpandedPixmap = KOGlobals::self()->smallIcon( "1downarrow" ); mNotExpandedPixmap = KOGlobals::self()->smallIcon( "1uparrow" ); } else { mExpandedPixmap = KOGlobals::self()->smallIcon( isRTL ? "1leftarrow" : "1rightarrow" ); mNotExpandedPixmap = KOGlobals::self()->smallIcon( isRTL ? "1rightarrow" : "1leftarrow" ); } } QBoxLayout *topLayout = new QVBoxLayout(this); // Create day name labels for agenda columns mDayLabelsFrame = new QHBox(this); topLayout->addWidget(mDayLabelsFrame); // Create agenda splitter #ifndef KORG_NOSPLITTER mSplitterAgenda = new QSplitter(Vertical,this); topLayout->addWidget(mSplitterAgenda); #if KDE_IS_VERSION( 3, 1, 93 ) mSplitterAgenda->setOpaqueResize( KGlobalSettings::opaqueResize() ); #else mSplitterAgenda->setOpaqueResize(); #endif mAllDayFrame = new QHBox(mSplitterAgenda); QWidget *agendaFrame = new QWidget(mSplitterAgenda); #else QVBox *mainBox = new QVBox( this ); topLayout->addWidget( mainBox ); mAllDayFrame = new QHBox(mainBox); QWidget *agendaFrame = new QWidget(mainBox); #endif // Create all-day agenda widget mDummyAllDayLeft = new QVBox( mAllDayFrame ); if ( isSideBySide ) mDummyAllDayLeft->hide(); if ( KOPrefs::instance()->compactDialogs() ) { mExpandButton = new QPushButton(mDummyAllDayLeft); mExpandButton->setPixmap( mNotExpandedPixmap ); mExpandButton->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); connect( mExpandButton, SIGNAL( clicked() ), SIGNAL( toggleExpand() ) ); } else { QLabel *label = new QLabel( i18n("All Day"), mDummyAllDayLeft ); label->setAlignment( Qt::AlignRight | Qt::AlignVCenter | Qt::WordBreak ); } mAllDayAgenda = new KOAgenda(1,mAllDayFrame); QWidget *dummyAllDayRight = new QWidget(mAllDayFrame); // Create agenda frame QGridLayout *agendaLayout = new QGridLayout(agendaFrame,3,3); // QHBox *agendaFrame = new QHBox(splitterAgenda); // create event indicator bars mEventIndicatorTop = new EventIndicator(EventIndicator::Top,agendaFrame); agendaLayout->addWidget(mEventIndicatorTop,0,1); mEventIndicatorBottom = new EventIndicator(EventIndicator::Bottom, agendaFrame); agendaLayout->addWidget(mEventIndicatorBottom,2,1); QWidget *dummyAgendaRight = new QWidget(agendaFrame); agendaLayout->addWidget(dummyAgendaRight,0,2); // Create time labels mTimeLabels = new TimeLabels(24,agendaFrame); agendaLayout->addWidget(mTimeLabels,1,0); // Create agenda mAgenda = new KOAgenda(1,96,KOPrefs::instance()->mHourSize,agendaFrame); agendaLayout->addMultiCellWidget(mAgenda,1,1,1,2); agendaLayout->setColStretch(1,1); // Create event context menu for agenda mAgendaPopup = eventPopup(); // Create event context menu for all day agenda mAllDayAgendaPopup = eventPopup(); // make connections between dependent widgets mTimeLabels->setAgenda(mAgenda); if ( isSideBySide ) mTimeLabels->hide(); // Update widgets to reflect user preferences // updateConfig(); createDayLabels(); if ( !isSideBySide ) { // these blank widgets make the All Day Event box line up with the agenda dummyAllDayRight->setFixedWidth(mAgenda->verticalScrollBar()->width()); dummyAgendaRight->setFixedWidth(mAgenda->verticalScrollBar()->width()); } updateTimeBarWidth(); // Scrolling connect(mAgenda->verticalScrollBar(),SIGNAL(valueChanged(int)), mTimeLabels, SLOT(positionChanged())); connect( mAgenda, SIGNAL( zoomView( const int, const QPoint & ,const Qt::Orientation ) ), SLOT( zoomView( const int, const QPoint &, const Qt::Orientation ) ) ); connect(mTimeLabels->verticalScrollBar(),SIGNAL(valueChanged(int)), SLOT(setContentsPos(int))); // Create Events, depends on type of agenda connect( mAgenda, SIGNAL(newTimeSpanSignal(const QPoint &, const QPoint &)), SLOT(newTimeSpanSelected(const QPoint &, const QPoint &))); connect( mAllDayAgenda, SIGNAL(newTimeSpanSignal(const QPoint &, const QPoint &)), SLOT(newTimeSpanSelectedAllDay(const QPoint &, const QPoint &))); // event indicator update connect( mAgenda, SIGNAL(lowerYChanged(int)), SLOT(updateEventIndicatorTop(int))); connect( mAgenda, SIGNAL(upperYChanged(int)), SLOT(updateEventIndicatorBottom(int))); connectAgenda( mAgenda, mAgendaPopup, mAllDayAgenda ); connectAgenda( mAllDayAgenda, mAllDayAgendaPopup, mAgenda); if ( cal ) { cal->registerObserver( this ); } } KOAgendaView::~KOAgendaView() { if ( calendar() ) calendar()->unregisterObserver( this ); delete mAgendaPopup; delete mAllDayAgendaPopup; } void KOAgendaView::connectAgenda( KOAgenda *agenda, QPopupMenu *popup, KOAgenda *otherAgenda ) { connect( agenda, SIGNAL( showIncidencePopupSignal( Incidence *, const QDate & ) ), popup, SLOT( showIncidencePopup( Incidence *, const QDate & ) ) ); connect( agenda, SIGNAL( showNewEventPopupSignal() ), SLOT( showNewEventPopup() ) ); agenda->setCalendar( calendar() ); // Create/Show/Edit/Delete Event connect( agenda, SIGNAL( newEventSignal() ), SIGNAL( newEventSignal() ) ); connect( agenda, SIGNAL( newStartSelectSignal() ), otherAgenda, SLOT( clearSelection() ) ); connect( agenda, SIGNAL( newStartSelectSignal() ), SIGNAL( timeSpanSelectionChanged()) ); connect( agenda, SIGNAL( editIncidenceSignal( Incidence * ) ), SIGNAL( editIncidenceSignal( Incidence * ) ) ); connect( agenda, SIGNAL( showIncidenceSignal( Incidence * ) ), SIGNAL( showIncidenceSignal( Incidence * ) ) ); connect( agenda, SIGNAL( deleteIncidenceSignal( Incidence * ) ), SIGNAL( deleteIncidenceSignal( Incidence * ) ) ); connect( agenda, SIGNAL( startMultiModify( const QString & ) ), SIGNAL( startMultiModify( const QString & ) ) ); connect( agenda, SIGNAL( endMultiModify() ), SIGNAL( endMultiModify() ) ); connect( agenda, SIGNAL( itemModified( KOAgendaItem * ) ), SLOT( updateEventDates( KOAgendaItem * ) ) ); connect( agenda, SIGNAL( enableAgendaUpdate( bool ) ), SLOT( enableAgendaUpdate( bool ) ) ); // drag signals connect( agenda, SIGNAL( startDragSignal( Incidence * ) ), SLOT( startDrag( Incidence * ) ) ); // synchronize selections connect( agenda, SIGNAL( incidenceSelected( Incidence * ) ), otherAgenda, SLOT( deselectItem() ) ); connect( agenda, SIGNAL( incidenceSelected( Incidence * ) ), SIGNAL( incidenceSelected( Incidence * ) ) ); // rescheduling of todos by d'n'd connect( agenda, SIGNAL( droppedToDo( Todo *, const QPoint &, bool ) ), SLOT( slotTodoDropped( Todo *, const QPoint &, bool ) ) ); } void KOAgendaView::zoomInVertically( ) { if ( !mIsSideBySide ) KOPrefs::instance()->mHourSize++; mAgenda->updateConfig(); mAgenda->checkScrollBoundaries(); mTimeLabels->updateConfig(); mTimeLabels->positionChanged(); mTimeLabels->repaint(); updateView(); } void KOAgendaView::zoomOutVertically( ) { if ( KOPrefs::instance()->mHourSize > 4 || mIsSideBySide ) { if ( !mIsSideBySide ) KOPrefs::instance()->mHourSize--; mAgenda->updateConfig(); mAgenda->checkScrollBoundaries(); mTimeLabels->updateConfig(); mTimeLabels->positionChanged(); mTimeLabels->repaint(); updateView(); } } void KOAgendaView::zoomInHorizontally( const QDate &date) { QDate begin; QDate newBegin; QDate dateToZoom = date; int ndays,count; begin = mSelectedDates.first(); ndays = begin.daysTo( mSelectedDates.last() ); // zoom with Action and are there a selected Incidence?, Yes, I zoom in to it. if ( ! dateToZoom.isValid () ) dateToZoom=mAgenda->selectedIncidenceDate(); if( !dateToZoom.isValid() ) { if ( ndays > 1 ) { newBegin=begin.addDays(1); count = ndays-1; emit zoomViewHorizontally ( newBegin , count ); } } else { if ( ndays <= 2 ) { newBegin = dateToZoom; count = 1; } else { newBegin = dateToZoom.addDays( -ndays/2 +1 ); count = ndays -1 ; } emit zoomViewHorizontally ( newBegin , count ); } } void KOAgendaView::zoomOutHorizontally( const QDate &date ) { QDate begin; QDate newBegin; QDate dateToZoom = date; int ndays,count; begin = mSelectedDates.first(); ndays = begin.daysTo( mSelectedDates.last() ); // zoom with Action and are there a selected Incidence?, Yes, I zoom out to it. if ( ! dateToZoom.isValid () ) dateToZoom=mAgenda->selectedIncidenceDate(); if ( !dateToZoom.isValid() ) { newBegin = begin.addDays(-1); count = ndays+3 ; } else { newBegin = dateToZoom.addDays( -ndays/2-1 ); count = ndays+3; } if ( abs( count ) >= 31 ) kdDebug(5850) << "change to the mounth view?"<selectedIncidenceDate(); if ( date.isValid() ) zoomDate=date; else{ if ( !t->isActive() ) { zoomDate= mSelectedDates[pos.x()]; } t->start ( 1000,true ); } if ( delta > 0 ) zoomOutHorizontally( zoomDate ); else zoomInHorizontally( zoomDate ); } else { // Vertical zoom QPoint posConstentsOld = mAgenda->gridToContents(pos); if ( delta > 0 ) { zoomOutVertically(); } else { zoomInVertically(); } QPoint posConstentsNew = mAgenda->gridToContents(pos); mAgenda->scrollBy( 0, posConstentsNew.y() - posConstentsOld.y() ); } } void KOAgendaView::createDayLabels() { // kdDebug(5850) << "KOAgendaView::createDayLabels()" << endl; // ### Before deleting and recreating we could check if mSelectedDates changed... // It would remove some flickering and gain speed (since this is called by // each updateView() call) delete mDayLabels; mDayLabels = new QFrame (mDayLabelsFrame); mLayoutDayLabels = new QHBoxLayout(mDayLabels); if ( !mIsSideBySide ) mLayoutDayLabels->addSpacing(mTimeLabels->width()); const KCalendarSystem*calsys=KOGlobals::self()->calendarSystem(); DateList::ConstIterator dit; for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) { QDate date = *dit; QBoxLayout *dayLayout = new QVBoxLayout(mLayoutDayLabels); mLayoutDayLabels->setStretchFactor(dayLayout, 1); // dayLayout->setMinimumWidth(1); int dW = calsys->dayOfWeek(date); QString veryLongStr = KGlobal::locale()->formatDate( date ); QString longstr = i18n( "short_weekday date (e.g. Mon 13)","%1 %2" ) .arg( calsys->weekDayName( dW, true ) ) .arg( calsys->day(date) ); QString shortstr = QString::number(calsys->day(date)); KOAlternateLabel *dayLabel = new KOAlternateLabel(shortstr, longstr, veryLongStr, mDayLabels); dayLabel->setMinimumWidth(1); dayLabel->setAlignment(QLabel::AlignHCenter); if (date == QDate::currentDate()) { QFont font = dayLabel->font(); font.setBold(true); dayLabel->setFont(font); } dayLayout->addWidget(dayLabel); // if a holiday region is selected, show the holiday name QStringList texts = KOGlobals::self()->holiday( date ); QStringList::ConstIterator textit = texts.begin(); for ( ; textit != texts.end(); ++textit ) { // use a KOAlternateLabel so when the text doesn't fit any more a tooltip is used KOAlternateLabel*label = new KOAlternateLabel( (*textit), (*textit), QString::null, mDayLabels ); label->setMinimumWidth(1); label->setAlignment(AlignCenter); dayLayout->addWidget(label); } #ifndef KORG_NOPLUGINS CalendarDecoration::List cds = KOCore::self()->calendarDecorations(); CalendarDecoration *it; for(it = cds.first(); it; it = cds.next()) { QString text = it->shortText( date ); if ( !text.isEmpty() ) { // use a KOAlternateLabel so when the text doesn't fit any more a tooltip is used KOAlternateLabel*label = new KOAlternateLabel( text, text, QString::null, mDayLabels ); label->setMinimumWidth(1); label->setAlignment(AlignCenter); dayLayout->addWidget(label); } } for(it = cds.first(); it; it = cds.next()) { QWidget *wid = it->smallWidget(mDayLabels,date); if ( wid ) { // wid->setHeight(20); dayLayout->addWidget(wid); } } #endif } if ( !mIsSideBySide ) mLayoutDayLabels->addSpacing(mAgenda->verticalScrollBar()->width()); mDayLabels->show(); } void KOAgendaView::enableAgendaUpdate( bool enable ) { mAllowAgendaUpdate = enable; } int KOAgendaView::maxDatesHint() { // Not sure about the max number of events, so return 0 for now. return 0; } int KOAgendaView::currentDateCount() { return mSelectedDates.count(); } Incidence::List KOAgendaView::selectedIncidences() { Incidence::List selected; Incidence *incidence; incidence = mAgenda->selectedIncidence(); if (incidence) selected.append(incidence); incidence = mAllDayAgenda->selectedIncidence(); if (incidence) selected.append(incidence); return selected; } DateList KOAgendaView::selectedDates() { DateList selected; QDate qd; qd = mAgenda->selectedIncidenceDate(); if (qd.isValid()) selected.append(qd); qd = mAllDayAgenda->selectedIncidenceDate(); if (qd.isValid()) selected.append(qd); return selected; } bool KOAgendaView::eventDurationHint( QDateTime &startDt, QDateTime &endDt, bool &allDay ) { if ( selectionStart().isValid() ) { QDateTime start = selectionStart(); QDateTime end = selectionEnd(); if ( start.secsTo( end ) == 15*60 ) { // One cell in the agenda view selected, e.g. // because of a double-click, => Use the default duration QTime defaultDuration( KOPrefs::instance()->mDefaultDuration.time() ); int addSecs = ( defaultDuration.hour()*3600 ) + ( defaultDuration.minute()*60 ); end = start.addSecs( addSecs ); } startDt = start; endDt = end; allDay = selectedIsAllDay(); return true; } return false; } /** returns if only a single cell is selected, or a range of cells */ bool KOAgendaView::selectedIsSingleCell() { if ( !selectionStart().isValid() || !selectionEnd().isValid() ) return false; if (selectedIsAllDay()) { int days = selectionStart().daysTo(selectionEnd()); return ( days < 1 ); } else { int secs = selectionStart().secsTo(selectionEnd()); return ( secs <= 24*60*60/mAgenda->rows() ); } } void KOAgendaView::updateView() { // kdDebug(5850) << "KOAgendaView::updateView()" << endl; fillAgenda(); } /* Update configuration settings for the agenda view. This method is not complete. */ void KOAgendaView::updateConfig() { // kdDebug(5850) << "KOAgendaView::updateConfig()" << endl; // update config for children mTimeLabels->updateConfig(); mAgenda->updateConfig(); mAllDayAgenda->updateConfig(); // widget synchronization // FIXME: find a better way, maybe signal/slot mTimeLabels->positionChanged(); // for some reason, this needs to be called explicitly mTimeLabels->repaint(); updateTimeBarWidth(); // ToolTips displaying summary of events KOAgendaItem::toolTipGroup()->setEnabled(KOPrefs::instance() ->mEnableToolTips); setHolidayMasks(); createDayLabels(); updateView(); } void KOAgendaView::updateTimeBarWidth() { int width; width = mDummyAllDayLeft->fontMetrics().width( i18n("All Day") ); width = QMAX( width, mTimeLabels->width() ); mDummyAllDayLeft->setFixedWidth( width ); mTimeLabels->setFixedWidth( width ); } void KOAgendaView::updateEventDates( KOAgendaItem *item ) { kdDebug(5850) << "KOAgendaView::updateEventDates(): " << item->text() << endl; QDateTime startDt,endDt; // Start date of this incidence, calculate the offset from it (so recurring and // non-recurring items can be treated exactly the same, we never need to check // for doesRecur(), because we only move the start day by the number of days the // agenda item was really moved. Smart, isn't it?) QDate thisDate; if ( item->cellXLeft() < 0 ) { thisDate = ( mSelectedDates.first() ).addDays( item->cellXLeft() ); } else { thisDate = mSelectedDates[ item->cellXLeft() ]; } QDate oldThisDate( item->itemDate() ); int daysOffset = oldThisDate.daysTo( thisDate ); int daysLength = 0; // startDt.setDate( startDate ); Incidence *incidence = item->incidence(); if ( !incidence ) return; if ( !mChanger || !mChanger->beginChange(incidence) ) return; Incidence *oldIncidence = incidence->clone(); QTime startTime(0,0,0), endTime(0,0,0); if ( incidence->doesFloat() ) { daysLength = item->cellWidth() - 1; } else { startTime = mAgenda->gyToTime( item->cellYTop() ); if ( item->lastMultiItem() ) { endTime = mAgenda->gyToTime( item->lastMultiItem()->cellYBottom() + 1 ); daysLength = item->lastMultiItem()->cellXLeft() - item->cellXLeft(); } else { endTime = mAgenda->gyToTime( item->cellYBottom() + 1 ); } } // kdDebug(5850) << "KOAgendaView::updateEventDates(): now setting dates" << endl; // FIXME: use a visitor here if ( incidence->type() == "Event" ) { startDt = incidence->dtStart(); startDt = startDt.addDays( daysOffset ); startDt.setTime( startTime ); endDt = startDt.addDays( daysLength ); endDt.setTime( endTime ); Event*ev = static_cast(incidence); if( incidence->dtStart() == startDt && ev->dtEnd() == endDt ) { // No change delete oldIncidence; return; } incidence->setDtStart( startDt ); ev->setDtEnd( endDt ); } else if ( incidence->type() == "Todo" ) { Todo *td = static_cast(incidence); startDt = td->hasStartDate() ? td->dtStart() : td->dtDue(); startDt = thisDate.addDays( td->dtDue().daysTo( startDt ) ); startDt.setTime( startTime ); endDt.setDate( thisDate ); endDt.setTime( endTime ); if( td->dtDue() == endDt ) { // No change delete oldIncidence; return; } } // FIXME: Adjusting the recurrence should really go to CalendarView so this // functionality will also be available in other views! // TODO_Recurrence: This does not belong here, and I'm not really sure // how it's supposed to work anyway. /* Recurrence *recur = incidence->recurrence(); if ( recur->doesRecur() && daysOffset != 0 ) { switch ( recur->recurrenceType() ) { case Recurrence::rYearlyPos: { int freq = recur->frequency(); int duration = recur->duration(); QDate endDt( recur->endDate() ); bool negative = false; QPtrList monthPos( recur->yearMonthPositions() ); if ( monthPos.first() ) { negative = monthPos.first()->negative; } QBitArray days( 7 ); int pos = 0; days.fill( false ); days.setBit( thisDate.dayOfWeek() - 1 ); if ( negative ) { pos = - ( thisDate.daysInMonth() - thisDate.day() - 1 ) / 7 - 1; } else { pos = ( thisDate.day()-1 ) / 7 + 1; } // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again recur->unsetRecurs(); if ( duration != 0 ) { recur->setYearly( Recurrence::rYearlyPos, freq, duration ); } else { recur->setYearly( Recurrence::rYearlyPos, freq, endDt ); } recur->addYearlyMonthPos( pos, days ); recur->addYearlyNum( thisDate.month() ); break; } case Recurrence::rYearlyDay: { int freq = recur->frequency(); int duration = recur->duration(); QDate endDt( recur->endDate() ); // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again recur->unsetRecurs(); if ( duration == 0 ) { // end by date recur->setYearly( Recurrence::rYearlyDay, freq, endDt ); } else { recur->setYearly( Recurrence::rYearlyDay, freq, duration ); } recur->addYearlyNum( thisDate.dayOfYear() ); break; } case Recurrence::rYearlyMonth: { int freq = recur->frequency(); int duration = recur->duration(); QDate endDt( recur->endDate() ); // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again recur->unsetRecurs(); if ( duration != 0 ) { recur->setYearlyByDate( thisDate.day(), recur->feb29YearlyType(), freq, duration ); } else { recur->setYearlyByDate( thisDate.day(), recur->feb29YearlyType(), freq, endDt ); } recur->addYearlyNum( thisDate.month() ); break; } case Recurrence::rMonthlyPos: { int freq = recur->frequency(); int duration = recur->duration(); QDate endDt( recur->endDate() ); QPtrList monthPos( recur->monthPositions() ); if ( !monthPos.isEmpty() ) { // FIXME: How shall I adapt the day x of week Y if we move the date across month borders??? // for now, just use the date of the moved item and assume the recurrence only occurs on that day. // That's fine for korganizer, but might mess up other organizers. QBitArray rDays( 7 ); rDays = monthPos.first()->rDays; bool negative = monthPos.first()->negative; int newPos; rDays.fill( false ); rDays.setBit( thisDate.dayOfWeek() - 1 ); if ( negative ) { newPos = - ( thisDate.daysInMonth() - thisDate.day() - 1 ) / 7 - 1; } else { newPos = ( thisDate.day()-1 ) / 7 + 1; } // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again recur->unsetRecurs(); if ( duration == 0 ) { // end by date recur->setMonthly( Recurrence::rMonthlyPos, freq, endDt ); } else { recur->setMonthly( Recurrence::rMonthlyPos, freq, duration ); } recur->addMonthlyPos( newPos, rDays ); } break;} case Recurrence::rMonthlyDay: { int freq = recur->frequency(); int duration = recur->duration(); QDate endDt( recur->endDate() ); QPtrList monthDays( recur->monthDays() ); // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again recur->unsetRecurs(); if ( duration == 0 ) { // end by date recur->setMonthly( Recurrence::rMonthlyDay, freq, endDt ); } else { recur->setMonthly( Recurrence::rMonthlyDay, freq, duration ); } // FIXME: How shall I adapt the n-th day if we move the date across month borders??? // for now, just use the date of the moved item and assume the recurrence only occurs on that day. // That's fine for korganizer, but might mess up other organizers. recur->addMonthlyDay( thisDate.day() ); break;} case Recurrence::rWeekly: { QBitArray days(7), oldDays( recur->days() ); int offset = daysOffset % 7; if ( offset<0 ) offset = (offset+7) % 7; // rotate the days for (int d=0; d<7; d++ ) { days.setBit( (d+offset) % 7, oldDays.at(d) ); } if ( recur->duration() == 0 ) { // end by date recur->setWeekly( recur->frequency(), days, recur->endDate(), recur->weekStart() ); } else { // duration or no end recur->setWeekly( recur->frequency(), days, recur->duration(), recur->weekStart() ); } break;} // nothing to be done for the following: case Recurrence::rDaily: case Recurrence::rHourly: case Recurrence::rMinutely: case Recurrence::rNone: default: break; } if ( recur->duration()==0 ) { // end by date recur->setEndDate( recur->endDate().addDays( daysOffset ) ); } KMessageBox::information( this, i18n("A recurring calendar item was moved " "to a different day. The recurrence settings " "have been updated with that move. Please check " "them in the editor."), i18n("Recurrence Moved"), "RecurrenceMoveInAgendaWarning" ); }*/ // FIXME: use a visitor here if ( incidence->type() == "Event" ) { incidence->setDtStart( startDt ); (static_cast( incidence ) )->setDtEnd( endDt ); } else if ( incidence->type() == "Todo" ) { Todo *td = static_cast( incidence ); if ( td->hasStartDate() ) td->setDtStart( startDt ); td->setDtDue( endDt ); } item->setItemDate( startDt.date() ); KOIncidenceToolTip::remove( item ); KOIncidenceToolTip::add( item, calendar(), incidence, KOAgendaItem::toolTipGroup() ); const bool result = mChanger->changeIncidence( oldIncidence, incidence ); mChanger->endChange(incidence); delete oldIncidence; if ( !result ) { mPendingChanges = true; QTimer::singleShot( 0, this, SLOT(updateView()) ); return; } // don't update the agenda as the item already has the correct coordinates. // an update would delete the current item and recreate it, but we are still // using a pointer to that item! => CRASH enableAgendaUpdate( false ); // We need to do this in a timer to make sure we are not deleting the item // we are currently working on, which would lead to crashes // Only the actually moved agenda item is already at the correct position and mustn't be // recreated. All others have to!!! if ( incidence->doesRecur() ) { mUpdateItem = incidence; QTimer::singleShot( 0, this, SLOT( doUpdateItem() ) ); } enableAgendaUpdate( true ); // kdDebug(5850) << "KOAgendaView::updateEventDates() done " << endl; } void KOAgendaView::doUpdateItem() { if ( mUpdateItem ) { changeIncidenceDisplay( mUpdateItem, KOGlobals::INCIDENCEEDITED ); mUpdateItem = 0; } } void KOAgendaView::showDates( const QDate &start, const QDate &end ) { // kdDebug(5850) << "KOAgendaView::selectDates" << endl; if ( !mSelectedDates.isEmpty() && mSelectedDates.first() == start && mSelectedDates.last() == end && !mPendingChanges ) return; mSelectedDates.clear(); QDate d = start; while (d <= end) { mSelectedDates.append(d); d = d.addDays( 1 ); } // and update the view fillAgenda(); } void KOAgendaView::showIncidences( const Incidence::List & ) { kdDebug(5850) << "KOAgendaView::showIncidences( const Incidence::List & ) is not yet implemented" << endl; } void KOAgendaView::insertIncidence( Incidence *incidence, const QDate &curDate, int curCol ) { if ( !filterByResource( incidence ) ) return; // FIXME: Use a visitor here, or some other method to get rid of the dynamic_cast's Event *event = dynamic_cast( incidence ); Todo *todo = dynamic_cast( incidence ); if ( curCol < 0 ) { curCol = mSelectedDates.findIndex( curDate ); } // The date for the event is not displayed, just ignore it if ( curCol < 0 || curCol > int( mSelectedDates.size() ) ) return; int beginX; int endX; if ( event ) { beginX = curDate.daysTo( incidence->dtStart().date() ) + curCol; endX = curDate.daysTo( event->dateEnd() ) + curCol; } else if ( todo ) { if ( ! todo->hasDueDate() ) return; // todo shall not be displayed if it has no date beginX = curDate.daysTo( todo->dtDue().date() ) + curCol; endX = beginX; } else { return; } if ( todo && todo->isOverdue() ) { mAllDayAgenda->insertAllDayItem( incidence, curDate, curCol, curCol ); } else if ( incidence->doesFloat() ) { // FIXME: This breaks with recurring multi-day events! if ( incidence->recurrence()->doesRecur() ) { mAllDayAgenda->insertAllDayItem( incidence, curDate, curCol, curCol ); } else { // Insert multi-day events only on the first day, otherwise it will // appear multiple times if ( ( beginX <= 0 && curCol == 0 ) || beginX == curCol ) { mAllDayAgenda->insertAllDayItem( incidence, curDate, beginX, endX ); } } } else if ( event && event->isMultiDay() ) { int startY = mAgenda->timeToY( event->dtStart().time() ); QTime endtime( event->dtEnd().time() ); if ( endtime == QTime( 0, 0, 0 ) ) endtime = QTime( 23, 59, 59 ); int endY = mAgenda->timeToY( endtime ) - 1; if ( (beginX <= 0 && curCol == 0) || beginX == curCol ) { mAgenda->insertMultiItem( event, curDate, beginX, endX, startY, endY ); } if ( beginX == curCol ) { mMaxY[curCol] = mAgenda->timeToY( QTime(23,59) ); if ( startY < mMinY[curCol] ) mMinY[curCol] = startY; } else if ( endX == curCol ) { mMinY[curCol] = mAgenda->timeToY( QTime(0,0) ); if ( endY > mMaxY[curCol] ) mMaxY[curCol] = endY; } else { mMinY[curCol] = mAgenda->timeToY( QTime(0,0) ); mMaxY[curCol] = mAgenda->timeToY( QTime(23,59) ); } } else { int startY = 0, endY = 0; if ( event ) { startY = mAgenda->timeToY( incidence->dtStart().time() ); QTime endtime( event->dtEnd().time() ); if ( endtime == QTime( 0, 0, 0 ) ) endtime = QTime( 23, 59, 59 ); endY = mAgenda->timeToY( endtime ) - 1; } if ( todo ) { QTime t = todo->dtDue().time(); endY = mAgenda->timeToY( t ) - 1; startY = mAgenda->timeToY( t.addSecs( -1800 ) ); } if ( endY < startY ) endY = startY; mAgenda->insertItem( incidence, curDate, curCol, startY, endY ); if ( startY < mMinY[curCol] ) mMinY[curCol] = startY; if ( endY > mMaxY[curCol] ) mMaxY[curCol] = endY; } } void KOAgendaView::changeIncidenceDisplayAdded( Incidence *incidence ) { Todo *todo = dynamic_cast(incidence); CalFilter *filter = calendar()->filter(); if ( ( filter && !filter->filterIncidence( incidence ) ) || ( todo && !KOPrefs::instance()->showAllDayTodo() ) ) return; QDate f = mSelectedDates.first(); QDate l = mSelectedDates.last(); QDate startDt = incidence->dtStart().date(); if ( incidence->doesRecur() ) { DateList::ConstIterator dit; QDate curDate; for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) { curDate = *dit; // FIXME: This breaks with recurring multi-day events! if ( incidence->recursOn( curDate ) ) { insertIncidence( incidence, curDate ); } } return; } QDate endDt; if ( incidence->type() == "Event" ) endDt = (static_cast(incidence))->dateEnd(); if ( todo ) { endDt = todo->isOverdue() ? QDate::currentDate() : todo->dtDue().date(); if ( endDt >= f && endDt <= l ) { insertIncidence( incidence, endDt ); return; } } if ( startDt >= f && startDt <= l ) { insertIncidence( incidence, startDt ); } } void KOAgendaView::changeIncidenceDisplay( Incidence *incidence, int mode ) { switch ( mode ) { case KOGlobals::INCIDENCEADDED: { // Add an event. No need to recreate the whole view! // recreating everything even causes troubles: dropping to the day matrix // recreates the agenda items, but the evaluation is still in an agendaItems' code, // which was deleted in the mean time. Thus KOrg crashes... if ( mAllowAgendaUpdate ) changeIncidenceDisplayAdded( incidence ); break; } case KOGlobals::INCIDENCEEDITED: { if ( !mAllowAgendaUpdate ) { updateEventIndicators(); } else { removeIncidence( incidence ); updateEventIndicators(); changeIncidenceDisplayAdded( incidence ); } break; } case KOGlobals::INCIDENCEDELETED: { mAgenda->removeIncidence( incidence ); mAllDayAgenda->removeIncidence( incidence ); updateEventIndicators(); break; } default: updateView(); } } void KOAgendaView::fillAgenda( const QDate & ) { fillAgenda(); } void KOAgendaView::fillAgenda() { mPendingChanges = false; /* Remember the uids of the selected items. In case one of the * items was deleted and re-added, we want to reselect it. */ const QString &selectedAgendaUid = mAgenda->lastSelectedUid(); const QString &selectedAllDayAgendaUid = mAllDayAgenda->lastSelectedUid(); enableAgendaUpdate( true ); clearView(); mAllDayAgenda->changeColumns(mSelectedDates.count()); mAgenda->changeColumns(mSelectedDates.count()); mEventIndicatorTop->changeColumns(mSelectedDates.count()); mEventIndicatorBottom->changeColumns(mSelectedDates.count()); createDayLabels(); setHolidayMasks(); mMinY.resize(mSelectedDates.count()); mMaxY.resize(mSelectedDates.count()); Event::List dayEvents; // ToDo items shall be displayed for the day they are due, but only shown today if they are already overdue. // Therefore, get all of them. Todo::List todos = calendar()->todos(); mAgenda->setDateList(mSelectedDates); QDate today = QDate::currentDate(); bool somethingReselected = false; DateList::ConstIterator dit; int curCol = 0; for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) { QDate currentDate = *dit; // kdDebug(5850) << "KOAgendaView::fillAgenda(): " << currentDate.toString() // << endl; dayEvents = calendar()->events(currentDate, EventSortStartDate, SortDirectionAscending); // Default values, which can never be reached mMinY[curCol] = mAgenda->timeToY(QTime(23,59)) + 1; mMaxY[curCol] = mAgenda->timeToY(QTime(0,0)) - 1; unsigned int numEvent; for(numEvent=0;numEventsummary() << endl; insertIncidence( event, currentDate, curCol ); if( event->uid() == selectedAgendaUid && !selectedAgendaUid.isNull() ) { mAgenda->selectItemByUID( event->uid() ); somethingReselected = true; } if( event->uid() == selectedAllDayAgendaUid && !selectedAllDayAgendaUid.isNull() ) { mAllDayAgenda->selectItemByUID( event->uid() ); somethingReselected = true; } } // if (numEvent == 0) kdDebug(5850) << " No events" << endl; // ---------- [display Todos -------------- if ( KOPrefs::instance()->showAllDayTodo() ) { unsigned int numTodo; for (numTodo = 0; numTodo < todos.count(); ++numTodo) { Todo *todo = *todos.at(numTodo); if ( ! todo->hasDueDate() ) continue; // todo shall not be displayed if it has no date if ( !filterByResource( todo ) ) continue; // ToDo items shall be displayed for the day they are due, but only showed today if they are already overdue. // Already completed items can be displayed on their original due date bool overdue = todo->isOverdue(); if ( (( todo->dtDue().date() == currentDate) && !overdue) || (( currentDate == today) && overdue) || ( todo->recursOn( currentDate ) ) ) { if ( todo->doesFloat() || overdue ) { // Todo has no due-time set or is already overdue //kdDebug(5850) << "todo without time:" << todo->dtDueDateStr() << ";" << todo->summary() << endl; mAllDayAgenda->insertAllDayItem(todo, currentDate, curCol, curCol); } else { //kdDebug(5850) << "todo with time:" << todo->dtDueStr() << ";" << todo->summary() << endl; int endY = mAgenda->timeToY(todo->dtDue().time()) - 1; int startY = endY - 1; mAgenda->insertItem(todo,currentDate,curCol,startY,endY); if (startY < mMinY[curCol]) mMinY[curCol] = startY; if (endY > mMaxY[curCol]) mMaxY[curCol] = endY; } } } } // ---------- display Todos] -------------- ++curCol; } mAgenda->checkScrollBoundaries(); updateEventIndicators(); // mAgenda->viewport()->update(); // mAllDayAgenda->viewport()->update(); // make invalid deleteSelectedDateTime(); if( !somethingReselected ) { emit incidenceSelected( 0 ); } // kdDebug(5850) << "Fill Agenda done" << endl; } void KOAgendaView::clearView() { // kdDebug(5850) << "ClearView" << endl; mAllDayAgenda->clear(); mAgenda->clear(); } CalPrinterBase::PrintType KOAgendaView::printType() { if ( currentDateCount() == 1 ) return CalPrinterBase::Day; else return CalPrinterBase::Week; } void KOAgendaView::updateEventIndicatorTop( int newY ) { uint i; for( i = 0; i < mMinY.size(); ++i ) { mEventIndicatorTop->enableColumn( i, newY >= mMinY[i] ); } mEventIndicatorTop->update(); } void KOAgendaView::updateEventIndicatorBottom( int newY ) { uint i; for( i = 0; i < mMaxY.size(); ++i ) { mEventIndicatorBottom->enableColumn( i, newY <= mMaxY[i] ); } mEventIndicatorBottom->update(); } void KOAgendaView::slotTodoDropped( Todo *todo, const QPoint &gpos, bool allDay ) { if ( gpos.x()<0 || gpos.y()<0 ) return; QDate day = mSelectedDates[gpos.x()]; QTime time = mAgenda->gyToTime( gpos.y() ); QDateTime newTime( day, time ); if ( todo ) { Todo *existingTodo = calendar()->todo( todo->uid() ); if ( existingTodo ) { kdDebug(5850) << "Drop existing Todo" << endl; Todo *oldTodo = existingTodo->clone(); if ( mChanger && mChanger->beginChange( existingTodo ) ) { existingTodo->setDtDue( newTime ); existingTodo->setFloats( allDay ); existingTodo->setHasDueDate( true ); mChanger->changeIncidence( oldTodo, existingTodo ); mChanger->endChange( existingTodo ); } else { KMessageBox::sorry( this, i18n("Unable to modify this to-do, " "because it cannot be locked.") ); } delete oldTodo; } else { kdDebug(5850) << "Drop new Todo" << endl; todo->setDtDue( newTime ); todo->setFloats( allDay ); todo->setHasDueDate( true ); if ( !mChanger->addIncidence( todo, this ) ) { KODialogManager::errorSaveIncidence( this, todo ); } } } } void KOAgendaView::startDrag( Incidence *incidence ) { #ifndef KORG_NODND DndFactory factory( calendar() ); ICalDrag *vd = factory.createDrag( incidence, this ); if ( vd->drag() ) { kdDebug(5850) << "KOAgendaView::startDrag(): Delete drag source" << endl; } #endif } void KOAgendaView::readSettings() { readSettings(KOGlobals::self()->config()); } void KOAgendaView::readSettings(KConfig *config) { // kdDebug(5850) << "KOAgendaView::readSettings()" << endl; config->setGroup("Views"); #ifndef KORG_NOSPLITTER QValueList sizes = config->readIntListEntry("Separator AgendaView"); if (sizes.count() == 2) { mSplitterAgenda->setSizes(sizes); } #endif updateConfig(); } void KOAgendaView::writeSettings(KConfig *config) { // kdDebug(5850) << "KOAgendaView::writeSettings()" << endl; config->setGroup("Views"); #ifndef KORG_NOSPLITTER QValueList list = mSplitterAgenda->sizes(); config->writeEntry("Separator AgendaView",list); #endif } void KOAgendaView::setHolidayMasks() { - if ( mSelectedDates.isEmpty() ) { + if ( mSelectedDates.isEmpty() || !mSelectedDates[0].isValid() ) { return; } mHolidayMask.resize( mSelectedDates.count() + 1 ); for( uint i = 0; i < mSelectedDates.count(); ++i ) { mHolidayMask[i] = !KOGlobals::self()->isWorkDay( mSelectedDates[ i ] ); } // Store the information about the day before the visible area (needed for // overnight working hours) in the last bit of the mask: bool showDay = !KOGlobals::self()->isWorkDay( mSelectedDates[ 0 ].addDays( -1 ) ); mHolidayMask[ mSelectedDates.count() ] = showDay; mAgenda->setHolidayMask( &mHolidayMask ); mAllDayAgenda->setHolidayMask( &mHolidayMask ); } void KOAgendaView::setContentsPos( int y ) { mAgenda->setContentsPos( 0, y ); } void KOAgendaView::setExpandedButton( bool expanded ) { if ( !mExpandButton ) return; if ( expanded ) { mExpandButton->setPixmap( mExpandedPixmap ); } else { mExpandButton->setPixmap( mNotExpandedPixmap ); } } void KOAgendaView::clearSelection() { mAgenda->deselectItem(); mAllDayAgenda->deselectItem(); } void KOAgendaView::newTimeSpanSelectedAllDay( const QPoint &start, const QPoint &end ) { newTimeSpanSelected( start, end ); mTimeSpanInAllDay = true; } void KOAgendaView::newTimeSpanSelected( const QPoint &start, const QPoint &end ) { if (!mSelectedDates.count()) return; mTimeSpanInAllDay = false; QDate dayStart = mSelectedDates[ kClamp( start.x(), 0, (int)mSelectedDates.size() - 1 ) ]; QDate dayEnd = mSelectedDates[ kClamp( end.x(), 0, (int)mSelectedDates.size() - 1 ) ]; QTime timeStart = mAgenda->gyToTime(start.y()); QTime timeEnd = mAgenda->gyToTime( end.y() + 1 ); QDateTime dtStart(dayStart,timeStart); QDateTime dtEnd(dayEnd,timeEnd); mTimeSpanBegin = dtStart; mTimeSpanEnd = dtEnd; } void KOAgendaView::deleteSelectedDateTime() { mTimeSpanBegin.setDate(QDate()); mTimeSpanEnd.setDate(QDate()); mTimeSpanInAllDay = false; } void KOAgendaView::setTypeAheadReceiver( QObject *o ) { mAgenda->setTypeAheadReceiver( o ); mAllDayAgenda->setTypeAheadReceiver( o ); } void KOAgendaView::finishTypeAhead() { mAgenda->finishTypeAhead(); mAllDayAgenda->finishTypeAhead(); } void KOAgendaView::removeIncidence( Incidence *incidence ) { mAgenda->removeIncidence( incidence ); mAllDayAgenda->removeIncidence( incidence ); } void KOAgendaView::updateEventIndicators() { mMinY = mAgenda->minContentsY(); mMaxY = mAgenda->maxContentsY(); mAgenda->checkScrollBoundaries(); updateEventIndicatorTop( mAgenda->visibleContentsYMin() ); updateEventIndicatorBottom( mAgenda->visibleContentsYMax() ); } void KOAgendaView::setIncidenceChanger( IncidenceChangerBase *changer ) { mChanger = changer; mAgenda->setIncidenceChanger( changer ); mAllDayAgenda->setIncidenceChanger( changer ); } void KOAgendaView::clearTimeSpanSelection() { mAgenda->clearSelection(); mAllDayAgenda->clearSelection(); deleteSelectedDateTime(); } void KOAgendaView::setResource(KCal::ResourceCalendar * res, const QString & subResource) { mResource = res; mSubResource = subResource; } bool KOAgendaView::filterByResource(Incidence * incidence) { if ( !mResource ) return true; CalendarResources *calRes = dynamic_cast( calendar() ); if ( !calRes ) return true; if ( calRes->resource( incidence ) != mResource ) return false; if ( !mSubResource.isEmpty() ) { if ( mResource->subresourceIdentifier( incidence ) != mSubResource ) return false; } return true; } void KOAgendaView::resourcesChanged() { mPendingChanges = true; } void KOAgendaView::calendarIncidenceAdded(Incidence * incidence) { Q_UNUSED( incidence ); mPendingChanges = true; } void KOAgendaView::calendarIncidenceChanged(Incidence * incidence) { Q_UNUSED( incidence ); mPendingChanges = true; } void KOAgendaView::calendarIncidenceRemoved(Incidence * incidence) { Q_UNUSED( incidence ); mPendingChanges = true; }