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