korganizer Library API Documentation

koagendaview.cpp

00001 /*
00002     This file is part of KOrganizer.
00003     Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
00004 
00005     This program is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program; if not, write to the Free Software
00017     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00018 
00019     As a special exception, permission is given to link this program
00020     with any edition of Qt, and distribute the resulting executable,
00021     without including the source code for Qt in the source distribution.
00022 */
00023 
00024 #include <qhbox.h>
00025 #include <qvbox.h>
00026 #include <qlabel.h>
00027 #include <qframe.h>
00028 #include <qlayout.h>
00029 #ifndef KORG_NOSPLITTER
00030 #include <qsplitter.h>
00031 #endif
00032 #include <qfont.h>
00033 #include <qfontmetrics.h>
00034 #include <qpopupmenu.h>
00035 #include <qtooltip.h>
00036 #include <qpainter.h>
00037 #include <qpushbutton.h>
00038 #include <qcursor.h>
00039 #include <qbitarray.h>
00040 
00041 #include <kapplication.h>
00042 #include <kdebug.h>
00043 #include <kstandarddirs.h>
00044 #include <kiconloader.h>
00045 #include <klocale.h>
00046 #include <kconfig.h>
00047 #include <kglobal.h>
00048 #include <kglobalsettings.h>
00049 
00050 #include <libkcal/calendar.h>
00051 #include <libkcal/icaldrag.h>
00052 #include <libkcal/dndfactory.h>
00053 #include <libkcal/calfilter.h>
00054 
00055 #include <kcalendarsystem.h>
00056 
00057 #include "koglobals.h"
00058 #ifndef KORG_NOPLUGINS
00059 #include "kocore.h"
00060 #endif
00061 #include "koprefs.h"
00062 #include "koagenda.h"
00063 #include "koagendaitem.h"
00064 #ifndef KORG_NOPRINTER
00065 #include "calprinter.h"
00066 #endif
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 TimeLabels::TimeLabels(int rows,QWidget *parent,const char *name,WFlags f) :
00079   QScrollView(parent,name,f)
00080 {
00081   mRows = rows;
00082 
00083   mCellHeight = KOPrefs::instance()->mHourSize*4;
00084 
00085   enableClipper(true);
00086 
00087   setHScrollBarMode(AlwaysOff);
00088   setVScrollBarMode(AlwaysOff);
00089 
00090   resizeContents(50,mRows * mCellHeight);
00091 
00092   viewport()->setBackgroundMode( PaletteBackground );
00093 }
00094 
00095 void TimeLabels::setCellHeight(int height)
00096 {
00097   mCellHeight = height;
00098 }
00099 
00100 /*
00101   Optimization so that only the "dirty" portion of the scroll view
00102   is redrawn.  Unfortunately, this is not called by default paintEvent() method.
00103 */
00104 void TimeLabels::drawContents(QPainter *p,int cx, int cy, int cw, int ch)
00105 {
00106   // bug:  the parameters cx, cy, cw, ch are the areas that need to be
00107   //       redrawn, not the area of the widget.  unfortunately, this
00108   //       code assumes the latter...
00109 
00110   // now, for a workaround...
00111   // these two assignments fix the weird redraw bug
00112   cx = contentsX() + 2;
00113   cw = contentsWidth() - 2;
00114   int visWidth = visibleWidth();
00115   double cellHeight=mCellHeight;
00116   if (mAgenda) cellHeight=(4*mAgenda->gridSpacingY());
00117   // end of workaround
00118 
00119   int cell = ((int)(cy/cellHeight));
00120   double y = (cell * cellHeight);
00121   QFontMetrics fm = fontMetrics();
00122   QString hour;
00123   QString suffix;
00124   QString fullTime;
00125 
00126   while (y < cy + ch) {
00127     p->drawLine(cx,(int)y,cx+cw,(int)y);
00128     hour.setNum(cell);
00129     suffix = "am";
00130 
00131     // handle 24h and am/pm time formats
00132     if (KGlobal::locale()->use12Clock()) {
00133       if (cell > 11) suffix = "pm";
00134       if (cell == 0) hour.setNum(12);
00135       if (cell > 12) hour.setNum(cell - 12);
00136     } else {
00137       suffix = ":00";
00138     }
00139 
00140     // create string in format of "XX:XX" or "XXpm/am"
00141     fullTime = hour + suffix;
00142 
00143     // center and draw the time label
00144     QRect r( cx, (int)y+3, visWidth-4, (int)(y+cellHeight-3) );
00145     p->drawText ( r, Qt::AlignHCenter | Qt::AlignTop | Qt::SingleLine, fullTime );
00146 
00147     // increment indices
00148     y += cellHeight;
00149     cell++;
00150   }
00151 }
00152 
00156 int TimeLabels::minimumWidth() const
00157 {
00158   QFontMetrics fm = fontMetrics();
00159 
00160   int borderWidth = 4;
00161 
00162   // the maximum width possible
00163   int width = fm.width("88:88") + 2*borderWidth;
00164 
00165   return width;
00166 }
00167 
00169 void TimeLabels::updateConfig()
00170 {
00171   // set the font
00172 //  config->setGroup("Fonts");
00173 //  QFont font = config->readFontEntry("TimeBar Font");
00174   setFont(KOPrefs::instance()->mTimeBarFont);
00175 
00176   // update geometry restrictions based on new settings
00177   setFixedWidth(minimumWidth());
00178 
00179   // update HourSize
00180   mCellHeight = KOPrefs::instance()->mHourSize*4;
00181   if (mCellHeight>mAgenda->gridSpacingY())
00182     mCellHeight=(int)(4*mAgenda->gridSpacingY());
00183         // FIXME: Why the heck do we set the width to 50???
00184   resizeContents(50,mRows * mCellHeight);
00185 }
00186 
00188 void TimeLabels::positionChanged()
00189 {
00190   int adjustment = mAgenda->contentsY();
00191   setContentsPos(0, adjustment);
00192 }
00193 
00195 void TimeLabels::setAgenda(KOAgenda* agenda)
00196 {
00197   mAgenda = agenda;
00198 }
00199 
00200 
00202 void TimeLabels::paintEvent(QPaintEvent*)
00203 {
00204 //  kdDebug(5850) << "paintevent..." << endl;
00205   // this is another hack!
00206 //  QPainter painter(this);
00207   //QString c
00208   repaintContents(contentsX(), contentsY(), visibleWidth(), visibleHeight());
00209 }
00210 
00212 
00213 EventIndicator::EventIndicator(Location loc,QWidget *parent,const char *name)
00214   : QFrame(parent,name)
00215 {
00216   mColumns = 1;
00217   mTopBox = 0;
00218   mLocation = loc;
00219   mTopLayout = 0;
00220 
00221   if (mLocation == Top) mPixmap = KOGlobals::self()->smallIcon("1uparrow");
00222   else mPixmap = KOGlobals::self()->smallIcon("1downarrow");
00223 
00224   setMinimumHeight(mPixmap.height());
00225 }
00226 
00227 EventIndicator::~EventIndicator()
00228 {
00229 }
00230 
00231 void EventIndicator::drawContents(QPainter *p)
00232 {
00233 //  kdDebug(5850) << "======== top: " << contentsRect().top() << "  bottom "
00234 //         << contentsRect().bottom() << "  left " << contentsRect().left()
00235 //         << "  right " << contentsRect().right() << endl;
00236 
00237   int i;
00238   for(i=0;i<mColumns;++i) {
00239     if (mEnabled[i]) {
00240       int cellWidth = contentsRect().right()/mColumns;
00241       int xOffset = KOGlobals::self()->reverseLayout() ?
00242                (mColumns - 1 - i)*cellWidth + cellWidth/2 -mPixmap.width()/2 :
00243                i*cellWidth + cellWidth/2 -mPixmap.width()/2;
00244       p->drawPixmap(QPoint(xOffset,0),mPixmap);
00245     }
00246   }
00247 }
00248 
00249 void EventIndicator::changeColumns(int columns)
00250 {
00251   mColumns = columns;
00252   mEnabled.resize(mColumns);
00253 
00254   update();
00255 }
00256 
00257 void EventIndicator::enableColumn(int column, bool enable)
00258 {
00259   mEnabled[column] = enable;
00260 }
00261 
00262 
00263 #include <libkcal/incidence.h>
00264 
00268 
00269 
00270 KOAlternateLabel::KOAlternateLabel(QString shortlabel, QString longlabel,
00271     QString extensivelabel, QWidget *parent, const char *name )
00272   : QLabel(parent, name), mTextTypeFixed(false), mShortText(shortlabel),
00273     mLongText(longlabel), mExtensiveText(extensivelabel)
00274 {
00275   setSizePolicy(QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ));
00276   if (mExtensiveText.isEmpty()) mExtensiveText = mLongText;
00277   squeezeTextToLabel();
00278 }
00279 
00280 KOAlternateLabel::~KOAlternateLabel()
00281 {
00282 }
00283 
00284 void KOAlternateLabel::useShortText()
00285 {
00286   mTextTypeFixed = true;
00287   QLabel::setText( mShortText );
00288   QToolTip::remove( this );
00289   QToolTip::add( this, mExtensiveText );
00290 }
00291 
00292 void KOAlternateLabel::useLongText()
00293 {
00294   mTextTypeFixed = true;
00295   QLabel::setText( mLongText );
00296   QToolTip::remove( this );
00297   QToolTip::add( this, mExtensiveText );
00298 }
00299 
00300 void KOAlternateLabel::useExtensiveText()
00301 {
00302   mTextTypeFixed = true;
00303   QLabel::setText( mExtensiveText );
00304   QToolTip::remove( this );
00305   QToolTip::hide();
00306 }
00307 
00308 void KOAlternateLabel::useDefaultText()
00309 {
00310   mTextTypeFixed = false;
00311   squeezeTextToLabel();
00312 }
00313 
00314 void KOAlternateLabel::squeezeTextToLabel()
00315 {
00316   if (mTextTypeFixed) return;
00317 
00318   QFontMetrics fm(fontMetrics());
00319   int labelWidth = size().width();
00320   int textWidth = fm.width(mLongText);
00321   int longTextWidth = fm.width(mExtensiveText);
00322   if (longTextWidth <= labelWidth) {
00323     QLabel::setText( mExtensiveText );
00324     QToolTip::remove( this );
00325     QToolTip::hide();
00326   } else if (textWidth <= labelWidth) {
00327     QLabel::setText( mLongText );
00328     QToolTip::remove( this );
00329     QToolTip::add( this, mExtensiveText );
00330   } else {
00331     QLabel::setText( mShortText );
00332     QToolTip::remove( this );
00333     QToolTip::add( this, mExtensiveText );
00334   }
00335 }
00336 
00337 void KOAlternateLabel::resizeEvent( QResizeEvent * )
00338 {
00339   squeezeTextToLabel();
00340 }
00341 
00342 QSize KOAlternateLabel::minimumSizeHint() const
00343 {
00344   QSize sh = QLabel::minimumSizeHint();
00345   sh.setWidth(-1);
00346   return sh;
00347 }
00348 
00349 void KOAlternateLabel::setText( const QString &text ) {
00350   mLongText = text;
00351   squeezeTextToLabel();
00352 }
00353 
00354 
00358 
00359 KOAgendaView::KOAgendaView(Calendar *cal,QWidget *parent,const char *name) :
00360   KOEventView (cal,parent,name), mAllowAgendaUpdate( true ), mUpdateItem( 0 )
00361 {
00362   mSelectedDates.append(QDate::currentDate());
00363 
00364   mLayoutDayLabels = 0;
00365   mDayLabelsFrame = 0;
00366   mDayLabels = 0;
00367 
00368   bool isRTL = KOGlobals::self()->reverseLayout();
00369 
00370   if ( KOPrefs::instance()->mVerticalScreen ) {
00371     mExpandedPixmap = KOGlobals::self()->smallIcon( "1downarrow" );
00372     mNotExpandedPixmap = KOGlobals::self()->smallIcon( "1uparrow" );
00373   } else {
00374     mExpandedPixmap = KOGlobals::self()->smallIcon( isRTL ? "1leftarrow" : "1rightarrow" );
00375     mNotExpandedPixmap = KOGlobals::self()->smallIcon( isRTL ? "1rightarrow" : "1leftarrow" );
00376   }
00377 
00378   QBoxLayout *topLayout = new QVBoxLayout(this);
00379 
00380   // Create day name labels for agenda columns
00381   mDayLabelsFrame = new QHBox(this);
00382   topLayout->addWidget(mDayLabelsFrame);
00383 
00384   // Create agenda splitter
00385 #ifndef KORG_NOSPLITTER
00386   mSplitterAgenda = new QSplitter(Vertical,this);
00387   topLayout->addWidget(mSplitterAgenda);
00388 
00389 #if KDE_IS_VERSION( 3, 1, 93 )
00390   mSplitterAgenda->setOpaqueResize( KGlobalSettings::opaqueResize() );
00391 #else
00392   mSplitterAgenda->setOpaqueResize();
00393 #endif
00394 
00395   mAllDayFrame = new QHBox(mSplitterAgenda);
00396 
00397   QWidget *agendaFrame = new QWidget(mSplitterAgenda);
00398 #else
00399   QVBox *mainBox = new QVBox( this );
00400   topLayout->addWidget( mainBox );
00401 
00402   mAllDayFrame = new QHBox(mainBox);
00403 
00404   QWidget *agendaFrame = new QWidget(mainBox);
00405 #endif
00406 
00407   // Create all-day agenda widget
00408   mDummyAllDayLeft = new QVBox( mAllDayFrame );
00409 
00410   mExpandButton = new QPushButton(mDummyAllDayLeft);
00411   mExpandButton->setPixmap( mNotExpandedPixmap );
00412   mExpandButton->setSizePolicy( QSizePolicy( QSizePolicy::Fixed,
00413                                 QSizePolicy::Fixed ) );
00414   connect( mExpandButton, SIGNAL( clicked() ), SIGNAL( toggleExpand() ) );
00415 
00416   mAllDayAgenda = new KOAgenda(1,mAllDayFrame);
00417   QWidget *dummyAllDayRight = new QWidget(mAllDayFrame);
00418 
00419   // Create agenda frame
00420   QGridLayout *agendaLayout = new QGridLayout(agendaFrame,3,3);
00421 //  QHBox *agendaFrame = new QHBox(splitterAgenda);
00422 
00423   // create event indicator bars
00424   mEventIndicatorTop = new EventIndicator(EventIndicator::Top,agendaFrame);
00425   agendaLayout->addWidget(mEventIndicatorTop,0,1);
00426   mEventIndicatorBottom = new EventIndicator(EventIndicator::Bottom,
00427                                              agendaFrame);
00428   agendaLayout->addWidget(mEventIndicatorBottom,2,1);
00429   QWidget *dummyAgendaRight = new QWidget(agendaFrame);
00430   agendaLayout->addWidget(dummyAgendaRight,0,2);
00431 
00432   // Create time labels
00433   mTimeLabels = new TimeLabels(24,agendaFrame);
00434   agendaLayout->addWidget(mTimeLabels,1,0);
00435 
00436   // Create agenda
00437   mAgenda = new KOAgenda(1,96,KOPrefs::instance()->mHourSize,agendaFrame);
00438   agendaLayout->addMultiCellWidget(mAgenda,1,1,1,2);
00439   agendaLayout->setColStretch(1,1);
00440 
00441   // Create event context menu for agenda
00442   mAgendaPopup = eventPopup();
00443 
00444   // Create event context menu for all day agenda
00445   mAllDayAgendaPopup = eventPopup();
00446 
00447   // make connections between dependent widgets
00448   mTimeLabels->setAgenda(mAgenda);
00449 
00450   // Update widgets to reflect user preferences
00451 //  updateConfig();
00452 
00453   createDayLabels();
00454 
00455   // these blank widgets make the All Day Event box line up with the agenda
00456   dummyAllDayRight->setFixedWidth(mAgenda->verticalScrollBar()->width());
00457   dummyAgendaRight->setFixedWidth(mAgenda->verticalScrollBar()->width());
00458   mDummyAllDayLeft->setFixedWidth(mTimeLabels->width());
00459 
00460   // Scrolling
00461   connect(mAgenda->verticalScrollBar(),SIGNAL(valueChanged(int)),
00462           mTimeLabels, SLOT(positionChanged()));
00463   connect(mTimeLabels->verticalScrollBar(),SIGNAL(valueChanged(int)),
00464           SLOT(setContentsPos(int)));
00465 
00466   // Create Events, depends on type of agenda
00467   connect( mAgenda, SIGNAL(newEventSignal(const QPoint &)),
00468                     SLOT(newEvent(const QPoint &)));
00469   connect( mAllDayAgenda, SIGNAL(newEventSignal(const QPoint &)),
00470                           SLOT(newEventAllDay(const QPoint &)));
00471   connect( mAgenda, SIGNAL(newEventSignal(const QPoint &, const QPoint &)),
00472                     SLOT(newEvent(const QPoint &, const QPoint &)));
00473   connect( mAllDayAgenda, SIGNAL(newEventSignal(const QPoint &, const QPoint &)),
00474                           SLOT(newEventAllDay(const QPoint &)));
00475   connect( mAgenda, SIGNAL(newTimeSpanSignal(const QPoint &, const QPoint &)),
00476                     SLOT(newTimeSpanSelected(const QPoint &, const QPoint &)));
00477   connect( mAllDayAgenda, SIGNAL(newTimeSpanSignal(const QPoint &, const QPoint &)),
00478                           SLOT(newTimeSpanSelectedAllDay(const QPoint &, const QPoint &)));
00479 
00480   // event indicator update
00481   connect( mAgenda, SIGNAL(lowerYChanged(int)),
00482                     SLOT(updateEventIndicatorTop(int)));
00483   connect( mAgenda, SIGNAL(upperYChanged(int)),
00484                     SLOT(updateEventIndicatorBottom(int)));
00485 
00486   connectAgenda( mAgenda, mAgendaPopup, mAllDayAgenda );
00487   connectAgenda( mAllDayAgenda, mAllDayAgendaPopup, mAgenda);
00488 }
00489 
00490 
00491 KOAgendaView::~KOAgendaView()
00492 {
00493   delete mAgendaPopup;
00494   delete mAllDayAgendaPopup;
00495 }
00496 
00497 void KOAgendaView::connectAgenda( KOAgenda *agenda, QPopupMenu *popup,
00498                                   KOAgenda *otherAgenda )
00499 {
00500   connect( agenda, SIGNAL( showIncidencePopupSignal( Incidence *, const QDate & ) ),
00501            popup, SLOT( showIncidencePopup( Incidence *, const QDate & ) ) );
00502 
00503   connect( agenda, SIGNAL( showNewEventPopupSignal() ),
00504            SLOT( showNewEventPopup() ) );
00505 
00506   agenda->setCalendar( calendar() );
00507 
00508   // Create/Show/Edit/Delete Event
00509   connect( agenda, SIGNAL( newEventSignal() ), SIGNAL( newEventSignal() ) );
00510 
00511   connect( agenda, SIGNAL( newStartSelectSignal() ),
00512            otherAgenda, SLOT( clearSelection() ) );
00513 
00514   connect( agenda, SIGNAL( editIncidenceSignal( Incidence * ) ),
00515                    SIGNAL( editIncidenceSignal( Incidence * ) ) );
00516   connect( agenda, SIGNAL( showIncidenceSignal( Incidence * ) ),
00517                    SIGNAL( showIncidenceSignal( Incidence * ) ) );
00518   connect( agenda, SIGNAL( deleteIncidenceSignal( Incidence * ) ),
00519                    SIGNAL( deleteIncidenceSignal( Incidence * ) ) );
00520 
00521   connect( agenda, SIGNAL( incidenceChanged( Incidence *, Incidence * ) ),
00522                    SIGNAL( incidenceChanged( Incidence *, Incidence * ) ) );
00523   connect( agenda, SIGNAL( incidenceAdded( Incidence * ) ),
00524                    SIGNAL( incidenceAdded( Incidence * ) ) );
00525 
00526   connect( agenda, SIGNAL( startMultiModify( const QString & ) ),
00527                    SIGNAL( startMultiModify( const QString & ) ) );
00528   connect( agenda, SIGNAL( endMultiModify() ),
00529                    SIGNAL( endMultiModify() ) );
00530 
00531   connect( agenda, SIGNAL( itemModified( KOAgendaItem * ) ),
00532                    SLOT( updateEventDates( KOAgendaItem * ) ) );
00533   connect( agenda, SIGNAL( enableAgendaUpdate( bool ) ),
00534                    SLOT( enableAgendaUpdate( bool ) ) );
00535 
00536   // drag signals
00537   connect( agenda, SIGNAL( startDragSignal( Incidence * ) ),
00538            SLOT( startDrag( Incidence * ) ) );
00539 
00540   // synchronize selections
00541   connect( agenda, SIGNAL( incidenceSelected( Incidence * ) ),
00542            otherAgenda, SLOT( deselectItem() ) );
00543   connect( agenda, SIGNAL( incidenceSelected( Incidence * ) ),
00544            SIGNAL( incidenceSelected( Incidence * ) ) );
00545 
00546   // rescheduling of todos by d'n'd
00547   connect( agenda, SIGNAL( droppedToDo( Todo *, const QPoint &, bool ) ),
00548            SLOT( slotTodoDropped( Todo *, const QPoint &, bool ) ) );
00549 
00550 }
00551 
00552 void KOAgendaView::createDayLabels()
00553 {
00554 //  kdDebug(5850) << "KOAgendaView::createDayLabels()" << endl;
00555 
00556   // ### Before deleting and recreating we could check if mSelectedDates changed...
00557   // It would remove some flickering and gain speed (since this is called by
00558   // each updateView() call)
00559   delete mDayLabels;
00560 
00561   mDayLabels = new QFrame (mDayLabelsFrame);
00562   mLayoutDayLabels = new QHBoxLayout(mDayLabels);
00563   mLayoutDayLabels->addSpacing(mTimeLabels->width());
00564 
00565   const KCalendarSystem*calsys=KOGlobals::self()->calendarSystem();
00566 
00567   DateList::ConstIterator dit;
00568   for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) {
00569     QDate date = *dit;
00570     QBoxLayout *dayLayout = new QVBoxLayout(mLayoutDayLabels);
00571     mLayoutDayLabels->setStretchFactor(dayLayout, 1);
00572 //    dayLayout->setMinimumWidth(1);
00573 
00574     int dW = calsys->dayOfWeek(date);
00575     QString veryLongStr = KGlobal::locale()->formatDate( date );
00576     QString longstr = i18n( "short_weekday date (e.g. Mon 13)","%1 %2" )
00577         .arg( calsys->weekDayName( dW, true ) )
00578         .arg( calsys->day(date) );
00579     QString shortstr = QString::number(calsys->day(date));
00580 
00581     KOAlternateLabel *dayLabel = new KOAlternateLabel(shortstr,
00582       longstr, veryLongStr, mDayLabels);
00583     dayLabel->setMinimumWidth(1);
00584     dayLabel->setAlignment(QLabel::AlignHCenter);
00585     if (date == QDate::currentDate()) {
00586       QFont font = dayLabel->font();
00587       font.setBold(true);
00588       dayLabel->setFont(font);
00589     }
00590     dayLayout->addWidget(dayLabel);
00591 
00592 #ifndef KORG_NOPLUGINS
00593     CalendarDecoration::List cds = KOCore::self()->calendarDecorations();
00594     CalendarDecoration *it;
00595     for(it = cds.first(); it; it = cds.next()) {
00596       QString text = it->shortText( date );
00597       if ( !text.isEmpty() ) {
00598         // use a KOAlternateLabel so when the text doesn't fit any more a tooltip is used
00599         KOAlternateLabel*label = new KOAlternateLabel( text, text, QString::null, mDayLabels );
00600         label->setMinimumWidth(1);
00601         label->setAlignment(AlignCenter);
00602         dayLayout->addWidget(label);
00603       }
00604     }
00605 
00606     for(it = cds.first(); it; it = cds.next()) {
00607       QWidget *wid = it->smallWidget(mDayLabels,date);
00608       if ( wid ) {
00609 //      wid->setHeight(20);
00610         dayLayout->addWidget(wid);
00611       }
00612     }
00613 #endif
00614   }
00615 
00616   mLayoutDayLabels->addSpacing(mAgenda->verticalScrollBar()->width());
00617   mDayLabels->show();
00618 }
00619 
00620 void KOAgendaView::enableAgendaUpdate( bool enable )
00621 {
00622   mAllowAgendaUpdate = enable;
00623 }
00624 
00625 int KOAgendaView::maxDatesHint()
00626 {
00627   // Not sure about the max number of events, so return 0 for now.
00628   return 0;
00629 }
00630 
00631 int KOAgendaView::currentDateCount()
00632 {
00633   return mSelectedDates.count();
00634 }
00635 
00636 Incidence::List KOAgendaView::selectedIncidences()
00637 {
00638   Incidence::List selected;
00639   Incidence *incidence;
00640 
00641   incidence = mAgenda->selectedIncidence();
00642   if (incidence) selected.append(incidence);
00643 
00644   incidence = mAllDayAgenda->selectedIncidence();
00645   if (incidence) selected.append(incidence);
00646 
00647   return selected;
00648 }
00649 
00650 DateList KOAgendaView::selectedDates()
00651 {
00652   DateList selected;
00653   QDate qd;
00654 
00655   qd = mAgenda->selectedIncidenceDate();
00656   if (qd.isValid()) selected.append(qd);
00657 
00658   qd = mAllDayAgenda->selectedIncidenceDate();
00659   if (qd.isValid()) selected.append(qd);
00660 
00661   return selected;
00662 }
00663 
00664 bool KOAgendaView::eventDurationHint( QDateTime &startDt, QDateTime &endDt,
00665                                       bool &allDay )
00666 {
00667   if ( selectionStart().isValid() ) {
00668     startDt = selectionStart();
00669     endDt = selectionEnd();
00670     allDay = selectedIsAllDay();
00671     return true;
00672   }
00673   return false;
00674 }
00675 
00677 bool KOAgendaView::selectedIsSingleCell()
00678 {
00679   if ( !selectionStart().isValid() || !selectionEnd().isValid() ) return false;
00680 
00681   if (selectedIsAllDay()) {
00682     int days = selectionStart().daysTo(selectionEnd());
00683     return ( days < 1 );
00684   } else {
00685     int secs = selectionStart().secsTo(selectionEnd());
00686     return ( secs <= 24*60*60/mAgenda->rows() );
00687   }
00688 }
00689 
00690 
00691 void KOAgendaView::updateView()
00692 {
00693 //  kdDebug(5850) << "KOAgendaView::updateView()" << endl;
00694   fillAgenda();
00695 }
00696 
00697 
00698 /*
00699   Update configuration settings for the agenda view. This method is not
00700   complete.
00701 */
00702 void KOAgendaView::updateConfig()
00703 {
00704 //  kdDebug(5850) << "KOAgendaView::updateConfig()" << endl;
00705 
00706   // update config for children
00707   mTimeLabels->updateConfig();
00708   mAgenda->updateConfig();
00709   mAllDayAgenda->updateConfig();
00710 
00711   // widget synchronization
00712   //TODO: find a better way, maybe signal/slot
00713   mTimeLabels->positionChanged();
00714 
00715   // for some reason, this needs to be called explicitly
00716   mTimeLabels->repaint();
00717 
00718   mDummyAllDayLeft->setFixedWidth(mTimeLabels->width());
00719 
00720   // ToolTips displaying summary of events
00721   KOAgendaItem::toolTipGroup()->setEnabled(KOPrefs::instance()
00722                                            ->mEnableToolTips);
00723 
00724   setHolidayMasks();
00725 
00726   createDayLabels();
00727 
00728   updateView();
00729 }
00730 
00731 
00732 void KOAgendaView::updateEventDates( KOAgendaItem *item )
00733 {
00734 //  kdDebug(5850) << "KOAgendaView::updateEventDates(): " << item->text() << endl;
00735 
00736   QDateTime startDt,endDt;
00737 
00738   // Start date of this incidence, calculate the offset from it (so recurring and
00739   // non-recurring items can be treated exactly the same, we never need to check
00740   // for doesRecur(), because we only move the start day by the number of days the
00741   // agenda item was really moved. Smart, isn't it?)
00742   QDate thisDate;
00743   if ( item->cellXLeft() < 0 ) {
00744     thisDate = ( mSelectedDates.first() ).addDays( item->cellXLeft() );
00745   } else {
00746     thisDate = mSelectedDates[ item->cellXLeft() ];
00747   }
00748   QDate oldThisDate( item->itemDate() );
00749   int daysOffset = oldThisDate.daysTo( thisDate );
00750   int daysLength = 0;
00751 
00752 //  startDt.setDate( startDate );
00753 
00754   Incidence *incidence = item->incidence();
00755   if ( !incidence ) return;
00756   Incidence *oldIncidence = incidence->clone();
00757 
00758   QTime startTime(0,0,0), endTime(0,0,0);
00759   if ( incidence->doesFloat() ) {
00760     daysLength = item->cellWidth() - 1;
00761   } else {
00762     startTime = mAgenda->gyToTime( item->cellYTop() );
00763     if ( item->lastMultiItem() ) {
00764       endTime = mAgenda->gyToTime( item->lastMultiItem()->cellYBottom() + 1 );
00765       daysLength = item->lastMultiItem()->cellXLeft() - item->cellXLeft();
00766     } else {
00767       endTime = mAgenda->gyToTime( item->cellYBottom() + 1 );
00768     }
00769   }
00770 
00771 //  kdDebug(5850) << "KOAgendaView::updateEventDates(): now setting dates" << endl;
00772   Incidence *i = incidence->clone();
00773   if ( i->type() == "Event" ) {
00774     startDt = i->dtStart();
00775     startDt = startDt.addDays( daysOffset );
00776     startDt.setTime( startTime );
00777     endDt = startDt.addDays( daysLength );
00778     endDt.setTime( endTime );
00779     Event*ev = static_cast<Event*>(i);
00780     if( i->dtStart() == startDt && ev->dtEnd() == endDt ) {
00781       // No change
00782       delete i;
00783       return;
00784     }
00785     i->setDtStart( startDt );
00786     ev->setDtEnd( endDt );
00787   } else if ( i->type() == "Todo" ) {
00788     Todo *td = static_cast<Todo*>(i);
00789     startDt = td->dtStart();
00790     startDt = startDt.addDays( daysOffset );
00791     endDt = td->dtDue();
00792     endDt = endDt.addDays( daysOffset );
00793     endDt.setTime( endTime );
00794 
00795     if( td->dtDue() == endDt ) {
00796       // No change
00797       delete i;
00798       return;
00799     }
00800     td->setDtDue( endDt );
00801   }
00802   // TODO: Adjusting the recurrence should really go to CalendarView so this
00803   // functionality will also be available in other views!
00804   Recurrence *recur = incidence->recurrence();
00805   if ( recur && (recur->doesRecur()!=Recurrence::rNone) && (daysOffset!=0) ) {
00806     switch ( recur->doesRecur() ) {
00807       case Recurrence::rYearlyPos: {
00808         int freq = recur->frequency();
00809         int duration = recur->duration();
00810         QDate endDt( recur->endDate() );
00811         bool negative = false;
00812 
00813         QPtrList<Recurrence::rMonthPos> monthPos( recur->yearMonthPositions() );
00814         if ( monthPos.first() ) {
00815           negative = monthPos.first()->negative;
00816         }
00817         QBitArray days( 7 );
00818         int pos = 0;
00819         days.fill( false );
00820         days.setBit( thisDate.dayOfWeek() - 1 );
00821         if ( negative ) {
00822           pos =  - ( thisDate.daysInMonth() - thisDate.day() - 1 ) / 7 - 1;
00823         } else {
00824           pos =  ( thisDate.day()-1 ) / 7 + 1;
00825         }
00826         // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again
00827         recur->unsetRecurs();
00828         if ( duration != 0 ) {
00829           recur->setYearly( Recurrence::rYearlyPos, freq, duration );
00830         } else {
00831           recur->setYearly( Recurrence::rYearlyPos, freq, endDt );
00832         }
00833         recur->addYearlyMonthPos( pos, days );
00834         recur->addYearlyNum( thisDate.month() );
00835 
00836         break; }
00837         case Recurrence::rYearlyDay: {
00838           int freq = recur->frequency();
00839           int duration = recur->duration();
00840           QDate endDt( recur->endDate() );
00841         // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again
00842           recur->unsetRecurs();
00843           if ( duration == 0 ) { // end by date
00844             recur->setYearly( Recurrence::rYearlyDay, freq, endDt );
00845           } else {
00846             recur->setYearly( Recurrence::rYearlyDay, freq, duration );
00847           }
00848           recur->addYearlyNum( thisDate.dayOfYear() );
00849           break; }
00850           case Recurrence::rYearlyMonth: {
00851             int freq = recur->frequency();
00852             int duration = recur->duration();
00853             QDate endDt( recur->endDate() );
00854         // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again
00855             recur->unsetRecurs();
00856             if ( duration != 0 ) {
00857               recur->setYearlyByDate( thisDate.day(), recur->feb29YearlyType(), freq, duration );
00858             } else {
00859               recur->setYearlyByDate( thisDate.day(), recur->feb29YearlyType(), freq, endDt );
00860             }
00861             recur->addYearlyNum( thisDate.month() );
00862             break; }
00863             case Recurrence::rMonthlyPos: {
00864               int freq = recur->frequency();
00865               int duration = recur->duration();
00866               QDate endDt( recur->endDate() );
00867               QPtrList<Recurrence::rMonthPos> monthPos( recur->monthPositions() );
00868               if ( !monthPos.isEmpty() ) {
00869           // TODO: How shall I adapt the day x of week Y if we move the date across month borders???
00870           // for now, just use the date of the moved item and assume the recurrence only occurs on that day.
00871           // That's fine for korganizer, but might mess up other organizers.
00872                 QBitArray rDays( 7 );
00873                 rDays = monthPos.first()->rDays;
00874                 bool negative = monthPos.first()->negative;
00875                 int newPos;
00876                 rDays.fill( false );
00877                 rDays.setBit( thisDate.dayOfWeek() - 1 );
00878                 if ( negative ) {
00879                   newPos =  - ( thisDate.daysInMonth() - thisDate.day() - 1 ) / 7 - 1;
00880                 } else {
00881                   newPos =  ( thisDate.day()-1 ) / 7 + 1;
00882                 }
00883 
00884           // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again
00885                 recur->unsetRecurs();
00886                 if ( duration == 0 ) { // end by date
00887                   recur->setMonthly( Recurrence::rMonthlyPos, freq, endDt );
00888                 } else {
00889                   recur->setMonthly( Recurrence::rMonthlyPos, freq, duration );
00890                 }
00891                 recur->addMonthlyPos( newPos, rDays );
00892               }
00893               break;}
00894               case Recurrence::rMonthlyDay: {
00895                 int freq = recur->frequency();
00896                 int duration = recur->duration();
00897                 QDate endDt( recur->endDate() );
00898                 QPtrList<int> monthDays( recur->monthDays() );
00899         // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again
00900                 recur->unsetRecurs();
00901                 if ( duration == 0 ) { // end by date
00902                   recur->setMonthly( Recurrence::rMonthlyDay, freq, endDt );
00903                 } else {
00904                   recur->setMonthly( Recurrence::rMonthlyDay, freq, duration );
00905                 }
00906         // TODO: How shall I adapt the n-th day if we move the date across month borders???
00907         // for now, just use the date of the moved item and assume the recurrence only occurs on that day.
00908         // That's fine for korganizer, but might mess up other organizers.
00909                 recur->addMonthlyDay( thisDate.day() );
00910 
00911                 break;}
00912                 case Recurrence::rWeekly: {
00913                   QBitArray days(7), oldDays( recur->days() );
00914                   int offset = daysOffset % 7;
00915                   if ( offset<0 ) offset = (offset+7) % 7;
00916         // rotate the days
00917                   for (int d=0; d<7; d++ ) {
00918                     days.setBit( (d+offset) % 7, oldDays.at(d) );
00919                   }
00920                   if ( recur->duration() == 0 ) { // end by date
00921                     recur->setWeekly( recur->frequency(), days, recur->endDate(), recur->weekStart() );
00922                   } else { // duration or no end
00923                     recur->setWeekly( recur->frequency(), days, recur->duration(), recur->weekStart() );
00924                   }
00925                   break;}
00926       // nothing to be done for the following:
00927       case Recurrence::rDaily:
00928       case Recurrence::rHourly:
00929       case Recurrence::rMinutely:
00930       case Recurrence::rNone:
00931       default:
00932         break;
00933     }
00934     if ( recur->duration()==0 ) { // end by date
00935       recur->setEndDate( recur->endDate().addDays( daysOffset ) );
00936     }
00937     KMessageBox::information( this, i18n("A recurring incidence was moved to a different day. The recurrence settings have been updated with that move. Please check them in the incidence editor."), i18n("Recurrence Moved"), "RecurrenceMoveInAgendaWarning" );
00938   }
00939 
00940   i->setRevision( i->revision() + 1 );
00941   if( !KOPrefs::instance()->mUseGroupwareCommunication ||
00942        KOGroupware::instance()->sendICalMessage( this, KCal::Scheduler::Request,
00943   i ) ) {
00944     if ( i->type() == "Event" ) {
00945       incidence->setDtStart( startDt );
00946       (static_cast<Event*>( incidence ) )->setDtEnd( endDt );
00947     } else if ( i->type() == "Todo" ) {
00948       (static_cast<Todo*>( incidence ) )->setDtDue( endDt );
00949     }
00950     incidence->setRevision( i->revision() );
00951     item->setItemDate( startDt.date() );
00952 
00953     KOIncidenceToolTip<KOAgendaItem>::remove( item );
00954     KOIncidenceToolTip<KOAgendaItem>::add( item, KOAgendaItem::toolTipGroup() );
00955 
00956     // don't update the agenda as the item already has the correct coordinates.
00957     // an update would delete the current item and recreate it, but we are still
00958     // using a pointer to that item! => CRASH
00959     enableAgendaUpdate( false );
00960     // We need to do this in a timer to make sure we are not deleting the item
00961     // we are currently working on, which would lead to crashes
00962     // Only the actually moved agenda item is already at the correct position and mustn't be
00963     // recreated. All others have to!!!
00964     if ( incidence->doesRecur() ) {
00965       mUpdateItem = incidence;
00966       QTimer::singleShot( 0, this, SLOT( doUpdateItem() ) );
00967     }
00968 
00969     emit incidenceChanged( oldIncidence, incidence );
00970     enableAgendaUpdate( true );
00971   } else {
00972     updateView();
00973   }
00974 
00975   delete i;
00976   delete oldIncidence;
00977 //  kdDebug(5850) << "KOAgendaView::updateEventDates() done " << endl;
00978 }
00979 
00980 void KOAgendaView::doUpdateItem()
00981 {
00982   if ( mUpdateItem ) {
00983     changeIncidenceDisplay( mUpdateItem, KOGlobals::INCIDENCEEDITED );
00984     mUpdateItem = 0;
00985   }
00986 }
00987 
00988 
00989 
00990 void KOAgendaView::showDates( const QDate &start, const QDate &end )
00991 {
00992 //  kdDebug(5850) << "KOAgendaView::selectDates" << endl;
00993 
00994   mSelectedDates.clear();
00995 
00996   QDate d = start;
00997   while (d <= end) {
00998     mSelectedDates.append(d);
00999     d = d.addDays( 1 );
01000   }
01001 
01002   // and update the view
01003   fillAgenda();
01004 }
01005 
01006 
01007 void KOAgendaView::showIncidences( const Incidence::List & )
01008 {
01009   kdDebug(5850) << "KOAgendaView::showIncidences( const Incidence::List & ) is not yet implemented" << endl;
01010 }
01011 
01012 void KOAgendaView::insertIncidence( Incidence *incidence, QDate curDate,
01013                                     int curCol )
01014 {
01015   Event *event = dynamic_cast<Event *>( incidence );
01016   Todo  *todo  = dynamic_cast<Todo  *>( incidence );
01017 
01018   if ( curCol < 0 ) {
01019     curCol = mSelectedDates.findIndex( curDate );
01020   }
01021   // The date for the event is not displayed, just ignore it
01022   if ( curCol < 0 || curCol > int( mSelectedDates.size() ) )
01023     return;
01024 
01025   int beginX;
01026   int endX;
01027   if ( event ) {
01028     beginX = curDate.daysTo( incidence->dtStart().date() ) + curCol;
01029     endX = curDate.daysTo( event->dtEnd().date() ) + curCol;
01030   } else if ( todo ) {
01031     beginX = curDate.daysTo( todo->dtDue().date() ) + curCol;
01032     endX = beginX;
01033   } else {
01034     return;
01035   }
01036 
01037   if ( incidence->doesFloat() ) {
01038     if ( incidence->recurrence()->doesRecur() ) {
01039       mAllDayAgenda->insertAllDayItem( incidence, curDate, curCol, curCol );
01040     } else {
01041       if ( ( beginX <= 0 && curCol == 0 ) || beginX == curCol ) {
01042         mAllDayAgenda->insertAllDayItem( incidence, curDate, beginX, endX );
01043       }
01044     }
01045   } else if ( event && event->isMultiDay() ) {
01046     int startY = mAgenda->timeToY( event->dtStart().time() );
01047     int endY = mAgenda->timeToY( event->dtEnd().time() ) - 1;
01048     if ( (beginX <= 0 && curCol == 0) || beginX == curCol ) {
01049       mAgenda->insertMultiItem( event, curDate, beginX, endX, startY, endY );
01050     }
01051     if ( beginX == curCol ) {
01052       mMaxY[curCol] = mAgenda->timeToY( QTime(23,59) );
01053       if ( startY < mMinY[curCol] ) mMinY[curCol] = startY;
01054     } else if ( endX == curCol ) {
01055       mMinY[curCol] = mAgenda->timeToY( QTime(0,0) );
01056       if ( endY > mMaxY[curCol] ) mMaxY[curCol] = endY;
01057     } else {
01058       mMinY[curCol] = mAgenda->timeToY( QTime(0,0) );
01059       mMaxY[curCol] = mAgenda->timeToY( QTime(23,59) );
01060     }
01061   } else {
01062     int startY = 0, endY = 0;
01063     if ( event ) {
01064       startY = mAgenda->timeToY( incidence->dtStart().time() );
01065       endY = mAgenda->timeToY( event->dtEnd().time() ) - 1;
01066     }
01067     if ( todo ) {
01068       QTime t = todo->dtDue().time();
01069       endY = mAgenda->timeToY( t ) - 1;
01070       startY = mAgenda->timeToY( t.addSecs( -1800 ) );
01071     }
01072     if ( endY < startY ) endY = startY;
01073     mAgenda->insertItem( incidence, curDate, curCol, startY, endY );
01074     if ( startY < mMinY[curCol] ) mMinY[curCol] = startY;
01075     if ( endY > mMaxY[curCol] ) mMaxY[curCol] = endY;
01076   }
01077 }
01078 
01079 void KOAgendaView::changeIncidenceDisplayAdded( Incidence *incidence )
01080 {
01081   Todo *todo = dynamic_cast<Todo *>(incidence);
01082   if ( !calendar()->filter()->filterIncidence( incidence ) ||
01083      ( todo && !KOPrefs::instance()->showAllDayTodo() ) )
01084     return;
01085 
01086   QDate f = mSelectedDates.first();
01087   QDate l = mSelectedDates.last();
01088   QDate startDt = incidence->dtStart().date();
01089 
01090   if ( incidence->doesRecur() ) {
01091     DateList::ConstIterator dit;
01092     QDate curDate;
01093     for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) {
01094       curDate = *dit;
01095       if ( incidence->recursOn( curDate ) ) {
01096         insertIncidence( incidence, curDate );
01097       }
01098     }
01099     return;
01100   }
01101 
01102   QDate endDt;
01103   if ( incidence->type() == "Event" )
01104     endDt = (static_cast<Event *>(incidence))->dtEnd().date();
01105   if ( todo ) {
01106     bool overdue = (!todo->isCompleted()) &&
01107                    (todo->dtDue() < QDate::currentDate() );
01108     endDt = overdue ? QDate::currentDate()
01109                     : todo->dtDue().date();
01110     if ( endDt >= f && endDt <= l ) {
01111       insertIncidence( incidence, endDt );
01112       return;
01113     }
01114   }
01115 
01116   if ( startDt <= l ) {
01117     if ( startDt >= f ) {
01118       insertIncidence( incidence, startDt );
01119     } else if ( endDt >= f ) {
01120       insertIncidence( incidence, endDt );
01121     }
01122   }
01123 }
01124 
01125 void KOAgendaView::changeIncidenceDisplay( Incidence *incidence, int mode )
01126 {
01127   switch ( mode ) {
01128     case KOGlobals::INCIDENCEADDED: {
01129         //  Add an event. No need to recreate the whole view!
01130         // recreating everything even causes troubles: dropping to the day matrix
01131         // recreates the agenda items, but the evaluation is still in an agendaItems' code,
01132         // which was deleted in the mean time. Thus KOrg crashes...
01133       changeIncidenceDisplayAdded( incidence );
01134       break;
01135     }
01136     case KOGlobals::INCIDENCEEDITED: {
01137       if ( !mAllowAgendaUpdate ) {
01138         updateEventIndicators();
01139       } else {
01140         removeIncidence( incidence );
01141         updateEventIndicators();
01142         changeIncidenceDisplayAdded( incidence );
01143       }
01144       break;
01145     }
01146     case KOGlobals::INCIDENCEDELETED: {
01147       mAgenda->removeIncidence( incidence );
01148       mAllDayAgenda->removeIncidence( incidence );
01149       updateEventIndicators();
01150       break;
01151     }
01152     default:
01153       updateView();
01154   }
01155 }
01156 
01157 void KOAgendaView::fillAgenda( const QDate & )
01158 {
01159   fillAgenda();
01160 }
01161 
01162 void KOAgendaView::fillAgenda()
01163 {
01164   /* Remember the uids of the selected items. In case one of the
01165    * items was deleted and re-added, we want to reselect it. */
01166   const QString &selectedAgendaUid = mAgenda->lastSelectedUid();
01167   const QString &selectedAllDayAgendaUid = mAllDayAgenda->lastSelectedUid();
01168 
01169   enableAgendaUpdate( true );
01170   clearView();
01171 
01172   mAllDayAgenda->changeColumns(mSelectedDates.count());
01173   mAgenda->changeColumns(mSelectedDates.count());
01174   mEventIndicatorTop->changeColumns(mSelectedDates.count());
01175   mEventIndicatorBottom->changeColumns(mSelectedDates.count());
01176 
01177   createDayLabels();
01178   setHolidayMasks();
01179 
01180   mMinY.resize(mSelectedDates.count());
01181   mMaxY.resize(mSelectedDates.count());
01182 
01183   Event::List dayEvents;
01184 
01185   // ToDo items shall be displayed for the day they are due, but only shown today if they are already overdue.
01186   // Therefore, get all of them.
01187   Todo::List todos  = calendar()->todos();
01188 
01189   mAgenda->setDateList(mSelectedDates);
01190 
01191   QDate today = QDate::currentDate();
01192 
01193   bool somethingReselected = false;
01194   DateList::ConstIterator dit;
01195   int curCol = 0;
01196   for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) {
01197     QDate currentDate = *dit;
01198 //    kdDebug(5850) << "KOAgendaView::fillAgenda(): " << currentDate.toString()
01199 //              << endl;
01200 
01201     dayEvents = calendar()->events(currentDate,true);
01202 
01203     // Default values, which can never be reached
01204     mMinY[curCol] = mAgenda->timeToY(QTime(23,59)) + 1;
01205     mMaxY[curCol] = mAgenda->timeToY(QTime(0,0)) - 1;
01206 
01207     unsigned int numEvent;
01208     for(numEvent=0;numEvent<dayEvents.count();++numEvent) {
01209       Event *event = *dayEvents.at(numEvent);
01210 //      kdDebug(5850) << " Event: " << event->summary() << endl;
01211       insertIncidence( event, currentDate, curCol );
01212       if( event->uid() == selectedAgendaUid && !selectedAgendaUid.isNull() ) {
01213         mAgenda->selectItemByUID( event->uid() );
01214         somethingReselected = true;
01215       }
01216       if( event->uid() == selectedAllDayAgendaUid && !selectedAllDayAgendaUid.isNull() ) {
01217         mAllDayAgenda->selectItemByUID( event->uid() );
01218         somethingReselected = true;
01219       }
01220 
01221     }
01222 //    if (numEvent == 0) kdDebug(5850) << " No events" << endl;
01223 
01224 
01225     // ---------- [display Todos --------------
01226     if ( KOPrefs::instance()->showAllDayTodo() ) {
01227       unsigned int numTodo;
01228       for (numTodo = 0; numTodo < todos.count(); ++numTodo) {
01229         Todo *todo = *todos.at(numTodo);
01230 
01231         if ( ! todo->hasDueDate() ) continue;  // todo shall not be displayed if it has no date
01232 
01233         // ToDo items shall be displayed for the day they are due, but only showed today if they are already overdue.
01234         // Already completed items can be displayed on their original due date
01235         bool overdue = (!todo->isCompleted()) && (todo->dtDue() < today);
01236 
01237         if ( (( todo->dtDue().date() == currentDate) && !overdue) ||
01238              (( currentDate == today) && overdue) ||
01239              ( todo->recursOn( currentDate ) ) ) {
01240           if ( todo->doesFloat() || overdue ) {  // Todo has no due-time set or is already overdue
01241             //kdDebug(5850) << "todo without time:" << todo->dtDueDateStr() << ";" << todo->summary() << endl;
01242 
01243             mAllDayAgenda->insertAllDayItem(todo, currentDate, curCol, curCol);
01244           } else {
01245             //kdDebug(5850) << "todo with time:" << todo->dtDueStr() << ";" << todo->summary() << endl;
01246 
01247             int endY = mAgenda->timeToY(todo->dtDue().time()) - 1;
01248             int startY = endY - 1;
01249 
01250             mAgenda->insertItem(todo,currentDate,curCol,startY,endY);
01251 
01252             if (startY < mMinY[curCol]) mMinY[curCol] = startY;
01253             if (endY > mMaxY[curCol]) mMaxY[curCol] = endY;
01254           }
01255         }
01256       }
01257     }
01258     // ---------- display Todos] --------------
01259 
01260     ++curCol;
01261   }
01262 
01263   mAgenda->checkScrollBoundaries();
01264 
01265 //  mAgenda->viewport()->update();
01266 //  mAllDayAgenda->viewport()->update();
01267 
01268 // make invalid
01269   deleteSelectedDateTime();
01270 
01271   if( !somethingReselected ) {
01272     emit incidenceSelected( 0 );
01273   }
01274 
01275 //  kdDebug(5850) << "Fill Agenda done" << endl;
01276 }
01277 
01278 void KOAgendaView::clearView()
01279 {
01280 //  kdDebug(5850) << "ClearView" << endl;
01281   mAllDayAgenda->clear();
01282   mAgenda->clear();
01283 }
01284 
01285 void KOAgendaView::printPreview(CalPrinter *calPrinter, const QDate &fd,
01286                                const QDate &td)
01287 {
01288 #ifndef KORG_NOPRINTER
01289   if (fd == td)
01290     calPrinter->preview(CalPrinter::Day, fd, td);
01291   else
01292     calPrinter->preview(CalPrinter::Week, fd, td);
01293 #endif
01294 }
01295 
01296 CalPrinter::PrintType KOAgendaView::printType()
01297 {
01298   if ( currentDateCount() == 1 ) return CalPrinter::Day;
01299   else return CalPrinter::Week;
01300 }
01301 
01302 void KOAgendaView::newEvent( const QPoint &pos)
01303 {
01304   if (!mSelectedDates.count()) return;
01305 
01306   QDate day = mSelectedDates[pos.x()];
01307 
01308   QTime time = mAgenda->gyToTime(pos.y());
01309   QDateTime dt(day,time);
01310 
01311   emit newEventSignal(dt);
01312 }
01313 
01314 void KOAgendaView::newEvent(const QPoint &start, const QPoint &end)
01315 {
01316   if (!mSelectedDates.count()) return;
01317 
01318   QDate dayStart = mSelectedDates[start.x()];
01319   QDate dayEnd = mSelectedDates[end.x()];
01320 
01321   QTime timeStart = mAgenda->gyToTime( start.y() );
01322   QTime timeEnd = mAgenda->gyToTime( end.y() + 1 );
01323 
01324   QDateTime dtStart(dayStart,timeStart);
01325   QDateTime dtEnd(dayEnd,timeEnd);
01326 
01327   emit newEventSignal(dtStart,dtEnd);
01328 }
01329 
01330 void KOAgendaView::newEventAllDay( const QPoint &start )
01331 {
01332   if (!mSelectedDates.count()) return;
01333 
01334   QDate day = mSelectedDates[start.x()];
01335 
01336   emit newEventSignal(day);
01337 }
01338 
01339 void KOAgendaView::updateEventIndicatorTop(int newY)
01340 {
01341   uint i;
01342   for(i=0;i<mMinY.size();++i) {
01343     if (newY >= mMinY[i]) mEventIndicatorTop->enableColumn(i,true);
01344     else mEventIndicatorTop->enableColumn(i,false);
01345   }
01346 
01347   mEventIndicatorTop->update();
01348 }
01349 
01350 void KOAgendaView::updateEventIndicatorBottom(int newY)
01351 {
01352   uint i;
01353   for(i=0;i<mMaxY.size();++i) {
01354     if (newY <= mMaxY[i]) mEventIndicatorBottom->enableColumn(i,true);
01355     else mEventIndicatorBottom->enableColumn(i,false);
01356   }
01357 
01358   mEventIndicatorBottom->update();
01359 }
01360 
01361 void KOAgendaView::slotTodoDropped( Todo *todo, const QPoint &gpos, bool allDay )
01362 {
01363   if (gpos.x()<0 || gpos.y()<0) return;
01364   QDate day = mSelectedDates[gpos.x()];
01365   QTime time = mAgenda->gyToTime(gpos.y());
01366   QDateTime newTime(day, time);
01367 
01368   if (todo) {
01369     Todo *existingTodo = calendar()->todo(todo->uid());
01370     if(existingTodo) {
01371       kdDebug(5850) << "Drop existing Todo" << endl;
01372       Todo *oldTodo = existingTodo->clone();
01373       existingTodo->setDtDue( newTime );
01374       existingTodo->setFloats( allDay );
01375       existingTodo->setHasDueDate( true );
01376       existingTodo->setRevision( existingTodo->revision() + 1 );
01377       emit incidenceChanged( oldTodo, existingTodo );
01378       delete oldTodo;
01379     } else {
01380       kdDebug(5850) << "Drop new Todo" << endl;
01381       todo->setDtDue( newTime );
01382       todo->setFloats( allDay );
01383       existingTodo->setHasDueDate( true );
01384       if ( calendar()->addTodo( todo ) ) {
01385         emit incidenceAdded(todo);
01386       } else {
01387         KODialogManager::errorSaveTodo( this );
01388       }
01389     }
01390   }
01391 }
01392 
01393 void KOAgendaView::startDrag( Incidence *incidence )
01394 {
01395 #ifndef KORG_NODND
01396   DndFactory factory( calendar() );
01397   ICalDrag *vd = factory.createDrag( incidence, this );
01398   if ( vd->drag() ) {
01399     kdDebug(5850) << "KOAgendaView::startDrag(): Delete drag source" << endl;
01400   }
01401 #endif
01402 }
01403 
01404 void KOAgendaView::readSettings()
01405 {
01406   readSettings(KOGlobals::self()->config());
01407 }
01408 
01409 void KOAgendaView::readSettings(KConfig *config)
01410 {
01411 //  kdDebug(5850) << "KOAgendaView::readSettings()" << endl;
01412 
01413   config->setGroup("Views");
01414 
01415 #ifndef KORG_NOSPLITTER
01416   QValueList<int> sizes = config->readIntListEntry("Separator AgendaView");
01417   if (sizes.count() == 2) {
01418     mSplitterAgenda->setSizes(sizes);
01419   }
01420 #endif
01421 
01422   updateConfig();
01423 }
01424 
01425 void KOAgendaView::writeSettings(KConfig *config)
01426 {
01427 //  kdDebug(5850) << "KOAgendaView::writeSettings()" << endl;
01428 
01429   config->setGroup("Views");
01430 
01431 #ifndef KORG_NOSPLITTER
01432   QValueList<int> list = mSplitterAgenda->sizes();
01433   config->writeEntry("Separator AgendaView",list);
01434 #endif
01435 }
01436 
01437 void KOAgendaView::setHolidayMasks()
01438 {
01439   mHolidayMask.resize( mSelectedDates.count() + 1 );
01440 
01441   for( uint i = 0; i < mSelectedDates.count(); ++i ) {
01442     mHolidayMask[i] = !KOCore::self()->isWorkDay( mSelectedDates[ i ] );
01443   }
01444 
01445   // Store the information about the day before the visible area (needed for
01446   // overnight working hours) in the last bit of the mask:
01447   bool showDay = !KOCore::self()->isWorkDay( mSelectedDates[ 0 ].addDays( -1 ) );
01448   mHolidayMask[ mSelectedDates.count() ] = showDay;
01449 
01450   mAgenda->setHolidayMask( &mHolidayMask );
01451   mAllDayAgenda->setHolidayMask( &mHolidayMask );
01452 }
01453 
01454 void KOAgendaView::setContentsPos( int y )
01455 {
01456   mAgenda->setContentsPos( 0, y );
01457 }
01458 
01459 void KOAgendaView::setExpandedButton( bool expanded )
01460 {
01461   if ( expanded ) {
01462     mExpandButton->setPixmap( mExpandedPixmap );
01463   } else {
01464     mExpandButton->setPixmap( mNotExpandedPixmap );
01465   }
01466 }
01467 
01468 void KOAgendaView::clearSelection()
01469 {
01470   mAgenda->deselectItem();
01471   mAllDayAgenda->deselectItem();
01472 }
01473 
01474 void KOAgendaView::newTimeSpanSelectedAllDay( const QPoint &start, const QPoint &end )
01475 {
01476   newTimeSpanSelected( start, end );
01477   mTimeSpanInAllDay = true;
01478 }
01479 
01480 void KOAgendaView::newTimeSpanSelected( const QPoint &start, const QPoint &end )
01481 {
01482   if (!mSelectedDates.count()) return;
01483 
01484   mTimeSpanInAllDay = false;
01485 
01486   QDate dayStart = mSelectedDates[start.x()];
01487   QDate dayEnd = mSelectedDates[end.x()];
01488 
01489   QTime timeStart = mAgenda->gyToTime(start.y());
01490   QTime timeEnd = mAgenda->gyToTime( end.y() + 1 );
01491 
01492   QDateTime dtStart(dayStart,timeStart);
01493   QDateTime dtEnd(dayEnd,timeEnd);
01494 
01495   mTimeSpanBegin = dtStart;
01496   mTimeSpanEnd = dtEnd;
01497 }
01498 
01499 void KOAgendaView::deleteSelectedDateTime()
01500 {
01501   mTimeSpanBegin.setDate(QDate());
01502   mTimeSpanEnd.setDate(QDate());
01503   mTimeSpanInAllDay = false;
01504 }
01505 
01506 void KOAgendaView::setTypeAheadReceiver( QObject *o )
01507 {
01508   mAgenda->setTypeAheadReceiver( o );
01509   mAllDayAgenda->setTypeAheadReceiver( o );
01510 }
01511 
01512 void KOAgendaView::finishTypeAhead()
01513 {
01514   mAgenda->finishTypeAhead();
01515   mAllDayAgenda->finishTypeAhead();
01516 }
01517 
01518 void KOAgendaView::removeIncidence( Incidence *incidence )
01519 {
01520   mAgenda->removeIncidence( incidence );
01521   mAllDayAgenda->removeIncidence( incidence );
01522 }
01523 
01524 void KOAgendaView::updateEventIndicators()
01525 {
01526   mMinY = mAgenda->minContentsY();
01527   mMaxY = mAgenda->maxContentsY();
01528 
01529   mAgenda->checkScrollBoundaries();
01530 }
KDE Logo
This file is part of the documentation for korganizer Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jan 31 15:55:48 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003