00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <qhbox.h>
00026 #include <qvbox.h>
00027 #include <qlabel.h>
00028 #include <qframe.h>
00029 #include <qlayout.h>
00030 #ifndef KORG_NOSPLITTER
00031 #include <qsplitter.h>
00032 #endif
00033 #include <qfont.h>
00034 #include <qfontmetrics.h>
00035 #include <qpopupmenu.h>
00036 #include <qtooltip.h>
00037 #include <qpainter.h>
00038 #include <qpushbutton.h>
00039 #include <qcursor.h>
00040 #include <qbitarray.h>
00041
00042 #include <kapplication.h>
00043 #include <kdebug.h>
00044 #include <kstandarddirs.h>
00045 #include <kiconloader.h>
00046 #include <klocale.h>
00047 #include <kconfig.h>
00048 #include <kglobal.h>
00049 #include <kglobalsettings.h>
00050 #include <kholidays.h>
00051
00052 #include <libkcal/calendar.h>
00053 #include <libkcal/icaldrag.h>
00054 #include <libkcal/dndfactory.h>
00055 #include <libkcal/calfilter.h>
00056
00057 #include <kcalendarsystem.h>
00058
00059 #include "koglobals.h"
00060 #ifndef KORG_NOPLUGINS
00061 #include "kocore.h"
00062 #endif
00063 #include "koprefs.h"
00064 #include "koagenda.h"
00065 #include "koagendaitem.h"
00066 #include "timelabels.h"
00067
00068 #include "koincidencetooltip.h"
00069 #include "kogroupware.h"
00070 #include "kodialogmanager.h"
00071 #include "koeventpopupmenu.h"
00072
00073 #include "koagendaview.h"
00074 #include "koagendaview.moc"
00075
00076 using namespace KOrg;
00077
00078 bool KOAgendaView::sProcessingDrop = false;
00079
00080
00081 EventIndicator::EventIndicator(Location loc,QWidget *parent,const char *name)
00082 : QFrame(parent,name)
00083 {
00084 mColumns = 1;
00085 mEnabled.resize( mColumns );
00086 mLocation = loc;
00087
00088 if (mLocation == Top) mPixmap = KOGlobals::self()->smallIcon("upindicator");
00089 else mPixmap = KOGlobals::self()->smallIcon("downindicator");
00090
00091 setMinimumHeight(mPixmap.height());
00092 }
00093
00094 EventIndicator::~EventIndicator()
00095 {
00096 }
00097
00098 void EventIndicator::drawContents(QPainter *p)
00099 {
00100
00101
00102
00103
00104 int i;
00105 for(i=0;i<mColumns;++i) {
00106 if (mEnabled[i]) {
00107 int cellWidth = contentsRect().right()/mColumns;
00108 int xOffset = KOGlobals::self()->reverseLayout() ?
00109 (mColumns - 1 - i)*cellWidth + cellWidth/2 -mPixmap.width()/2 :
00110 i*cellWidth + cellWidth/2 -mPixmap.width()/2;
00111 p->drawPixmap(QPoint(xOffset,0),mPixmap);
00112 }
00113 }
00114 }
00115
00116 void EventIndicator::changeColumns(int columns)
00117 {
00118 mColumns = columns;
00119 mEnabled.resize(mColumns);
00120
00121 update();
00122 }
00123
00124 void EventIndicator::enableColumn(int column, bool enable)
00125 {
00126 mEnabled[column] = enable;
00127 }
00128
00129
00130 #include <libkcal/incidence.h>
00131
00135
00136
00137 KOAlternateLabel::KOAlternateLabel(const QString &shortlabel, const QString &longlabel,
00138 const QString &extensivelabel, QWidget *parent, const char *name )
00139 : QLabel(parent, name), mTextTypeFixed(false), mShortText(shortlabel),
00140 mLongText(longlabel), mExtensiveText(extensivelabel)
00141 {
00142 setSizePolicy(QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ));
00143 if (mExtensiveText.isEmpty()) mExtensiveText = mLongText;
00144 squeezeTextToLabel();
00145 }
00146
00147 KOAlternateLabel::~KOAlternateLabel()
00148 {
00149 }
00150
00151 void KOAlternateLabel::useShortText()
00152 {
00153 mTextTypeFixed = true;
00154 QLabel::setText( mShortText );
00155 QToolTip::remove( this );
00156 QToolTip::add( this, mExtensiveText );
00157 update();
00158 }
00159
00160 void KOAlternateLabel::useLongText()
00161 {
00162 mTextTypeFixed = true;
00163 QLabel::setText( mLongText );
00164 QToolTip::remove( this );
00165 QToolTip::add( this, mExtensiveText );
00166 update();
00167 }
00168
00169 void KOAlternateLabel::useExtensiveText()
00170 {
00171 mTextTypeFixed = true;
00172 QLabel::setText( mExtensiveText );
00173 QToolTip::remove( this );
00174 QToolTip::add( this, "" );
00175 update();
00176 }
00177
00178 void KOAlternateLabel::useDefaultText()
00179 {
00180 mTextTypeFixed = false;
00181 squeezeTextToLabel();
00182 }
00183
00184 KOAlternateLabel::TextType KOAlternateLabel::largestFittingTextType() const
00185 {
00186 QFontMetrics fm( fontMetrics() );
00187 const int labelWidth = size().width();
00188 const int longTextWidth = fm.width( mLongText );
00189 const int extensiveTextWidth = fm.width( mExtensiveText );
00190 if ( extensiveTextWidth <= labelWidth )
00191 return Extensive;
00192 else if ( longTextWidth <= labelWidth )
00193 return Long;
00194 else
00195 return Short;
00196 }
00197
00198 void KOAlternateLabel::setFixedType( TextType type )
00199 {
00200 switch ( type )
00201 {
00202 case Extensive: useExtensiveText(); break;
00203 case Long: useLongText(); break;
00204 case Short: useShortText(); break;
00205 }
00206 }
00207
00208 void KOAlternateLabel::squeezeTextToLabel()
00209 {
00210 if ( mTextTypeFixed )
00211 return;
00212
00213 const TextType type = largestFittingTextType();
00214 switch ( type )
00215 {
00216 case Extensive:
00217 QLabel::setText( mExtensiveText );
00218 QToolTip::remove( this );
00219 QToolTip::add( this, "" );
00220 break;
00221 case Long:
00222 QLabel::setText( mLongText );
00223 QToolTip::remove( this );
00224 QToolTip::add( this, mExtensiveText );
00225 break;
00226 case Short:
00227 QLabel::setText( mShortText );
00228 QToolTip::remove( this );
00229 QToolTip::add( this, mExtensiveText );
00230 break;
00231 }
00232 update();
00233 }
00234
00235 void KOAlternateLabel::resizeEvent( QResizeEvent * )
00236 {
00237 squeezeTextToLabel();
00238 }
00239
00240 QSize KOAlternateLabel::minimumSizeHint() const
00241 {
00242 QSize sh = QLabel::minimumSizeHint();
00243 sh.setWidth(-1);
00244 return sh;
00245 }
00246
00250
00251 KOAgendaView::KOAgendaView( Calendar *cal,
00252 CalendarView *calendarView,
00253 QWidget *parent,
00254 const char *name,
00255 bool isSideBySide ) :
00256 KOrg::AgendaView (cal, parent,name), mExpandButton( 0 ),
00257 mAllowAgendaUpdate( true ),
00258 mUpdateItem( 0 ),
00259 mIsSideBySide( isSideBySide ),
00260 mPendingChanges( true ),
00261 mAreDatesInitialized( false )
00262 {
00263 mSelectedDates.append(QDate::currentDate());
00264
00265 mLayoutDayLabels = 0;
00266 mDayLabelsFrame = 0;
00267 mDayLabels = 0;
00268
00269 bool isRTL = KOGlobals::self()->reverseLayout();
00270
00271 if ( KOPrefs::instance()->compactDialogs() ) {
00272 if ( KOPrefs::instance()->mVerticalScreen ) {
00273 mExpandedPixmap = KOGlobals::self()->smallIcon( "1downarrow" );
00274 mNotExpandedPixmap = KOGlobals::self()->smallIcon( "1uparrow" );
00275 } else {
00276 mExpandedPixmap = KOGlobals::self()->smallIcon( isRTL ? "1leftarrow" : "1rightarrow" );
00277 mNotExpandedPixmap = KOGlobals::self()->smallIcon( isRTL ? "1rightarrow" : "1leftarrow" );
00278 }
00279 }
00280
00281 QBoxLayout *topLayout = new QVBoxLayout(this);
00282
00283
00284 mDayLabelsFrame = new QHBox(this);
00285 topLayout->addWidget(mDayLabelsFrame);
00286
00287
00288 #ifndef KORG_NOSPLITTER
00289 mSplitterAgenda = new QSplitter(Vertical,this);
00290 topLayout->addWidget(mSplitterAgenda);
00291
00292 #if KDE_IS_VERSION( 3, 1, 93 )
00293 mSplitterAgenda->setOpaqueResize( KGlobalSettings::opaqueResize() );
00294 #else
00295 mSplitterAgenda->setOpaqueResize();
00296 #endif
00297
00298 mAllDayFrame = new QHBox(mSplitterAgenda);
00299
00300 QWidget *agendaFrame = new QWidget(mSplitterAgenda);
00301 #else
00302 QVBox *mainBox = new QVBox( this );
00303 topLayout->addWidget( mainBox );
00304
00305 mAllDayFrame = new QHBox(mainBox);
00306
00307 QWidget *agendaFrame = new QWidget(mainBox);
00308 #endif
00309
00310
00311 mDummyAllDayLeft = new QVBox( mAllDayFrame );
00312 if ( isSideBySide )
00313 mDummyAllDayLeft->hide();
00314
00315 if ( KOPrefs::instance()->compactDialogs() ) {
00316 mExpandButton = new QPushButton(mDummyAllDayLeft);
00317 mExpandButton->setPixmap( mNotExpandedPixmap );
00318 mExpandButton->setSizePolicy( QSizePolicy( QSizePolicy::Fixed,
00319 QSizePolicy::Fixed ) );
00320 connect( mExpandButton, SIGNAL( clicked() ), SIGNAL( toggleExpand() ) );
00321 } else {
00322 QLabel *label = new QLabel( i18n("All Day"), mDummyAllDayLeft );
00323 label->setAlignment( Qt::AlignRight | Qt::AlignVCenter | Qt::WordBreak );
00324 }
00325
00326 mAllDayAgenda = new KOAgenda( 1, calendarView, this, mAllDayFrame );
00327 mAllDayAgenda->setCalendar( calendar() );
00328 QWidget *dummyAllDayRight = new QWidget(mAllDayFrame);
00329
00330
00331 QGridLayout *agendaLayout = new QGridLayout(agendaFrame,3,3);
00332
00333
00334
00335 mEventIndicatorTop = new EventIndicator(EventIndicator::Top,agendaFrame);
00336 agendaLayout->addWidget(mEventIndicatorTop,0,1);
00337 mEventIndicatorBottom = new EventIndicator(EventIndicator::Bottom,
00338 agendaFrame);
00339 agendaLayout->addWidget(mEventIndicatorBottom,2,1);
00340 QWidget *dummyAgendaRight = new QWidget(agendaFrame);
00341 agendaLayout->addWidget(dummyAgendaRight,0,2);
00342
00343
00344 mTimeLabels = new TimeLabels(24,agendaFrame);
00345 agendaLayout->addWidget(mTimeLabels,1,0);
00346
00347
00348 mAgenda = new KOAgenda( 1, 96, KOPrefs::instance()->mHourSize, calendarView, this, agendaFrame );
00349 mAgenda->setCalendar( calendar() );
00350 agendaLayout->addMultiCellWidget(mAgenda,1,1,1,2);
00351 agendaLayout->setColStretch(1,1);
00352
00353
00354 mAgendaPopup = eventPopup();
00355
00356
00357 mAllDayAgendaPopup = eventPopup();
00358
00359
00360 mTimeLabels->setAgenda(mAgenda);
00361 if ( isSideBySide )
00362 mTimeLabels->hide();
00363
00364
00365
00366
00367 createDayLabels( true );
00368
00369 if ( !isSideBySide ) {
00370
00371 dummyAllDayRight->setFixedWidth(mAgenda->verticalScrollBar()->width());
00372 dummyAgendaRight->setFixedWidth(mAgenda->verticalScrollBar()->width());
00373 }
00374
00375 updateTimeBarWidth();
00376
00377
00378 connect(mAgenda->verticalScrollBar(),SIGNAL(valueChanged(int)),
00379 mTimeLabels, SLOT(positionChanged()));
00380
00381 connect( mAgenda,
00382 SIGNAL( zoomView( const int, const QPoint & ,const Qt::Orientation ) ),
00383 SLOT( zoomView( const int, const QPoint &, const Qt::Orientation ) ) );
00384
00385 connect(mTimeLabels->verticalScrollBar(),SIGNAL(valueChanged(int)),
00386 SLOT(setContentsPos(int)));
00387
00388
00389 connect( mAgenda, SIGNAL(newTimeSpanSignal(const QPoint &, const QPoint &)),
00390 SLOT(newTimeSpanSelected(const QPoint &, const QPoint &)));
00391 connect( mAllDayAgenda, SIGNAL(newTimeSpanSignal(const QPoint &, const QPoint &)),
00392 SLOT(newTimeSpanSelectedAllDay(const QPoint &, const QPoint &)));
00393
00394
00395 connect( mAgenda, SIGNAL(lowerYChanged(int)),
00396 SLOT(updateEventIndicatorTop(int)));
00397 connect( mAgenda, SIGNAL(upperYChanged(int)),
00398 SLOT(updateEventIndicatorBottom(int)));
00399
00400 if ( !readOnly() ) {
00401 connectAgenda( mAgenda, mAgendaPopup, mAllDayAgenda );
00402 connectAgenda( mAllDayAgenda, mAllDayAgendaPopup, mAgenda);
00403 }
00404
00405 if ( cal ) {
00406 cal->registerObserver( this );
00407 }
00408 }
00409
00410
00411 KOAgendaView::~KOAgendaView()
00412 {
00413 if ( calendar() )
00414 calendar()->unregisterObserver( this );
00415 delete mAgendaPopup;
00416 delete mAllDayAgendaPopup;
00417 }
00418
00419 void KOAgendaView::connectAgenda( KOAgenda *agenda, QPopupMenu *popup,
00420 KOAgenda *otherAgenda )
00421 {
00422 connect( agenda, SIGNAL(showIncidencePopupSignal(Calendar *,Incidence *,const QDate &)),
00423 popup, SLOT(showIncidencePopup(Calendar *,Incidence *,const QDate &)) );
00424
00425 connect( agenda, SIGNAL(showNewEventPopupSignal()),
00426 SLOT(showNewEventPopup()) );
00427
00428
00429
00430 connect( agenda, SIGNAL(newEventSignal(ResourceCalendar *,const QString &)),
00431 SIGNAL(newEventSignal(ResourceCalendar *,const QString &)) );
00432
00433 connect( agenda, SIGNAL(newStartSelectSignal()),
00434 otherAgenda, SLOT(clearSelection()) );
00435 connect( agenda, SIGNAL(newStartSelectSignal()),
00436 SIGNAL(timeSpanSelectionChanged()) );
00437
00438 connect( agenda, SIGNAL(editIncidenceSignal(Incidence *,const QDate &)),
00439 SIGNAL(editIncidenceSignal(Incidence *,const QDate &)) );
00440 connect( agenda, SIGNAL(showIncidenceSignal(Incidence *,const QDate &)),
00441 SIGNAL(showIncidenceSignal(Incidence *,const QDate &)) );
00442 connect( agenda, SIGNAL(deleteIncidenceSignal(Incidence *)),
00443 SIGNAL(deleteIncidenceSignal(Incidence *)) );
00444
00445 connect( agenda, SIGNAL(startMultiModify(const QString &)),
00446 SIGNAL(startMultiModify(const QString &)) );
00447 connect( agenda, SIGNAL(endMultiModify()),
00448 SIGNAL(endMultiModify()) );
00449
00450
00451 connect( agenda, SIGNAL(startDragSignal(Incidence *)),
00452 SLOT(startDrag(Incidence *)) );
00453
00454
00455 connect( agenda, SIGNAL(incidenceSelected(Incidence *,const QDate &)),
00456 otherAgenda, SLOT(deselectItem()) );
00457 connect( agenda, SIGNAL(incidenceSelected(Incidence *,const QDate &)),
00458 SIGNAL(incidenceSelected(Incidence *,const QDate &)) );
00459
00460
00461 connect( agenda, SIGNAL(droppedIncidence(Incidence *,const QPoint &,bool)),
00462 SLOT(slotIncidenceDropped(Incidence *,const QPoint &,bool)) );
00463
00464 }
00465
00466 void KOAgendaView::zoomInVertically( )
00467 {
00468 if ( !mIsSideBySide )
00469 KOPrefs::instance()->mHourSize++;
00470 mAgenda->updateConfig();
00471 mAgenda->checkScrollBoundaries();
00472
00473 mTimeLabels->updateConfig();
00474 mTimeLabels->positionChanged();
00475 mTimeLabels->repaint();
00476
00477 updateView();
00478 }
00479
00480 void KOAgendaView::zoomOutVertically( )
00481 {
00482
00483 if ( KOPrefs::instance()->mHourSize > 4 || mIsSideBySide ) {
00484
00485 if ( !mIsSideBySide )
00486 KOPrefs::instance()->mHourSize--;
00487 mAgenda->updateConfig();
00488 mAgenda->checkScrollBoundaries();
00489
00490 mTimeLabels->updateConfig();
00491 mTimeLabels->positionChanged();
00492 mTimeLabels->repaint();
00493
00494 updateView();
00495 }
00496 }
00497
00498 void KOAgendaView::zoomInHorizontally( const QDate &date)
00499 {
00500 QDate begin;
00501 QDate newBegin;
00502 QDate dateToZoom = date;
00503 int ndays,count;
00504
00505 begin = mSelectedDates.first();
00506 ndays = begin.daysTo( mSelectedDates.last() );
00507
00508
00509 if ( ! dateToZoom.isValid () )
00510 dateToZoom=mAgenda->selectedIncidenceDate();
00511
00512 if( !dateToZoom.isValid() ) {
00513 if ( ndays > 1 ) {
00514 newBegin=begin.addDays(1);
00515 count = ndays-1;
00516 emit zoomViewHorizontally ( newBegin , count );
00517 }
00518 } else {
00519 if ( ndays <= 2 ) {
00520 newBegin = dateToZoom;
00521 count = 1;
00522 } else {
00523 newBegin = dateToZoom.addDays( -ndays/2 +1 );
00524 count = ndays -1 ;
00525 }
00526 emit zoomViewHorizontally ( newBegin , count );
00527 }
00528 }
00529
00530 void KOAgendaView::zoomOutHorizontally( const QDate &date )
00531 {
00532 QDate begin;
00533 QDate newBegin;
00534 QDate dateToZoom = date;
00535 int ndays,count;
00536
00537 begin = mSelectedDates.first();
00538 ndays = begin.daysTo( mSelectedDates.last() );
00539
00540
00541 if ( ! dateToZoom.isValid () )
00542 dateToZoom=mAgenda->selectedIncidenceDate();
00543
00544 if ( !dateToZoom.isValid() ) {
00545 newBegin = begin.addDays(-1);
00546 count = ndays+3 ;
00547 } else {
00548 newBegin = dateToZoom.addDays( -ndays/2-1 );
00549 count = ndays+3;
00550 }
00551
00552 if ( abs( count ) >= 31 )
00553 kdDebug(5850) << "change to the mounth view?"<<endl;
00554 else
00555
00556 emit zoomViewHorizontally( newBegin, count );
00557 }
00558
00559 void KOAgendaView::zoomView( const int delta, const QPoint &pos,
00560 const Qt::Orientation orient )
00561 {
00562 static QDate zoomDate;
00563 static QTimer *t = new QTimer( this );
00564
00565
00566
00567
00568 if ( orient == Qt::Horizontal ) {
00569 QDate date=mAgenda->selectedIncidenceDate();
00570 if ( date.isValid() )
00571 zoomDate=date;
00572 else{
00573 if ( !t->isActive() ) {
00574 zoomDate= mSelectedDates[pos.x()];
00575 }
00576 t->start ( 1000,true );
00577 }
00578 if ( delta > 0 )
00579 zoomOutHorizontally( zoomDate );
00580 else
00581 zoomInHorizontally( zoomDate );
00582 } else {
00583
00584 QPoint posConstentsOld = mAgenda->gridToContents(pos);
00585 if ( delta > 0 ) {
00586 zoomOutVertically();
00587 } else {
00588 zoomInVertically();
00589 }
00590 QPoint posConstentsNew = mAgenda->gridToContents(pos);
00591 mAgenda->scrollBy( 0, posConstentsNew.y() - posConstentsOld.y() );
00592 }
00593 }
00594
00595 void KOAgendaView::createDayLabels( bool force )
00596 {
00597
00598
00599
00600
00601 if ( !force && mSaveSelectedDates == mSelectedDates ) {
00602 return;
00603 }
00604 mSaveSelectedDates = mSelectedDates;
00605
00606 delete mDayLabels;
00607 mDateDayLabels.clear();
00608
00609 mDayLabels = new QFrame (mDayLabelsFrame);
00610 mLayoutDayLabels = new QHBoxLayout(mDayLabels);
00611 if ( !mIsSideBySide )
00612 mLayoutDayLabels->addSpacing(mTimeLabels->width());
00613
00614 const KCalendarSystem*calsys=KOGlobals::self()->calendarSystem();
00615
00616 DateList::ConstIterator dit;
00617 for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) {
00618 QDate date = *dit;
00619 QBoxLayout *dayLayout = new QVBoxLayout(mLayoutDayLabels);
00620 mLayoutDayLabels->setStretchFactor(dayLayout, 1);
00621
00622
00623 int dW = calsys->dayOfWeek(date);
00624 QString veryLongStr = KGlobal::locale()->formatDate( date );
00625 QString longstr = i18n( "short_weekday date (e.g. Mon 13)","%1 %2" )
00626 .arg( calsys->weekDayName( dW, true ) )
00627 .arg( calsys->day(date) );
00628 QString shortstr = QString::number(calsys->day(date));
00629
00630 KOAlternateLabel *dayLabel = new KOAlternateLabel(shortstr,
00631 longstr, veryLongStr, mDayLabels);
00632 dayLabel->useShortText();
00633 dayLabel->setMinimumWidth(1);
00634 dayLabel->setAlignment(QLabel::AlignHCenter);
00635 if (date == QDate::currentDate()) {
00636 QFont font = dayLabel->font();
00637 font.setBold(true);
00638 dayLabel->setFont(font);
00639 }
00640 dayLayout->addWidget(dayLabel);
00641 mDateDayLabels.append( dayLabel );
00642
00643
00644 QStringList texts = KOGlobals::self()->holiday( date );
00645 QStringList::ConstIterator textit = texts.begin();
00646 for ( ; textit != texts.end(); ++textit ) {
00647
00648 KOAlternateLabel*label = new KOAlternateLabel( (*textit), (*textit), QString::null, mDayLabels );
00649 label->setMinimumWidth(1);
00650 label->setAlignment(AlignCenter);
00651 dayLayout->addWidget(label);
00652 }
00653
00654 #ifndef KORG_NOPLUGINS
00655 CalendarDecoration::List cds = KOCore::self()->calendarDecorations();
00656 CalendarDecoration *it;
00657 for(it = cds.first(); it; it = cds.next()) {
00658 QString text = it->shortText( date );
00659 if ( !text.isEmpty() ) {
00660
00661 KOAlternateLabel*label = new KOAlternateLabel( text, text, QString::null, mDayLabels );
00662 label->setMinimumWidth(1);
00663 label->setAlignment(AlignCenter);
00664 dayLayout->addWidget(label);
00665 }
00666 }
00667
00668 for(it = cds.first(); it; it = cds.next()) {
00669 QWidget *wid = it->smallWidget(mDayLabels,date);
00670 if ( wid ) {
00671
00672 dayLayout->addWidget(wid);
00673 }
00674 }
00675 #endif
00676 }
00677
00678 if ( !mIsSideBySide )
00679 mLayoutDayLabels->addSpacing(mAgenda->verticalScrollBar()->width());
00680 mDayLabels->show();
00681 QTimer::singleShot( 0, this, SLOT( updateDayLabelSizes() ) );
00682 }
00683
00684 void KOAgendaView::enableAgendaUpdate( bool enable )
00685 {
00686 mAllowAgendaUpdate = enable;
00687 }
00688
00689 int KOAgendaView::maxDatesHint()
00690 {
00691
00692 return 0;
00693 }
00694
00695 int KOAgendaView::currentDateCount()
00696 {
00697 return mSelectedDates.count();
00698 }
00699
00700 Incidence::List KOAgendaView::selectedIncidences()
00701 {
00702 Incidence::List selected;
00703 Incidence *incidence;
00704
00705 incidence = mAgenda->selectedIncidence();
00706 if (incidence) selected.append(incidence);
00707
00708 incidence = mAllDayAgenda->selectedIncidence();
00709 if (incidence) selected.append(incidence);
00710
00711 return selected;
00712 }
00713
00714 DateList KOAgendaView::selectedIncidenceDates()
00715 {
00716 DateList selected;
00717 QDate qd;
00718
00719 qd = mAgenda->selectedIncidenceDate();
00720 if (qd.isValid()) selected.append(qd);
00721
00722 qd = mAllDayAgenda->selectedIncidenceDate();
00723 if (qd.isValid()) selected.append(qd);
00724
00725 return selected;
00726 }
00727
00728 bool KOAgendaView::eventDurationHint( QDateTime &startDt, QDateTime &endDt,
00729 bool &allDay )
00730 {
00731 if ( selectionStart().isValid() ) {
00732 QDateTime start = selectionStart();
00733 QDateTime end = selectionEnd();
00734
00735 if ( start.secsTo( end ) == 15*60 ) {
00736
00737
00738 QTime defaultDuration( KOPrefs::instance()->mDefaultDuration.time() );
00739 int addSecs = ( defaultDuration.hour()*3600 ) +
00740 ( defaultDuration.minute()*60 );
00741 end = start.addSecs( addSecs );
00742 }
00743
00744 startDt = start;
00745 endDt = end;
00746 allDay = selectedIsAllDay();
00747 return true;
00748 }
00749 return false;
00750 }
00751
00753 bool KOAgendaView::selectedIsSingleCell()
00754 {
00755 if ( !selectionStart().isValid() || !selectionEnd().isValid() ) return false;
00756
00757 if (selectedIsAllDay()) {
00758 int days = selectionStart().daysTo(selectionEnd());
00759 return ( days < 1 );
00760 } else {
00761 int secs = selectionStart().secsTo(selectionEnd());
00762 return ( secs <= 24*60*60/mAgenda->rows() );
00763 }
00764 }
00765
00766
00767 void KOAgendaView::updateView()
00768 {
00769
00770 fillAgenda();
00771 }
00772
00773
00774
00775
00776
00777
00778 void KOAgendaView::updateConfig()
00779 {
00780
00781
00782
00783 mTimeLabels->updateConfig();
00784 mAgenda->updateConfig();
00785 mAllDayAgenda->updateConfig();
00786
00787
00788
00789 mTimeLabels->positionChanged();
00790
00791
00792 mTimeLabels->repaint();
00793
00794 updateTimeBarWidth();
00795
00796
00797 KOAgendaItem::toolTipGroup()->setEnabled(KOPrefs::instance()
00798 ->mEnableToolTips);
00799
00800 setHolidayMasks();
00801
00802 createDayLabels( true );
00803
00804 updateView();
00805 }
00806
00807 void KOAgendaView::updateTimeBarWidth()
00808 {
00809 int width;
00810
00811 width = mDummyAllDayLeft->fontMetrics().width( i18n("All Day") );
00812 width = QMAX( width, mTimeLabels->width() );
00813
00814 mDummyAllDayLeft->setFixedWidth( width );
00815 mTimeLabels->setFixedWidth( width );
00816 }
00817
00818 void KOAgendaView::updateDayLabelSizes()
00819 {
00820
00821 KOAlternateLabel::TextType overallType = KOAlternateLabel::Extensive;
00822 QPtrList<KOAlternateLabel>::const_iterator it = mDateDayLabels.constBegin();
00823 for( ; it != mDateDayLabels.constEnd(); it++ ) {
00824 KOAlternateLabel::TextType type = (*it)->largestFittingTextType();
00825 if ( type < overallType )
00826 overallType = type;
00827 }
00828
00829
00830 it = mDateDayLabels.constBegin();
00831 for( ; it != mDateDayLabels.constEnd(); it++ ) {
00832 (*it)->setFixedType( overallType );
00833 }
00834 }
00835
00836 void KOAgendaView::resizeEvent( QResizeEvent *resizeEvent )
00837 {
00838 updateDayLabelSizes();
00839 KOrg::AgendaView::resizeEvent( resizeEvent );
00840 }
00841
00842 void KOAgendaView::updateEventDates( KOAgendaItem *item,
00843 bool useLastGroupwareDialogAnswer,
00844 ResourceCalendar *res,
00845 const QString &subRes,
00846 bool addIncidence )
00847 {
00848 kdDebug(5850) << "KOAgendaView::updateEventDates(): " << item->text()
00849 << "; item->cellXLeft(): " << item->cellXLeft()
00850 << "; item->cellYTop(): " << item->cellYTop()
00851 << "; item->lastMultiItem(): " << item->lastMultiItem()
00852 << "; item->itemPos(): " << item->itemPos()
00853 << "; item->itemCount(): " << item->itemCount()
00854 << endl;
00855
00856 QDateTime startDt, endDt;
00857
00858
00859
00860
00861
00862 QDate thisDate;
00863 if ( item->cellXLeft() < 0 ) {
00864 thisDate = ( mSelectedDates.first() ).addDays( item->cellXLeft() );
00865 } else {
00866 thisDate = mSelectedDates[ item->cellXLeft() ];
00867 }
00868 const QDate oldThisDate( item->itemDate() );
00869 const int daysOffset = oldThisDate.daysTo( thisDate );
00870 int daysLength = 0;
00871
00872 Incidence *incidence = item->incidence();
00873
00874 if ( !incidence || !mChanger ||
00875 ( !addIncidence && !mChanger->beginChange( incidence,
00876 resourceCalendar(),
00877 subResourceCalendar() ) ) ) {
00878 kdDebug() << "Weird, application has a bug?" << endl;
00879 return;
00880 }
00881 incidence->startUpdates();
00882 Incidence *oldIncidence = incidence->clone();
00883
00884 QTime startTime( 0, 0, 0 ), endTime( 0, 0, 0 );
00885 if ( incidence->doesFloat() ) {
00886 daysLength = item->cellWidth() - 1;
00887 } else {
00888 startTime = mAgenda->gyToTime( item->cellYTop() );
00889 if ( item->lastMultiItem() ) {
00890 endTime = mAgenda->gyToTime( item->lastMultiItem()->cellYBottom() + 1 );
00891 daysLength = item->lastMultiItem()->cellXLeft() - item->cellXLeft();
00892 kdDebug(5850) << "item->lastMultiItem()->cellXLeft(): " << item->lastMultiItem()->cellXLeft()
00893 << endl;
00894 } else if ( item->itemPos() == item->itemCount() && item->itemCount() > 1 ) {
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905 endTime = mAgenda->gyToTime( item->cellYBottom() + 1 );
00906 daysLength = item->itemCount() - 1;
00907 startTime = incidence->dtStart().time();
00908 } else if ( item->itemPos() == 1 && item->itemCount() > 1 ) {
00909
00910 endTime = incidence->dtEnd().time();
00911 daysLength = item->itemCount() - 1;
00912 } else {
00913 endTime = mAgenda->gyToTime( item->cellYBottom() + 1 );
00914 }
00915 }
00916
00917 kdDebug(5850) << "daysLength: " << daysLength << "; startTime: " << startTime
00918 << "; endTime: " << endTime << "; thisDate: " << thisDate
00919 << "; incidence->dtStart(): " << incidence->dtStart() << endl;
00920
00921 if ( incidence->type() == "Event" ) {
00922 startDt = incidence->dtStart();
00923 startDt = startDt.addDays( daysOffset );
00924 startDt.setTime( startTime );
00925 endDt = startDt.addDays( daysLength );
00926 endDt.setTime( endTime );
00927 Event* ev = static_cast<Event*>( incidence );
00928 if ( incidence->dtStart() == startDt && ev->dtEnd() == endDt ) {
00929
00930 delete oldIncidence;
00931 incidence->cancelUpdates();
00932 return;
00933 }
00934 incidence->setDtStart( startDt );
00935 ev->setDtEnd( endDt );
00936 } else if ( incidence->type() == "Todo" ) {
00937
00938
00939 Todo *td = static_cast<Todo*>( incidence );
00940 startDt = td->hasStartDate() ? td->dtStart() : td->dtDue();
00941 startDt = thisDate.addDays( td->dtDue().daysTo( startDt ) );
00942 startDt.setTime( startTime );
00943 endDt.setDate( thisDate );
00944 endDt.setTime( endTime );
00945
00946 if ( td->dtDue() == endDt ) {
00947
00948 delete oldIncidence;
00949 incidence->cancelUpdates();
00950 return;
00951 }
00952
00953 if ( td->hasStartDate() ) {
00954 td->setDtStart( startDt );
00955 }
00956 td->setDtDue( endDt );
00957 }
00958
00959 item->setItemDate( startDt.date() );
00960
00961 KOIncidenceToolTip::remove( item );
00962 KOIncidenceToolTip::add( item, calendar(), incidence, thisDate, KOAgendaItem::toolTipGroup() );
00963
00964
00965 bool result;
00966 kdDebug() << "New date is " << incidence->dtStart() << endl;
00967 if ( addIncidence ) {
00968 result = mChanger->addIncidence( incidence, res, subRes, this, useLastGroupwareDialogAnswer );
00969 } else {
00970 result = mChanger->changeIncidence( oldIncidence, incidence,
00971 KOGlobals::DATE_MODIFIED, this, useLastGroupwareDialogAnswer );
00972 mChanger->endChange( incidence, resourceCalendar(), subResourceCalendar() );
00973 }
00974
00975 delete oldIncidence;
00976
00977 if ( !result ) {
00978 mPendingChanges = true;
00979 QTimer::singleShot( 0, this, SLOT(updateView()) );
00980 incidence->cancelUpdates();
00981 return;
00982 } else {
00983 incidence->endUpdates();
00984 }
00985
00986
00987
00988
00989 enableAgendaUpdate( false );
00990
00991
00992
00993
00994
00995 if ( incidence->doesRecur() ) {
00996 mUpdateItem = incidence;
00997 QTimer::singleShot( 0, this, SLOT( doUpdateItem() ) );
00998 }
00999
01000 enableAgendaUpdate( true );
01001 }
01002
01003 void KOAgendaView::doUpdateItem()
01004 {
01005 if ( mUpdateItem ) {
01006 changeIncidenceDisplay( mUpdateItem, KOGlobals::INCIDENCEEDITED );
01007 mUpdateItem = 0;
01008 }
01009 }
01010
01011
01012
01013 void KOAgendaView::showDates( const QDate &start, const QDate &end )
01014 {
01015
01016 if ( !mSelectedDates.isEmpty() && mSelectedDates.first() == start
01017 && mSelectedDates.last() == end && !mPendingChanges )
01018 return;
01019
01020 mSelectedDates.clear();
01021
01022 QDate d = start;
01023 while ( d <= end ) {
01024 mSelectedDates.append( d );
01025 d = d.addDays( 1 );
01026 }
01027
01028 mAreDatesInitialized = true;
01029
01030
01031 fillAgenda();
01032 }
01033
01034
01035 void KOAgendaView::showIncidences( const Incidence::List &, const QDate & )
01036 {
01037 kdDebug(5850) << "KOAgendaView::showIncidences( const Incidence::List & ) is not yet implemented" << endl;
01038 }
01039
01040 void KOAgendaView::insertIncidence( Incidence *incidence, const QDate &curDate )
01041 {
01042 if ( !filterByResource( incidence ) ) {
01043 return;
01044 }
01045
01046
01047 Event *event = dynamic_cast<Event *>( incidence );
01048 Todo *todo = dynamic_cast<Todo *>( incidence );
01049
01050 int curCol = mSelectedDates.first().daysTo( curDate );
01051
01052
01053 if ( curCol < 0 ) {
01054 curCol = 0;
01055 }
01056
01057
01058 if ( curCol >= static_cast<int>( mSelectedDates.count() ) ) {
01059 return;
01060 }
01061
01062
01063 mMinY[curCol] = mAgenda->timeToY( QTime( 23, 59 ) ) + 1;
01064 mMaxY[curCol] = mAgenda->timeToY( QTime( 0, 0 ) ) - 1;
01065
01066 int beginX;
01067 int endX;
01068 QDate columnDate;
01069 if ( event ) {
01070 QDate firstVisibleDate = mSelectedDates.first();
01071
01072 if ( curDate < firstVisibleDate ) {
01073 beginX = curCol + firstVisibleDate.daysTo( curDate );
01074 endX = beginX + event->dtStart().daysTo( event->dtEnd() );
01075 columnDate = firstVisibleDate;
01076 } else {
01077 beginX = curCol;
01078 endX = beginX + event->dtStart().daysTo( event->dtEnd() );
01079 columnDate = curDate;
01080 }
01081 } else if ( todo ) {
01082 if ( !todo->hasDueDate() ) {
01083 return;
01084 }
01085 columnDate = curDate;
01086 beginX = endX = curCol;
01087
01088 } else {
01089 return;
01090 }
01091 if ( todo && todo->isOverdue() ) {
01092 mAllDayAgenda->insertAllDayItem( incidence, columnDate, curCol, curCol );
01093 } else if ( incidence->doesFloat() ||
01094 ( todo &&
01095 !todo->dtDue().isValid() ) ) {
01096 mAllDayAgenda->insertAllDayItem( incidence, columnDate, beginX, endX );
01097 } else if ( event && event->isMultiDay() ) {
01098 int startY = mAgenda->timeToY( event->dtStart().time() );
01099 QTime endtime = event->dtEnd().time();
01100 if ( endtime == QTime( 0, 0, 0 ) ) {
01101 endtime = QTime( 23, 59, 59 );
01102 }
01103 int endY = mAgenda->timeToY( endtime ) - 1;
01104 if ( ( beginX <= 0 && curCol == 0 ) || beginX == curCol ) {
01105 mAgenda->insertMultiItem( event, columnDate, beginX, endX, startY, endY );
01106
01107 }
01108 if ( beginX == curCol ) {
01109 mMaxY[curCol] = mAgenda->timeToY( QTime( 23, 59 ) );
01110 if ( startY < mMinY[curCol] ) {
01111 mMinY[curCol] = startY;
01112 }
01113 } else if ( endX == curCol ) {
01114 mMinY[curCol] = mAgenda->timeToY( QTime( 0, 0 ) );
01115 if ( endY > mMaxY[curCol] ) {
01116 mMaxY[curCol] = endY;
01117 }
01118 } else {
01119 mMinY[curCol] = mAgenda->timeToY( QTime( 0, 0 ) );
01120 mMaxY[curCol] = mAgenda->timeToY( QTime( 23, 59 ) );
01121 }
01122 } else {
01123 int startY = 0, endY = 0;
01124 if ( event ) {
01125 startY = mAgenda->timeToY( incidence->dtStart().time() );
01126 QTime endtime = event->dtEnd().time();
01127 if ( endtime == QTime( 0, 0, 0 ) ) {
01128 endtime = QTime( 23, 59, 59 );
01129 }
01130 endY = mAgenda->timeToY( endtime ) - 1;
01131 }
01132 if ( todo ) {
01133 QTime t = todo->dtDue().time();
01134
01135 if ( t == QTime( 0, 0 ) ) {
01136 t = QTime( 23, 59 );
01137 }
01138
01139 int halfHour = 1800;
01140 if ( t.addSecs( -halfHour ) < t ) {
01141 startY = mAgenda->timeToY( t.addSecs( -halfHour ) );
01142 endY = mAgenda->timeToY( t ) - 1;
01143 } else {
01144 startY = 0;
01145 endY = mAgenda->timeToY( t.addSecs( halfHour ) ) - 1;
01146 }
01147 }
01148 if ( endY < startY ) {
01149 endY = startY;
01150 }
01151 mAgenda->insertItem( incidence, columnDate, curCol, startY, endY, 1, 1 );
01152 if ( startY < mMinY[curCol] ) {
01153 mMinY[curCol] = startY;
01154 }
01155 if ( endY > mMaxY[curCol] ) {
01156 mMaxY[curCol] = endY;
01157 }
01158 }
01159 }
01160
01161 void KOAgendaView::changeIncidenceDisplayAdded( Incidence *incidence )
01162 {
01163 Todo *todo = dynamic_cast<Todo *>(incidence);
01164 CalFilter *filter = calendar()->filter();
01165 if ( ( filter && !filter->filterIncidence( incidence ) ) ||
01166 ( ( todo && !KOPrefs::instance()->showAllDayTodo() ) ) ) {
01167 return;
01168 }
01169
01170 displayIncidence( incidence );
01171 }
01172
01173 void KOAgendaView::changeIncidenceDisplay( Incidence *incidence, int mode )
01174 {
01175 switch ( mode ) {
01176 case KOGlobals::INCIDENCEADDED:
01177 {
01178
01179
01180
01181
01182
01183 changeIncidenceDisplayAdded( incidence );
01184 updateEventIndicators();
01185 break;
01186 }
01187 case KOGlobals::INCIDENCEEDITED:
01188 {
01189 if ( mAllowAgendaUpdate ) {
01196 removeIncidence( incidence, false );
01197 changeIncidenceDisplayAdded( incidence );
01198 }
01199 updateEventIndicators();
01200 break;
01201 }
01202 case KOGlobals::INCIDENCEDELETED:
01203 {
01204 removeIncidence( incidence );
01205 updateEventIndicators();
01206 break;
01207 }
01208 default:
01209 return;
01210 }
01211
01212
01213
01214
01215
01216 if ( incidence->doesFloat() ) {
01217 if ( sProcessingDrop ) {
01218 QTimer::singleShot( 0, this, SLOT(updateView()) );
01219 } else {
01220 updateView();
01221 }
01222 }
01223 }
01224
01225 void KOAgendaView::fillAgenda( const QDate & )
01226 {
01227 fillAgenda();
01228 }
01229
01230 void KOAgendaView::fillAgenda()
01231 {
01232 if ( !mAreDatesInitialized ) {
01233 return;
01234 }
01235
01236 mPendingChanges = false;
01237
01238
01239
01240 const QString &selectedAgendaUid = mAgenda->lastSelectedUid();
01241 const QString &selectedAllDayAgendaUid = mAllDayAgenda->lastSelectedUid();
01242
01243 enableAgendaUpdate( true );
01244 clearView();
01245
01246 mAllDayAgenda->changeColumns( mSelectedDates.count() );
01247 mAgenda->changeColumns( mSelectedDates.count() );
01248 mEventIndicatorTop->changeColumns( mSelectedDates.count() );
01249 mEventIndicatorBottom->changeColumns( mSelectedDates.count() );
01250
01251 createDayLabels( false );
01252 setHolidayMasks();
01253
01254 mMinY.resize( mSelectedDates.count() );
01255 mMaxY.resize( mSelectedDates.count() );
01256
01257 mAgenda->setDateList( mSelectedDates );
01258
01259 bool somethingReselected = false;
01260 Incidence::List incidences = calendar()->incidences();
01261
01262 for ( Incidence::List::ConstIterator it = incidences.begin(); it!=incidences.constEnd(); ++it ) {
01263 Incidence *incidence = (*it);
01264 displayIncidence( incidence );
01265
01266 if( incidence->uid() == selectedAgendaUid && !selectedAgendaUid.isNull() ) {
01267 mAgenda->selectItemByUID( incidence->uid() );
01268 somethingReselected = true;
01269 }
01270
01271 if( incidence->uid() == selectedAllDayAgendaUid && !selectedAllDayAgendaUid.isNull() ) {
01272 mAllDayAgenda->selectItemByUID( incidence->uid() );
01273 somethingReselected = true;
01274 }
01275
01276 }
01277
01278 mAgenda->checkScrollBoundaries();
01279 updateEventIndicators();
01280
01281
01282
01283
01284
01285 deleteSelectedDateTime();
01286
01287 if( !somethingReselected ) {
01288 emit incidenceSelected( 0, QDate() );
01289 }
01290 }
01291
01292 void KOAgendaView::displayIncidence( Incidence *incidence )
01293 {
01294 QDate today = QDate::currentDate();
01295 DateTimeList::iterator t;
01296
01297
01298 Todo *todo = dynamic_cast<Todo *>( incidence );
01299 Event *event = dynamic_cast<Event *>( incidence );
01300
01301 QDateTime firstVisibleDateTime = mSelectedDates.first();
01302 QDateTime lastVisibleDateTime = mSelectedDates.last();
01303
01304 lastVisibleDateTime.setTime( QTime( 23, 59, 59, 59 ) );
01305 firstVisibleDateTime.setTime( QTime( 0, 0 ) );
01306 DateTimeList dateTimeList;
01307
01308 QDateTime incDtStart = incidence->dtStart();
01309 QDateTime incDtEnd = incidence->dtEnd();
01310
01311 if ( todo &&
01312 ( !KOPrefs::instance()->showAllDayTodo() || !todo->hasDueDate() ) ) {
01313 return;
01314 }
01315
01316 if ( incidence->doesRecur() ) {
01317 int eventDuration = event ? incDtStart.daysTo( incDtEnd ) : 0;
01318
01319
01320
01321
01322 QDateTime startDateTimeWithOffset = firstVisibleDateTime.addDays( -eventDuration );
01323 dateTimeList =
01324 incidence->recurrence()->timesInInterval( startDateTimeWithOffset,
01325 lastVisibleDateTime );
01326 } else {
01327 QDateTime dateToAdd;
01328 QDateTime incidenceStart;
01329 QDateTime incidenceEnd;
01330
01331 if ( todo && todo->hasDueDate() && !todo->isOverdue() ) {
01332
01333 dateToAdd = todo->dtDue();
01334
01335
01336
01337 if ( !todo->doesFloat() && dateToAdd.time() == QTime( 0, 0 ) ) {
01338 dateToAdd = dateToAdd.addSecs( -1 );
01339 }
01340
01341 incidenceEnd = dateToAdd;
01342 } else if ( event ) {
01343 dateToAdd = incDtStart;
01344 incidenceEnd = incDtEnd;
01345 }
01346
01347 if ( incidence->doesFloat() ) {
01348
01349 dateToAdd.setTime( QTime( 0, 0 ) );
01350 incidenceEnd.setTime( QTime( 23, 59, 59, 59 ) );
01351 }
01352
01353 if ( dateToAdd <= lastVisibleDateTime && incidenceEnd > firstVisibleDateTime ) {
01354 dateTimeList += dateToAdd;
01355 }
01356 }
01357
01358
01359 QDateTime dateTimeToday = today;
01360 if ( todo &&
01361 todo->isOverdue() &&
01362 dateTimeToday >= firstVisibleDateTime &&
01363 dateTimeToday <= lastVisibleDateTime ) {
01364
01365 bool doAdd = true;
01366
01367 if ( todo->doesRecur() ) {
01368
01369
01370 for ( t = dateTimeList.begin(); t != dateTimeList.end(); ++t ) {
01371 if ( (*t).date() == today ) {
01372 doAdd = false;
01373 break;
01374 }
01375 }
01376 }
01377
01378 if ( doAdd ) {
01379 dateTimeList += dateTimeToday;
01380 }
01381 }
01382
01383 const bool makesDayBusy = KOEventView::makesWholeDayBusy( incidence );
01384 for ( t = dateTimeList.begin(); t != dateTimeList.end(); ++t ) {
01385 if ( makesDayBusy ) {
01386 Event::List &busyEvents = mBusyDays[(*t).date()];
01387 busyEvents.append( event );
01388 }
01389 insertIncidence( incidence, (*t).date() );
01390 }
01391
01392
01393 if ( event && makesDayBusy && event->isMultiDay() ) {
01394 const QDate lastVisibleDate = mSelectedDates.last();
01395 for ( QDate date = event->dtStart().date();
01396 date <= event->dtEnd().date() && date <= lastVisibleDate ;
01397 date = date.addDays( 1 ) ) {
01398 Event::List &busyEvents = mBusyDays[date];
01399 busyEvents.append( event );
01400 }
01401 }
01402 }
01403
01404 void KOAgendaView::clearView()
01405 {
01406
01407 mAllDayAgenda->clear();
01408 mAgenda->clear();
01409 mBusyDays.clear();
01410 }
01411
01412 CalPrinterBase::PrintType KOAgendaView::printType()
01413 {
01414 if ( currentDateCount() == 1 ) return CalPrinterBase::Day;
01415 else return CalPrinterBase::Week;
01416 }
01417
01418 void KOAgendaView::updateEventIndicatorTop( int newY )
01419 {
01420 uint i;
01421 for( i = 0; i < mMinY.size(); ++i ) {
01422 mEventIndicatorTop->enableColumn( i, newY > mMinY[i] );
01423 }
01424 mEventIndicatorTop->update();
01425 }
01426
01427 void KOAgendaView::updateEventIndicatorBottom( int newY )
01428 {
01429 uint i;
01430 for( i = 0; i < mMaxY.size(); ++i ) {
01431 mEventIndicatorBottom->enableColumn( i, newY <= mMaxY[i] );
01432 }
01433 mEventIndicatorBottom->update();
01434 }
01435
01436 void KOAgendaView::slotIncidenceDropped( Incidence *incidence, const QPoint &gpos, bool allDay )
01437 {
01438 struct BoolChanger {
01439 BoolChanger( bool &bb ) : b( bb )
01440 {
01441 b = true;
01442 }
01443
01444 ~BoolChanger()
01445 {
01446 b = false;
01447 }
01448 bool &b;
01449 };
01450
01451 BoolChanger boolChanger( sProcessingDrop );
01452
01453 if ( gpos.x()<0 || gpos.y()<0 ) return;
01454 QDate day = mSelectedDates[gpos.x()];
01455 QTime time = mAgenda->gyToTime( gpos.y() );
01456 QDateTime newTime( day, time );
01457
01458 Event *event = 0;
01459 Todo *todo = 0;
01460
01461 if ( incidence->type() == "Event" )
01462 event = static_cast<Event*>( incidence );
01463
01464 if ( incidence->type() == "Todo" )
01465 todo = static_cast<Todo*>( incidence );
01466
01467 if ( !event && !todo )
01468 return;
01469
01470 if ( todo ) {
01471 Todo *existingTodo = calendar()->todo( todo->uid() );
01472 if ( existingTodo ) {
01473 kdDebug(5850) << "Drop existing Todo" << endl;
01474 Todo *oldTodo = existingTodo->clone();
01475 if ( mChanger &&
01476 mChanger->beginChange( existingTodo, resourceCalendar(), subResourceCalendar() ) ) {
01477
01478 existingTodo->setDtDue( newTime );
01479 existingTodo->setFloats( allDay );
01480 existingTodo->setHasDueDate( true );
01481 mChanger->changeIncidence( oldTodo, existingTodo,
01482 KOGlobals::DATE_MODIFIED, this );
01483 mChanger->endChange( existingTodo, resourceCalendar(), subResourceCalendar() );
01484 } else {
01485 KMessageBox::sorry( this, i18n("Unable to modify this to-do, "
01486 "because it cannot be locked.") );
01487 }
01488 delete oldTodo;
01489 } else {
01490 kdDebug(5850) << "Drop new Todo" << endl;
01491 todo->setDtDue( newTime );
01492 todo->setFloats( allDay );
01493 todo->setHasDueDate( true );
01494 if ( !mChanger->addIncidence( todo, 0, QString(), this ) ) {
01495 KODialogManager::errorSaveIncidence( this, todo );
01496 }
01497 }
01498 } else if ( event ) {
01499 Event *existingEvent = calendar()->event( event->uid() );
01500 Event *existingEventInSameResource = 0;
01501
01502 if ( existingEvent ) {
01503
01504
01505
01506 if ( !resourceCalendar() ) {
01507
01508 existingEventInSameResource = existingEvent;
01509 } else if ( resourceCalendar()->incidence( incidence->uid() ) ) {
01510
01511 if ( subResourceCalendar() == resourceCalendar()->subresourceIdentifier( incidence ) ) {
01512 existingEventInSameResource = existingEvent;
01513 }
01514 }
01515 }
01516
01517 if ( existingEventInSameResource ) {
01518 kdDebug(5850) << "Drop existing Event" << endl;
01519 Event *oldEvent = existingEventInSameResource->clone();
01520 if ( mChanger &&
01521 mChanger->beginChange( existingEvent, resourceCalendar(), subResourceCalendar() ) ) {
01522 existingEventInSameResource->setDtStart( newTime );
01523
01524 const int duration = ( existingEventInSameResource->doesFloat() && !allDay ) ?
01525 3600 : oldEvent->dtStart().secsTo( oldEvent->dtEnd() );
01526
01527 existingEventInSameResource->setFloats( allDay );
01528 existingEventInSameResource->setDtEnd( newTime.addSecs( duration ) );
01529 mChanger->changeIncidence( oldEvent, existingEventInSameResource,
01530 KOGlobals::DATE_MODIFIED, this );
01531 mChanger->endChange( existingEventInSameResource, resourceCalendar(), subResourceCalendar() );
01532 } else {
01533 KMessageBox::sorry( this, i18n("Unable to modify this event, "
01534 "because it cannot be locked.") );
01535 }
01536 delete oldEvent;
01537 } else {
01538 kdDebug(5850) << "Drop new Event" << endl;
01539 const int duration = event->dtStart().secsTo( event->dtEnd() );
01540 event->setDtStart( newTime );
01541 event->setFloats( allDay );
01542 event->setUid( CalFormat::createUniqueId() );
01543 event->setDtEnd( newTime.addSecs( duration ) );
01544 if ( mChanger->addIncidence( event, resourceCalendar(), subResourceCalendar(), this ) ) {
01545 if ( existingEvent && !existingEventInSameResource ) {
01546
01547 mChanger->deleteIncidence( existingEvent, this );
01548 }
01549 } else {
01550 KODialogManager::errorSaveIncidence( this, event );
01551 }
01552 }
01553 }
01554 }
01555
01556 void KOAgendaView::startDrag( Incidence *incidence )
01557 {
01558 #ifndef KORG_NODND
01559 sProcessingDrop = true;
01560 DndFactory factory( calendar() );
01561 ICalDrag *vd = factory.createDrag( incidence, this );
01562 if ( vd->drag() ) {
01563 kdDebug(5850) << "KOAgendaView::startDrag(): Delete drag source" << endl;
01564 }
01565 sProcessingDrop = false;
01566 #endif
01567 }
01568
01569 void KOAgendaView::readSettings()
01570 {
01571 readSettings(KOGlobals::self()->config());
01572 }
01573
01574 void KOAgendaView::readSettings(KConfig *config)
01575 {
01576
01577
01578 config->setGroup("Views");
01579
01580 #ifndef KORG_NOSPLITTER
01581 QValueList<int> sizes = config->readIntListEntry("Separator AgendaView");
01582 if (sizes.count() == 2) {
01583 mSplitterAgenda->setSizes(sizes);
01584 }
01585 #endif
01586
01587 updateConfig();
01588 }
01589
01590 void KOAgendaView::writeSettings(KConfig *config)
01591 {
01592
01593
01594 config->setGroup("Views");
01595
01596 #ifndef KORG_NOSPLITTER
01597 QValueList<int> list = mSplitterAgenda->sizes();
01598 config->writeEntry("Separator AgendaView",list);
01599 #endif
01600 }
01601
01602 void KOAgendaView::setHolidayMasks()
01603 {
01604 if ( mSelectedDates.isEmpty() || !mSelectedDates[0].isValid() ) {
01605 return;
01606 }
01607
01608 mHolidayMask.resize( mSelectedDates.count() + 1 );
01609
01610 for( uint i = 0; i < mSelectedDates.count(); ++i ) {
01611 mHolidayMask[i] = !KOGlobals::self()->isWorkDay( mSelectedDates[ i ] );
01612 }
01613
01614
01615
01616 bool showDay = !KOGlobals::self()->isWorkDay( mSelectedDates[ 0 ].addDays( -1 ) );
01617 mHolidayMask[ mSelectedDates.count() ] = showDay;
01618
01619 mAgenda->setHolidayMask( &mHolidayMask );
01620 mAllDayAgenda->setHolidayMask( &mHolidayMask );
01621 }
01622
01623 QMemArray<bool> KOAgendaView::busyDayMask()
01624 {
01625 if ( mSelectedDates.isEmpty() || !mSelectedDates[0].isValid() ) {
01626 return QMemArray<bool>();
01627 }
01628
01629 QMemArray<bool> busyDayMask;
01630 busyDayMask.resize( mSelectedDates.count() );
01631
01632 for( uint i = 0; i < mSelectedDates.count(); ++i ) {
01633 busyDayMask[i] = !mBusyDays[mSelectedDates[i]].isEmpty();
01634 }
01635
01636 return busyDayMask;
01637 }
01638
01639 void KOAgendaView::setContentsPos( int y )
01640 {
01641 mAgenda->setContentsPos( 0, y );
01642 }
01643
01644 void KOAgendaView::setExpandedButton( bool expanded )
01645 {
01646 if ( !mExpandButton ) return;
01647
01648 if ( expanded ) {
01649 mExpandButton->setPixmap( mExpandedPixmap );
01650 } else {
01651 mExpandButton->setPixmap( mNotExpandedPixmap );
01652 }
01653 }
01654
01655 void KOAgendaView::clearSelection()
01656 {
01657 mAgenda->deselectItem();
01658 mAllDayAgenda->deselectItem();
01659 }
01660
01661 void KOAgendaView::newTimeSpanSelectedAllDay( const QPoint &start, const QPoint &end )
01662 {
01663 newTimeSpanSelected( start, end );
01664 mTimeSpanInAllDay = true;
01665 }
01666
01667 void KOAgendaView::newTimeSpanSelected( const QPoint &start, const QPoint &end )
01668 {
01669 if (!mSelectedDates.count()) return;
01670
01671 mTimeSpanInAllDay = false;
01672
01673 QDate dayStart = mSelectedDates[ kClamp( start.x(), 0, (int)mSelectedDates.size() - 1 ) ];
01674 QDate dayEnd = mSelectedDates[ kClamp( end.x(), 0, (int)mSelectedDates.size() - 1 ) ];
01675
01676 QTime timeStart = mAgenda->gyToTime(start.y());
01677 QTime timeEnd = mAgenda->gyToTime( end.y() + 1 );
01678
01679 QDateTime dtStart(dayStart,timeStart);
01680 QDateTime dtEnd(dayEnd,timeEnd);
01681
01682 mTimeSpanBegin = dtStart;
01683 mTimeSpanEnd = dtEnd;
01684 }
01685
01686 void KOAgendaView::deleteSelectedDateTime()
01687 {
01688 mTimeSpanBegin.setDate(QDate());
01689 mTimeSpanEnd.setDate(QDate());
01690 mTimeSpanInAllDay = false;
01691 }
01692
01693 void KOAgendaView::setTypeAheadReceiver( QObject *o )
01694 {
01695 mAgenda->setTypeAheadReceiver( o );
01696 mAllDayAgenda->setTypeAheadReceiver( o );
01697 }
01698
01699 void KOAgendaView::finishTypeAhead()
01700 {
01701 mAgenda->finishTypeAhead();
01702 mAllDayAgenda->finishTypeAhead();
01703 }
01704
01705 void KOAgendaView::removeIncidence( Incidence *incidence, bool relayoutNeighbours )
01706 {
01707 mAgenda->removeIncidence( incidence, relayoutNeighbours );
01708 mAllDayAgenda->removeIncidence( incidence, relayoutNeighbours );
01709 }
01710
01711 void KOAgendaView::updateEventIndicators()
01712 {
01713 mMinY = mAgenda->minContentsY();
01714 mMaxY = mAgenda->maxContentsY();
01715
01716 mAgenda->checkScrollBoundaries();
01717 updateEventIndicatorTop( mAgenda->visibleContentsYMin() );
01718 updateEventIndicatorBottom( mAgenda->visibleContentsYMax() );
01719 }
01720
01721 void KOAgendaView::setIncidenceChanger( IncidenceChangerBase *changer )
01722 {
01723 mChanger = changer;
01724 mAgenda->setIncidenceChanger( changer );
01725 mAllDayAgenda->setIncidenceChanger( changer );
01726 }
01727
01728 void KOAgendaView::clearTimeSpanSelection()
01729 {
01730 mAgenda->clearSelection();
01731 mAllDayAgenda->clearSelection();
01732 deleteSelectedDateTime();
01733 }
01734
01735 bool KOAgendaView::filterByResource( Incidence *incidence )
01736 {
01737
01738
01739
01740
01741 if ( resourceCalendar() && incidence->type() == "Todo" ) {
01742 QString subRes = resourceCalendar()->subresourceIdentifier( incidence );
01743 if ( resourceCalendar()->subresourceType( subRes ) == "todo" ) {
01744 QString calmatch = "/.INBOX.directory/Calendar";
01745 QString i18nmatch = "/.INBOX.directory/" + i18n( "Calendar" );
01746 if ( subResourceCalendar().contains( calmatch ) ||
01747 subResourceCalendar().contains( i18nmatch ) ) {
01748 return true;
01749 }
01750 }
01751 }
01752
01753
01754 if ( !resourceCalendar() )
01755 return true;
01756 CalendarResources *calRes = dynamic_cast<CalendarResources*>( calendar() );
01757 if ( !calRes )
01758 return true;
01759 if ( calRes->resource( incidence ) != resourceCalendar() )
01760 return false;
01761 if ( !subResourceCalendar().isEmpty() ) {
01762 if ( resourceCalendar()->subresourceIdentifier( incidence ) != subResourceCalendar() )
01763 return false;
01764 }
01765 return true;
01766 }
01767
01768 void KOAgendaView::resourcesChanged()
01769 {
01770 mPendingChanges = true;
01771 }
01772
01773 void KOAgendaView::calendarIncidenceAdded(Incidence * incidence)
01774 {
01775 Q_UNUSED( incidence );
01776 mPendingChanges = true;
01777 }
01778
01779 void KOAgendaView::calendarIncidenceChanged(Incidence * incidence)
01780 {
01781 Q_UNUSED( incidence );
01782 mPendingChanges = true;
01783
01784
01785 if ( !sProcessingDrop )
01786 fillAgenda();
01787 }
01788
01789 void KOAgendaView::calendarIncidenceDeleted(Incidence * incidence)
01790 {
01791 Q_UNUSED( incidence );
01792 mPendingChanges = true;
01793 }