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