2 This file is part of KOrganizer.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4 Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 As a special exception, permission is given to link this program
21 with any edition of Qt, and distribute the resulting executable,
22 without including the source code for Qt in the source distribution.
25 #include "koagendaview.h"
26 #include "koglobals.h"
27 #ifndef KORG_NOPLUGINS
29 #include "kodecorationlabel.h"
33 #include "koagendaitem.h"
34 #include "kogroupware.h"
35 #include "kodialogmanager.h"
36 #include "koeventpopupmenu.h"
37 #include "koalternatelabel.h"
38 #include "timelabelszone.h"
40 #include <kcal/calendar.h>
41 #include <kcal/icaldrag.h>
42 #include <kcal/dndfactory.h>
43 #include <kcal/calfilter.h>
44 #include <kcal/incidence.h>
45 #include <kcal/incidenceformatter.h>
47 #include <kapplication.h>
48 #include <kcalendarsystem.h>
50 #include <kstandarddirs.h>
51 #include <kiconloader.h>
55 #include <kglobalsettings.h>
56 #include <kholidays.h>
58 #include <ksystemtimezone.h>
59 #include <kpushbutton.h>
60 #include <kcombobox.h>
67 #include <QFontMetrics>
70 #include <QPushButton>
71 #include <QToolButton>
74 #include <QPaintEvent>
75 #include <QGridLayout>
77 #include <QHBoxLayout>
78 #include <QResizeEvent>
79 #include <QVBoxLayout>
80 #include <QListWidget>
84 EventIndicator::EventIndicator( Location loc
, QWidget
*parent
) : QFrame( parent
)
87 mEnabled
.resize( mColumns
);
90 if (mLocation
== Top
) {
91 mPixmap
= KOGlobals::self()->smallIcon( "arrow-up-double" );
93 mPixmap
= KOGlobals::self()->smallIcon( "arrow-down-double" );
96 setMinimumHeight(mPixmap
.height());
99 EventIndicator::~EventIndicator()
103 void EventIndicator::paintEvent( QPaintEvent
*event
)
105 QFrame::paintEvent( event
);
107 QPainter
painter( this );
110 for(i
=0;i
<mColumns
;++i
) {
112 int cellWidth
= contentsRect().right()/mColumns
;
113 int xOffset
= KOGlobals::self()->reverseLayout() ?
114 (mColumns
- 1 - i
)*cellWidth
+ cellWidth
/2 -mPixmap
.width()/2 :
115 i
*cellWidth
+ cellWidth
/2 -mPixmap
.width()/2;
116 painter
.drawPixmap(QPoint(xOffset
,0),mPixmap
);
121 void EventIndicator::changeColumns(int columns
)
124 mEnabled
.resize(mColumns
);
129 void EventIndicator::enableColumn(int column
, bool enable
)
131 mEnabled
[column
] = enable
;
134 ////////////////////////////////////////////////////////////////////////////
135 ////////////////////////////////////////////////////////////////////////////
136 ////////////////////////////////////////////////////////////////////////////
138 KOAgendaView::KOAgendaView( Calendar
*cal
, QWidget
*parent
, bool isSideBySide
) :
139 KOrg::AgendaView( cal
, parent
),
140 mTimeLabelsZone( 0 ),
141 mAllowAgendaUpdate( true ),
144 mIsSideBySide( isSideBySide
)
146 mSelectedDates
.append( QDate::currentDate() );
148 mLayoutDayLabels
= 0;
151 mLayoutBottomDayLabels
= 0;
152 mBottomDayLabelsFrame
= 0;
153 mBottomDayLabels
= 0;
155 mTopLayout
= new QGridLayout( this );
156 mTopLayout
->setMargin( 0 );
158 /* Create agenda splitter */
159 mSplitterAgenda
= new QSplitter( Qt::Vertical
, this );
160 mTopLayout
->addWidget( mSplitterAgenda
, 1, 0 );
161 mSplitterAgenda
->setOpaqueResize( KGlobalSettings::opaqueResize() );
164 /* Create day name labels for agenda columns */
165 mDayLabelsFrame
= new KHBox( mSplitterAgenda
);
166 mDayLabelsFrame
->setSpacing( 2 );
169 /* Create all-day agenda widget */
170 mAllDayFrame
= new KHBox( mSplitterAgenda
);
171 mAllDayFrame
->setSpacing( 2 );
173 // Alignment and description widgets
174 mTimeBarHeaderFrame
= new KHBox( mAllDayFrame
);
177 mAllDayAgenda
= new KOAgenda( 1, mAllDayFrame
);
178 QWidget
*dummyAllDayRight
= new QWidget( mAllDayFrame
);
180 // Create the event context menu for the all-day agenda
181 mAllDayAgendaPopup
= eventPopup();
184 /* Create the main agenda widget and the related widgets */
185 QWidget
*agendaFrame
= new QWidget( mSplitterAgenda
);
186 mAgendaLayout
= new QGridLayout( agendaFrame
);
187 mAgendaLayout
->setMargin( 0 );
188 mAgendaLayout
->setHorizontalSpacing( 2 );
189 mAgendaLayout
->setVerticalSpacing( 0 );
191 mTimeBarHeaderFrame
->hide();
193 // Create event indicator bars
194 mEventIndicatorTop
= new EventIndicator( EventIndicator::Top
, agendaFrame
);
195 mAgendaLayout
->addWidget( mEventIndicatorTop
, 0, 1 );
196 mEventIndicatorBottom
= new EventIndicator( EventIndicator::Bottom
,
198 mAgendaLayout
->addWidget( mEventIndicatorBottom
, 2, 1 );
200 // Alignment and description widgets
201 QWidget
*dummyAgendaRight
= new QWidget( agendaFrame
);
202 mAgendaLayout
->addWidget( dummyAgendaRight
, 0, 2 );
205 mAgenda
= new KOAgenda( 1, 96, KOPrefs::instance()->mHourSize
, agendaFrame
);
206 mAgendaLayout
->addWidget( mAgenda
, 1, 1, 1, 2 );
207 mAgendaLayout
->setColumnStretch( 1, 1 );
209 // Create time labels
210 mTimeLabelsZone
= new TimeLabelsZone( this, mAgenda
);
211 mAgendaLayout
->addWidget( mTimeLabelsZone
, 1, 0 );
213 // Create event context menu for agenda
214 mAgendaPopup
= eventPopup();
218 SIGNAL( zoomView(const int, const QPoint
&, const Qt::Orientation
) ),
219 SLOT( zoomView(const int, const QPoint
&, const Qt::Orientation
) ) );
221 // Event indicator updates
222 connect( mAgenda
, SIGNAL( lowerYChanged(int) ),
223 SLOT( updateEventIndicatorTop(int) ) );
224 connect( mAgenda
, SIGNAL( upperYChanged(int) ),
225 SLOT( updateEventIndicatorBottom(int) ) );
227 mTimeLabelsZone
->hide();
230 /* Create a frame at the bottom which may be used by decorations */
231 mBottomDayLabelsFrame
= new KHBox( mSplitterAgenda
);
232 mBottomDayLabelsFrame
->setSpacing( 2 );
234 if ( !isSideBySide
) {
235 /* Make the all-day and normal agendas line up with each other */
236 dummyAllDayRight
->setFixedWidth( mAgenda
->verticalScrollBar()->width()
237 - mAgendaLayout
->horizontalSpacing() );
238 dummyAgendaRight
->setFixedWidth(mAgenda
->verticalScrollBar()->width());
241 updateTimeBarWidth();
244 /* Update widgets to reflect user preferences */
249 /* Connect the agendas */
250 connectAgenda( mAgenda
, mAgendaPopup
, mAllDayAgenda
);
251 connectAgenda( mAllDayAgenda
, mAllDayAgendaPopup
, mAgenda
);
254 SIGNAL( newTimeSpanSignal( const QPoint
&, const QPoint
& ) ),
255 SLOT( newTimeSpanSelected( const QPoint
&, const QPoint
& ) ) );
256 connect( mAllDayAgenda
,
257 SIGNAL( newTimeSpanSignal( const QPoint
&, const QPoint
& ) ),
258 SLOT( newTimeSpanSelectedAllDay( const QPoint
&, const QPoint
& ) ) );
262 KOAgendaView::~KOAgendaView()
265 delete mAllDayAgendaPopup
;
268 void KOAgendaView::connectAgenda( KOAgenda
*agenda
, QMenu
*popup
,
269 KOAgenda
*otherAgenda
)
271 connect( agenda
, SIGNAL( showIncidencePopupSignal( Incidence
*, const QDate
& ) ),
272 popup
, SLOT( showIncidencePopup( Incidence
*, const QDate
& ) ) );
274 connect( agenda
, SIGNAL( showNewEventPopupSignal() ),
275 SLOT( showNewEventPopup() ) );
277 agenda
->setCalendar( calendar() );
279 // Create/Show/Edit/Delete Event
280 connect( agenda
, SIGNAL( newEventSignal() ), SIGNAL( newEventSignal() ) );
282 connect( agenda
, SIGNAL( newStartSelectSignal() ),
283 otherAgenda
, SLOT( clearSelection() ) );
284 connect( agenda
, SIGNAL( newStartSelectSignal() ),
285 SIGNAL( timeSpanSelectionChanged()) );
287 connect( agenda
, SIGNAL( editIncidenceSignal( Incidence
* ) ),
288 SIGNAL( editIncidenceSignal( Incidence
* ) ) );
289 connect( agenda
, SIGNAL( showIncidenceSignal( Incidence
* ) ),
290 SIGNAL( showIncidenceSignal( Incidence
* ) ) );
291 connect( agenda
, SIGNAL( deleteIncidenceSignal( Incidence
* ) ),
292 SIGNAL( deleteIncidenceSignal( Incidence
* ) ) );
294 connect( agenda
, SIGNAL( startMultiModify( const QString
& ) ),
295 SIGNAL( startMultiModify( const QString
& ) ) );
296 connect( agenda
, SIGNAL( endMultiModify() ),
297 SIGNAL( endMultiModify() ) );
299 connect( agenda
, SIGNAL( itemModified( KOAgendaItem
* ) ),
300 SLOT( updateEventDates( KOAgendaItem
* ) ) );
301 connect( agenda
, SIGNAL( enableAgendaUpdate( bool ) ),
302 SLOT( enableAgendaUpdate( bool ) ) );
305 connect( agenda
, SIGNAL( startDragSignal( Incidence
* ) ),
306 SLOT( startDrag( Incidence
* ) ) );
308 // synchronize selections
309 connect( agenda
, SIGNAL( incidenceSelected( Incidence
* ) ),
310 otherAgenda
, SLOT( deselectItem() ) );
311 connect( agenda
, SIGNAL( incidenceSelected( Incidence
* ) ),
312 SIGNAL( incidenceSelected( Incidence
* ) ) );
314 // rescheduling of todos by d'n'd
315 connect( agenda
, SIGNAL( droppedToDo( Todo
*, const QPoint
&, bool ) ),
316 SLOT( slotTodoDropped( Todo
*, const QPoint
&, bool ) ) );
320 void KOAgendaView::zoomInVertically( )
322 if ( !mIsSideBySide
)
323 KOPrefs::instance()->mHourSize
++;
324 mAgenda
->updateConfig();
325 mAgenda
->checkScrollBoundaries();
327 mTimeLabelsZone
->updateAll();
333 void KOAgendaView::zoomOutVertically( )
336 if ( KOPrefs::instance()->mHourSize
> 4 || mIsSideBySide
) {
338 if ( !mIsSideBySide
)
339 KOPrefs::instance()->mHourSize
--;
340 mAgenda
->updateConfig();
341 mAgenda
->checkScrollBoundaries();
343 mTimeLabelsZone
->updateAll();
348 void KOAgendaView::zoomInHorizontally( const QDate
&date
)
352 QDate dateToZoom
= date
;
355 begin
= mSelectedDates
.first();
356 ndays
= begin
.daysTo( mSelectedDates
.last() );
358 // zoom with Action and are there a selected Incidence?, Yes, I zoom in to it.
359 if ( ! dateToZoom
.isValid () )
360 dateToZoom
=mAgenda
->selectedIncidenceDate();
362 if( !dateToZoom
.isValid() ) {
364 newBegin
=begin
.addDays(1);
366 emit
zoomViewHorizontally ( newBegin
, count
);
370 newBegin
= dateToZoom
;
373 newBegin
= dateToZoom
.addDays( -ndays
/2 +1 );
376 emit
zoomViewHorizontally ( newBegin
, count
);
380 void KOAgendaView::zoomOutHorizontally( const QDate
&date
)
384 QDate dateToZoom
= date
;
387 begin
= mSelectedDates
.first();
388 ndays
= begin
.daysTo( mSelectedDates
.last() );
390 // zoom with Action and are there a selected Incidence?, Yes, I zoom out to it.
391 if ( ! dateToZoom
.isValid () )
392 dateToZoom
=mAgenda
->selectedIncidenceDate();
394 if ( !dateToZoom
.isValid() ) {
395 newBegin
= begin
.addDays(-1);
398 newBegin
= dateToZoom
.addDays( -ndays
/2-1 );
402 if ( abs( count
) >= 31 ) {
403 kDebug() << "change to the month view?";
405 //We want to center the date
406 emit
zoomViewHorizontally( newBegin
, count
);
410 void KOAgendaView::zoomView( const int delta
, const QPoint
&pos
,
411 const Qt::Orientation orient
)
413 static QDate zoomDate
;
414 static QTimer
*t
= new QTimer( this );
417 //Zoom to the selected incidence, on the other way
418 // zoom to the date on screen after the first mousewheel move.
419 if ( orient
== Qt::Horizontal
) {
420 QDate date
=mAgenda
->selectedIncidenceDate();
421 if ( date
.isValid() )
424 if ( !t
->isActive() ) {
425 zoomDate
= mSelectedDates
[pos
.x()];
427 t
->setSingleShot( true );
431 zoomOutHorizontally( zoomDate
);
433 zoomInHorizontally( zoomDate
);
436 QPoint posConstentsOld
= mAgenda
->gridToContents(pos
);
442 QPoint posConstentsNew
= mAgenda
->gridToContents(pos
);
443 mAgenda
->scrollBy( 0, posConstentsNew
.y() - posConstentsOld
.y() );
447 void KOAgendaView::createDayLabels()
449 // ### Before deleting and recreating we could check if mSelectedDates changed...
450 // It would remove some flickering and gain speed (since this is called by
451 // each updateView() call)
453 delete mBottomDayLabels
;
455 mDayLabels
= new QFrame (mDayLabelsFrame
);
456 mLayoutDayLabels
= new QHBoxLayout(mDayLabels
);
457 mLayoutDayLabels
->setMargin(0);
458 KVBox
*weekLabelBox
= new KVBox( mDayLabels
);
459 mLayoutDayLabels
->addWidget( weekLabelBox
);
460 weekLabelBox
->setFixedWidth( mTimeLabelsZone
->width()
461 - mAgendaLayout
->horizontalSpacing() );
463 weekLabelBox
->hide();
465 mBottomDayLabels
= new QFrame (mBottomDayLabelsFrame
);
466 mBottomDayLabelsFrame
->setStretchFactor(mBottomDayLabels
, 1);
467 mLayoutBottomDayLabels
= new QHBoxLayout(mBottomDayLabels
);
468 mLayoutBottomDayLabels
->setMargin(0);
469 KVBox
*bottomWeekLabelBox
= new KVBox( mBottomDayLabels
);
470 mLayoutBottomDayLabels
->addWidget( bottomWeekLabelBox
);
471 bottomWeekLabelBox
->setFixedWidth( mTimeLabelsZone
->width()
472 - mAgendaLayout
->horizontalSpacing() );
474 const KCalendarSystem
*calsys
= KOGlobals::self()->calendarSystem();
476 #ifndef KORG_NOPLUGINS
477 if ( KOPrefs::instance()->decorationsAtAgendaViewTop().count() > 0 ) {
478 mDayLabelsFrame
->setParent( mSplitterAgenda
);
480 mDayLabelsFrame
->setParent( this );
481 mTopLayout
->addWidget( mDayLabelsFrame
, 0, 0 );
483 if ( KOPrefs::instance()->decorationsAtAgendaViewBottom().count() > 0 ) {
484 mBottomDayLabelsFrame
->setParent( mSplitterAgenda
);
486 mBottomDayLabelsFrame
->setParent( this );
487 mTopLayout
->addWidget( mBottomDayLabelsFrame
, 0, 0 );
491 DateList::ConstIterator dit
;
492 for( dit
= mSelectedDates
.begin(); dit
!= mSelectedDates
.end(); ++dit
) {
494 KVBox
*dayLabelBox
= new KVBox( mDayLabels
);
495 mLayoutDayLabels
->addWidget( dayLabelBox
);
496 KVBox
*bottomDayLabelBox
= new KVBox( mBottomDayLabels
);
497 mLayoutBottomDayLabels
->addWidget( bottomDayLabelBox
);
499 int dW
= calsys
->dayOfWeek(date
);
500 QString veryLongStr
= KGlobal::locale()->formatDate( date
);
501 QString longstr
= i18nc( "short_weekday date (e.g. Mon 13)","%1 %2" ,
502 calsys
->weekDayName( dW
, KCalendarSystem::ShortDayName
) ,
504 QString shortstr
= QString::number(calsys
->day(date
));
506 KOAlternateLabel
*dayLabel
= new KOAlternateLabel(shortstr
,
507 longstr
, veryLongStr
, dayLabelBox
);
508 dayLabel
->setMinimumWidth(1);
509 dayLabel
->setAlignment(Qt::AlignHCenter
);
510 if (date
== QDate::currentDate()) {
511 QFont font
= dayLabel
->font();
513 dayLabel
->setFont(font
);
516 // if a holiday region is selected, show the holiday name
517 QStringList texts
= KOGlobals::self()->holiday( date
);
518 QStringList::ConstIterator textit
= texts
.begin();
519 for ( ; textit
!= texts
.end(); ++textit
) {
520 // use a KOAlternateLabel so when the text doesn't fit any more a tooltip is used
521 KOAlternateLabel
*label
= new KOAlternateLabel( (*textit
), (*textit
), QString(), dayLabelBox
);
522 label
->setMinimumWidth(1);
523 label
->setAlignment(Qt::AlignCenter
);
526 #ifndef KORG_NOPLUGINS
527 foreach ( QString decoName
,
528 KOPrefs::instance()->decorationsAtAgendaViewTop() ) {
529 if ( KOPrefs::instance()->selectedPlugins().contains( decoName
) ) {
530 CalendarDecoration::Decoration
* deco
531 = KOCore::self()->loadCalendarDecoration( decoName
);
533 CalendarDecoration::Element::List elements
;
534 elements
= deco
->dayElements( date
);
535 if ( elements
.count() > 0 ) {
536 KHBox
*decoHBox
= new KHBox( dayLabelBox
);
537 decoHBox
->setFrameShape( QFrame::StyledPanel
);
538 decoHBox
->setMinimumWidth( 1 );
540 foreach ( CalendarDecoration::Element
* it
, elements
) {
541 kDebug() << "adding Element " << it
->id()
542 << " of Decoration " << deco
->info()
543 << " to the top of the agenda view";
544 KODecorationLabel
*label
= new KODecorationLabel( it
, decoHBox
);
545 label
->setAlignment( Qt::AlignBottom
);
546 label
->setMinimumWidth( 1 );
552 foreach ( QString decoName
,
553 KOPrefs::instance()->decorationsAtAgendaViewBottom() ) {
554 if ( KOPrefs::instance()->selectedPlugins().contains( decoName
) ) {
555 CalendarDecoration::Decoration
* deco
556 = KOCore::self()->loadCalendarDecoration( decoName
);
558 CalendarDecoration::Element::List elements
;
559 elements
= deco
->dayElements( date
);
560 if ( elements
.count() > 0 ) {
561 KHBox
*decoHBox
= new KHBox( bottomDayLabelBox
);
562 decoHBox
->setFrameShape( QFrame::StyledPanel
);
563 decoHBox
->setMinimumWidth( 1 );
565 foreach ( CalendarDecoration::Element
* it
, elements
) {
566 kDebug() << "adding Element " << it
->id()
567 << " of Decoration " << deco
->info()
568 << " to the bottom of the agenda view";
569 KODecorationLabel
*label
= new KODecorationLabel( it
, decoHBox
);
570 label
->setAlignment( Qt::AlignBottom
);
571 label
->setMinimumWidth( 1 );
579 #ifndef KORG_NOPLUGINS
580 // Week decoration labels
581 foreach ( QString decoName
,
582 KOPrefs::instance()->decorationsAtAgendaViewTop() ) {
583 if ( KOPrefs::instance()->selectedPlugins().contains( decoName
) ) {
584 CalendarDecoration::Decoration
* deco
585 = KOCore::self()->loadCalendarDecoration( decoName
);
587 CalendarDecoration::Element::List elements
;
588 elements
= deco
->weekElements( mSelectedDates
.first() );
589 if ( elements
.count() > 0 ) {
590 KHBox
*decoHBox
= new KHBox( weekLabelBox
);
591 decoHBox
->setFrameShape( QFrame::StyledPanel
);
592 decoHBox
->setMinimumWidth( 1 );
594 foreach ( CalendarDecoration::Element
* it
, elements
) {
595 kDebug() << "adding Element " << it
->id()
596 << " of Decoration " << deco
->info()
597 << " to the week part of the agenda view";
598 KODecorationLabel
*label
= new KODecorationLabel( it
, decoHBox
);
599 label
->setAlignment( Qt::AlignBottom
);
600 label
->setMinimumWidth( 1 );
605 foreach ( QString decoName
,
606 KOPrefs::instance()->decorationsAtAgendaViewBottom() ) {
607 if ( KOPrefs::instance()->selectedPlugins().contains( decoName
) ) {
608 CalendarDecoration::Decoration
* deco
609 = KOCore::self()->loadCalendarDecoration( decoName
);
611 CalendarDecoration::Element::List elements
;
612 elements
= deco
->weekElements( mSelectedDates
.first() );
613 if ( elements
.count() > 0 ) {
614 KHBox
*decoHBox
= new KHBox( bottomWeekLabelBox
);
615 decoHBox
->setFrameShape( QFrame::StyledPanel
);
616 decoHBox
->setMinimumWidth( 1 );
618 foreach ( CalendarDecoration::Element
* it
, elements
) {
619 kDebug() << "adding Element " << it
->id()
620 << " of Decoration " << deco
->info()
621 << " to the week part of the agenda view";
622 KODecorationLabel
*label
= new KODecorationLabel( it
, decoHBox
);
623 label
->setAlignment( Qt::AlignBottom
);
624 label
->setMinimumWidth( 1 );
631 if ( !mIsSideBySide
) {
632 mLayoutDayLabels
->addSpacing(mAgenda
->verticalScrollBar()->width());
633 mLayoutBottomDayLabels
->addSpacing(mAgenda
->verticalScrollBar()->width());
636 mBottomDayLabels
->show();
639 void KOAgendaView::enableAgendaUpdate( bool enable
)
641 mAllowAgendaUpdate
= enable
;
644 int KOAgendaView::maxDatesHint()
646 // Not sure about the max number of events, so return 0 for now.
650 int KOAgendaView::currentDateCount()
652 return mSelectedDates
.count();
655 Incidence::List
KOAgendaView::selectedIncidences()
657 Incidence::List selected
;
658 Incidence
*incidence
;
660 incidence
= mAgenda
->selectedIncidence();
661 if (incidence
) selected
.append(incidence
);
663 incidence
= mAllDayAgenda
->selectedIncidence();
664 if (incidence
) selected
.append(incidence
);
669 DateList
KOAgendaView::selectedDates()
674 qd
= mAgenda
->selectedIncidenceDate();
675 if (qd
.isValid()) selected
.append(qd
);
677 qd
= mAllDayAgenda
->selectedIncidenceDate();
678 if (qd
.isValid()) selected
.append(qd
);
683 bool KOAgendaView::eventDurationHint( QDateTime
&startDt
, QDateTime
&endDt
,
686 if ( selectionStart().isValid() ) {
687 QDateTime start
= selectionStart();
688 QDateTime end
= selectionEnd();
690 if ( start
.secsTo( end
) == 15*60 ) {
691 // One cell in the agenda view selected, e.g.
692 // because of a double-click, => Use the default duration
693 QTime
defaultDuration( KOPrefs::instance()->mDefaultDuration
.time() );
694 int addSecs
= ( defaultDuration
.hour()*3600 ) +
695 ( defaultDuration
.minute()*60 );
696 end
= start
.addSecs( addSecs
);
701 allDay
= selectedIsAllDay();
707 /** returns if only a single cell is selected, or a range of cells */
708 bool KOAgendaView::selectedIsSingleCell()
710 if ( !selectionStart().isValid() || !selectionEnd().isValid() ) return false;
712 if (selectedIsAllDay()) {
713 int days
= selectionStart().daysTo(selectionEnd());
716 int secs
= selectionStart().secsTo(selectionEnd());
717 return ( secs
<= 24*60*60/mAgenda
->rows() );
722 void KOAgendaView::updateView()
729 Update configuration settings for the agenda view. This method is not
732 void KOAgendaView::updateConfig()
734 mAgenda
->updateConfig();
735 mAllDayAgenda
->updateConfig();
737 mTimeLabelsZone
->updateAll();
739 updateTimeBarWidth();
748 void KOAgendaView::createTimeBarHeaders()
750 qDeleteAll( mTimeBarHeaders
);
751 mTimeBarHeaders
.clear();
753 foreach( TimeLabels
*timeLabel
, mTimeLabelsZone
->timeLabels() ) {
754 QLabel
*label
= new QLabel( i18n("All Day"), mTimeBarHeaderFrame
);
755 label
->setText( timeLabel
->header() );
756 label
->setAlignment( Qt::AlignBottom
| Qt::AlignHCenter
);
757 label
->setWordWrap( true );
758 label
->setToolTip( timeLabel
->headerToolTip() );
759 mTimeBarHeaders
.append( label
);
763 void KOAgendaView::updateTimeBarWidth()
765 createTimeBarHeaders();
767 int width
= mTimeLabelsZone
->timeLabelsWidth();
769 mTimeBarHeaderFrame
->setFixedWidth( width
);
770 mTimeLabelsZone
->setTimeLabelsWidth( width
);
774 void KOAgendaView::updateEventDates( KOAgendaItem
*item
)
776 kDebug() << item
->text();
778 KDateTime startDt
,endDt
;
780 // Start date of this incidence, calculate the offset from it (so recurring and
781 // non-recurring items can be treated exactly the same, we never need to check
782 // for recurs(), because we only move the start day by the number of days the
783 // agenda item was really moved. Smart, isn't it?)
785 if ( item
->cellXLeft() < 0 ) {
786 thisDate
= ( mSelectedDates
.first() ).addDays( item
->cellXLeft() );
788 thisDate
= mSelectedDates
[ item
->cellXLeft() ];
790 QDate
oldThisDate( item
->itemDate() );
791 int daysOffset
= oldThisDate
.daysTo( thisDate
);
793 // startDt.setDate( startDate );
795 Incidence
*incidence
= item
->incidence();
796 if ( !incidence
) return;
797 if ( !mChanger
|| !mChanger
->beginChange(incidence
) ) return;
798 Incidence
*oldIncidence
= incidence
->clone();
800 QTime
startTime(0,0,0), endTime(0,0,0);
801 if ( incidence
->allDay() ) {
802 daysLength
= item
->cellWidth() - 1;
804 startTime
= mAgenda
->gyToTime( item
->cellYTop() );
805 if ( item
->lastMultiItem() ) {
806 endTime
= mAgenda
->gyToTime( item
->lastMultiItem()->cellYBottom() + 1 );
807 daysLength
= item
->lastMultiItem()->cellXLeft() - item
->cellXLeft();
809 endTime
= mAgenda
->gyToTime( item
->cellYBottom() + 1 );
813 // FIXME: use a visitor here
814 if ( incidence
->type() == "Event" ) {
815 startDt
= incidence
->dtStart();
816 // convert to calendar timespec because we then manipulate it with time coming from
818 startDt
= startDt
.toTimeSpec( KOPrefs::instance()->timeSpec() );
819 startDt
= startDt
.addDays( daysOffset
);
820 if ( !startDt
.isDateOnly() )
821 startDt
.setTime( startTime
);
822 endDt
= startDt
.addDays( daysLength
);
823 if ( !endDt
.isDateOnly() )
824 endDt
.setTime( endTime
);
825 Event
*ev
= static_cast<Event
*>(incidence
);
826 if( incidence
->dtStart().toTimeSpec( KOPrefs::instance()->timeSpec() ) == startDt
827 && ev
->dtEnd().toTimeSpec( KOPrefs::instance()->timeSpec() ) == endDt
) {
832 } else if ( incidence
->type() == "Todo" ) {
833 Todo
*td
= static_cast<Todo
*>(incidence
);
835 startDt
= td
->hasStartDate() ? td
->dtStart() : td
->dtDue();
836 // convert to calendar timespec because we then manipulate it with time coming from
838 startDt
= startDt
.toTimeSpec( KOPrefs::instance()->timeSpec() );
839 startDt
.setDate( thisDate
.addDays( td
->dtDue().daysTo( startDt
) ) );
840 if ( !startDt
.isDateOnly() ) {
841 startDt
.setTime( startTime
);
845 endDt
.setDate( thisDate
);
846 if ( !endDt
.isDateOnly() )
847 endDt
.setTime( endTime
);
849 if( td
->dtDue().toTimeSpec( KOPrefs::instance()->timeSpec() ) == endDt
) {
855 // FIXME: Adjusting the recurrence should really go to CalendarView so this
856 // functionality will also be available in other views!
857 // TODO_Recurrence: This does not belong here, and I'm not really sure
858 // how it's supposed to work anyway.
859 /* Recurrence *recur = incidence->recurrence();
860 if ( recur->recurs() && daysOffset != 0 ) {
861 switch ( recur->recurrenceType() ) {
862 case Recurrence::rYearlyPos: {
863 int freq = recur->frequency();
864 int duration = recur->duration();
865 QDate endDt( recur->endDate() );
866 bool negative = false;
868 QPtrList<Recurrence::rMonthPos> monthPos( recur->yearMonthPositions() );
869 if ( monthPos.first() ) {
870 negative = monthPos.first()->negative;
875 days.setBit( thisDate.dayOfWeek() - 1 );
877 pos = - ( thisDate.daysInMonth() - thisDate.day() - 1 ) / 7 - 1;
879 pos = ( thisDate.day()-1 ) / 7 + 1;
881 // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again
882 recur->unsetRecurs();
883 if ( duration != 0 ) {
884 recur->setYearly( Recurrence::rYearlyPos, freq, duration );
886 recur->setYearly( Recurrence::rYearlyPos, freq, endDt );
888 recur->addYearlyMonthPos( pos, days );
889 recur->addYearlyNum( thisDate.month() );
892 case Recurrence::rYearlyDay: {
893 int freq = recur->frequency();
894 int duration = recur->duration();
895 QDate endDt( recur->endDate() );
896 // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again
897 recur->unsetRecurs();
898 if ( duration == 0 ) { // end by date
899 recur->setYearly( Recurrence::rYearlyDay, freq, endDt );
901 recur->setYearly( Recurrence::rYearlyDay, freq, duration );
903 recur->addYearlyNum( thisDate.dayOfYear() );
905 case Recurrence::rYearlyMonth: {
906 int freq = recur->frequency();
907 int duration = recur->duration();
908 QDate endDt( recur->endDate() );
909 // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again
910 recur->unsetRecurs();
911 if ( duration != 0 ) {
912 recur->setYearlyByDate( thisDate.day(), recur->feb29YearlyType(), freq, duration );
914 recur->setYearlyByDate( thisDate.day(), recur->feb29YearlyType(), freq, endDt );
916 recur->addYearlyNum( thisDate.month() );
918 case Recurrence::rMonthlyPos: {
919 int freq = recur->frequency();
920 int duration = recur->duration();
921 QDate endDt( recur->endDate() );
922 QPtrList<Recurrence::rMonthPos> monthPos( recur->monthPositions() );
923 if ( !monthPos.isEmpty() ) {
924 // FIXME: How shall I adapt the day x of week Y if we move the date across month borders???
925 // for now, just use the date of the moved item and assume the recurrence only occurs on that day.
926 // That's fine for korganizer, but might mess up other organizers.
927 QBitArray rDays( 7 );
928 rDays = monthPos.first()->rDays;
929 bool negative = monthPos.first()->negative;
932 rDays.setBit( thisDate.dayOfWeek() - 1 );
934 newPos = - ( thisDate.daysInMonth() - thisDate.day() - 1 ) / 7 - 1;
936 newPos = ( thisDate.day()-1 ) / 7 + 1;
939 // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again
940 recur->unsetRecurs();
941 if ( duration == 0 ) { // end by date
942 recur->setMonthly( Recurrence::rMonthlyPos, freq, endDt );
944 recur->setMonthly( Recurrence::rMonthlyPos, freq, duration );
946 recur->addMonthlyPos( newPos, rDays );
949 case Recurrence::rMonthlyDay: {
950 int freq = recur->frequency();
951 int duration = recur->duration();
952 QDate endDt( recur->endDate() );
953 QPtrList<int> monthDays( recur->monthDays() );
954 // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again
955 recur->unsetRecurs();
956 if ( duration == 0 ) { // end by date
957 recur->setMonthly( Recurrence::rMonthlyDay, freq, endDt );
959 recur->setMonthly( Recurrence::rMonthlyDay, freq, duration );
961 // FIXME: How shall I adapt the n-th day if we move the date across month borders???
962 // for now, just use the date of the moved item and assume the recurrence only occurs on that day.
963 // That's fine for korganizer, but might mess up other organizers.
964 recur->addMonthlyDay( thisDate.day() );
967 case Recurrence::rWeekly: {
968 QBitArray days(7), oldDays( recur->days() );
969 int offset = daysOffset % 7;
970 if ( offset<0 ) offset = (offset+7) % 7;
972 for (int d=0; d<7; d++ ) {
973 days.setBit( (d+offset) % 7, oldDays.at(d) );
975 if ( recur->duration() == 0 ) { // end by date
976 recur->setWeekly( recur->frequency(), days, recur->endDate(), recur->weekStart() );
977 } else { // duration or no end
978 recur->setWeekly( recur->frequency(), days, recur->duration(), recur->weekStart() );
981 // nothing to be done for the following:
982 case Recurrence::rDaily:
983 case Recurrence::rHourly:
984 case Recurrence::rMinutely:
985 case Recurrence::rNone:
989 if ( recur->duration()==0 ) { // end by date
990 recur->setEndDate( recur->endDate().addDays( daysOffset ) );
992 KMessageBox::information( this, i18n("A recurring calendar item was moved "
993 "to a different day. The recurrence settings "
994 "have been updated with that move. Please check "
995 "them in the editor."),
996 i18n("Recurrence Moved"),
997 "RecurrenceMoveInAgendaWarning" );
1000 // FIXME: use a visitor here
1001 if ( incidence
->type() == "Event" ) {
1002 incidence
->setDtStart( startDt
.toTimeSpec( incidence
->dtStart().timeSpec() ) );
1003 (static_cast<Event
*>( incidence
) )->setDtEnd( endDt
.toTimeSpec( incidence
->dtEnd().timeSpec() ) );
1004 } else if ( incidence
->type() == "Todo" ) {
1005 Todo
*td
= static_cast<Todo
*>( incidence
);
1006 if ( td
->hasStartDate() )
1007 td
->setDtStart( startDt
.toTimeSpec( incidence
->dtStart().timeSpec() ) );
1008 td
->setDtDue( endDt
.toTimeSpec( td
->dtDue().timeSpec() ) );
1010 item
->setItemDate( startDt
.toTimeSpec( KOPrefs::instance()->timeSpec() ).date() );
1012 item
->setToolTip( IncidenceFormatter::toolTipString( incidence
));
1014 mChanger
->changeIncidence( oldIncidence
, incidence
);
1015 mChanger
->endChange(incidence
);
1016 delete oldIncidence
;
1018 // don't update the agenda as the item already has the correct coordinates.
1019 // an update would delete the current item and recreate it, but we are still
1020 // using a pointer to that item! => CRASH
1021 enableAgendaUpdate( false );
1022 // We need to do this in a timer to make sure we are not deleting the item
1023 // we are currently working on, which would lead to crashes
1024 // Only the actually moved agenda item is already at the correct position and mustn't be
1025 // recreated. All others have to!!!
1026 if ( incidence
->recurs() ) {
1027 mUpdateItem
= incidence
;
1028 QTimer::singleShot( 0, this, SLOT( doUpdateItem() ) );
1031 enableAgendaUpdate( true );
1034 void KOAgendaView::doUpdateItem()
1036 if ( mUpdateItem
) {
1037 changeIncidenceDisplay( mUpdateItem
, KOGlobals::INCIDENCEEDITED
);
1042 void KOAgendaView::showDates( const QDate
&start
, const QDate
&end
)
1044 mSelectedDates
.clear();
1048 mSelectedDates
.append(d
);
1052 // and update the view
1057 void KOAgendaView::showIncidences( const Incidence::List
&incidences
)
1059 // we must check if they are not filtered; if they are, remove the filter
1060 CalFilter
*filter
= calendar()->filter();
1061 bool wehaveall
= true;
1063 for ( Incidence::List::ConstIterator it
= incidences
.constBegin();
1064 it
!= incidences
.constEnd(); ++it
)
1065 if ( !( wehaveall
= filter
->filterIncidence( *it
) ) )
1069 calendar()->setFilter( 0 );
1071 KDateTime start
= incidences
.first()->dtStart().toTimeSpec( KOPrefs::instance()->timeSpec() ),
1072 end
= incidences
.first()->dtEnd().toTimeSpec( KOPrefs::instance()->timeSpec() );
1073 Incidence
*first
= incidences
.first();
1074 for ( Incidence::List::ConstIterator it
= incidences
.constBegin();
1075 it
!= incidences
.constEnd(); ++it
) {
1076 if ( ( *it
)->dtStart().toTimeSpec( KOPrefs::instance()->timeSpec() ) < start
)
1078 start
= qMin( start
, ( *it
)->dtStart().toTimeSpec( KOPrefs::instance()->timeSpec() ) );
1079 end
= qMax( start
, ( *it
)->dtEnd().toTimeSpec( KOPrefs::instance()->timeSpec() ) );
1082 end
.toTimeSpec( start
); // allow direct comparison of dates
1083 if ( start
.date().daysTo( end
.date() ) + 1 <= currentDateCount() )
1084 showDates( start
.date(), end
.date() );
1086 showDates( start
.date(), start
.date().addDays( currentDateCount() - 1 ) );
1088 mAgenda
->selectItemByUID( first
->uid() );
1091 void KOAgendaView::insertIncidence( Incidence
*incidence
, const QDate
&curDate
,
1094 if ( !filterByResource( incidence
) )
1097 // FIXME: Use a visitor here, or some other method to get rid of the dynamic_cast's
1098 Event
*event
= dynamic_cast<Event
*>( incidence
);
1099 Todo
*todo
= dynamic_cast<Todo
*>( incidence
);
1102 curCol
= mSelectedDates
.indexOf( curDate
);
1104 // The date for the event is not displayed, just ignore it
1105 if ( curCol
< 0 || curCol
> int( mSelectedDates
.size() ) )
1111 beginX
= curDate
.daysTo( incidence
->dtStart().toTimeSpec( KOPrefs::instance()->timeSpec() ).date() ) + curCol
;
1112 endX
= curDate
.daysTo( event
->dtEnd().toTimeSpec( KOPrefs::instance()->timeSpec() ).date() ) + curCol
;
1113 } else if ( todo
) {
1114 if ( ! todo
->hasDueDate() ) return; // todo shall not be displayed if it has no date
1115 beginX
= curDate
.daysTo( todo
->dtDue().date() ) + curCol
;
1120 if ( todo
&& todo
->isOverdue() ) {
1121 mAllDayAgenda
->insertAllDayItem( incidence
, curDate
, curCol
, curCol
);
1122 } else if ( incidence
->allDay() ) {
1123 // FIXME: This breaks with recurring multi-day events!
1124 if ( incidence
->recurrence()->recurs() ) {
1125 mAllDayAgenda
->insertAllDayItem( incidence
, curDate
, curCol
, curCol
);
1127 // Insert multi-day events only on the first day, otherwise it will
1128 // appear multiple times
1129 if ( ( beginX
<= 0 && curCol
== 0 ) || beginX
== curCol
) {
1130 mAllDayAgenda
->insertAllDayItem( incidence
, curDate
, beginX
, endX
);
1133 } else if ( event
&& event
->isMultiDay( KOPrefs::instance()->timeSpec() ) ) {
1134 int startY
= mAgenda
->timeToY( event
->dtStart().toTimeSpec( KOPrefs::instance()->timeSpec() ).time() );
1135 QTime
endtime( event
->dtEnd().toTimeSpec( KOPrefs::instance()->timeSpec() ).time() );
1136 if ( endtime
== QTime( 0, 0, 0 ) ) endtime
= QTime( 23, 59, 59 );
1137 int endY
= mAgenda
->timeToY( endtime
) - 1;
1138 if ( (beginX
<= 0 && curCol
== 0) || beginX
== curCol
) {
1139 mAgenda
->insertMultiItem( event
, curDate
, beginX
, endX
, startY
, endY
);
1141 if ( beginX
== curCol
) {
1142 mMaxY
[curCol
] = mAgenda
->timeToY( QTime(23,59) );
1143 if ( startY
< mMinY
[curCol
] ) mMinY
[curCol
] = startY
;
1144 } else if ( endX
== curCol
) {
1145 mMinY
[curCol
] = mAgenda
->timeToY( QTime(0,0) );
1146 if ( endY
> mMaxY
[curCol
] ) mMaxY
[curCol
] = endY
;
1148 mMinY
[curCol
] = mAgenda
->timeToY( QTime(0,0) );
1149 mMaxY
[curCol
] = mAgenda
->timeToY( QTime(23,59) );
1152 int startY
= 0, endY
= 0;
1154 startY
= mAgenda
->timeToY( incidence
->dtStart().toTimeSpec( KOPrefs::instance()->timeSpec() ).time() );
1155 QTime
endtime( event
->dtEnd().toTimeSpec( KOPrefs::instance()->timeSpec() ).time() );
1156 if ( endtime
== QTime( 0, 0, 0 ) ) endtime
= QTime( 23, 59, 59 );
1157 endY
= mAgenda
->timeToY( endtime
) - 1;
1160 QTime t
= todo
->dtDue().toTimeSpec( KOPrefs::instance()->timeSpec() ).time();
1161 endY
= mAgenda
->timeToY( t
) - 1;
1162 startY
= mAgenda
->timeToY( t
.addSecs( -1800 ) );
1164 if ( endY
< startY
) endY
= startY
;
1165 mAgenda
->insertItem( incidence
, curDate
, curCol
, startY
, endY
);
1166 if ( startY
< mMinY
[curCol
] ) mMinY
[curCol
] = startY
;
1167 if ( endY
> mMaxY
[curCol
] ) mMaxY
[curCol
] = endY
;
1171 void KOAgendaView::changeIncidenceDisplayAdded( Incidence
*incidence
)
1173 Todo
*todo
= dynamic_cast<Todo
*>(incidence
);
1174 CalFilter
*filter
= calendar()->filter();
1175 if ( filter
&& !filter
->filterIncidence( incidence
) ||
1176 ( todo
&& !KOPrefs::instance()->showAllDayTodo() ) )
1179 QDate f
= mSelectedDates
.first();
1180 QDate l
= mSelectedDates
.last();
1182 QDate startDt
= incidence
->dtStart().toTimeSpec( KOPrefs::instance()->timeSpec() ).date();
1184 if ( incidence
->recurs() ) {
1185 DateList::ConstIterator dit
;
1187 for( dit
= mSelectedDates
.begin(); dit
!= mSelectedDates
.end(); ++dit
) {
1189 // FIXME: This breaks with recurring multi-day events!
1190 if ( incidence
->recursOn( curDate
, KOPrefs::instance()->timeSpec() ) ) {
1191 insertIncidence( incidence
, curDate
);
1198 if ( incidence
->type() == "Event" )
1199 endDt
= (static_cast<Event
*>(incidence
))->dtEnd().toTimeSpec( KOPrefs::instance()->timeSpec() ).date();
1201 endDt
= todo
->isOverdue() ? QDate::currentDate()
1202 : todo
->dtDue().date();
1204 if ( endDt
>= f
&& endDt
<= l
) {
1205 insertIncidence( incidence
, endDt
);
1209 if ( startDt
>= f
&& startDt
<= l
) {
1210 insertIncidence( incidence
, startDt
);
1214 void KOAgendaView::changeIncidenceDisplay( Incidence
*incidence
, int mode
)
1217 case KOGlobals::INCIDENCEADDED
: {
1218 // Add an event. No need to recreate the whole view!
1219 // recreating everything even causes troubles: dropping to the day matrix
1220 // recreates the agenda items, but the evaluation is still in an agendaItems' code,
1221 // which was deleted in the mean time. Thus KOrg crashes...
1222 changeIncidenceDisplayAdded( incidence
);
1225 case KOGlobals::INCIDENCEEDITED
: {
1226 if ( !mAllowAgendaUpdate
) {
1227 updateEventIndicators();
1229 removeIncidence( incidence
);
1230 updateEventIndicators();
1231 changeIncidenceDisplayAdded( incidence
);
1235 case KOGlobals::INCIDENCEDELETED
: {
1236 mAgenda
->removeIncidence( incidence
);
1237 mAllDayAgenda
->removeIncidence( incidence
);
1238 updateEventIndicators();
1246 void KOAgendaView::fillAgenda( const QDate
& )
1251 void KOAgendaView::fillAgenda()
1253 /* Remember the uids of the selected items. In case one of the
1254 * items was deleted and re-added, we want to reselect it. */
1255 const QString
&selectedAgendaUid
= mAgenda
->lastSelectedUid();
1256 const QString
&selectedAllDayAgendaUid
= mAllDayAgenda
->lastSelectedUid();
1258 enableAgendaUpdate( true );
1261 mAllDayAgenda
->changeColumns(mSelectedDates
.count());
1262 mAgenda
->changeColumns(mSelectedDates
.count());
1263 mEventIndicatorTop
->changeColumns(mSelectedDates
.count());
1264 mEventIndicatorBottom
->changeColumns(mSelectedDates
.count());
1269 mMinY
.resize(mSelectedDates
.count());
1270 mMaxY
.resize(mSelectedDates
.count());
1272 Event::List dayEvents
;
1274 // ToDo items shall be displayed for the day they are due, but only shown today if they are already overdue.
1275 // Therefore, get all of them.
1276 Todo::List todos
= calendar()->todos();
1278 mAgenda
->setDateList(mSelectedDates
);
1280 QDate today
= QDate::currentDate();
1282 bool somethingReselected
= false;
1283 DateList::ConstIterator dit
;
1285 for( dit
= mSelectedDates
.begin(); dit
!= mSelectedDates
.end(); ++dit
) {
1286 QDate currentDate
= *dit
;
1287 dayEvents
= calendar()->events(currentDate
, KOPrefs::instance()->timeSpec(),
1289 SortDirectionAscending
);
1291 // Default values, which can never be reached
1292 mMinY
[curCol
] = mAgenda
->timeToY(QTime(23,59)) + 1;
1293 mMaxY
[curCol
] = mAgenda
->timeToY(QTime(0,0)) - 1;
1296 for(numEvent
=0;numEvent
<dayEvents
.count();++numEvent
) {
1297 Event
*event
= dayEvents
.at(numEvent
);
1298 insertIncidence( event
, currentDate
, curCol
);
1299 if( event
->uid() == selectedAgendaUid
&& !selectedAgendaUid
.isNull() ) {
1300 mAgenda
->selectItemByUID( event
->uid() );
1301 somethingReselected
= true;
1303 if( event
->uid() == selectedAllDayAgendaUid
&& !selectedAllDayAgendaUid
.isNull() ) {
1304 mAllDayAgenda
->selectItemByUID( event
->uid() );
1305 somethingReselected
= true;
1310 // ---------- [display Todos --------------
1311 if ( KOPrefs::instance()->showAllDayTodo() ) {
1313 for (numTodo
= 0; numTodo
< todos
.count(); ++numTodo
) {
1314 Todo
*todo
= todos
.at(numTodo
);
1316 if ( ! todo
->hasDueDate() ) continue; // todo shall not be displayed if it has no date
1318 // ToDo items shall be displayed for the day they are due, but only showed today if they are already overdue.
1319 // Already completed items can be displayed on their original due date
1320 bool overdue
= todo
->isOverdue();
1322 if ( (( todo
->dtDue().date() == currentDate
) && !overdue
) ||
1323 (( currentDate
== today
) && overdue
) ||
1324 ( todo
->recursOn( currentDate
, KOPrefs::instance()->timeSpec() ) ) ) {
1325 if ( todo
->allDay() || overdue
) { // Todo has no due-time set or is already overdue
1326 mAllDayAgenda
->insertAllDayItem(todo
, currentDate
, curCol
, curCol
);
1328 int endY
= mAgenda
->timeToY(todo
->dtDue().toTimeSpec( KOPrefs::instance()->timeSpec() ).time()) - 1;
1329 int startY
= endY
- 1;
1331 mAgenda
->insertItem(todo
,currentDate
,curCol
,startY
,endY
);
1333 if (startY
< mMinY
[curCol
]) mMinY
[curCol
] = startY
;
1334 if (endY
> mMaxY
[curCol
]) mMaxY
[curCol
] = endY
;
1339 // ---------- display Todos] --------------
1344 mAgenda
->checkScrollBoundaries();
1345 updateEventIndicators();
1347 // mAgenda->viewport()->update();
1348 // mAllDayAgenda->viewport()->update();
1351 deleteSelectedDateTime();
1353 if( !somethingReselected
) {
1354 emit
incidenceSelected( 0 );
1358 void KOAgendaView::clearView()
1360 mAllDayAgenda
->clear();
1364 CalPrinter::PrintType
KOAgendaView::printType()
1366 if ( currentDateCount() == 1 ) return CalPrinter::Day
;
1367 else return CalPrinter::Week
;
1370 void KOAgendaView::updateEventIndicatorTop( int newY
)
1372 for(int i
= 0; i
< mMinY
.size(); ++i
) {
1373 mEventIndicatorTop
->enableColumn( i
, newY
>= mMinY
[i
] );
1375 mEventIndicatorTop
->update();
1378 void KOAgendaView::updateEventIndicatorBottom( int newY
)
1380 for(int i
= 0; i
< mMaxY
.size(); ++i
) {
1381 mEventIndicatorBottom
->enableColumn( i
, newY
<= mMaxY
[i
] );
1383 mEventIndicatorBottom
->update();
1386 void KOAgendaView::slotTodoDropped( Todo
*todo
, const QPoint
&gpos
, bool allDay
)
1388 if ( gpos
.x()<0 || gpos
.y()<0 ) return;
1389 QDate day
= mSelectedDates
[gpos
.x()];
1390 QTime time
= mAgenda
->gyToTime( gpos
.y() );
1391 KDateTime
newTime( day
, time
, KOPrefs::instance()->timeSpec() );
1392 newTime
.setDateOnly( allDay
);
1395 Todo
*existingTodo
= calendar()->todo( todo
->uid() );
1396 if ( existingTodo
) {
1397 kDebug() << "Drop existing Todo";
1398 Todo
*oldTodo
= existingTodo
->clone();
1399 if ( mChanger
&& mChanger
->beginChange( existingTodo
) ) {
1400 existingTodo
->setDtDue( newTime
);
1401 existingTodo
->setAllDay( allDay
);
1402 existingTodo
->setHasDueDate( true );
1403 mChanger
->changeIncidence( oldTodo
, existingTodo
);
1404 mChanger
->endChange( existingTodo
);
1406 KMessageBox::sorry( this, i18n("Unable to modify this to-do, "
1407 "because it cannot be locked.") );
1411 kDebug() << "Drop new Todo";
1412 todo
->setDtDue( newTime
);
1413 todo
->setAllDay( allDay
);
1414 todo
->setHasDueDate( true );
1415 if ( !mChanger
->addIncidence( todo
, this ) ) {
1416 KODialogManager::errorSaveIncidence( this, todo
);
1422 void KOAgendaView::startDrag( Incidence
*incidence
)
1425 DndFactory
factory( calendar() );
1426 QDrag
*drag
= factory
.createDrag( incidence
, this );
1427 if ( drag
->start() ) {
1428 kDebug() << "Delete drag source";
1433 void KOAgendaView::readSettings()
1435 readSettings(KOGlobals::self()->config());
1438 void KOAgendaView::readSettings( KConfig
*config
)
1440 KConfigGroup group
= config
->group( "Views" );
1442 QList
<int> sizes
= group
.readEntry( "Separator AgendaView", QList
<int>() );
1443 if ( sizes
.count() == 4 ) { // Number of sections divided by separators in the view
1444 mSplitterAgenda
->setSizes( sizes
);
1450 void KOAgendaView::writeSettings( KConfig
*config
)
1452 KConfigGroup group
= config
->group( "Views" );
1454 QList
<int> list
= mSplitterAgenda
->sizes();
1455 group
.writeEntry( "Separator AgendaView", list
);
1458 void KOAgendaView::setHolidayMasks()
1460 mHolidayMask
.resize( mSelectedDates
.count() + 1 );
1462 for( int i
= 0; i
< mSelectedDates
.count(); ++i
) {
1463 mHolidayMask
[i
] = !KOGlobals::self()->isWorkDay( mSelectedDates
[ i
] );
1466 // Store the information about the day before the visible area (needed for
1467 // overnight working hours) in the last bit of the mask:
1468 bool showDay
= !KOGlobals::self()->isWorkDay( mSelectedDates
[ 0 ].addDays( -1 ) );
1469 mHolidayMask
[ mSelectedDates
.count() ] = showDay
;
1471 mAgenda
->setHolidayMask( &mHolidayMask
);
1472 mAllDayAgenda
->setHolidayMask( &mHolidayMask
);
1475 void KOAgendaView::setContentsPos( int y
)
1477 if ( y
!= mAgenda
->contentsY() )
1478 mAgenda
->setContentsPos( 0, y
);
1481 void KOAgendaView::clearSelection()
1483 mAgenda
->deselectItem();
1484 mAllDayAgenda
->deselectItem();
1487 void KOAgendaView::newTimeSpanSelectedAllDay( const QPoint
&start
, const QPoint
&end
)
1489 newTimeSpanSelected( start
, end
);
1490 mTimeSpanInAllDay
= true;
1493 void KOAgendaView::newTimeSpanSelected( const QPoint
&start
, const QPoint
&end
)
1495 if (!mSelectedDates
.count()) return;
1497 mTimeSpanInAllDay
= false;
1499 QDate dayStart
= mSelectedDates
[start
.x()];
1500 QDate dayEnd
= mSelectedDates
[end
.x()];
1502 QTime timeStart
= mAgenda
->gyToTime(start
.y());
1503 QTime timeEnd
= mAgenda
->gyToTime( end
.y() + 1 );
1505 QDateTime
dtStart(dayStart
,timeStart
);
1506 QDateTime
dtEnd(dayEnd
,timeEnd
);
1508 mTimeSpanBegin
= dtStart
;
1509 mTimeSpanEnd
= dtEnd
;
1512 void KOAgendaView::deleteSelectedDateTime()
1514 mTimeSpanBegin
.setDate(QDate());
1515 mTimeSpanEnd
.setDate(QDate());
1516 mTimeSpanInAllDay
= false;
1519 void KOAgendaView::setTypeAheadReceiver( QObject
*o
)
1521 mAgenda
->setTypeAheadReceiver( o
);
1522 mAllDayAgenda
->setTypeAheadReceiver( o
);
1525 void KOAgendaView::finishTypeAhead()
1527 mAgenda
->finishTypeAhead();
1528 mAllDayAgenda
->finishTypeAhead();
1531 void KOAgendaView::removeIncidence( Incidence
*incidence
)
1533 mAgenda
->removeIncidence( incidence
);
1534 mAllDayAgenda
->removeIncidence( incidence
);
1537 void KOAgendaView::updateEventIndicators()
1539 mMinY
= mAgenda
->minContentsY();
1540 mMaxY
= mAgenda
->maxContentsY();
1542 mAgenda
->checkScrollBoundaries();
1543 updateEventIndicatorTop( mAgenda
->visibleContentsYMin() );
1544 updateEventIndicatorBottom( mAgenda
->visibleContentsYMax() );
1547 void KOAgendaView::setIncidenceChanger( IncidenceChangerBase
*changer
)
1550 mAgenda
->setIncidenceChanger( changer
);
1551 mAllDayAgenda
->setIncidenceChanger( changer
);
1554 void KOAgendaView::clearTimeSpanSelection()
1556 mAgenda
->clearSelection();
1557 mAllDayAgenda
->clearSelection();
1558 deleteSelectedDateTime();
1561 void KOAgendaView::setResource(KCal::ResourceCalendar
* res
, const QString
& subResource
)
1564 mSubResource
= subResource
;
1567 bool KOAgendaView::filterByResource(Incidence
* incidence
)
1571 CalendarResources
*calRes
= dynamic_cast<CalendarResources
*>( calendar() );
1574 if ( calRes
->resource( incidence
) != mResource
)
1576 if ( !mSubResource
.isEmpty() ) {
1577 if ( mResource
->subresourceIdentifier( incidence
) != mSubResource
)
1583 #include "koagendaview.moc"