korganizer Library API Documentation

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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 
00031 #include <kdebug.h>
00032 #include <klocale.h>
00033 #include <kiconloader.h>
00034 #include <kmessagebox.h>
00035 
00036 #include <libkcal/event.h>
00037 #include <libkcal/freebusy.h>
00038 
00039 #include <kdgantt/KDGanttView.h>
00040 #include <kdgantt/KDGanttViewTaskItem.h>
00041 
00042 #include "koprefs.h"
00043 #include "koglobals.h"
00044 #include "kogroupware.h"
00045 #include "freebusymanager.h"
00046 #include "freebusyurldialog.h"
00047 
00048 #include "koeditorfreebusy.h"
00049 
00050 
00051 // We can't use the CustomListViewItem base class, since we need a
00052 // different inheritance hierarchy for supporting the Gantt view.
00053 class FreeBusyItem : public KDGanttViewTaskItem
00054 {
00055   public:
00056     FreeBusyItem( Attendee *attendee, KDGanttView *parent ) :
00057       KDGanttViewTaskItem( parent ), mAttendee( attendee ), mTimerID( 0 ),
00058       mIsDownloading( false )
00059     {
00060       Q_ASSERT( attendee );
00061       updateItem();
00062       setFreeBusyPeriods( 0 );
00063       setDisplaySubitemsAsGroup( true );
00064       if ( listView () )
00065           listView ()->setRootIsDecorated( false );
00066     }
00067     ~FreeBusyItem() {}
00068 
00069     void updateItem();
00070 
00071     Attendee *attendee() const { return mAttendee; }
00072     void setFreeBusy( KCal::FreeBusy *fb ) { mFreeBusy = fb; }
00073     KCal::FreeBusy* freeBusy() const { return mFreeBusy; }
00074 
00075     void setFreeBusyPeriods( FreeBusy *fb );
00076 
00077     QString key( int column, bool ) const
00078     {
00079       QMap<int,QString>::ConstIterator it = mKeyMap.find( column );
00080       if ( it == mKeyMap.end() ) return listViewText( column );
00081       else return *it;
00082     }
00083 
00084     void setSortKey( int column, const QString &key )
00085     {
00086       mKeyMap.insert( column, key );
00087     }
00088 
00089     QString email() const { return mAttendee->email(); }
00090 
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     setStartTime( fb->dtStart() );
00134     setEndTime( fb->dtEnd() );
00135     // Clean out the old entries
00136     for( KDGanttViewItem* it = firstChild(); it; it = firstChild() )
00137       delete it;
00138 
00139     // Evaluate free/busy information
00140     QValueList<KCal::Period> busyPeriods = fb->busyPeriods();
00141     for( QValueList<KCal::Period>::Iterator it = busyPeriods.begin();
00142      it != busyPeriods.end(); ++it ) {
00143       KDGanttViewTaskItem* newSubItem = new KDGanttViewTaskItem( this );
00144       newSubItem->setStartTime( (*it).start() );
00145       newSubItem->setEndTime( (*it).end() );
00146       newSubItem->setColors( Qt::red, Qt::red, Qt::red );
00147     }
00148     setFreeBusy( fb );
00149     setShowNoInformation( false );
00150     setShowNoInformationBeforeAndAfter( true );
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 
00173 
00174 KOEditorFreeBusy::KOEditorFreeBusy( int spacing, QWidget *parent,
00175                                     const char *name )
00176   : QWidget( parent, name )
00177 {
00178   QVBoxLayout *topLayout = new QVBoxLayout( this );
00179   topLayout->setSpacing( spacing );
00180 
00181   // Label for status summary information
00182   // Uses the tooltip palette to highlight it
00183   mIsOrganizer = false; // Will be set later. This is just valgrind silencing
00184   mStatusSummaryLabel = new QLabel( this );
00185   mStatusSummaryLabel->setPalette( QToolTip::palette() );
00186   mStatusSummaryLabel->setFrameStyle( QFrame::Plain | QFrame::Box );
00187   mStatusSummaryLabel->setLineWidth( 1 );
00188   mStatusSummaryLabel->hide(); // Will be unhidden later if you are organizer
00189   topLayout->addWidget( mStatusSummaryLabel );
00190 
00191   // The control panel for the gantt widget
00192   QBoxLayout *controlLayout = new QHBoxLayout( topLayout );
00193 
00194   QLabel *label = new QLabel( i18n( "Scale: " ), this );
00195   controlLayout->addWidget( label );
00196 
00197   scaleCombo = new QComboBox( this );
00198   scaleCombo->insertItem( i18n( "Hour" ) );
00199   scaleCombo->insertItem( i18n( "Day" ) );
00200   scaleCombo->insertItem( i18n( "Week" ) );
00201   scaleCombo->insertItem( i18n( "Month" ) );
00202   scaleCombo->insertItem( i18n( "Automatic" ) );
00203   scaleCombo->setCurrentItem( 0 ); // start with "hour"
00204   connect( scaleCombo, SIGNAL( activated( int ) ),
00205            SLOT( slotScaleChanged( int ) ) );
00206   controlLayout->addWidget( scaleCombo );
00207 
00208   QPushButton *button = new QPushButton( i18n( "Center on Start" ), this );
00209   connect( button, SIGNAL( clicked() ), SLOT( slotCenterOnStart() ) );
00210   controlLayout->addWidget( button );
00211 
00212   button = new QPushButton( i18n( "Zoom to Fit" ), this );
00213   connect( button, SIGNAL( clicked() ), SLOT( slotZoomToTime() ) );
00214   controlLayout->addWidget( button );
00215 
00216   controlLayout->addStretch( 1 );
00217 
00218   button = new QPushButton( i18n( "Pick Date" ), this );
00219   connect( button, SIGNAL( clicked() ), SLOT( slotPickDate() ) );
00220   controlLayout->addWidget( button );
00221 
00222   controlLayout->addStretch( 1 );
00223 
00224   button = new QPushButton( i18n("Reload"), this );
00225   controlLayout->addWidget( button );
00226   connect( button, SIGNAL( clicked() ), SLOT( reload() ) );
00227 
00228   mGanttView = new KDGanttView( this, "mGanttView" );
00229   topLayout->addWidget( mGanttView );
00230   // Remove the predefined "Task Name" column
00231   mGanttView->removeColumn( 0 );
00232   mGanttView->addColumn( i18n("Name"), 180 );
00233   mGanttView->addColumn( i18n("Email"), 180 );
00234   mGanttView->addColumn( i18n("Role"), 60 );
00235   mGanttView->addColumn( i18n("Status"), 100 );
00236   mGanttView->addColumn( i18n("RSVP"), 35 );
00237   if ( KOPrefs::instance()->mCompactDialogs ) {
00238     mGanttView->setFixedHeight( 78 );
00239   }
00240   mGanttView->setHeaderVisible( true );
00241   mGanttView->setScale( KDGanttView::Hour );
00242   mGanttView->setShowHeaderPopupMenu( true, true, true, false, false, true );
00243   // Initially, show 15 days back and forth
00244   // set start to even hours, i.e. to 12:AM 0 Min 0 Sec
00245   QDateTime horizonStart = QDateTime( QDateTime::currentDateTime()
00246                            .addDays( -15 ).date() );
00247   QDateTime horizonEnd = QDateTime::currentDateTime().addDays( 15 );
00248   mGanttView->setHorizonStart( horizonStart );
00249   mGanttView->setHorizonEnd( horizonEnd );
00250   mGanttView->setCalendarMode( true );
00251   //mGanttView->setDisplaySubitemsAsGroup( true );
00252   mGanttView->setShowLegendButton( false );
00253   // Initially, center to current date
00254   mGanttView->centerTimelineAfterShow( QDateTime::currentDateTime() );
00255   if ( KGlobal::locale()->use12Clock() )
00256     mGanttView->setHourFormat( KDGanttView::Hour_12 );
00257   else
00258     mGanttView->setHourFormat( KDGanttView::Hour_24_FourDigit );
00259   connect( mGanttView, SIGNAL ( timeIntervalSelected( const QDateTime &,
00260                                                       const QDateTime & ) ),
00261            mGanttView, SLOT( zoomToSelection( const QDateTime &,
00262                                               const  QDateTime & ) ) );
00263   connect( mGanttView, SIGNAL( lvItemDoubleClicked( KDGanttViewItem * ) ),
00264            SLOT( editFreeBusyUrl( KDGanttViewItem * ) ) );
00265 
00266   FreeBusyManager *m = KOGroupware::instance()->freeBusyManager();
00267   connect( m, SIGNAL( freeBusyRetrieved( KCal::FreeBusy *, const QString & ) ),
00268            SLOT( slotInsertFreeBusy( KCal::FreeBusy *, const QString & ) ) );
00269 
00270   connect( &mReloadTimer, SIGNAL( timeout() ), SLOT( reload() ) );
00271 }
00272 
00273 KOEditorFreeBusy::~KOEditorFreeBusy()
00274 {
00275 }
00276 
00277 void KOEditorFreeBusy::removeAttendee( Attendee *attendee )
00278 {
00279   FreeBusyItem *anItem =
00280       static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00281   while( anItem ) {
00282     if( anItem->attendee() == attendee ) {
00283       if ( anItem->updateTimerID() != 0 )
00284         killTimer( anItem->updateTimerID() );
00285       delete anItem;
00286       updateStatusSummary();
00287       break;
00288     }
00289     anItem = static_cast<FreeBusyItem *>( anItem->nextSibling() );
00290   }
00291 }
00292 
00293 void KOEditorFreeBusy::insertAttendee( Attendee *attendee, bool readFBList )
00294 {
00295   FreeBusyItem* item = new FreeBusyItem( attendee, mGanttView );
00296   if ( readFBList )
00297     updateFreeBusyData( item );
00298   updateStatusSummary();
00299 }
00300 
00301 void KOEditorFreeBusy::updateAttendee( Attendee *attendee )
00302 {
00303   FreeBusyItem *anItem =
00304       static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00305   while( anItem ) {
00306     if( anItem->attendee() == attendee ) {
00307       anItem->updateItem();
00308       updateFreeBusyData( anItem );
00309       updateStatusSummary();
00310       break;
00311     }
00312     anItem = static_cast<FreeBusyItem *>( anItem->nextSibling() );
00313   }
00314 }
00315 
00316 void KOEditorFreeBusy::clearAttendees()
00317 {
00318   mGanttView->clear();
00319 }
00320 
00321 
00322 void KOEditorFreeBusy::setUpdateEnabled( bool enabled )
00323 {
00324   mGanttView->setUpdateEnabled( enabled );
00325 }
00326 
00327 bool KOEditorFreeBusy::updateEnabled() const
00328 {
00329   return mGanttView->getUpdateEnabled();
00330 }
00331 
00332 
00333 void KOEditorFreeBusy::readEvent( Event *event )
00334 {
00335   setDateTimes( event->dtStart(), event->dtEnd() );
00336   mIsOrganizer = KOPrefs::instance()->thatIsMe( event->organizer().email() );
00337   updateStatusSummary();
00338 }
00339 
00340 
00341 void KOEditorFreeBusy::setDateTimes( QDateTime start, QDateTime end )
00342 {
00343 
00344   slotUpdateGanttView( start, end );
00345 }
00346 
00347 void KOEditorFreeBusy::slotScaleChanged( int newScale )
00348 {
00349   // The +1 is for the Minute scale which we don't offer in the combo box.
00350   KDGanttView::Scale scale = static_cast<KDGanttView::Scale>( newScale+1 );
00351   mGanttView->setScale( scale );
00352   slotCenterOnStart();
00353 }
00354 
00355 void KOEditorFreeBusy::slotCenterOnStart()
00356 {
00357   mGanttView->centerTimeline( mDtStart );
00358 }
00359 
00360 void KOEditorFreeBusy::slotZoomToTime()
00361 {
00362   mGanttView->zoomToFit();
00363 }
00364 
00365 void KOEditorFreeBusy::updateFreeBusyData( FreeBusyItem* item )
00366 {
00367   if ( item->isDownloading() )
00368     // This item is already in the process of fetching the FB list
00369     return;
00370 
00371   if ( item->updateTimerID() != 0 )
00372     // An update timer is already running. Reset it
00373     killTimer( item->updateTimerID() );
00374 
00375   // This item does not have a download running, and no timer is set
00376   // Do the download in five seconds
00377   item->setUpdateTimerID( startTimer( 5000 ) );
00378 }
00379 
00380 void KOEditorFreeBusy::timerEvent( QTimerEvent* event )
00381 {
00382   killTimer( event->timerId() );
00383   FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00384   while( item ) {
00385     if( item->updateTimerID() == event->timerId() ) {
00386       item->setUpdateTimerID( 0 );
00387       item->startDownload();
00388       return;
00389     }
00390     item = static_cast<FreeBusyItem *>( item->nextSibling() );
00391   }
00392 }
00393 
00394 // Set the Free Busy list for everyone having this email address
00395 // If fb == 0, this disabled the free busy list for them
00396 void KOEditorFreeBusy::slotInsertFreeBusy( KCal::FreeBusy *fb,
00397                                            const QString &email )
00398 {
00399   kdDebug() << "KOEditorFreeBusy::slotInsertFreeBusy() " << email << endl;
00400 
00401   if( fb ) {
00402     fb->sortList();
00403     // weed out dummies
00404     if ( fb->dtEnd().toTime_t() == 0 ) return;
00405   }
00406   bool block = mGanttView->getUpdateEnabled();
00407   mGanttView->setUpdateEnabled( false );
00408   for( KDGanttViewItem *it = mGanttView->firstChild(); it;
00409        it = it->nextSibling() ) {
00410     FreeBusyItem *item = static_cast<FreeBusyItem *>( it );
00411     if( item->email() == email )
00412       item->setFreeBusyPeriods( fb );
00413   }
00414   mGanttView->setUpdateEnabled( block );
00415 }
00416 
00417 
00422 void KOEditorFreeBusy::slotUpdateGanttView( QDateTime dtFrom, QDateTime dtTo )
00423 {
00424   mDtStart = dtFrom;
00425   mDtEnd = dtTo;
00426   bool block = mGanttView->getUpdateEnabled( );
00427   mGanttView->setUpdateEnabled( false );
00428   QDateTime horizonStart = QDateTime( dtFrom.addDays( -15 ).date() );
00429   mGanttView->setHorizonStart( horizonStart  );
00430   mGanttView->setHorizonEnd( dtTo.addDays( 15 ) );
00431   mGanttView->clearBackgroundColor();
00432   mGanttView->setIntervalBackgroundColor( dtFrom, dtTo, Qt::magenta );
00433   mGanttView->setUpdateEnabled( block );
00434   mGanttView->centerTimelineAfterShow( dtFrom );
00435 }
00436 
00437 
00441 void KOEditorFreeBusy::slotPickDate()
00442 {
00443   QDateTime start = mDtStart;
00444   QDateTime end = mDtEnd;
00445   bool success = findFreeSlot( start, end );
00446 
00447   if( success ) {
00448     if ( start == mDtStart && end == mDtEnd ) {
00449       KMessageBox::information( this,
00450           i18n( "The meeting has already suitable start/end times." ));
00451     } else {
00452       emit dateTimesChanged( start, end );
00453       slotUpdateGanttView( start, end );
00454       KMessageBox::information( this,
00455           i18n( "The meeting has been moved to\nStart: %1\nEnd: %2." )
00456           .arg( start.toString() ).arg( end.toString() ) );
00457     }
00458   } else
00459     KMessageBox::sorry( this, i18n( "No suitable date found." ) );
00460 }
00461 
00462 
00467 bool KOEditorFreeBusy::findFreeSlot( QDateTime &dtFrom, QDateTime &dtTo )
00468 {
00469   if( tryDate( dtFrom, dtTo ) )
00470     // Current time is acceptable
00471     return true;
00472 
00473   QDateTime tryFrom = dtFrom;
00474   QDateTime tryTo = dtTo;
00475 
00476   // Make sure that we never suggest a date in the past, even if the
00477   // user originally scheduled the meeting to be in the past.
00478   if( tryFrom < QDateTime::currentDateTime() ) {
00479     // The slot to look for is at least partially in the past.
00480     int secs = tryFrom.secsTo( tryTo );
00481     tryFrom = QDateTime::currentDateTime();
00482     tryTo = tryFrom.addSecs( secs );
00483   }
00484 
00485   bool found = false;
00486   while( !found ) {
00487     found = tryDate( tryFrom, tryTo );
00488     // PENDING(kalle) Make the interval configurable
00489     if( !found && dtFrom.daysTo( tryFrom ) > 365 )
00490       break; // don't look more than one year in the future
00491   }
00492 
00493   dtFrom = tryFrom;
00494   dtTo = tryTo;
00495 
00496   return found;
00497 }
00498 
00499 
00508 bool KOEditorFreeBusy::tryDate( QDateTime& tryFrom, QDateTime& tryTo )
00509 {
00510   FreeBusyItem* currentItem = static_cast<FreeBusyItem*>( mGanttView->firstChild() );
00511   while( currentItem ) {
00512     if( !tryDate( currentItem, tryFrom, tryTo ) ) {
00513       // kdDebug(5850) << "++++date is not OK, new suggestion: " << tryFrom.toString() << " to " << tryTo.toString() << endl;
00514       return false;
00515     }
00516 
00517     currentItem = static_cast<FreeBusyItem*>( currentItem->nextSibling() );
00518   }
00519 
00520   return true;
00521 }
00522 
00530 bool KOEditorFreeBusy::tryDate( FreeBusyItem *attendee,
00531                                 QDateTime &tryFrom, QDateTime &tryTo )
00532 {
00533   // If we don't have any free/busy information, assume the
00534   // participant is free. Otherwise a participant without available
00535   // information would block the whole allocation.
00536   KCal::FreeBusy *fb = attendee->freeBusy();
00537   if( !fb )
00538     return true;
00539 
00540   QValueList<KCal::Period> busyPeriods = fb->busyPeriods();
00541   for( QValueList<KCal::Period>::Iterator it = busyPeriods.begin();
00542        it != busyPeriods.end(); ++it ) {
00543     if( (*it).end() <= tryFrom || // busy period ends before try period
00544     (*it).start() >= tryTo )  // busy period starts after try period
00545       continue;
00546     else {
00547       // the current busy period blocks the try period, try
00548       // after the end of the current busy period
00549       int secsDuration = tryFrom.secsTo( tryTo );
00550       tryFrom = (*it).end();
00551       tryTo = tryFrom.addSecs( secsDuration );
00552       // try again with the new try period
00553       tryDate( attendee, tryFrom, tryTo );
00554       // we had to change the date at least once
00555       return false;
00556     }
00557   }
00558 
00559   return true;
00560 }
00561 
00562 void KOEditorFreeBusy::updateStatusSummary()
00563 {
00564   FreeBusyItem *aItem =
00565     static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00566   int total = 0;
00567   int accepted = 0;
00568   int tentative = 0;
00569   int declined = 0;
00570   while( aItem ) {
00571     ++total;
00572     switch( aItem->attendee()->status() ) {
00573     case Attendee::Accepted:
00574       ++accepted;
00575       break;
00576     case Attendee::Tentative:
00577       ++tentative;
00578       break;
00579     case Attendee::Declined:
00580       ++declined;
00581       break;
00582     case Attendee::NeedsAction:
00583     case Attendee::Delegated:
00584     case Attendee::Completed:
00585     case Attendee::InProcess:
00586       /* just to shut up the compiler */
00587       break;
00588     }
00589     aItem = static_cast<FreeBusyItem *>( aItem->nextSibling() );
00590   }
00591   if( total > 1 && mIsOrganizer ) {
00592     mStatusSummaryLabel->show();
00593     mStatusSummaryLabel->setText(
00594         i18n( "Of the %1 participants, %2 have accepted, %3"
00595               " have tentatively accepted, and %4 have declined.")
00596         .arg( total ).arg( accepted ).arg( tentative ).arg( declined ) );
00597   } else {
00598     mStatusSummaryLabel->hide();
00599   }
00600   mStatusSummaryLabel->adjustSize();
00601 }
00602 
00603 void KOEditorFreeBusy::triggerReload()
00604 {
00605   mReloadTimer.start( 1000, true );
00606 }
00607 
00608 void KOEditorFreeBusy::cancelReload()
00609 {
00610   mReloadTimer.stop();
00611 }
00612 
00613 void KOEditorFreeBusy::reload()
00614 {
00615   kdDebug() << "KOEditorFreeBusy::reload()" << endl;
00616 
00617   FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00618   while( item ) {
00619     updateFreeBusyData( item );
00620     item = static_cast<FreeBusyItem *>( item->nextSibling() );
00621   }
00622 }
00623 
00624 void KOEditorFreeBusy::editFreeBusyUrl( KDGanttViewItem *i )
00625 {
00626   FreeBusyItem *item = static_cast<FreeBusyItem *>( i );
00627   if ( !item ) return;
00628 
00629   Attendee *attendee = item->attendee();
00630 
00631   FreeBusyUrlDialog dialog( attendee, this );
00632   dialog.exec();
00633 }
00634 
00635 #include "koeditorfreebusy.moc"
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 Thu May 3 20:24:54 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003