korganizer

koeditorfreebusy.cpp

00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org>
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 #include <qtooltip.h>
00026 #include <qlayout.h>
00027 #include <qlabel.h>
00028 #include <qcombobox.h>
00029 #include <qpushbutton.h>
00030 #include <qwhatsthis.h>
00031 
00032 #include <kdebug.h>
00033 #include <klocale.h>
00034 #include <kiconloader.h>
00035 #include <kmessagebox.h>
00036 
00037 #include <libkcal/event.h>
00038 #include <libkcal/freebusy.h>
00039 
00040 #include <kdgantt/KDGanttView.h>
00041 #include <kdgantt/KDGanttViewTaskItem.h>
00042 
00043 #include "koprefs.h"
00044 #include "koglobals.h"
00045 #include "kogroupware.h"
00046 #include "freebusymanager.h"
00047 #include "freebusyurldialog.h"
00048 
00049 #include "koeditorfreebusy.h"
00050 
00051 
00052 // We can't use the CustomListViewItem base class, since we need a
00053 // different inheritance hierarchy for supporting the Gantt view.
00054 class FreeBusyItem : public KDGanttViewTaskItem
00055 {
00056   public:
00057     FreeBusyItem( Attendee *attendee, KDGanttView *parent ) :
00058       KDGanttViewTaskItem( parent ), mAttendee( attendee ), mTimerID( 0 ),
00059       mIsDownloading( false )
00060     {
00061       Q_ASSERT( attendee );
00062       updateItem();
00063       setFreeBusyPeriods( 0 );
00064       setDisplaySubitemsAsGroup( true );
00065       if ( listView () )
00066           listView ()->setRootIsDecorated( false );
00067     }
00068     ~FreeBusyItem() {}
00069 
00070     void updateItem();
00071 
00072     Attendee *attendee() const { return mAttendee; }
00073     void setFreeBusy( KCal::FreeBusy *fb ) { mFreeBusy = fb; }
00074     KCal::FreeBusy* freeBusy() const { return mFreeBusy; }
00075 
00076     void setFreeBusyPeriods( FreeBusy *fb );
00077 
00078     QString key( int column, bool ) const
00079     {
00080       QMap<int,QString>::ConstIterator it = mKeyMap.find( column );
00081       if ( it == mKeyMap.end() ) return listViewText( column );
00082       else return *it;
00083     }
00084 
00085     void setSortKey( int column, const QString &key )
00086     {
00087       mKeyMap.insert( column, key );
00088     }
00089 
00090     QString email() const { return mAttendee->email(); }
00091     void setUpdateTimerID( int id ) { mTimerID = id; }
00092     int updateTimerID() const { return mTimerID; }
00093 
00094     void startDownload() {
00095       mIsDownloading = true;
00096       FreeBusyManager *m = KOGroupware::instance()->freeBusyManager();
00097       if ( !m->retrieveFreeBusy( attendee()->email() ) )
00098         mIsDownloading = false;
00099     }
00100     void setIsDownloading( bool d ) { mIsDownloading = d; }
00101     bool isDownloading() const { return mIsDownloading; }
00102 
00103   private:
00104     Attendee *mAttendee;
00105     KCal::FreeBusy *mFreeBusy;
00106 
00107     QMap<int,QString> mKeyMap;
00108 
00109     // This is used for the update timer
00110     int mTimerID;
00111 
00112     // Only run one download job at a time
00113     bool mIsDownloading;
00114 };
00115 
00116 void FreeBusyItem::updateItem()
00117 {
00118   setListViewText( 0, mAttendee->name() );
00119   setListViewText( 1, mAttendee->email() );
00120   setListViewText( 2, mAttendee->roleStr() );
00121   setListViewText( 3, mAttendee->statusStr() );
00122   if ( mAttendee->RSVP() && !mAttendee->email().isEmpty() )
00123     setPixmap( 4, KOGlobals::self()->smallIcon( "mailappt" ) );
00124   else
00125     setPixmap( 4, KOGlobals::self()->smallIcon( "nomailappt" ) );
00126 }
00127 
00128 
00129 // Set the free/busy periods for this attendee
00130 void FreeBusyItem::setFreeBusyPeriods( FreeBusy* fb )
00131 {
00132   if( fb ) {
00133     // Clean out the old entries
00134     for( KDGanttViewItem* it = firstChild(); it; it = firstChild() )
00135       delete it;
00136 
00137     // Evaluate free/busy information
00138     QValueList<KCal::Period> busyPeriods = fb->busyPeriods();
00139     for( QValueList<KCal::Period>::Iterator it = busyPeriods.begin();
00140      it != busyPeriods.end(); ++it ) {
00141       KDGanttViewTaskItem* newSubItem = new KDGanttViewTaskItem( this );
00142       newSubItem->setStartTime( (*it).start() );
00143       newSubItem->setEndTime( (*it).end() );
00144       newSubItem->setColors( Qt::red, Qt::red, Qt::red );
00145     }
00146     setFreeBusy( fb );
00147     setShowNoInformation( false );
00148   } else {
00149       // No free/busy information
00150       //debug only start
00151       //   int ii ;
00152       //       QDateTime cur = QDateTime::currentDateTime();
00153       //       for( ii = 0; ii < 10 ;++ii ) {
00154       //           KDGanttViewTaskItem* newSubItem = new KDGanttViewTaskItem( this );
00155       //           cur = cur.addSecs( 7200 );
00156       //           newSubItem->setStartTime( cur );
00157       //           cur = cur.addSecs( 7200 );
00158       //           newSubItem->setEndTime( cur );
00159       //           newSubItem->setColors( Qt::red, Qt::red, Qt::red );
00160       //       }
00161       //debug only end
00162       setFreeBusy( 0 );
00163       setShowNoInformation( true );
00164   }
00165 
00166   // We are no longer downloading
00167   mIsDownloading = false;
00168 }
00169 
00170 
00171 KOEditorFreeBusy::KOEditorFreeBusy( int spacing, QWidget *parent,
00172                                     const char *name )
00173   : QWidget( parent, name )
00174 {
00175   QVBoxLayout *topLayout = new QVBoxLayout( this );
00176   topLayout->setSpacing( spacing );
00177 
00178   // Label for status summary information
00179   // Uses the tooltip palette to highlight it
00180   mIsOrganizer = false; // Will be set later. This is just valgrind silencing
00181   mStatusSummaryLabel = new QLabel( this );
00182   mStatusSummaryLabel->setPalette( QToolTip::palette() );
00183   mStatusSummaryLabel->setFrameStyle( QFrame::Plain | QFrame::Box );
00184   mStatusSummaryLabel->setLineWidth( 1 );
00185   mStatusSummaryLabel->hide(); // Will be unhidden later if you are organizer
00186   topLayout->addWidget( mStatusSummaryLabel );
00187 
00188   // The control panel for the gantt widget
00189   QBoxLayout *controlLayout = new QHBoxLayout( topLayout );
00190 
00191   QString whatsThis = i18n("Sets the zoom level on the Gantt chart. "
00192                "'Hour' shows a range of several hours, "
00193                "'Day' shows a range of a few days, "
00194                "'Week' shows a range of a few months, "
00195                "and 'Month' shows a range of a few years, "
00196                "while 'Automatic' selects the range most "
00197                "appropriate for the current event or to-do.");
00198   QLabel *label = new QLabel( i18n( "Scale: " ), this );
00199   QWhatsThis::add( label, whatsThis );
00200   controlLayout->addWidget( label );
00201 
00202   scaleCombo = new QComboBox( this ); 
00203   QWhatsThis::add( scaleCombo, whatsThis );
00204   scaleCombo->insertItem( i18n( "Hour" ) );
00205   scaleCombo->insertItem( i18n( "Day" ) );
00206   scaleCombo->insertItem( i18n( "Week" ) );
00207   scaleCombo->insertItem( i18n( "Month" ) );
00208   scaleCombo->insertItem( i18n( "Automatic" ) );
00209   scaleCombo->setCurrentItem( 0 ); // start with "hour"
00210   connect( scaleCombo, SIGNAL( activated( int ) ),
00211            SLOT( slotScaleChanged( int ) ) );
00212   controlLayout->addWidget( scaleCombo );
00213 
00214   QPushButton *button = new QPushButton( i18n( "Center on Start" ), this );
00215   QWhatsThis::add( button,
00216            i18n("Centers the Gantt chart on the start time "
00217                 "and day of this event.") );
00218   connect( button, SIGNAL( clicked() ), SLOT( slotCenterOnStart() ) );
00219   controlLayout->addWidget( button );
00220 
00221   button = new QPushButton( i18n( "Zoom to Fit" ), this );
00222   QWhatsThis::add( button,
00223            i18n("Zooms the Gantt chart so that you can see the "
00224             "entire duration of the event on it.") );
00225   connect( button, SIGNAL( clicked() ), SLOT( slotZoomToTime() ) );
00226   controlLayout->addWidget( button );
00227 
00228   controlLayout->addStretch( 1 );
00229 
00230   button = new QPushButton( i18n( "Pick Date" ), this );
00231   QWhatsThis::add( button,
00232            i18n("Moves the event to a date and time when all the "
00233             "attendees are free.") );
00234   connect( button, SIGNAL( clicked() ), SLOT( slotPickDate() ) );
00235   controlLayout->addWidget( button );
00236 
00237   controlLayout->addStretch( 1 );
00238 
00239   button = new QPushButton( i18n("Reload"), this );
00240   QWhatsThis::add( button,
00241            i18n("Reloads Free/Busy data for all attendees from "
00242             "the corresponding servers.") );
00243   controlLayout->addWidget( button );
00244   connect( button, SIGNAL( clicked() ), SLOT( reload() ) );
00245 
00246   mGanttView = new KDGanttView( this, "mGanttView" );
00247   QWhatsThis::add( mGanttView,
00248            i18n("Shows the free/busy status of all attendees. "
00249             "Double-clicking on an attendees entry in the "
00250             "list will allow you to enter the location of their "
00251             "Free/Busy Information.") );
00252   topLayout->addWidget( mGanttView );
00253   // Remove the predefined "Task Name" column
00254   mGanttView->removeColumn( 0 );
00255   mGanttView->addColumn( i18n("Name"), 180 );
00256   mGanttView->addColumn( i18n("Email"), 180 );
00257   mGanttView->addColumn( i18n("Role"), 60 );
00258   mGanttView->addColumn( i18n("Status"), 100 );
00259   mGanttView->addColumn( i18n("RSVP"), 35 );
00260   if ( KOPrefs::instance()->mCompactDialogs ) {
00261     mGanttView->setFixedHeight( 78 );
00262   }
00263   mGanttView->setHeaderVisible( true );
00264   mGanttView->setScale( KDGanttView::Hour );
00265   mGanttView->setShowHeaderPopupMenu( true, true, true, false, false, true );
00266   // Initially, show 15 days back and forth
00267   // set start to even hours, i.e. to 12:AM 0 Min 0 Sec
00268   QDateTime horizonStart = QDateTime( QDateTime::currentDateTime()
00269                            .addDays( -15 ).date() );
00270   QDateTime horizonEnd = QDateTime::currentDateTime().addDays( 15 );
00271   mGanttView->setHorizonStart( horizonStart );
00272   mGanttView->setHorizonEnd( horizonEnd );
00273   mGanttView->setCalendarMode( true );
00274   //mGanttView->setDisplaySubitemsAsGroup( true );
00275   mGanttView->setShowLegendButton( false );
00276   // Initially, center to current date
00277   mGanttView->centerTimelineAfterShow( QDateTime::currentDateTime() );
00278   if ( KGlobal::locale()->use12Clock() )
00279     mGanttView->setHourFormat( KDGanttView::Hour_12 );
00280   else
00281     mGanttView->setHourFormat( KDGanttView::Hour_24_FourDigit );
00282   connect( mGanttView, SIGNAL ( timeIntervalSelected( const QDateTime &,
00283                                                       const QDateTime & ) ),
00284            mGanttView, SLOT( zoomToSelection( const QDateTime &,
00285                                               const  QDateTime & ) ) );
00286   connect( mGanttView, SIGNAL( lvItemDoubleClicked( KDGanttViewItem * ) ),
00287            SLOT( editFreeBusyUrl( KDGanttViewItem * ) ) );
00288 
00289   FreeBusyManager *m = KOGroupware::instance()->freeBusyManager();
00290   connect( m, SIGNAL( freeBusyRetrieved( KCal::FreeBusy *, const QString & ) ),
00291            SLOT( slotInsertFreeBusy( KCal::FreeBusy *, const QString & ) ) );
00292 
00293   connect( &mReloadTimer, SIGNAL( timeout() ), SLOT( reload() ) );
00294 }
00295 
00296 KOEditorFreeBusy::~KOEditorFreeBusy()
00297 {
00298 }
00299 
00300 void KOEditorFreeBusy::removeAttendee( Attendee *attendee )
00301 {
00302   FreeBusyItem *anItem =
00303       static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00304   while( anItem ) {
00305     if( anItem->attendee() == attendee ) {
00306       if ( anItem->updateTimerID() != 0 )
00307         killTimer( anItem->updateTimerID() );
00308       delete anItem;
00309       updateStatusSummary();
00310       break;
00311     }
00312     anItem = static_cast<FreeBusyItem *>( anItem->nextSibling() );
00313   }
00314 }
00315 
00316 void KOEditorFreeBusy::insertAttendee( Attendee *attendee, bool readFBList )
00317 {
00318   FreeBusyItem* item = new FreeBusyItem( attendee, mGanttView );
00319   if ( readFBList )
00320     updateFreeBusyData( item );
00321   updateStatusSummary();
00322 }
00323 
00324 void KOEditorFreeBusy::updateAttendee( Attendee *attendee )
00325 {
00326   FreeBusyItem *anItem =
00327       static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00328   while( anItem ) {
00329     if( anItem->attendee() == attendee ) {
00330       anItem->updateItem();
00331       updateFreeBusyData( anItem );
00332       updateStatusSummary();
00333       break;
00334     }
00335     anItem = static_cast<FreeBusyItem *>( anItem->nextSibling() );
00336   }
00337 }
00338 
00339 void KOEditorFreeBusy::clearAttendees()
00340 {
00341   mGanttView->clear();
00342 }
00343 
00344 
00345 void KOEditorFreeBusy::setUpdateEnabled( bool enabled )
00346 {
00347   mGanttView->setUpdateEnabled( enabled );
00348 }
00349 
00350 bool KOEditorFreeBusy::updateEnabled() const
00351 {
00352   return mGanttView->getUpdateEnabled();
00353 }
00354 
00355 
00356 void KOEditorFreeBusy::readEvent( Event *event )
00357 {
00358   setDateTimes( event->dtStart(), event->dtEnd() );
00359   mIsOrganizer = KOPrefs::instance()->thatIsMe( event->organizer().email() );
00360   updateStatusSummary();
00361 }
00362 
00363 
00364 void KOEditorFreeBusy::setDateTimes( const QDateTime &start, const QDateTime &end )
00365 {
00366   slotUpdateGanttView( start, end );
00367 }
00368 
00369 void KOEditorFreeBusy::slotScaleChanged( int newScale )
00370 {
00371   // The +1 is for the Minute scale which we don't offer in the combo box.
00372   KDGanttView::Scale scale = static_cast<KDGanttView::Scale>( newScale+1 );
00373   mGanttView->setScale( scale );
00374   slotCenterOnStart();
00375 }
00376 
00377 void KOEditorFreeBusy::slotCenterOnStart()
00378 {
00379   mGanttView->centerTimeline( mDtStart );
00380 }
00381 
00382 void KOEditorFreeBusy::slotZoomToTime()
00383 {
00384   mGanttView->zoomToFit();
00385 }
00386 
00387 void KOEditorFreeBusy::updateFreeBusyData( FreeBusyItem* item )
00388 {
00389   if ( item->isDownloading() )
00390     // This item is already in the process of fetching the FB list
00391     return;
00392 
00393   if ( item->updateTimerID() != 0 )
00394     // An update timer is already running. Reset it
00395     killTimer( item->updateTimerID() );
00396 
00397   // This item does not have a download running, and no timer is set
00398   // Do the download in five seconds
00399   item->setUpdateTimerID( startTimer( 5000 ) );
00400 }
00401 
00402 void KOEditorFreeBusy::timerEvent( QTimerEvent* event )
00403 {
00404   killTimer( event->timerId() );
00405   FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00406   while( item ) {
00407     if( item->updateTimerID() == event->timerId() ) {
00408       item->setUpdateTimerID( 0 );
00409       item->startDownload();
00410       return;
00411     }
00412     item = static_cast<FreeBusyItem *>( item->nextSibling() );
00413   }
00414 }
00415 
00416 // Set the Free Busy list for everyone having this email address
00417 // If fb == 0, this disabled the free busy list for them
00418 void KOEditorFreeBusy::slotInsertFreeBusy( KCal::FreeBusy *fb,
00419                                            const QString &email )
00420 {
00421   kdDebug(5850) << "KOEditorFreeBusy::slotInsertFreeBusy() " << email << endl;
00422 
00423   if( fb )
00424     fb->sortList();
00425   bool block = mGanttView->getUpdateEnabled();
00426   mGanttView->setUpdateEnabled( false );
00427   for( KDGanttViewItem *it = mGanttView->firstChild(); it;
00428        it = it->nextSibling() ) {
00429     FreeBusyItem *item = static_cast<FreeBusyItem *>( it );
00430     if( item->email() == email )
00431       item->setFreeBusyPeriods( fb );
00432   }
00433   mGanttView->setUpdateEnabled( block );
00434 }
00435 
00436 
00441 void KOEditorFreeBusy::slotUpdateGanttView( const QDateTime &dtFrom, const QDateTime &dtTo )
00442 {
00443   mDtStart = dtFrom;
00444   mDtEnd = dtTo;
00445   bool block = mGanttView->getUpdateEnabled( );
00446   mGanttView->setUpdateEnabled( false );
00447   QDateTime horizonStart = QDateTime( dtFrom.addDays( -15 ).date() );
00448   mGanttView->setHorizonStart( horizonStart  );
00449   mGanttView->setHorizonEnd( dtTo.addDays( 15 ) );
00450   mGanttView->clearBackgroundColor();
00451   mGanttView->setIntervalBackgroundColor( dtFrom, dtTo, Qt::magenta );
00452   mGanttView->setUpdateEnabled( block );
00453   mGanttView->centerTimelineAfterShow( dtFrom );
00454 }
00455 
00456 
00460 void KOEditorFreeBusy::slotPickDate()
00461 {
00462   QDateTime start = mDtStart;
00463   QDateTime end = mDtEnd;
00464   bool success = findFreeSlot( start, end );
00465 
00466   if( success ) {
00467     if ( start == mDtStart && end == mDtEnd ) {
00468       KMessageBox::information( this,
00469           i18n( "The meeting already has suitable start/end times." ), QString::null, 
00470           "MeetingTimeOKFreeBusy" );
00471     } else {
00472       emit dateTimesChanged( start, end );
00473       slotUpdateGanttView( start, end );
00474       KMessageBox::information( this,
00475           i18n( "The meeting has been moved to\nStart: %1\nEnd: %2." )
00476           .arg( start.toString() ).arg( end.toString() ), QString::null,
00477           "MeetingMovedFreeBusy" );
00478     }
00479   } else
00480     KMessageBox::sorry( this, i18n( "No suitable date found." ) );
00481 }
00482 
00483 
00488 bool KOEditorFreeBusy::findFreeSlot( QDateTime &dtFrom, QDateTime &dtTo )
00489 {
00490   if( tryDate( dtFrom, dtTo ) )
00491     // Current time is acceptable
00492     return true;
00493 
00494   QDateTime tryFrom = dtFrom;
00495   QDateTime tryTo = dtTo;
00496 
00497   // Make sure that we never suggest a date in the past, even if the
00498   // user originally scheduled the meeting to be in the past.
00499   if( tryFrom < QDateTime::currentDateTime() ) {
00500     // The slot to look for is at least partially in the past.
00501     int secs = tryFrom.secsTo( tryTo );
00502     tryFrom = QDateTime::currentDateTime();
00503     tryTo = tryFrom.addSecs( secs );
00504   }
00505 
00506   bool found = false;
00507   while( !found ) {
00508     found = tryDate( tryFrom, tryTo );
00509     // PENDING(kalle) Make the interval configurable
00510     if( !found && dtFrom.daysTo( tryFrom ) > 365 )
00511       break; // don't look more than one year in the future
00512   }
00513 
00514   dtFrom = tryFrom;
00515   dtTo = tryTo;
00516 
00517   return found;
00518 }
00519 
00520 
00529 bool KOEditorFreeBusy::tryDate( QDateTime& tryFrom, QDateTime& tryTo )
00530 {
00531   FreeBusyItem* currentItem = static_cast<FreeBusyItem*>( mGanttView->firstChild() );
00532   while( currentItem ) {
00533     if( !tryDate( currentItem, tryFrom, tryTo ) ) {
00534       // kdDebug(5850) << "++++date is not OK, new suggestion: " << tryFrom.toString() << " to " << tryTo.toString() << endl;
00535       return false;
00536     }
00537 
00538     currentItem = static_cast<FreeBusyItem*>( currentItem->nextSibling() );
00539   }
00540 
00541   return true;
00542 }
00543 
00551 bool KOEditorFreeBusy::tryDate( FreeBusyItem *attendee,
00552                                 QDateTime &tryFrom, QDateTime &tryTo )
00553 {
00554   // If we don't have any free/busy information, assume the
00555   // participant is free. Otherwise a participant without available
00556   // information would block the whole allocation.
00557   KCal::FreeBusy *fb = attendee->freeBusy();
00558   if( !fb )
00559     return true;
00560 
00561   QValueList<KCal::Period> busyPeriods = fb->busyPeriods();
00562   for( QValueList<KCal::Period>::Iterator it = busyPeriods.begin();
00563        it != busyPeriods.end(); ++it ) {
00564     if( (*it).end() <= tryFrom || // busy period ends before try period
00565     (*it).start() >= tryTo )  // busy period starts after try period
00566       continue;
00567     else {
00568       // the current busy period blocks the try period, try
00569       // after the end of the current busy period
00570       int secsDuration = tryFrom.secsTo( tryTo );
00571       tryFrom = (*it).end();
00572       tryTo = tryFrom.addSecs( secsDuration );
00573       // try again with the new try period
00574       tryDate( attendee, tryFrom, tryTo );
00575       // we had to change the date at least once
00576       return false;
00577     }
00578   }
00579 
00580   return true;
00581 }
00582 
00583 void KOEditorFreeBusy::updateStatusSummary()
00584 {
00585   FreeBusyItem *aItem =
00586     static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00587   int total = 0;
00588   int accepted = 0;
00589   int tentative = 0;
00590   int declined = 0;
00591   while( aItem ) {
00592     ++total;
00593     switch( aItem->attendee()->status() ) {
00594     case Attendee::Accepted:
00595       ++accepted;
00596       break;
00597     case Attendee::Tentative:
00598       ++tentative;
00599       break;
00600     case Attendee::Declined:
00601       ++declined;
00602       break;
00603     case Attendee::NeedsAction:
00604     case Attendee::Delegated:
00605     case Attendee::Completed:
00606     case Attendee::InProcess:
00607       /* just to shut up the compiler */
00608       break;
00609     }
00610     aItem = static_cast<FreeBusyItem *>( aItem->nextSibling() );
00611   }
00612   if( total > 1 && mIsOrganizer ) {
00613     mStatusSummaryLabel->show();
00614     mStatusSummaryLabel->setText(
00615         i18n( "Of the %1 participants, %2 have accepted, %3"
00616               " have tentatively accepted, and %4 have declined.")
00617         .arg( total ).arg( accepted ).arg( tentative ).arg( declined ) );
00618   } else {
00619     mStatusSummaryLabel->hide();
00620   }
00621   mStatusSummaryLabel->adjustSize();
00622 }
00623 
00624 void KOEditorFreeBusy::triggerReload()
00625 {
00626   mReloadTimer.start( 1000, true );
00627 }
00628 
00629 void KOEditorFreeBusy::cancelReload()
00630 {
00631   mReloadTimer.stop();
00632 }
00633 
00634 void KOEditorFreeBusy::reload()
00635 {
00636   kdDebug(5850) << "KOEditorFreeBusy::reload()" << endl;
00637 
00638   FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00639   while( item ) {
00640     updateFreeBusyData( item );
00641     item = static_cast<FreeBusyItem *>( item->nextSibling() );
00642   }
00643 }
00644 
00645 void KOEditorFreeBusy::editFreeBusyUrl( KDGanttViewItem *i )
00646 {
00647   FreeBusyItem *item = static_cast<FreeBusyItem *>( i );
00648   if ( !item ) return;
00649 
00650   Attendee *attendee = item->attendee();
00651 
00652   FreeBusyUrlDialog dialog( attendee, this );
00653   dialog.exec();
00654 }
00655 
00656 #include "koeditorfreebusy.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys