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 "koeditordetails.h"
00026
00027 #include <qtooltip.h>
00028 #include <qfiledialog.h>
00029 #include <qlayout.h>
00030 #include <qvbox.h>
00031 #include <qbuttongroup.h>
00032 #include <qvgroupbox.h>
00033 #include <qwidgetstack.h>
00034 #include <qdatetime.h>
00035 #include <qdragobject.h>
00036 #include <qcombobox.h>
00037 #include <qlineedit.h>
00038 #include <qlabel.h>
00039 #include <qcheckbox.h>
00040 #include <qpushbutton.h>
00041 #include <qgroupbox.h>
00042 #include <qradiobutton.h>
00043 #include <qregexp.h>
00044 #include <qvaluevector.h>
00045
00046 #include <kdebug.h>
00047 #include <klocale.h>
00048 #include <kiconloader.h>
00049 #include <kmessagebox.h>
00050 #ifndef KORG_NOKABC
00051 #include <kabc/addresseedialog.h>
00052 #include <kabc/vcardconverter.h>
00053 #include <libkdepim/addressesdialog.h>
00054 #include <libkdepim/addresseelineedit.h>
00055 #include <kabc/distributionlist.h>
00056 #include <kabc/stdaddressbook.h>
00057 #endif
00058 #include <libkdepim/kvcarddrag.h>
00059 #include <libkdepim/email.h>
00060 #include <libkdepim/distributionlist.h>
00061
00062 #include <libkcal/incidence.h>
00063
00064 #include "koprefs.h"
00065 #include "koglobals.h"
00066
00067 #include "koeditorfreebusy.h"
00068
00069 #include "kocore.h"
00070
00071 template <>
00072 CustomListViewItem<KCal::Attendee *>::~CustomListViewItem()
00073 {
00074 delete mData;
00075 }
00076
00077 template <>
00078 void CustomListViewItem<KCal::Attendee *>::updateItem()
00079 {
00080 setText(0,mData->name());
00081 setText(1,mData->email());
00082 setText(2,mData->roleStr());
00083 setText(3,mData->statusStr());
00084 if (mData->RSVP() && !mData->email().isEmpty())
00085 setPixmap(4,KOGlobals::self()->smallIcon("mailappt"));
00086 else
00087 setPixmap(4,KOGlobals::self()->smallIcon("nomailappt"));
00088 }
00089
00090 KOAttendeeListView::KOAttendeeListView ( QWidget *parent, const char *name )
00091 : KListView(parent, name)
00092 {
00093 setAcceptDrops( true );
00094 setAllColumnsShowFocus( true );
00095 setSorting( -1 );
00096 }
00097
00103 KOAttendeeListView::~KOAttendeeListView()
00104 {
00105 }
00106
00107 void KOAttendeeListView::contentsDragEnterEvent( QDragEnterEvent *e )
00108 {
00109 dragEnterEvent(e);
00110 }
00111
00112 void KOAttendeeListView::contentsDragMoveEvent( QDragMoveEvent *e )
00113 {
00114 #ifndef KORG_NODND
00115 if ( KVCardDrag::canDecode( e ) || QTextDrag::canDecode( e ) ) {
00116 e->accept();
00117 } else {
00118 e->ignore();
00119 }
00120 #endif
00121 }
00122
00123 void KOAttendeeListView::dragEnterEvent( QDragEnterEvent *e )
00124 {
00125 #ifndef KORG_NODND
00126 if ( KVCardDrag::canDecode( e ) || QTextDrag::canDecode( e ) ) {
00127 e->accept();
00128 } else {
00129 e->ignore();
00130 }
00131 #endif
00132 }
00133
00134 void KOAttendeeListView::addAttendee( const QString &newAttendee )
00135 {
00136 kdDebug(5850) << " Email: " << newAttendee << endl;
00137 QString name;
00138 QString email;
00139 KPIM::getNameAndMail( newAttendee, name, email );
00140 emit dropped( new Attendee( name, email, true ) );
00141 }
00142
00143 void KOAttendeeListView::contentsDropEvent( QDropEvent *e )
00144 {
00145 dropEvent(e);
00146 }
00147
00148 void KOAttendeeListView::dropEvent( QDropEvent *e )
00149 {
00150 #ifndef KORG_NODND
00151 QString text;
00152 QString vcards;
00153
00154 #ifndef KORG_NOKABC
00155 if ( KVCardDrag::decode( e, vcards ) ) {
00156 KABC::VCardConverter converter;
00157
00158 KABC::Addressee::List list = converter.parseVCards( vcards );
00159 KABC::Addressee::List::Iterator it;
00160 for ( it = list.begin(); it != list.end(); ++it ) {
00161 QString em( (*it).fullEmail() );
00162 if (em.isEmpty()) {
00163 em=(*it).realName();
00164 }
00165 addAttendee( em );
00166 }
00167 } else
00168 #endif // KORG_NOKABC
00169 if (QTextDrag::decode(e,text)) {
00170 kdDebug(5850) << "Dropped : " << text << endl;
00171 QStringList emails = QStringList::split(",",text);
00172 for(QStringList::ConstIterator it = emails.begin();it!=emails.end();++it) {
00173 addAttendee(*it);
00174 }
00175 }
00176 #endif //KORG_NODND
00177 }
00178
00179
00180 KOEditorDetails::KOEditorDetails( int spacing, QWidget *parent,
00181 const char *name )
00182 : QWidget( parent, name), mDisableItemUpdate( false ), mFreeBusy( 0 )
00183 {
00184 QGridLayout *topLayout = new QGridLayout( this );
00185 topLayout->setSpacing( spacing );
00186
00187 mOrganizerHBox = new QHBox( this );
00188
00189
00190
00191
00192
00193 mOrganizerLabel = new QLabel( i18n( "Identity as organizer:" ),
00194 mOrganizerHBox );
00195 mOrganizerCombo = new QComboBox( mOrganizerHBox );
00196 fillOrganizerCombo();
00197 mOrganizerHBox->setStretchFactor( mOrganizerCombo, 100 );
00198
00199 mListView = new KOAttendeeListView( this, "mListView" );
00200 mListView->addColumn( i18n("Name"), 200 );
00201 mListView->addColumn( i18n("Email"), 200 );
00202 mListView->addColumn( i18n("Role"), 60 );
00203 mListView->addColumn( i18n("Status"), 100 );
00204 mListView->addColumn( i18n("RSVP"), 35 );
00205 mListView->setResizeMode( QListView::LastColumn );
00206 if ( KOPrefs::instance()->mCompactDialogs ) {
00207 mListView->setFixedHeight( 78 );
00208 }
00209
00210 connect( mListView, SIGNAL( selectionChanged( QListViewItem * ) ),
00211 SLOT( updateAttendeeInput() ) );
00212 #ifndef KORG_NODND
00213 connect( mListView, SIGNAL( dropped( Attendee * ) ),
00214 SLOT( insertAttendee( Attendee * ) ) );
00215 #endif
00216
00217 QLabel *attendeeLabel = new QLabel( this );
00218 attendeeLabel->setText( i18n("Na&me:") );
00219
00220 mNameEdit = new KPIM::AddresseeLineEdit( this );
00221 mNameEdit->setClickMessage( i18n("Click to add a new attendee") );
00222 attendeeLabel->setBuddy( mNameEdit );
00223 mNameEdit->installEventFilter( this );
00224 connect( mNameEdit, SIGNAL( textChanged( const QString & ) ),
00225 SLOT( updateAttendeeItem() ) );
00226
00227 mUidEdit = new QLineEdit( 0 );
00228 mUidEdit->setText( "" );
00229
00230 QLabel *attendeeRoleLabel = new QLabel( this );
00231 attendeeRoleLabel->setText( i18n("Ro&le:") );
00232
00233 mRoleCombo = new QComboBox( false, this );
00234 mRoleCombo->insertStringList( Attendee::roleList() );
00235 attendeeRoleLabel->setBuddy( mRoleCombo );
00236 connect( mRoleCombo, SIGNAL( activated( int ) ),
00237 SLOT( updateAttendeeItem() ) );
00238
00239 QLabel *statusLabel = new QLabel( this );
00240 statusLabel->setText( i18n("Stat&us:") );
00241
00242 mStatusCombo = new QComboBox( false, this );
00243 mStatusCombo->insertStringList( Attendee::statusList() );
00244 statusLabel->setBuddy( mStatusCombo );
00245 connect( mStatusCombo, SIGNAL( activated( int ) ),
00246 SLOT( updateAttendeeItem() ) );
00247
00248 mRsvpButton = new QCheckBox( this );
00249 mRsvpButton->setText( i18n("Re&quest response") );
00250 connect( mRsvpButton, SIGNAL( clicked() ), SLOT( updateAttendeeItem() ) );
00251
00252 QWidget *buttonBox = new QWidget( this );
00253 QVBoxLayout *buttonLayout = new QVBoxLayout( buttonBox );
00254
00255 QPushButton *newButton = new QPushButton( i18n("&New"), buttonBox );
00256 buttonLayout->addWidget( newButton );
00257 connect( newButton, SIGNAL( clicked() ), SLOT( addNewAttendee() ) );
00258
00259 mRemoveButton = new QPushButton( i18n("&Remove"), buttonBox );
00260 buttonLayout->addWidget( mRemoveButton );
00261 connect( mRemoveButton, SIGNAL( clicked() ), SLOT( removeAttendee() ) );
00262
00263 mAddressBookButton = new QPushButton( i18n("Select Addressee..."),
00264 buttonBox );
00265 buttonLayout->addWidget( mAddressBookButton );
00266 connect( mAddressBookButton, SIGNAL( clicked() ), SLOT( openAddressBook() ) );
00267
00268 topLayout->addMultiCellWidget( mOrganizerHBox, 0, 0, 0, 5 );
00269 topLayout->addMultiCellWidget( mListView, 1, 1, 0, 5 );
00270 topLayout->addWidget( attendeeLabel, 2, 0 );
00271 topLayout->addMultiCellWidget( mNameEdit, 2, 2, 1, 1 );
00272
00273 topLayout->addWidget( attendeeRoleLabel, 3, 0 );
00274 topLayout->addWidget( mRoleCombo, 3, 1 );
00275 #if 0
00276 topLayout->setColStretch( 2, 1 );
00277 topLayout->addWidget( statusLabel, 3, 3 );
00278 topLayout->addWidget( mStatusCombo, 3, 4 );
00279 #else
00280 topLayout->addWidget( statusLabel, 4, 0 );
00281 topLayout->addWidget( mStatusCombo, 4, 1 );
00282 #endif
00283 topLayout->addMultiCellWidget( mRsvpButton, 5, 5, 0, 1 );
00284 topLayout->addMultiCellWidget( buttonBox, 2, 4, 5, 5 );
00285
00286 #ifdef KORG_NOKABC
00287 mAddressBookButton->hide();
00288 #endif
00289
00290 updateAttendeeInput();
00291 }
00292
00293 KOEditorDetails::~KOEditorDetails()
00294 {
00295 }
00296
00297 bool KOEditorDetails::eventFilter( QObject *watched, QEvent *ev)
00298 {
00299 if ( watched && watched == mNameEdit && ev->type() == QEvent::FocusIn &&
00300 mListView->childCount() == 0 ) {
00301 addNewAttendee();
00302 }
00303
00304 return QWidget::eventFilter( watched, ev );
00305 }
00306
00307 void KOEditorDetails::removeAttendee()
00308 {
00309 AttendeeListItem *aItem =
00310 static_cast<AttendeeListItem *>( mListView->selectedItem() );
00311 if ( !aItem ) return;
00312
00313 Attendee *delA = new Attendee( aItem->data()->name(), aItem->data()->email(),
00314 aItem->data()->RSVP(), aItem->data()->status(),
00315 aItem->data()->role(), aItem->data()->uid() );
00316 mdelAttendees.append( delA );
00317
00318 if ( mFreeBusy ) mFreeBusy->removeAttendee( aItem->data() );
00319 delete aItem;
00320
00321 updateAttendeeInput();
00322 }
00323
00324
00325 void KOEditorDetails::openAddressBook()
00326 {
00327 #ifndef KORG_NOKABC
00328 KPIM::AddressesDialog *dia = new KPIM::AddressesDialog( this, "adddialog" );
00329 dia->setShowCC( false );
00330 dia->setShowBCC( false );
00331 if ( dia->exec() ) {
00332 KABC::Addressee::List aList = dia->allToAddressesNoDuplicates();
00333 for ( KABC::Addressee::List::iterator itr = aList.begin();
00334 itr != aList.end(); ++itr ) {
00335 insertAttendeeFromAddressee( (*itr) );
00336 }
00337 }
00338 delete dia;
00339 return;
00340 #if 0
00341
00342 KABC::Addressee a = KABC::AddresseeDialog::getAddressee(this);
00343 if (!a.isEmpty()) {
00344
00345
00346 bool myself = KOPrefs::instance()->thatIsMe( a.preferredEmail() );
00347 KCal::Attendee::PartStat partStat =
00348 myself ? KCal::Attendee::Accepted : KCal::Attendee::NeedsAction;
00349 insertAttendee( new Attendee( a.realName(), a.preferredEmail(),
00350 !myself, partStat,
00351 KCal::Attendee::ReqParticipant, a.uid() ) );
00352 }
00353 #endif
00354 #endif
00355 }
00356
00357
00358 void KOEditorDetails::addNewAttendee()
00359 {
00360 Attendee *a = new Attendee( i18n("Firstname Lastname"),
00361 i18n("name") + "@example.net", true );
00362 insertAttendee( a, false );
00363
00364 mNameEdit->setClickMessage( "" );
00365 mNameEdit->setFocus();
00366 QTimer::singleShot( 0, mNameEdit, SLOT( selectAll() ) );
00367 }
00368
00369
00370 void KOEditorDetails::insertAttendee( Attendee *a )
00371 {
00372 insertAttendee( a, true );
00373 }
00374
00375 void KOEditorDetails::insertAttendee( Attendee *a, bool goodEmailAddress )
00376 {
00377
00378 AttendeeListItem *item = new AttendeeListItem( a, mListView,
00379 static_cast<KListViewItem*>( mListView->lastItem() ) );
00380 mListView->setSelected( item, true );
00381 if( mFreeBusy ) mFreeBusy->insertAttendee( a, goodEmailAddress );
00382 }
00383
00384 void KOEditorDetails::setDefaults()
00385 {
00386 mRsvpButton->setChecked( true );
00387 }
00388
00389 void KOEditorDetails::readEvent( Incidence *event )
00390 {
00391
00392 bool block = false;
00393 if( mFreeBusy ) {
00394 block = mFreeBusy->updateEnabled();
00395 mFreeBusy->setUpdateEnabled( false );
00396 mFreeBusy->clearAttendees();
00397 }
00398
00399 mListView->clear();
00400 mdelAttendees.clear();
00401 Attendee::List al = event->attendees();
00402 Attendee::List::ConstIterator it;
00403 for( it = al.begin(); it != al.end(); ++it )
00404 insertAttendee( new Attendee( **it ), true );
00405
00406 mListView->setSelected( mListView->firstChild(), true );
00407
00408 if ( KOPrefs::instance()->thatIsMe( event->organizer().email() ) ) {
00409 if ( !mOrganizerCombo ) {
00410 mOrganizerCombo = new QComboBox( mOrganizerHBox );
00411 fillOrganizerCombo();
00412 }
00413 mOrganizerLabel->setText( i18n( "Identity as organizer:" ) );
00414
00415
00416
00417 for ( int i = 0 ; i < mOrganizerCombo->count(); ++i ) {
00418 QString itemTxt = KPIM::getEmailAddr( mOrganizerCombo->text( i ) );
00419 if ( KPIM::compareEmail( event->organizer().email(), itemTxt, false ) ) {
00420
00421 mOrganizerCombo->changeItem( event->organizer().fullName(), i );
00422 mOrganizerCombo->setCurrentItem( i );
00423 break;
00424 }
00425 }
00426 } else {
00427 if ( mOrganizerCombo ) {
00428 delete mOrganizerCombo;
00429 mOrganizerCombo = 0;
00430 }
00431 mOrganizerLabel->setText( i18n( "Organizer: %1" ).arg( event->organizer().fullName() ) );
00432 }
00433
00434
00435 if( mFreeBusy ) mFreeBusy->setUpdateEnabled( block );
00436 }
00437
00438 void KOEditorDetails::writeEvent(Incidence *event)
00439 {
00440 event->clearAttendees();
00441 QValueVector<QListViewItem*> toBeDeleted;
00442 QListViewItem *item;
00443 AttendeeListItem *a;
00444 for (item = mListView->firstChild(); item;
00445 item = item->nextSibling()) {
00446 a = (AttendeeListItem *)item;
00447 Attendee *attendee = a->data();
00448 Q_ASSERT( attendee );
00449
00450 if ( attendee->email().isEmpty() ) {
00451 KPIM::DistributionList list =
00452 KPIM::DistributionList::findByName( KABC::StdAddressBook::self(), attendee->name() );
00453 if ( !list.isEmpty() ) {
00454 toBeDeleted.push_back( item );
00455 KPIM::DistributionList::Entry::List entries = list.entries( KABC::StdAddressBook::self() );
00456 KPIM::DistributionList::Entry::List::Iterator it( entries.begin() );
00457 while ( it != entries.end() ) {
00458 KPIM::DistributionList::Entry &e = ( *it );
00459 ++it;
00460
00461 insertAttendeeFromAddressee( e.addressee, attendee );
00462
00463 }
00464 }
00465 } else {
00466 bool skip = false;
00467 if ( attendee->email().endsWith( "example.net" ) ) {
00468 if ( KMessageBox::warningYesNo( this, i18n("%1 does not look like a valid email address. "
00469 "Are you sure you want to invite this participant?").arg( attendee->email() ),
00470 i18n("Invalid email address") ) != KMessageBox::Yes ) {
00471 skip = true;
00472 }
00473 }
00474 if ( !skip ) {
00475 event->addAttendee( new Attendee( *attendee ) );
00476 }
00477 }
00478 }
00479 if ( mOrganizerCombo ) {
00480
00481 event->setOrganizer( mOrganizerCombo->currentText() );
00482 }
00483
00484 QValueVector<QListViewItem*>::iterator it;
00485 for( it = toBeDeleted.begin(); it != toBeDeleted.end(); ++it ) {
00486 delete *it;
00487 }
00488 }
00489
00490 void KOEditorDetails::cancelAttendeeEvent(Incidence *event)
00491 {
00492 event->clearAttendees();
00493 Attendee * att;
00494 for (att=mdelAttendees.first();att;att=mdelAttendees.next()) {
00495 event->addAttendee(new Attendee(*att));
00496 }
00497 mdelAttendees.clear();
00498 }
00499
00500 bool KOEditorDetails::validateInput()
00501 {
00502 return true;
00503 }
00504
00505 void KOEditorDetails::updateAttendeeInput()
00506 {
00507
00508 setEnableAttendeeInput(!mNameEdit->text().isEmpty());
00509 QListViewItem *item = mListView->selectedItem();
00510 AttendeeListItem *aItem = static_cast<AttendeeListItem *>( item );
00511 if (aItem) {
00512 fillAttendeeInput( aItem );
00513 } else {
00514 clearAttendeeInput();
00515 }
00516 }
00517
00518 void KOEditorDetails::clearAttendeeInput()
00519 {
00520 mNameEdit->setText("");
00521 mUidEdit->setText("");
00522 mRoleCombo->setCurrentItem(0);
00523 mStatusCombo->setCurrentItem(0);
00524 mRsvpButton->setChecked(true);
00525 setEnableAttendeeInput( false );
00526 }
00527
00528 void KOEditorDetails::fillAttendeeInput( AttendeeListItem *aItem )
00529 {
00530 Attendee *a = aItem->data();
00531 mDisableItemUpdate = true;
00532 QString name = a->name();
00533 if (!a->email().isEmpty()) {
00534
00535 QRegExp needQuotes( "[^ 0-9A-Za-z\\x0080-\\xFFFF]" );
00536 if ( name.find( needQuotes ) != -1 )
00537 name = "\"" + name + "\" <" + a->email() + ">";
00538 else
00539 name += " <" + a->email() + ">";
00540 }
00541 mNameEdit->setText(name);
00542 mUidEdit->setText(a->uid());
00543 mRoleCombo->setCurrentItem(a->role());
00544 mStatusCombo->setCurrentItem(a->status());
00545 mRsvpButton->setChecked(a->RSVP());
00546
00547 mDisableItemUpdate = false;
00548
00549 setEnableAttendeeInput( true );
00550 }
00551
00552 void KOEditorDetails::setEnableAttendeeInput( bool enabled )
00553 {
00554
00555 mRoleCombo->setEnabled( enabled );
00556 mStatusCombo->setEnabled( enabled );
00557 mRsvpButton->setEnabled( enabled );
00558
00559 mRemoveButton->setEnabled( enabled );
00560 }
00561
00562 void KOEditorDetails::updateAttendeeItem()
00563 {
00564 if (mDisableItemUpdate) return;
00565
00566 QListViewItem *item = mListView->selectedItem();
00567 AttendeeListItem *aItem = static_cast<AttendeeListItem *>( item );
00568 if ( !aItem ) return;
00569
00570 Attendee *a = aItem->data();
00571 QString name;
00572 QString email;
00573 KPIM::getNameAndMail(mNameEdit->text(), name, email);
00574
00575 bool iAmTheOrganizer = mOrganizerCombo &&
00576 KOPrefs::instance()->thatIsMe( mOrganizerCombo->currentText() );
00577 if ( iAmTheOrganizer ) {
00578 bool myself =
00579 KPIM::compareEmail( email, mOrganizerCombo->currentText(), false );
00580 bool wasMyself =
00581 KPIM::compareEmail( a->email(), mOrganizerCombo->currentText(), false );
00582 if ( myself ) {
00583 mStatusCombo->setCurrentItem( KCal::Attendee::Accepted );
00584 mRsvpButton->setChecked( false );
00585 mRsvpButton->setEnabled( false );
00586 } else if ( wasMyself ) {
00587
00588 mStatusCombo->setCurrentItem( KCal::Attendee::NeedsAction );
00589 mRsvpButton->setChecked( true );
00590 mRsvpButton->setEnabled( true );
00591 }
00592 }
00593 a->setName( name );
00594 a->setUid( mUidEdit->text() );
00595 a->setEmail( email );
00596 a->setRole( Attendee::Role( mRoleCombo->currentItem() ) );
00597 a->setStatus( Attendee::PartStat( mStatusCombo->currentItem() ) );
00598 a->setRSVP( mRsvpButton->isChecked() );
00599 aItem->updateItem();
00600 if ( mFreeBusy ) mFreeBusy->updateAttendee( a );
00601 }
00602
00603 void KOEditorDetails::setFreeBusyWidget( KOEditorFreeBusy *v )
00604 {
00605 mFreeBusy = v;
00606 }
00607
00608 void KOEditorDetails::fillOrganizerCombo()
00609 {
00610 Q_ASSERT( mOrganizerCombo );
00611
00612
00613 const QStringList lst = KOPrefs::instance()->fullEmails();
00614 QStringList uniqueList;
00615 for( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
00616 if ( uniqueList.find( *it ) == uniqueList.end() )
00617 uniqueList << *it;
00618 }
00619 mOrganizerCombo->insertStringList( uniqueList );
00620 }
00621
00622 void KOEditorDetails::insertAttendeeFromAddressee( const KABC::Addressee& a,
00623 const Attendee* at )
00624 {
00625 bool myself = KOPrefs::instance()->thatIsMe( a.preferredEmail() );
00626 bool sameAsOrganizer = mOrganizerCombo &&
00627 KPIM::compareEmail( a.preferredEmail(), mOrganizerCombo->currentText(), false );
00628 KCal::Attendee::PartStat partStat = at? at->status() : KCal::Attendee::NeedsAction;
00629 bool rsvp = at? at->RSVP() : true;
00630
00631 if ( myself && sameAsOrganizer ) {
00632 partStat = KCal::Attendee::Accepted;
00633 rsvp = false;
00634 }
00635 Attendee *newAt = new Attendee( a.realName(),
00636 a.preferredEmail(),
00637 !myself, partStat,
00638 at ? at->role() : Attendee::ReqParticipant,
00639 a.uid() );
00640 newAt->setRSVP( rsvp );
00641 insertAttendee( newAt, true );
00642 }
00643 #include "koeditordetails.moc"