diff options
Diffstat (limited to 'korganizer/koagendaview.cpp')
-rw-r--r-- | korganizer/koagendaview.cpp | 1618 |
1 files changed, 1618 insertions, 0 deletions
diff --git a/korganizer/koagendaview.cpp b/korganizer/koagendaview.cpp new file mode 100644 index 000000000..a526760e5 --- /dev/null +++ b/korganizer/koagendaview.cpp @@ -0,0 +1,1618 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> + + 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 <qhbox.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qframe.h> +#include <qlayout.h> +#ifndef KORG_NOSPLITTER +#include <qsplitter.h> +#endif +#include <qfont.h> +#include <qfontmetrics.h> +#include <qpopupmenu.h> +#include <qtooltip.h> +#include <qpainter.h> +#include <qpushbutton.h> +#include <qcursor.h> +#include <qbitarray.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kconfig.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kholidays.h> + +#include <libkcal/calendar.h> +#include <libkcal/icaldrag.h> +#include <libkcal/dndfactory.h> +#include <libkcal/calfilter.h> + +#include <kcalendarsystem.h> + +#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;i<mColumns;++i) { + if (mEnabled[i]) { + int cellWidth = contentsRect().right()/mColumns; + int xOffset = KOGlobals::self()->reverseLayout() ? + (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 <libkcal/incidence.h> + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// + + +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?"<<endl; + else + //We want to center the date + emit zoomViewHorizontally( newBegin, count ); +} + +void KOAgendaView::zoomView( const int delta, const QPoint &pos, + const Qt::Orientation orient ) +{ + static QDate zoomDate; + static QTimer *t = new QTimer( this ); + + + //Zoom to the selected incidence, on the other way + // zoom to the date on screen after the first mousewheel move. + if ( orient == Qt::Horizontal ) { + QDate date=mAgenda->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<Event*>(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<Todo*>(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<Recurrence::rMonthPos> 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<Recurrence::rMonthPos> 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<int> 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<Event*>( incidence ) )->setDtEnd( endDt ); + } else if ( incidence->type() == "Todo" ) { + Todo *td = static_cast<Todo*>( incidence ); + if ( td->hasStartDate() ) + td->setDtStart( startDt ); + td->setDtDue( endDt ); + } + + item->setItemDate( startDt.date() ); + + KOIncidenceToolTip::remove( item ); + KOIncidenceToolTip::add( item, incidence, KOAgendaItem::toolTipGroup() ); + + mChanger->changeIncidence( oldIncidence, incidence ); + mChanger->endChange(incidence); + delete oldIncidence; + + // 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<Event *>( incidence ); + Todo *todo = dynamic_cast<Todo *>( 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<Todo *>(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<Event *>(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;numEvent<dayEvents.count();++numEvent) { + Event *event = *dayEvents.at(numEvent); +// kdDebug(5850) << " Event: " << event->summary() << 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<int> 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<int> list = mSplitterAgenda->sizes(); + config->writeEntry("Separator AgendaView",list); +#endif +} + +void KOAgendaView::setHolidayMasks() +{ + 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<CalendarResources*>( 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; +} |