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 button = new QPushButton( i18n( "Zoom to Fit" ), this );
00258 QWhatsThis::add( button,
00259 i18n("Zooms the Gantt chart so that you can see the "
00260 "entire duration of the event on it.") );
00261 connect( button, SIGNAL( clicked() ), SLOT( slotZoomToTime() ) );
00262 controlLayout->addWidget( button );
00263
00264 controlLayout->addStretch( 1 );
00265
00266 button = new QPushButton( i18n( "Pick Date" ), this );
00267 QWhatsThis::add( button,
00268 i18n("Moves the event to a date and time when all the "
00269 "attendees are free.") );
00270 connect( button, SIGNAL( clicked() ), SLOT( slotPickDate() ) );
00271 controlLayout->addWidget( button );
00272
00273 controlLayout->addStretch( 1 );
00274
00275 button = new QPushButton( i18n("Reload"), this );
00276 QWhatsThis::add( button,
00277 i18n("Reloads Free/Busy data for all attendees from "
00278 "the corresponding servers.") );
00279 controlLayout->addWidget( button );
00280 connect( button, SIGNAL( clicked() ), SLOT( manualReload() ) );
00281
00282 mGanttView = new KDGanttView( this, "mGanttView" );
00283 QWhatsThis::add( mGanttView,
00284 i18n("Shows the free/busy status of all attendees. "
00285 "Double-clicking on an attendees entry in the "
00286 "list will allow you to enter the location of their "
00287 "Free/Busy Information.") );
00288 topLayout->addWidget( mGanttView );
00289
00290 mGanttView->removeColumn( 0 );
00291 mGanttView->addColumn( i18n("Attendee") );
00292 if ( KOPrefs::instance()->mCompactDialogs ) {
00293 mGanttView->setFixedHeight( 78 );
00294 }
00295 mGanttView->setHeaderVisible( true );
00296 mGanttView->setScale( KDGanttView::Hour );
00297 mGanttView->setShowHeaderPopupMenu( true, true, true, false, false, true );
00298
00299
00300 QDateTime horizonStart = QDateTime( QDateTime::currentDateTime()
00301 .addDays( -15 ).date() );
00302 QDateTime horizonEnd = QDateTime::currentDateTime().addDays( 15 );
00303 mGanttView->setHorizonStart( horizonStart );
00304 mGanttView->setHorizonEnd( horizonEnd );
00305 mGanttView->setCalendarMode( true );
00306
00307 mGanttView->setShowLegendButton( false );
00308
00309 mGanttView->centerTimelineAfterShow( QDateTime::currentDateTime() );
00310 if ( KGlobal::locale()->use12Clock() )
00311 mGanttView->setHourFormat( KDGanttView::Hour_12 );
00312 else
00313 mGanttView->setHourFormat( KDGanttView::Hour_24_FourDigit );
00314
00315
00316 mEventRectangle = new KDIntervalColorRectangle( mGanttView );
00317 mEventRectangle->setColor( Qt::magenta );
00318 mGanttView->addIntervalBackgroundColor( mEventRectangle );
00319
00320 connect( mGanttView, SIGNAL ( timeIntervalSelected( const QDateTime &,
00321 const QDateTime & ) ),
00322 mGanttView, SLOT( zoomToSelection( const QDateTime &,
00323 const QDateTime & ) ) );
00324 connect( mGanttView, SIGNAL( lvItemDoubleClicked( KDGanttViewItem * ) ),
00325 SLOT( editFreeBusyUrl( KDGanttViewItem * ) ) );
00326 connect( mGanttView, SIGNAL( intervalColorRectangleMoved( const QDateTime&, const QDateTime& ) ),
00327 this, SLOT( slotIntervalColorRectangleMoved( const QDateTime&, const QDateTime& ) ) );
00328
00329 connect( mGanttView, SIGNAL(lvSelectionChanged(KDGanttViewItem*)),
00330 this, SLOT(updateAttendeeInput()) );
00331 connect( mGanttView, SIGNAL(lvItemLeftClicked(KDGanttViewItem*)),
00332 this, SLOT(showAttendeeStatusMenu()) );
00333 connect( mGanttView, SIGNAL(lvItemRightClicked(KDGanttViewItem*)),
00334 this, SLOT(showAttendeeStatusMenu()) );
00335 connect( mGanttView, SIGNAL(lvMouseButtonClicked(int, KDGanttViewItem*, const QPoint&, int)),
00336 this, SLOT(listViewClicked(int, KDGanttViewItem*)) );
00337
00338 FreeBusyManager *m = KOGroupware::instance()->freeBusyManager();
00339 connect( m, SIGNAL( freeBusyRetrieved( KCal::FreeBusy *, const QString & ) ),
00340 SLOT( slotInsertFreeBusy( KCal::FreeBusy *, const QString & ) ) );
00341
00342 connect( &mReloadTimer, SIGNAL( timeout() ), SLOT( autoReload() ) );
00343
00344 initEditWidgets( this, topLayout );
00345 connect( mRemoveButton, SIGNAL(clicked()),
00346 SLOT(removeAttendee()) );
00347 }
00348
00349 KOEditorFreeBusy::~KOEditorFreeBusy()
00350 {
00351 }
00352
00353 void KOEditorFreeBusy::removeAttendee( Attendee *attendee )
00354 {
00355 FreeBusyItem *anItem =
00356 static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00357 while( anItem ) {
00358 if( anItem->attendee() == attendee ) {
00359 if ( anItem->updateTimerID() != 0 )
00360 killTimer( anItem->updateTimerID() );
00361 delete anItem;
00362 updateStatusSummary();
00363 break;
00364 }
00365 anItem = static_cast<FreeBusyItem *>( anItem->nextSibling() );
00366 }
00367 }
00368
00369 void KOEditorFreeBusy::insertAttendee( Attendee *attendee, bool readFBList )
00370 {
00371 FreeBusyItem* item = new FreeBusyItem( attendee, mGanttView );
00372 if ( readFBList )
00373 updateFreeBusyData( item );
00374 else {
00375 clearSelection();
00376 mGanttView->setSelected( item, true );
00377 }
00378 updateStatusSummary();
00379 emit updateAttendeeSummary( mGanttView->childCount() );
00380 }
00381
00382 void KOEditorFreeBusy::clearAttendees()
00383 {
00384 mGanttView->clear();
00385 }
00386
00387
00388 void KOEditorFreeBusy::setUpdateEnabled( bool enabled )
00389 {
00390 mGanttView->setUpdateEnabled( enabled );
00391 }
00392
00393 bool KOEditorFreeBusy::updateEnabled() const
00394 {
00395 return mGanttView->getUpdateEnabled();
00396 }
00397
00398
00399 void KOEditorFreeBusy::readEvent( Event *event )
00400 {
00401 bool block = updateEnabled();
00402 setUpdateEnabled( false );
00403 clearAttendees();
00404
00405 setDateTimes( event->dtStart(), event->dtEnd() );
00406 mIsOrganizer = KOPrefs::instance()->thatIsMe( event->organizer().email() );
00407 updateStatusSummary();
00408 clearSelection();
00409 KOAttendeeEditor::readEvent( event );
00410
00411 setUpdateEnabled( block );
00412 emit updateAttendeeSummary( mGanttView->childCount() );
00413 }
00414
00415 void KOEditorFreeBusy::slotIntervalColorRectangleMoved( const QDateTime& start, const QDateTime& end )
00416 {
00417 kdDebug() << k_funcinfo << "slotIntervalColorRectangleMoved " << start << "," << end << endl;
00418 mDtStart = start;
00419 mDtEnd = end;
00420 emit dateTimesChanged( start, end );
00421 }
00422
00423 void KOEditorFreeBusy::setDateTimes( const QDateTime &start, const QDateTime &end )
00424 {
00425 slotUpdateGanttView( start, end );
00426 }
00427
00428 void KOEditorFreeBusy::slotScaleChanged( int newScale )
00429 {
00430
00431 KDGanttView::Scale scale = static_cast<KDGanttView::Scale>( newScale+1 );
00432 mGanttView->setScale( scale );
00433 slotCenterOnStart();
00434 }
00435
00436 void KOEditorFreeBusy::slotCenterOnStart()
00437 {
00438 mGanttView->centerTimeline( mDtStart );
00439 }
00440
00441 void KOEditorFreeBusy::slotZoomToTime()
00442 {
00443 mGanttView->zoomToFit();
00444 }
00445
00446 void KOEditorFreeBusy::updateFreeBusyData( FreeBusyItem* item )
00447 {
00448 if ( item->isDownloading() )
00449
00450 return;
00451
00452 if ( item->updateTimerID() != 0 )
00453
00454 killTimer( item->updateTimerID() );
00455
00456
00457
00458 item->setUpdateTimerID( startTimer( 5000 ) );
00459 }
00460
00461 void KOEditorFreeBusy::timerEvent( QTimerEvent* event )
00462 {
00463 killTimer( event->timerId() );
00464 FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00465 while( item ) {
00466 if( item->updateTimerID() == event->timerId() ) {
00467 item->setUpdateTimerID( 0 );
00468 item->startDownload( mForceDownload );
00469 return;
00470 }
00471 item = static_cast<FreeBusyItem *>( item->nextSibling() );
00472 }
00473 }
00474
00475
00476
00477 void KOEditorFreeBusy::slotInsertFreeBusy( KCal::FreeBusy *fb,
00478 const QString &email )
00479 {
00480 kdDebug(5850) << "KOEditorFreeBusy::slotInsertFreeBusy() " << email << endl;
00481
00482 if( fb )
00483 fb->sortList();
00484 bool block = mGanttView->getUpdateEnabled();
00485 mGanttView->setUpdateEnabled( false );
00486 for( KDGanttViewItem *it = mGanttView->firstChild(); it;
00487 it = it->nextSibling() ) {
00488 FreeBusyItem *item = static_cast<FreeBusyItem *>( it );
00489 if( item->email() == email )
00490 item->setFreeBusyPeriods( fb );
00491 }
00492 mGanttView->setUpdateEnabled( block );
00493 }
00494
00495
00500 void KOEditorFreeBusy::slotUpdateGanttView( const QDateTime &dtFrom, const QDateTime &dtTo )
00501 {
00502 mDtStart = dtFrom;
00503 mDtEnd = dtTo;
00504 bool block = mGanttView->getUpdateEnabled( );
00505 mGanttView->setUpdateEnabled( false );
00506 QDateTime horizonStart = QDateTime( dtFrom.addDays( -15 ).date() );
00507 mGanttView->setHorizonStart( horizonStart );
00508 mGanttView->setHorizonEnd( dtTo.addDays( 15 ) );
00509 mEventRectangle->setDateTimes( dtFrom, dtTo );
00510 mGanttView->setUpdateEnabled( block );
00511 mGanttView->centerTimelineAfterShow( dtFrom );
00512 }
00513
00514
00518 void KOEditorFreeBusy::slotPickDate()
00519 {
00520 QDateTime start = mDtStart;
00521 QDateTime end = mDtEnd;
00522 bool success = findFreeSlot( start, end );
00523
00524 if( success ) {
00525 if ( start == mDtStart && end == mDtEnd ) {
00526 KMessageBox::information( this,
00527 i18n( "The meeting already has suitable start/end times." ), QString::null,
00528 "MeetingTimeOKFreeBusy" );
00529 } else {
00530 emit dateTimesChanged( start, end );
00531 slotUpdateGanttView( start, end );
00532 KMessageBox::information( this,
00533 i18n( "The meeting has been moved to\nStart: %1\nEnd: %2." )
00534 .arg( start.toString() ).arg( end.toString() ), QString::null,
00535 "MeetingMovedFreeBusy" );
00536 }
00537 } else
00538 KMessageBox::sorry( this, i18n( "No suitable date found." ) );
00539 }
00540
00541
00546 bool KOEditorFreeBusy::findFreeSlot( QDateTime &dtFrom, QDateTime &dtTo )
00547 {
00548 if( tryDate( dtFrom, dtTo ) )
00549
00550 return true;
00551
00552 QDateTime tryFrom = dtFrom;
00553 QDateTime tryTo = dtTo;
00554
00555
00556
00557 if( tryFrom < QDateTime::currentDateTime() ) {
00558
00559 int secs = tryFrom.secsTo( tryTo );
00560 tryFrom = QDateTime::currentDateTime();
00561 tryTo = tryFrom.addSecs( secs );
00562 }
00563
00564 bool found = false;
00565 while( !found ) {
00566 found = tryDate( tryFrom, tryTo );
00567
00568 if( !found && dtFrom.daysTo( tryFrom ) > 365 )
00569 break;
00570 }
00571
00572 dtFrom = tryFrom;
00573 dtTo = tryTo;
00574
00575 return found;
00576 }
00577
00578
00587 bool KOEditorFreeBusy::tryDate( QDateTime& tryFrom, QDateTime& tryTo )
00588 {
00589 FreeBusyItem* currentItem = static_cast<FreeBusyItem*>( mGanttView->firstChild() );
00590 while( currentItem ) {
00591 if( !tryDate( currentItem, tryFrom, tryTo ) ) {
00592
00593 return false;
00594 }
00595
00596 currentItem = static_cast<FreeBusyItem*>( currentItem->nextSibling() );
00597 }
00598
00599 return true;
00600 }
00601
00609 bool KOEditorFreeBusy::tryDate( FreeBusyItem *attendee,
00610 QDateTime &tryFrom, QDateTime &tryTo )
00611 {
00612
00613
00614
00615 KCal::FreeBusy *fb = attendee->freeBusy();
00616 if( !fb )
00617 return true;
00618
00619 QValueList<KCal::Period> busyPeriods = fb->busyPeriods();
00620 for( QValueList<KCal::Period>::Iterator it = busyPeriods.begin();
00621 it != busyPeriods.end(); ++it ) {
00622 if( (*it).end() <= tryFrom ||
00623 (*it).start() >= tryTo )
00624 continue;
00625 else {
00626
00627
00628 int secsDuration = tryFrom.secsTo( tryTo );
00629 tryFrom = (*it).end();
00630 tryTo = tryFrom.addSecs( secsDuration );
00631
00632 tryDate( attendee, tryFrom, tryTo );
00633
00634 return false;
00635 }
00636 }
00637
00638 return true;
00639 }
00640
00641 void KOEditorFreeBusy::updateStatusSummary()
00642 {
00643 FreeBusyItem *aItem =
00644 static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00645 int total = 0;
00646 int accepted = 0;
00647 int tentative = 0;
00648 int declined = 0;
00649 while( aItem ) {
00650 ++total;
00651 switch( aItem->attendee()->status() ) {
00652 case Attendee::Accepted:
00653 ++accepted;
00654 break;
00655 case Attendee::Tentative:
00656 ++tentative;
00657 break;
00658 case Attendee::Declined:
00659 ++declined;
00660 break;
00661 case Attendee::NeedsAction:
00662 case Attendee::Delegated:
00663 case Attendee::Completed:
00664 case Attendee::InProcess:
00665
00666 break;
00667 }
00668 aItem = static_cast<FreeBusyItem *>( aItem->nextSibling() );
00669 }
00670 if( total > 1 && mIsOrganizer ) {
00671 mStatusSummaryLabel->show();
00672 mStatusSummaryLabel->setText(
00673 i18n( "Of the %1 participants, %2 have accepted, %3"
00674 " have tentatively accepted, and %4 have declined.")
00675 .arg( total ).arg( accepted ).arg( tentative ).arg( declined ) );
00676 } else {
00677 mStatusSummaryLabel->hide();
00678 }
00679 mStatusSummaryLabel->adjustSize();
00680 }
00681
00682 void KOEditorFreeBusy::triggerReload()
00683 {
00684 mReloadTimer.start( 1000, true );
00685 }
00686
00687 void KOEditorFreeBusy::cancelReload()
00688 {
00689 mReloadTimer.stop();
00690 }
00691
00692 void KOEditorFreeBusy::manualReload()
00693 {
00694 mForceDownload = true;
00695 reload();
00696 }
00697
00698 void KOEditorFreeBusy::autoReload()
00699 {
00700 mForceDownload = false;
00701 reload();
00702 }
00703
00704 void KOEditorFreeBusy::reload()
00705 {
00706 kdDebug(5850) << "KOEditorFreeBusy::reload()" << endl;
00707
00708 FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() );
00709 while( item ) {
00710 if ( mForceDownload )
00711 item->startDownload( mForceDownload );
00712 else
00713 updateFreeBusyData( item );
00714
00715 item = static_cast<FreeBusyItem *>( item->nextSibling() );
00716 }
00717 }
00718
00719 void KOEditorFreeBusy::editFreeBusyUrl( KDGanttViewItem *i )
00720 {
00721 FreeBusyItem *item = static_cast<FreeBusyItem *>( i );
00722 if ( !item ) return;
00723
00724 Attendee *attendee = item->attendee();
00725
00726 FreeBusyUrlDialog dialog( attendee, this );
00727 dialog.exec();
00728 }
00729
00730 void KOEditorFreeBusy::writeEvent(KCal::Event * event)
00731 {
00732 event->clearAttendees();
00733 QValueVector<FreeBusyItem*> toBeDeleted;
00734 for ( FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() ); item;
00735 item = static_cast<FreeBusyItem*>( item->nextSibling() ) )
00736 {
00737 Attendee *attendee = item->attendee();
00738 Q_ASSERT( attendee );
00739
00740 if ( attendee->email().isEmpty() ) {
00741 KPIM::DistributionList list =
00742 KPIM::DistributionList::findByName( KABC::StdAddressBook::self(), attendee->name() );
00743 if ( !list.isEmpty() ) {
00744 toBeDeleted.push_back( item );
00745 KPIM::DistributionList::Entry::List entries = list.entries( KABC::StdAddressBook::self() );
00746 KPIM::DistributionList::Entry::List::Iterator it( entries.begin() );
00747 while ( it != entries.end() ) {
00748 KPIM::DistributionList::Entry &e = ( *it );
00749 ++it;
00750
00751 insertAttendeeFromAddressee( e.addressee, attendee );
00752
00753 }
00754 }
00755 } else {
00756 bool skip = false;
00757 if ( attendee->email().endsWith( "example.net" ) ) {
00758 if ( KMessageBox::warningYesNo( this, i18n("%1 does not look like a valid email address. "
00759 "Are you sure you want to invite this participant?").arg( attendee->email() ),
00760 i18n("Invalid email address") ) != KMessageBox::Yes ) {
00761 skip = true;
00762 }
00763 }
00764 if ( !skip ) {
00765 event->addAttendee( new Attendee( *attendee ) );
00766 }
00767 }
00768 }
00769
00770 KOAttendeeEditor::writeEvent( event );
00771
00772
00773 QValueVector<FreeBusyItem*>::iterator it;
00774 for( it = toBeDeleted.begin(); it != toBeDeleted.end(); ++it ) {
00775 delete *it;
00776 }
00777 }
00778
00779 KCal::Attendee * KOEditorFreeBusy::currentAttendee() const
00780 {
00781 KDGanttViewItem *item = mGanttView->selectedItem();
00782 FreeBusyItem *aItem = static_cast<FreeBusyItem*>( item );
00783 if ( !aItem )
00784 return 0;
00785 return aItem->attendee();
00786 }
00787
00788 void KOEditorFreeBusy::updateCurrentItem()
00789 {
00790 FreeBusyItem* item = static_cast<FreeBusyItem*>( mGanttView->selectedItem() );
00791 if ( item ) {
00792 item->updateItem();
00793 updateFreeBusyData( item );
00794 updateStatusSummary();
00795 }
00796 }
00797
00798 void KOEditorFreeBusy::removeAttendee()
00799 {
00800 FreeBusyItem *item = static_cast<FreeBusyItem*>( mGanttView->selectedItem() );
00801 if ( !item )
00802 return;
00803
00804 Attendee *delA = new Attendee( item->attendee()->name(), item->attendee()->email(),
00805 item->attendee()->RSVP(), item->attendee()->status(),
00806 item->attendee()->role(), item->attendee()->uid() );
00807 mdelAttendees.append( delA );
00808 delete item;
00809
00810 updateStatusSummary();
00811 updateAttendeeInput();
00812 emit updateAttendeeSummary( mGanttView->childCount() );
00813 }
00814
00815 void KOEditorFreeBusy::clearSelection() const
00816 {
00817 KDGanttViewItem *item = mGanttView->selectedItem();
00818 if ( item )
00819 mGanttView->setSelected( item, false );
00820 mGanttView->repaint();
00821 item->repaint();
00822 }
00823
00824 void KOEditorFreeBusy::changeStatusForMe(KCal::Attendee::PartStat status)
00825 {
00826 const QStringList myEmails = KOPrefs::instance()->allEmails();
00827 for ( FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() ); item;
00828 item = static_cast<FreeBusyItem*>( item->nextSibling() ) )
00829 {
00830 for ( QStringList::ConstIterator it2( myEmails.begin() ), end( myEmails.end() ); it2 != end; ++it2 ) {
00831 if ( item->attendee()->email() == *it2 ) {
00832 item->attendee()->setStatus( status );
00833 item->updateItem();
00834 }
00835 }
00836 }
00837 }
00838
00839 void KOEditorFreeBusy::showAttendeeStatusMenu()
00840 {
00841 if ( mGanttView->mapFromGlobal( QCursor::pos() ).x() > 22 )
00842 return;
00843 QPopupMenu popup;
00844 popup.insertItem( SmallIcon( "help" ), Attendee::statusName( Attendee::NeedsAction ), Attendee::NeedsAction );
00845 popup.insertItem( KOGlobals::self()->smallIcon( "ok" ), Attendee::statusName( Attendee::Accepted ), Attendee::Accepted );
00846 popup.insertItem( KOGlobals::self()->smallIcon( "no" ), Attendee::statusName( Attendee::Declined ), Attendee::Declined );
00847 popup.insertItem( KOGlobals::self()->smallIcon( "apply" ), Attendee::statusName( Attendee::Tentative ), Attendee::Tentative );
00848 popup.insertItem( KOGlobals::self()->smallIcon( "mail_forward" ), Attendee::statusName( Attendee::Delegated ), Attendee::Delegated );
00849 popup.insertItem( Attendee::statusName( Attendee::Completed ), Attendee::Completed );
00850 popup.insertItem( KOGlobals::self()->smallIcon( "help" ), Attendee::statusName( Attendee::InProcess ), Attendee::InProcess );
00851 popup.setItemChecked( currentAttendee()->status(), true );
00852 int status = popup.exec( QCursor::pos() );
00853 if ( status >= 0 ) {
00854 currentAttendee()->setStatus( (Attendee::PartStat)status );
00855 updateCurrentItem();
00856 updateAttendeeInput();
00857 }
00858 }
00859
00860 void KOEditorFreeBusy::listViewClicked(int button, KDGanttViewItem * item)
00861 {
00862 if ( button == Qt::LeftButton && item == 0 )
00863 addNewAttendee();
00864 }
00865
00866 #include "koeditorfreebusy.moc"