00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <qtooltip.h>
00026 #include <qlayout.h>
00027 #include <qlabel.h>
00028 #include <qcombobox.h>
00029 #include <qpushbutton.h>
00030 #include <qvaluevector.h>
00031 #include <qwhatsthis.h>
00032
00033 #include <kdebug.h>
00034 #include <klocale.h>
00035 #include <kiconloader.h>
00036 #include <kmessagebox.h>
00037
00038 #ifndef KORG_NOKABC
00039 #include <kabc/addresseedialog.h>
00040 #include <kabc/vcardconverter.h>
00041 #include <libkdepim/addressesdialog.h>
00042 #include <libkdepim/addresseelineedit.h>
00043 #include <libkdepim/distributionlist.h>
00044 #include <kabc/stdaddressbook.h>
00045 #endif
00046
00047 #include <libkcal/event.h>
00048 #include <libkcal/freebusy.h>
00049
00050 #include <kdgantt/KDGanttView.h>
00051 #include <kdgantt/KDGanttViewTaskItem.h>
00052 #include <kdgantt/KDGanttViewSubwidgets.h>
00053
00054 #include "koprefs.h"
00055 #include "koglobals.h"
00056 #include "kogroupware.h"
00057 #include "freebusymanager.h"
00058 #include "freebusyurldialog.h"
00059
00060 #include "koeditorfreebusy.h"
00061
00062
00063
00064
00065
00066
00067 class FreeBusyItem : public KDGanttViewTaskItem
00068 {
00069 public:
00070 FreeBusyItem( Attendee *attendee, KDGanttView *parent ) :
00071 KDGanttViewTaskItem( parent, parent->lastItem() ), mAttendee( attendee ), mTimerID( 0 ),
00072 mIsDownloading( false )
00073 {
00074 Q_ASSERT( attendee );
00075 updateItem();
00076 setFreeBusyPeriods( 0 );
00077 setDisplaySubitemsAsGroup( true );
00078 if ( listView () )
00079 listView ()->setRootIsDecorated( false );
00080 }
00081 ~FreeBusyItem() {}
00082
00083 void updateItem();
00084
00085 Attendee *attendee() const { return mAttendee; }
00086 void setFreeBusy( KCal::FreeBusy *fb ) { mFreeBusy = fb; }
00087 KCal::FreeBusy* freeBusy() const { return mFreeBusy; }
00088
00089 void setFreeBusyPeriods( FreeBusy *fb );
00090
00091 QString key( int column, bool ) const
00092 {
00093 QMap<int,QString>::ConstIterator it = mKeyMap.find( column );
00094 if ( it == mKeyMap.end() ) return listViewText( column );
00095 else return *it;
00096 }
00097
00098 void setSortKey( int column, const QString &key )
00099 {
00100 mKeyMap.insert( column, key );
00101 }
00102
00103 QString email() const { return mAttendee->email(); }
00104 void setUpdateTimerID( int id ) { mTimerID = id; }
00105 int updateTimerID() const { return mTimerID; }
00106
00107 void startDownload( bool forceDownload ) {
00108 mIsDownloading = true;
00109 FreeBusyManager *m = KOGroupware::instance()->freeBusyManager();
00110 if ( !m->retrieveFreeBusy( attendee()->email(), forceDownload ) )
00111 mIsDownloading = false;
00112 }
00113 void setIsDownloading( bool d ) { mIsDownloading = d; }
00114 bool isDownloading() const { return mIsDownloading; }
00115
00116 private:
00117 Attendee *mAttendee;
00118 KCal::FreeBusy *mFreeBusy;
00119
00120 QMap<int,QString> mKeyMap;
00121
00122
00123 int mTimerID;
00124
00125
00126 bool mIsDownloading;
00127 };
00128
00129 void FreeBusyItem::updateItem()
00130 {
00131 setListViewText( 0, mAttendee->fullName() );
00132 switch ( mAttendee->status() ) {
00133 case Attendee::Accepted:
00134 setPixmap( 0, KOGlobals::self()->smallIcon( "ok" ) );
00135 break;
00136 case Attendee::Declined:
00137 setPixmap( 0, KOGlobals::self()->smallIcon( "no" ) );
00138 break;
00139 case Attendee::NeedsAction:
00140 case Attendee::InProcess:
00141 setPixmap( 0, KOGlobals::self()->smallIcon( "help" ) );
00142 break;
00143 case Attendee::Tentative:
00144 setPixmap( 0, KOGlobals::self()->smallIcon( "apply" ) );
00145 break;
00146 case Attendee::Delegated:
00147 setPixmap( 0, KOGlobals::self()->smallIcon( "mail_forward" ) );
00148 break;
00149 default:
00150 setPixmap( 0, QPixmap() );
00151 }
00152 }
00153
00154
00155
00156 void FreeBusyItem::setFreeBusyPeriods( FreeBusy* fb )
00157 {
00158 if( fb ) {
00159
00160 for( KDGanttViewItem* it = firstChild(); it; it = firstChild() )
00161 delete it;
00162
00163
00164 QValueList<KCal::Period> busyPeriods = fb->busyPeriods();
00165 for( QValueList<KCal::Period>::Iterator it = busyPeriods.begin();
00166 it != busyPeriods.end(); ++it ) {
00167 KDGanttViewTaskItem* newSubItem = new KDGanttViewTaskItem( this );
00168 newSubItem->setStartTime( (*it).start() );
00169 newSubItem->setEndTime( (*it).end() );
00170 newSubItem->setColors( Qt::red, Qt::red, Qt::red );
00171 QString toolTip;
00172 if ( !(*it).summary().isEmpty() )
00173 toolTip += "<b>" + (*it).summary() + "</b><br/>";
00174 if ( !(*it).location().isEmpty() )
00175 toolTip += i18n( "Location: %1" ).arg( (*it).location() );
00176 if ( !toolTip.isEmpty() )
00177 newSubItem->setTooltipText( toolTip );
00178 }
00179 setFreeBusy( fb );
00180 setShowNoInformation( false );
00181 } else {
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 setFreeBusy( 0 );
00196 setShowNoInformation( true );
00197 }
00198
00199
00200 mIsDownloading = false;
00201 }
00202
00204
00205 KOEditorFreeBusy::KOEditorFreeBusy( int spacing, QWidget *parent,
00206 const char *name )
00207 : KOAttendeeEditor( parent, name )
00208 {
00209 QVBoxLayout *topLayout = new QVBoxLayout( this );
00210 topLayout->setSpacing( spacing );
00211
00212 initOrganizerWidgets( this, topLayout );
00213
00214
00215
00216 mIsOrganizer = false;
00217 mStatusSummaryLabel = new QLabel( this );
00218 mStatusSummaryLabel->setPalette( QToolTip::palette() );
00219 mStatusSummaryLabel->setFrameStyle( QFrame::Plain | QFrame::Box );
00220 mStatusSummaryLabel->setLineWidth( 1 );
00221 mStatusSummaryLabel->hide();
00222 topLayout->addWidget( mStatusSummaryLabel );
00223
00224
00225 QBoxLayout *controlLayout = new QHBoxLayout( topLayout );
00226
00227 QString whatsThis = i18n("Sets the zoom level on the Gantt chart. "
00228 "'Hour' shows a range of several hours, "
00229 "'Day' shows a range of a few days, "
00230 "'Week' shows a range of a few months, "
00231 "and 'Month' shows a range of a few years, "
00232 "while 'Automatic' selects the range most "
00233 "appropriate for the current event or to-do.");
00234 QLabel *label = new QLabel( i18n( "Scale: " ), this );
00235 QWhatsThis::add( label, whatsThis );
00236 controlLayout->addWidget( label );
00237
00238 scaleCombo = new QComboBox( this );
00239 QWhatsThis::add( scaleCombo, whatsThis );
00240 scaleCombo->insertItem( i18n( "Hour" ) );
00241 scaleCombo->insertItem( i18n( "Day" ) );
00242 scaleCombo->insertItem( i18n( "Week" ) );
00243 scaleCombo->insertItem( i18n( "Month" ) );
00244 scaleCombo->insertItem( i18n( "Automatic" ) );
00245 scaleCombo->setCurrentItem( 0 );
00246 connect( scaleCombo, SIGNAL( activated( int ) ),
00247 SLOT( slotScaleChanged( int ) ) );
00248 controlLayout->addWidget( scaleCombo );
00249
00250 QPushButton *button = new QPushButton( i18n( "Center on Start" ), this );
00251 QWhatsThis::add( button,
00252 i18n("Centers the Gantt chart on the start time "
00253 "and day of this event.") );
00254 connect( button, SIGNAL( clicked() ), SLOT( slotCenterOnStart() ) );
00255 controlLayout->addWidget( button );
00256
00257 controlLayout->addStretch( 1 );
00258
00259 button = new QPushButton( i18n( "Pick Date" ), this );
00260 QWhatsThis::add( button,
00261 i18n("Moves the event to a date and time when all the "
00262 "attendees are free.") );
00263 connect( button, SIGNAL( clicked() ), SLOT( slotPickDate() ) );
00264 controlLayout->addWidget( button );
00265
00266 controlLayout->addStretch( 1 );
00267
00268 button = new QPushButton( i18n("Reload"), this );
00269 QWhatsThis::add( button,
00270 i18n("Reloads Free/Busy data for all attendees from "
00271 "the corresponding servers.") );
00272 controlLayout->addWidget( button );
00273 connect( button, SIGNAL( clicked() ), SLOT( manualReload() ) );
00274
00275 mGanttView = new KDGanttView( this, "mGanttView" );
00276 QWhatsThis::add( mGanttView,
00277 i18n("Shows the free/busy status of all attendees. "
00278 "Double-clicking on an attendees entry in the "
00279 "list will allow you to enter the location of their "
00280 "Free/Busy Information.") );
00281 topLayout->addWidget( mGanttView );
00282
00283 mGanttView->removeColumn( 0 );
00284 mGanttView->addColumn( i18n("Attendee") );
00285 if ( KOPrefs::instance()->mCompactDialogs ) {
00286 mGanttView->setFixedHeight( 78 );
00287 }
00288 mGanttView->setHeaderVisible( true );
00289 mGanttView->setScale( KDGanttView::Hour );
00290 mGanttView->setShowHeaderPopupMenu( false, false, false, false, false, false );
00291
00292
00293 QDateTime horizonStart = QDateTime( QDateTime::currentDateTime()
00294 .addDays( -15 ).date() );
00295 QDateTime horizonEnd = QDateTime::currentDateTime().addDays( 15 );
00296 mGanttView->setHorizonStart( horizonStart );
00297 mGanttView->setHorizonEnd( horizonEnd );
00298 mGanttView->setCalendarMode( true );
00299
00300 mGanttView->setShowLegendButton( false );
00301
00302 mGanttView->centerTimelineAfterShow( QDateTime::currentDateTime() );
00303 if ( KGlobal::locale()->use12Clock() )
00304 mGanttView->setHourFormat( KDGanttView::Hour_12 );
00305 else
00306 mGanttView->setHourFormat( KDGanttView::Hour_24_FourDigit );
00307
00308
00309 mEventRectangle = new KDIntervalColorRectangle( mGanttView );
00310 mEventRectangle->setColor( Qt::magenta );
00311 mGanttView->addIntervalBackgroundColor( mEventRectangle );
00312
00313 connect( mGanttView, SIGNAL ( timeIntervalSelected( const QDateTime &,
00314 const QDateTime & ) ),
00315 mGanttView, SLOT( zoomToSelection( const QDateTime &,
00316 const QDateTime & ) ) );
00317 connect( mGanttView, SIGNAL( lvItemDoubleClicked( KDGanttViewItem * ) ),
00318 SLOT( editFreeBusyUrl( KDGanttViewItem * ) ) );
00319 connect( mGanttView, SIGNAL( intervalColorRectangleMoved( const QDateTime&, const QDateTime& ) ),
00320 this, SLOT( slotIntervalColorRectangleMoved( const QDateTime&, const QDateTime& ) ) );
00321
00322 connect( mGanttView, SIGNAL(lvSelectionChanged(KDGanttViewItem*)),
00323 this, SLOT(updateAttendeeInput()) );
00324 connect( mGanttView, SIGNAL(lvItemLeftClicked(KDGanttViewItem*)),
00325 this, SLOT(showAttendeeStatusMenu()) );
00326 connect( mGanttView, SIGNAL(lvItemRightClicked(KDGanttViewItem*)),
00327 this, SLOT(showAttendeeStatusMenu()) );
00328 connect( mGanttView, SIGNAL(lvMouseButtonClicked(int, KDGanttViewItem*, const QPoint&, int)),
00329 this, SLOT(listViewClicked(int, KDGanttViewItem*)) );
00330
00331 FreeBusyManager *m = KOGroupware::instance()->freeBusyManager();
00332 connect( m, SIGNAL( freeBusyRetrieved( KCal::FreeBusy *, const QString & ) ),
00333 SLOT( slotInsertFreeBusy( KCal::FreeBusy *, const QString & ) ) );
00334
00335 connect( &mReloadTimer, SIGNAL( timeout() ), SLOT( autoReload() ) );
00336
00337 initEditWidgets( this, topLayout );
00338 connect( mRemoveButton, SIGNAL(clicked()),
00339 SLOT(removeAttendee()) );
00340 }
00341
00342 KOEditorFreeBusy::~KOEditorFreeBusy()
00343 {
00344 }
00345
00346 void KOEditorFreeBusy::removeAttendee( Attendee *attendee )
00347 {
00348 FreeBusyItem *anItem =
00349 static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00350 while( anItem ) {
00351 if( anItem->attendee() == attendee ) {
00352 if ( anItem->updateTimerID() != 0 )
00353 killTimer( anItem->updateTimerID() );
00354 delete anItem;
00355 updateStatusSummary();
00356 break;
00357 }
00358 anItem = static_cast<FreeBusyItem *>( anItem->nextSibling() );
00359 }
00360 }
00361
00362 void KOEditorFreeBusy::insertAttendee( Attendee *attendee, bool readFBList )
00363 {
00364 FreeBusyItem* item = new FreeBusyItem( attendee, mGanttView );
00365 if ( readFBList )
00366 updateFreeBusyData( item );
00367 else {
00368 clearSelection();
00369 mGanttView->setSelected( item, true );
00370 }
00371 updateStatusSummary();
00372 emit updateAttendeeSummary( mGanttView->childCount() );
00373 }
00374
00375 void KOEditorFreeBusy::clearAttendees()
00376 {
00377 mGanttView->clear();
00378 }
00379
00380
00381 void KOEditorFreeBusy::setUpdateEnabled( bool enabled )
00382 {
00383 mGanttView->setUpdateEnabled( enabled );
00384 }
00385
00386 bool KOEditorFreeBusy::updateEnabled() const
00387 {
00388 return mGanttView->getUpdateEnabled();
00389 }
00390
00391
00392 void KOEditorFreeBusy::readEvent( Event *event )
00393 {
00394 bool block = updateEnabled();
00395 setUpdateEnabled( false );
00396 clearAttendees();
00397
00398 setDateTimes( event->dtStart(), event->dtEnd() );
00399 mIsOrganizer = KOPrefs::instance()->thatIsMe( event->organizer().email() );
00400 updateStatusSummary();
00401 clearSelection();
00402 KOAttendeeEditor::readEvent( event );
00403
00404 setUpdateEnabled( block );
00405 emit updateAttendeeSummary( mGanttView->childCount() );
00406 }
00407
00408 void KOEditorFreeBusy::slotIntervalColorRectangleMoved( const QDateTime& start, const QDateTime& end )
00409 {
00410 kdDebug() << k_funcinfo << "slotIntervalColorRectangleMoved " << start << "," << end << endl;
00411 mDtStart = start;
00412 mDtEnd = end;
00413 emit dateTimesChanged( start, end );
00414 }
00415
00416 void KOEditorFreeBusy::setDateTimes( const QDateTime &start, const QDateTime &end )
00417 {
00418 slotUpdateGanttView( start, end );
00419 }
00420
00421 void KOEditorFreeBusy::slotScaleChanged( int newScale )
00422 {
00423
00424 KDGanttView::Scale scale = static_cast<KDGanttView::Scale>( newScale+1 );
00425 mGanttView->setScale( scale );
00426 slotCenterOnStart();
00427 }
00428
00429 void KOEditorFreeBusy::slotCenterOnStart()
00430 {
00431 mGanttView->centerTimeline( mDtStart );
00432 }
00433
00434 void KOEditorFreeBusy::slotZoomToTime()
00435 {
00436 mGanttView->zoomToFit();
00437 }
00438
00439 void KOEditorFreeBusy::updateFreeBusyData( FreeBusyItem* item )
00440 {
00441 if ( item->isDownloading() )
00442
00443 return;
00444
00445 if ( item->updateTimerID() != 0 )
00446
00447 killTimer( item->updateTimerID() );
00448
00449
00450
00451 item->setUpdateTimerID( startTimer( 5000 ) );
00452 }
00453
00454 void KOEditorFreeBusy::timerEvent( QTimerEvent* event )
00455 {
00456 killTimer( event->timerId() );
00457 FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00458 while( item ) {
00459 if( item->updateTimerID() == event->timerId() ) {
00460 item->setUpdateTimerID( 0 );
00461 item->startDownload( mForceDownload );
00462 return;
00463 }
00464 item = static_cast<FreeBusyItem *>( item->nextSibling() );
00465 }
00466 }
00467
00468
00469
00470 void KOEditorFreeBusy::slotInsertFreeBusy( KCal::FreeBusy *fb,
00471 const QString &email )
00472 {
00473 kdDebug(5850) << "KOEditorFreeBusy::slotInsertFreeBusy() " << email << endl;
00474
00475 if( fb )
00476 fb->sortList();
00477 bool block = mGanttView->getUpdateEnabled();
00478 mGanttView->setUpdateEnabled( false );
00479 for( KDGanttViewItem *it = mGanttView->firstChild(); it;
00480 it = it->nextSibling() ) {
00481 FreeBusyItem *item = static_cast<FreeBusyItem *>( it );
00482 if( item->email() == email )
00483 item->setFreeBusyPeriods( fb );
00484 }
00485 mGanttView->setUpdateEnabled( block );
00486 }
00487
00488
00493 void KOEditorFreeBusy::slotUpdateGanttView( const QDateTime &dtFrom, const QDateTime &dtTo )
00494 {
00495 mDtStart = dtFrom;
00496 mDtEnd = dtTo;
00497 bool block = mGanttView->getUpdateEnabled( );
00498 mGanttView->setUpdateEnabled( false );
00499 QDateTime horizonStart = QDateTime( dtFrom.addDays( -15 ).date() );
00500 mGanttView->setHorizonStart( horizonStart );
00501 mGanttView->setHorizonEnd( dtTo.addDays( 15 ) );
00502 mEventRectangle->setDateTimes( dtFrom, dtTo );
00503 mGanttView->setUpdateEnabled( block );
00504 mGanttView->centerTimelineAfterShow( dtFrom );
00505 }
00506
00507
00511 void KOEditorFreeBusy::slotPickDate()
00512 {
00513 QDateTime start = mDtStart;
00514 QDateTime end = mDtEnd;
00515 bool success = findFreeSlot( start, end );
00516
00517 if( success ) {
00518 if ( start == mDtStart && end == mDtEnd ) {
00519 KMessageBox::information( this,
00520 i18n( "The meeting already has suitable start/end times." ), QString::null,
00521 "MeetingTimeOKFreeBusy" );
00522 } else {
00523 emit dateTimesChanged( start, end );
00524 slotUpdateGanttView( start, end );
00525 KMessageBox::information( this,
00526 i18n( "The meeting has been moved to\nStart: %1\nEnd: %2." )
00527 .arg( start.toString() ).arg( end.toString() ), QString::null,
00528 "MeetingMovedFreeBusy" );
00529 }
00530 } else
00531 KMessageBox::sorry( this, i18n( "No suitable date found." ) );
00532 }
00533
00534
00539 bool KOEditorFreeBusy::findFreeSlot( QDateTime &dtFrom, QDateTime &dtTo )
00540 {
00541 if( tryDate( dtFrom, dtTo ) )
00542
00543 return true;
00544
00545 QDateTime tryFrom = dtFrom;
00546 QDateTime tryTo = dtTo;
00547
00548
00549
00550 if( tryFrom < QDateTime::currentDateTime() ) {
00551
00552 int secs = tryFrom.secsTo( tryTo );
00553 tryFrom = QDateTime::currentDateTime();
00554 tryTo = tryFrom.addSecs( secs );
00555 }
00556
00557 bool found = false;
00558 while( !found ) {
00559 found = tryDate( tryFrom, tryTo );
00560
00561 if( !found && dtFrom.daysTo( tryFrom ) > 365 )
00562 break;
00563 }
00564
00565 dtFrom = tryFrom;
00566 dtTo = tryTo;
00567
00568 return found;
00569 }
00570
00571
00580 bool KOEditorFreeBusy::tryDate( QDateTime& tryFrom, QDateTime& tryTo )
00581 {
00582 FreeBusyItem* currentItem = static_cast<FreeBusyItem*>( mGanttView->firstChild() );
00583 while( currentItem ) {
00584 if( !tryDate( currentItem, tryFrom, tryTo ) ) {
00585
00586 return false;
00587 }
00588
00589 currentItem = static_cast<FreeBusyItem*>( currentItem->nextSibling() );
00590 }
00591
00592 return true;
00593 }
00594
00602 bool KOEditorFreeBusy::tryDate( FreeBusyItem *attendee,
00603 QDateTime &tryFrom, QDateTime &tryTo )
00604 {
00605
00606
00607
00608 KCal::FreeBusy *fb = attendee->freeBusy();
00609 if( !fb )
00610 return true;
00611
00612 QValueList<KCal::Period> busyPeriods = fb->busyPeriods();
00613 for( QValueList<KCal::Period>::Iterator it = busyPeriods.begin();
00614 it != busyPeriods.end(); ++it ) {
00615 if( (*it).end() <= tryFrom ||
00616 (*it).start() >= tryTo )
00617 continue;
00618 else {
00619
00620
00621 int secsDuration = tryFrom.secsTo( tryTo );
00622 tryFrom = (*it).end();
00623 tryTo = tryFrom.addSecs( secsDuration );
00624
00625 tryDate( attendee, tryFrom, tryTo );
00626
00627 return false;
00628 }
00629 }
00630
00631 return true;
00632 }
00633
00634 void KOEditorFreeBusy::updateStatusSummary()
00635 {
00636 FreeBusyItem *aItem =
00637 static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00638 int total = 0;
00639 int accepted = 0;
00640 int tentative = 0;
00641 int declined = 0;
00642 while( aItem ) {
00643 ++total;
00644 switch( aItem->attendee()->status() ) {
00645 case Attendee::Accepted:
00646 ++accepted;
00647 break;
00648 case Attendee::Tentative:
00649 ++tentative;
00650 break;
00651 case Attendee::Declined:
00652 ++declined;
00653 break;
00654 case Attendee::NeedsAction:
00655 case Attendee::Delegated:
00656 case Attendee::Completed:
00657 case Attendee::InProcess:
00658
00659 break;
00660 }
00661 aItem = static_cast<FreeBusyItem *>( aItem->nextSibling() );
00662 }
00663 if( total > 1 && mIsOrganizer ) {
00664 mStatusSummaryLabel->show();
00665 mStatusSummaryLabel->setText(
00666 i18n( "Of the %1 participants, %2 have accepted, %3"
00667 " have tentatively accepted, and %4 have declined.")
00668 .arg( total ).arg( accepted ).arg( tentative ).arg( declined ) );
00669 } else {
00670 mStatusSummaryLabel->hide();
00671 }
00672 mStatusSummaryLabel->adjustSize();
00673 }
00674
00675 void KOEditorFreeBusy::triggerReload()
00676 {
00677 mReloadTimer.start( 1000, true );
00678 }
00679
00680 void KOEditorFreeBusy::cancelReload()
00681 {
00682 mReloadTimer.stop();
00683 }
00684
00685 void KOEditorFreeBusy::manualReload()
00686 {
00687 mForceDownload = true;
00688 reload();
00689 }
00690
00691 void KOEditorFreeBusy::autoReload()
00692 {
00693 mForceDownload = false;
00694 reload();
00695 }
00696
00697 void KOEditorFreeBusy::reload()
00698 {
00699 kdDebug(5850) << "KOEditorFreeBusy::reload()" << endl;
00700
00701 FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00702 while( item ) {
00703 if ( mForceDownload )
00704 item->startDownload( mForceDownload );
00705 else
00706 updateFreeBusyData( item );
00707
00708 item = static_cast<FreeBusyItem *>( item->nextSibling() );
00709 }
00710 }
00711
00712 void KOEditorFreeBusy::editFreeBusyUrl( KDGanttViewItem *i )
00713 {
00714 FreeBusyItem *item = static_cast<FreeBusyItem *>( i );
00715 if ( !item ) return;
00716
00717 Attendee *attendee = item->attendee();
00718
00719 FreeBusyUrlDialog dialog( attendee, this );
00720 dialog.exec();
00721 }
00722
00723 void KOEditorFreeBusy::writeEvent(KCal::Event * event)
00724 {
00725 event->clearAttendees();
00726 QValueVector<FreeBusyItem*> toBeDeleted;
00727 for ( FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() ); item;
00728 item = static_cast<FreeBusyItem*>( item->nextSibling() ) )
00729 {
00730 Attendee *attendee = item->attendee();
00731 Q_ASSERT( attendee );
00732
00733 if ( attendee->email().isEmpty() ) {
00734 KPIM::DistributionList list =
00735 KPIM::DistributionList::findByName( KABC::StdAddressBook::self(), attendee->name() );
00736 if ( !list.isEmpty() ) {
00737 toBeDeleted.push_back( item );
00738 KPIM::DistributionList::Entry::List entries = list.entries( KABC::StdAddressBook::self() );
00739 KPIM::DistributionList::Entry::List::Iterator it( entries.begin() );
00740 while ( it != entries.end() ) {
00741 KPIM::DistributionList::Entry &e = ( *it );
00742 ++it;
00743
00744 insertAttendeeFromAddressee( e.addressee, attendee );
00745
00746 }
00747 }
00748 } else {
00749 bool skip = false;
00750 if ( attendee->email().endsWith( "example.net" ) ) {
00751 if ( KMessageBox::warningYesNo( this, i18n("%1 does not look like a valid email address. "
00752 "Are you sure you want to invite this participant?").arg( attendee->email() ),
00753 i18n("Invalid email address") ) != KMessageBox::Yes ) {
00754 skip = true;
00755 }
00756 }
00757 if ( !skip ) {
00758 event->addAttendee( new Attendee( *attendee ) );
00759 }
00760 }
00761 }
00762
00763 KOAttendeeEditor::writeEvent( event );
00764
00765
00766 QValueVector<FreeBusyItem*>::iterator it;
00767 for( it = toBeDeleted.begin(); it != toBeDeleted.end(); ++it ) {
00768 delete *it;
00769 }
00770 }
00771
00772 KCal::Attendee * KOEditorFreeBusy::currentAttendee() const
00773 {
00774 KDGanttViewItem *item = mGanttView->selectedItem();
00775 FreeBusyItem *aItem = static_cast<FreeBusyItem*>( item );
00776 if ( !aItem )
00777 return 0;
00778 return aItem->attendee();
00779 }
00780
00781 void KOEditorFreeBusy::updateCurrentItem()
00782 {
00783 FreeBusyItem* item = static_cast<FreeBusyItem*>( mGanttView->selectedItem() );
00784 if ( item ) {
00785 item->updateItem();
00786 updateFreeBusyData( item );
00787 updateStatusSummary();
00788 }
00789 }
00790
00791 void KOEditorFreeBusy::removeAttendee()
00792 {
00793 FreeBusyItem *item = static_cast<FreeBusyItem*>( mGanttView->selectedItem() );
00794 if ( !item )
00795 return;
00796
00797 Attendee *delA = new Attendee( item->attendee()->name(), item->attendee()->email(),
00798 item->attendee()->RSVP(), item->attendee()->status(),
00799 item->attendee()->role(), item->attendee()->uid() );
00800 mdelAttendees.append( delA );
00801 delete item;
00802
00803 updateStatusSummary();
00804 updateAttendeeInput();
00805 emit updateAttendeeSummary( mGanttView->childCount() );
00806 }
00807
00808 void KOEditorFreeBusy::clearSelection() const
00809 {
00810 KDGanttViewItem *item = mGanttView->selectedItem();
00811 if ( item )
00812 mGanttView->setSelected( item, false );
00813 mGanttView->repaint();
00814 item->repaint();
00815 }
00816
00817 void KOEditorFreeBusy::changeStatusForMe(KCal::Attendee::PartStat status)
00818 {
00819 const QStringList myEmails = KOPrefs::instance()->allEmails();
00820 for ( FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() ); item;
00821 item = static_cast<FreeBusyItem*>( item->nextSibling() ) )
00822 {
00823 for ( QStringList::ConstIterator it2( myEmails.begin() ), end( myEmails.end() ); it2 != end; ++it2 ) {
00824 if ( item->attendee()->email() == *it2 ) {
00825 item->attendee()->setStatus( status );
00826 item->updateItem();
00827 }
00828 }
00829 }
00830 }
00831
00832 void KOEditorFreeBusy::showAttendeeStatusMenu()
00833 {
00834 if ( mGanttView->mapFromGlobal( QCursor::pos() ).x() > 22 )
00835 return;
00836 QPopupMenu popup;
00837 popup.insertItem( SmallIcon( "help" ), Attendee::statusName( Attendee::NeedsAction ), Attendee::NeedsAction );
00838 popup.insertItem( KOGlobals::self()->smallIcon( "ok" ), Attendee::statusName( Attendee::Accepted ), Attendee::Accepted );
00839 popup.insertItem( KOGlobals::self()->smallIcon( "no" ), Attendee::statusName( Attendee::Declined ), Attendee::Declined );
00840 popup.insertItem( KOGlobals::self()->smallIcon( "apply" ), Attendee::statusName( Attendee::Tentative ), Attendee::Tentative );
00841 popup.insertItem( KOGlobals::self()->smallIcon( "mail_forward" ), Attendee::statusName( Attendee::Delegated ), Attendee::Delegated );
00842 popup.insertItem( Attendee::statusName( Attendee::Completed ), Attendee::Completed );
00843 popup.insertItem( KOGlobals::self()->smallIcon( "help" ), Attendee::statusName( Attendee::InProcess ), Attendee::InProcess );
00844 popup.setItemChecked( currentAttendee()->status(), true );
00845 int status = popup.exec( QCursor::pos() );
00846 if ( status >= 0 ) {
00847 currentAttendee()->setStatus( (Attendee::PartStat)status );
00848 updateCurrentItem();
00849 updateAttendeeInput();
00850 }
00851 }
00852
00853 void KOEditorFreeBusy::listViewClicked(int button, KDGanttViewItem * item)
00854 {
00855 if ( button == Qt::LeftButton && item == 0 )
00856 addNewAttendee();
00857 }
00858
00859 #include "koeditorfreebusy.moc"