korganizer

koattendeeeditor.cpp

00001 /*
00002     Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
00003     Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00004     Copyright (c) 2007 Volker Krause <vkrause@kde.org>
00005 
00006         This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "koattendeeeditor.h"
00022 #include "koprefs.h"
00023 #include "koglobals.h"
00024 
00025 #ifndef KORG_NOKABC
00026 #include <kabc/addresseedialog.h>
00027 #include <libkdepim/addressesdialog.h>
00028 #include <libkdepim/addresseelineedit.h>
00029 #endif
00030 
00031 #include <libkcal/incidence.h>
00032 
00033 #include <libemailfunctions/email.h>
00034 
00035 #include <kiconloader.h>
00036 #include <klocale.h>
00037 #include <kmessagebox.h>
00038 
00039 #include <qcheckbox.h>
00040 #include <qcombobox.h>
00041 #include <qhbox.h>
00042 #include <qlabel.h>
00043 #include <qlayout.h>
00044 #include <qpushbutton.h>
00045 #include <qwhatsthis.h>
00046 
00047 using namespace KCal;
00048 
00049 KOAttendeeEditor::KOAttendeeEditor( QWidget * parent, const char *name ) :
00050     QWidget( parent, name ),
00051     mDisableItemUpdate( true )
00052 {
00053 }
00054 
00055 void KOAttendeeEditor::initOrganizerWidgets(QWidget * parent, QBoxLayout * layout)
00056 {
00057   mOrganizerHBox = new QHBox( parent );
00058   layout->addWidget( mOrganizerHBox );
00059   // If creating a new event, then the user is the organizer -> show the
00060   // identity combo
00061   // readEvent will delete it and set another label text instead, if the user
00062   // isn't the organizer.
00063   // Note that the i18n text below is duplicated in readEvent
00064   QString whatsThis = i18n("Sets the identity corresponding to "
00065                            "the organizer of this to-do or event. "
00066                            "Identities can be set in the 'Personal' "
00067                            "section of the KOrganizer configuration, or in the "
00068                            "'Security & Privacy'->'Password & User Account' "
00069                            "section of the KDE Control Center. In addition, "
00070                            "identities are gathered from your KMail settings "
00071                            "and from your address book. If you choose "
00072                            "to set it globally for KDE in the Control Center, "
00073                            "be sure to check 'Use email settings from "
00074                            "Control Center' in the 'Personal' section of the "
00075                            "KOrganizer configuration.");
00076   mOrganizerLabel = new QLabel( i18n( "Identity as organizer:" ),
00077                                 mOrganizerHBox );
00078   mOrganizerCombo = new QComboBox( mOrganizerHBox );
00079   QWhatsThis::add( mOrganizerLabel, whatsThis );
00080   QWhatsThis::add( mOrganizerCombo, whatsThis );
00081   fillOrganizerCombo();
00082   mOrganizerHBox->setStretchFactor( mOrganizerCombo, 100 );
00083 }
00084 
00085 void KOAttendeeEditor::initEditWidgets(QWidget * parent, QBoxLayout * layout)
00086 {
00087   QGridLayout *topLayout = new QGridLayout();
00088   layout->addLayout( topLayout );
00089 
00090   QString whatsThis = i18n("Edits the name of the attendee selected in the list "
00091                            "above, or adds a new attendee if there are no attendees"
00092                            "in the list.");
00093   QLabel *attendeeLabel = new QLabel( parent );
00094   QWhatsThis::add( attendeeLabel, whatsThis );
00095   attendeeLabel->setText( i18n("Na&me:") );
00096   topLayout->addWidget( attendeeLabel, 0, 0 );
00097 
00098   mNameEdit = new KPIM::AddresseeLineEdit( parent );
00099   QWhatsThis::add( mNameEdit, whatsThis );
00100   mNameEdit->setClickMessage( i18n("Click to add a new attendee") );
00101   attendeeLabel->setBuddy( mNameEdit );
00102   mNameEdit->installEventFilter( this );
00103   connect( mNameEdit, SIGNAL( textChanged( const QString & ) ),
00104            SLOT( updateAttendee() ) );
00105   topLayout->addMultiCellWidget( mNameEdit, 0, 0, 1, 2 );
00106 
00107   whatsThis = i18n("Edits the role of the attendee selected "
00108                    "in the list above.");
00109   QLabel *attendeeRoleLabel = new QLabel( parent );
00110   QWhatsThis::add( attendeeRoleLabel, whatsThis );
00111   attendeeRoleLabel->setText( i18n("Ro&le:") );
00112   topLayout->addWidget( attendeeRoleLabel, 1, 0 );
00113 
00114   mRoleCombo = new QComboBox( false, parent );
00115   QWhatsThis::add( mRoleCombo, whatsThis );
00116   mRoleCombo->insertStringList( Attendee::roleList() );
00117   attendeeRoleLabel->setBuddy( mRoleCombo );
00118   connect( mRoleCombo, SIGNAL( activated( int ) ),
00119            SLOT( updateAttendee() ) );
00120   topLayout->addWidget( mRoleCombo, 1, 1 );
00121 
00122   mDelegateLabel = new QLabel( parent );
00123   topLayout->addWidget( mDelegateLabel, 1, 2 );
00124 
00125   whatsThis = i18n("Edits the current attendance status of the attendee "
00126                    "selected in the list above.");
00127   QLabel *statusLabel = new QLabel( parent );
00128   QWhatsThis::add( statusLabel, whatsThis );
00129   statusLabel->setText( i18n("Stat&us:") );
00130   topLayout->addWidget( statusLabel, 2, 0 );
00131 
00132   mStatusCombo = new QComboBox( false, parent );
00133   QWhatsThis::add( mStatusCombo, whatsThis );
00134 //   mStatusCombo->insertStringList( Attendee::statusList() );
00135   mStatusCombo->insertItem( SmallIcon( "help" ), Attendee::statusName( Attendee::NeedsAction ) );
00136   mStatusCombo->insertItem( KOGlobals::self()->smallIcon( "ok" ), Attendee::statusName( Attendee::Accepted ) );
00137   mStatusCombo->insertItem( KOGlobals::self()->smallIcon( "no" ), Attendee::statusName( Attendee::Declined ) );
00138   mStatusCombo->insertItem( KOGlobals::self()->smallIcon( "apply" ), Attendee::statusName( Attendee::Tentative ) );
00139   mStatusCombo->insertItem( KOGlobals::self()->smallIcon( "mail_forward" ), Attendee::statusName( Attendee::Delegated ) );
00140   mStatusCombo->insertItem( Attendee::statusName( Attendee::Completed ) );
00141   mStatusCombo->insertItem( KOGlobals::self()->smallIcon( "help" ), Attendee::statusName( Attendee::InProcess ) );
00142 
00143   statusLabel->setBuddy( mStatusCombo );
00144   connect( mStatusCombo, SIGNAL( activated( int ) ),
00145            SLOT( updateAttendee() ) );
00146   topLayout->addWidget( mStatusCombo, 2, 1 );
00147 
00148   topLayout->setColStretch( 2, 1 );
00149 
00150   mRsvpButton = new QCheckBox( parent );
00151   QWhatsThis::add( mRsvpButton,
00152            i18n("Edits whether to send an email to the attendee "
00153             "selected in the list above to request "
00154             "a response concerning attendance.") );
00155   mRsvpButton->setText( i18n("Re&quest response") );
00156   connect( mRsvpButton, SIGNAL( clicked() ), SLOT( updateAttendee() ) );
00157   topLayout->addWidget( mRsvpButton, 2, 2 );
00158 
00159   QWidget *buttonBox = new QWidget( parent );
00160   QVBoxLayout *buttonLayout = new QVBoxLayout( buttonBox );
00161 
00162   mAddButton = new QPushButton( i18n("&New"), buttonBox );
00163   QWhatsThis::add( mAddButton,
00164            i18n("Adds a new attendee to the list. Once the "
00165             "attendee is added, you will be able to "
00166             "edit the attendee's name, role, attendance "
00167             "status, and whether or not the attendee is required "
00168             "to respond to the invitation. To select an attendee "
00169             "from your addressbook, click the 'Select Addressee' "
00170             "button instead.") );
00171   buttonLayout->addWidget( mAddButton );
00172   connect( mAddButton, SIGNAL( clicked() ), SLOT( addNewAttendee() ) );
00173 
00174   mRemoveButton = new QPushButton( i18n("&Remove"), buttonBox );
00175   QWhatsThis::add( mRemoveButton,
00176            i18n("Removes the attendee selected in "
00177             "the list above.") );
00178   buttonLayout->addWidget( mRemoveButton );
00179 
00180   mAddressBookButton = new QPushButton( i18n("Select Addressee..."),
00181                                         buttonBox );
00182   QWhatsThis::add( mAddressBookButton,
00183            i18n("Opens your address book, allowing you to select "
00184             "new attendees from it.") );
00185   buttonLayout->addWidget( mAddressBookButton );
00186   connect( mAddressBookButton, SIGNAL( clicked() ), SLOT( openAddressBook() ) );
00187 
00188   topLayout->addMultiCellWidget( buttonBox, 0, 3, 3, 3 );
00189 
00190 #ifdef KORG_NOKABC
00191   mAddressBookButton->hide();
00192 #endif
00193 }
00194 
00195 void KOAttendeeEditor::openAddressBook()
00196 {
00197 #ifndef KORG_NOKABC
00198   KPIM::AddressesDialog *dia = new KPIM::AddressesDialog( this, "adddialog" );
00199   dia->setShowCC( false );
00200   dia->setShowBCC( false );
00201   if ( dia->exec() ) {
00202     KABC::Addressee::List aList = dia->allToAddressesNoDuplicates();
00203     for ( KABC::Addressee::List::iterator itr = aList.begin();
00204           itr != aList.end(); ++itr ) {
00205       insertAttendeeFromAddressee( (*itr) );
00206     }
00207   }
00208   delete dia;
00209   return;
00210 #if 0
00211     // old code
00212     KABC::Addressee a = KABC::AddresseeDialog::getAddressee(this);
00213     if (!a.isEmpty()) {
00214         // If this is myself, I don't want to get a response but instead
00215         // assume I will be available
00216         bool myself = KOPrefs::instance()->thatIsMe( a.preferredEmail() );
00217         KCal::Attendee::PartStat partStat =
00218             myself ? KCal::Attendee::Accepted : KCal::Attendee::NeedsAction;
00219         insertAttendee( new Attendee( a.realName(), a.preferredEmail(),
00220                                       !myself, partStat,
00221                                       KCal::Attendee::ReqParticipant, a.uid() ) );
00222     }
00223 #endif
00224 #endif
00225 }
00226 
00227 void KOAttendeeEditor::insertAttendeeFromAddressee(const KABC::Addressee &a, const Attendee * at)
00228 {
00229   bool myself = KOPrefs::instance()->thatIsMe( a.preferredEmail() );
00230   bool sameAsOrganizer = mOrganizerCombo &&
00231   KPIM::compareEmail( a.preferredEmail(), mOrganizerCombo->currentText(), false );
00232   KCal::Attendee::PartStat partStat = at? at->status() : KCal::Attendee::NeedsAction;
00233   bool rsvp = at? at->RSVP() : true;
00234 
00235   if ( myself && sameAsOrganizer ) {
00236     partStat = KCal::Attendee::Accepted;
00237     rsvp = false;
00238   }
00239   Attendee *newAt = new Attendee( a.realName(),
00240                                a.preferredEmail(),
00241                                !myself, partStat,
00242                                at ? at->role() : Attendee::ReqParticipant,
00243                                a.uid() );
00244   newAt->setRSVP( rsvp );
00245   insertAttendee( newAt, true );
00246 }
00247 
00248 void KOAttendeeEditor::fillOrganizerCombo()
00249 {
00250   Q_ASSERT( mOrganizerCombo );
00251   // Get all emails from KOPrefs (coming from various places),
00252   // and insert them - removing duplicates
00253   const QStringList lst = KOPrefs::instance()->fullEmails();
00254   QStringList uniqueList;
00255   for( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
00256     if ( uniqueList.find( *it ) == uniqueList.end() )
00257       uniqueList << *it;
00258   }
00259   mOrganizerCombo->insertStringList( uniqueList );
00260 }
00261 
00262 void KOAttendeeEditor::addNewAttendee()
00263 {
00264   // check if there's still an unchanged example entry, and if so
00265   // suggest to edit that first
00266   if ( QListViewItem* item = hasExampleAttendee() ) {
00267       KMessageBox::information( this,
00268           i18n( "Please edit the example attendee, before adding more." ), QString::null,
00269           "EditExistingExampleAttendeeFirst" );
00270       // make sure the example attendee is selected
00271       item->setSelected( true );
00272       item->listView()->setCurrentItem( item );
00273       return;
00274   }
00275   Attendee *a = new Attendee( i18n("Firstname Lastname"),
00276                               i18n("name") + "@example.net", true );
00277   insertAttendee( a, false );
00278   mnewAttendees.append(a);
00279   updateAttendeeInput();
00280   // We don't want the hint again
00281   mNameEdit->setClickMessage( "" );
00282   mNameEdit->setFocus();
00283   QTimer::singleShot( 0, mNameEdit, SLOT( selectAll() ) );
00284 }
00285 
00286 void KOAttendeeEditor::readEvent(KCal::Incidence * incidence)
00287 {
00288   mdelAttendees.clear();
00289   mnewAttendees.clear();
00290   if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) || incidence->organizer().isEmpty() ) {
00291     if ( !mOrganizerCombo ) {
00292       mOrganizerCombo = new QComboBox( mOrganizerHBox );
00293       fillOrganizerCombo();
00294     }
00295     mOrganizerLabel->setText( i18n( "Identity as organizer:" ) );
00296 
00297     int found = -1;
00298     QString fullOrganizer = incidence->organizer().fullName();
00299     for ( int i = 0 ; i < mOrganizerCombo->count(); ++i ) {
00300       if ( mOrganizerCombo->text( i ) == fullOrganizer ) {
00301         found = i;
00302         mOrganizerCombo->setCurrentItem( i );
00303         break;
00304       }
00305     }
00306     if ( found < 0 ) {
00307       mOrganizerCombo->insertItem( fullOrganizer, 0 );
00308       mOrganizerCombo->setCurrentItem( 0 );
00309     }
00310   } else { // someone else is the organizer
00311     if ( mOrganizerCombo ) {
00312       delete mOrganizerCombo;
00313       mOrganizerCombo = 0;
00314     }
00315     mOrganizerLabel->setText( i18n( "Organizer: %1" ).arg( incidence->organizer().fullName() ) );
00316   }
00317 
00318   Attendee::List al = incidence->attendees();
00319   Attendee::List::ConstIterator it;
00320   Attendee *first = 0;
00321   for( it = al.begin(); it != al.end(); ++it ) {
00322     Attendee *a = new Attendee( **it );
00323     if ( !first ) {
00324       first = a;
00325     }
00326     insertAttendee( a, true );
00327   }
00328 
00329   // Set the initial editing values to the first attendee in the list.
00330   if ( first ) {
00331     mNameEdit->setText( first->fullName() );
00332     mUid = first->uid();
00333     mRoleCombo->setCurrentItem( first->role() );
00334     if ( first->status() != KCal::Attendee::None ) {
00335       mStatusCombo->setCurrentItem( first->status() );
00336     } else {
00337       mStatusCombo->setCurrentItem( KCal::Attendee::NeedsAction );
00338     }
00339     mRsvpButton->setChecked( first->RSVP() );
00340     mRsvpButton->setEnabled( true );
00341   }
00342 }
00343 
00344 void KOAttendeeEditor::writeEvent(KCal::Incidence * incidence)
00345 {
00346   if ( mOrganizerCombo ) {
00347     // TODO: Don't take a string and split it up... Is there a better way?
00348     incidence->setOrganizer( mOrganizerCombo->currentText() );
00349   }
00350 }
00351 
00352 void KOAttendeeEditor::setEnableAttendeeInput(bool enabled)
00353 {
00354   //mNameEdit->setEnabled( enabled );
00355   mRoleCombo->setEnabled( enabled );
00356   mStatusCombo->setEnabled( enabled );
00357   mRsvpButton->setEnabled( enabled );
00358 
00359   mRemoveButton->setEnabled( enabled );
00360 }
00361 
00362 void KOAttendeeEditor::clearAttendeeInput()
00363 {
00364   mNameEdit->setText("");
00365   mUid = QString::null;
00366   mRoleCombo->setCurrentItem(0);
00367   mStatusCombo->setCurrentItem(0);
00368   mRsvpButton->setChecked(true);
00369   setEnableAttendeeInput( false );
00370   mDelegateLabel->setText( QString() );
00371 }
00372 
00373 void KOAttendeeEditor::updateAttendee()
00374 {
00375   Attendee *a = currentAttendee();
00376   if ( !a || mDisableItemUpdate )
00377     return;
00378 
00379   QString name;
00380   QString email;
00381   KPIM::getNameAndMail(mNameEdit->text(), name, email);
00382 
00383   bool iAmTheOrganizer = mOrganizerCombo &&
00384     KOPrefs::instance()->thatIsMe( mOrganizerCombo->currentText() );
00385   if ( iAmTheOrganizer ) {
00386     bool myself =
00387       KPIM::compareEmail( email, mOrganizerCombo->currentText(), false );
00388     bool wasMyself =
00389       KPIM::compareEmail( a->email(), mOrganizerCombo->currentText(), false );
00390     if ( myself ) {
00391       mRsvpButton->setChecked( false );
00392       mRsvpButton->setEnabled( false );
00393     } else if ( wasMyself ) {
00394       // this was me, but is no longer, reset
00395       mStatusCombo->setCurrentItem( KCal::Attendee::NeedsAction );
00396       mRsvpButton->setChecked( true );
00397       mRsvpButton->setEnabled( true );
00398     }
00399   }
00400   a->setName( name );
00401   a->setUid( mUid );
00402   a->setEmail( email );
00403   a->setRole( Attendee::Role( mRoleCombo->currentItem() ) );
00404   a->setStatus( Attendee::PartStat( mStatusCombo->currentItem() ) );
00405   a->setRSVP( mRsvpButton->isChecked() );
00406 
00407   updateCurrentItem();
00408 }
00409 
00410 void KOAttendeeEditor::fillAttendeeInput( KCal::Attendee *a )
00411 {
00412   mDisableItemUpdate = true;
00413 
00414   QString tname, temail;
00415   QString username = a->name();
00416   if ( !a->email().isEmpty() ) {
00417     username = KPIM::quoteNameIfNecessary( username );
00418 
00419     KPIM::getNameAndMail( username, tname, temail ); // ignore return value
00420                                                      // which is always false
00421     tname += " <" + a->email() + '>';
00422   }
00423 
00424   bool myself = KOPrefs::instance()->thatIsMe( a->email() );
00425   bool sameAsOrganizer = mOrganizerCombo &&
00426           KPIM::compareEmail( a->email(),
00427                                    mOrganizerCombo->currentText(), false );
00428   KCal::Attendee::PartStat partStat = a->status();
00429   bool rsvp = a->RSVP();
00430 
00431   if ( myself && sameAsOrganizer && a->status() == KCal::Attendee::None ) {
00432       partStat = KCal::Attendee::Accepted;
00433       rsvp = false;
00434   }
00435 
00436   mNameEdit->setText(tname);
00437   mUid = a->uid();
00438   mRoleCombo->setCurrentItem(a->role());
00439   if ( partStat != KCal::Attendee::None ) {
00440     mStatusCombo->setCurrentItem( partStat );
00441   } else {
00442     mStatusCombo->setCurrentItem( KCal::Attendee::NeedsAction );
00443   }
00444   mRsvpButton->setChecked( rsvp );
00445 
00446   mDisableItemUpdate = false;
00447   setEnableAttendeeInput( true );
00448 
00449   if ( a->status() == Attendee::Delegated ) {
00450     if ( !a->delegate().isEmpty() )
00451       mDelegateLabel->setText( i18n( "Delegated to %1" ).arg( a->delegate() ) );
00452     else if ( !a->delegator().isEmpty() )
00453       mDelegateLabel->setText( i18n( "Delegated from %1" ).arg( a->delegator() ) );
00454     else
00455       mDelegateLabel->setText( i18n( "Not delegated" ) );
00456   }
00457   if( myself )
00458     mRsvpButton->setEnabled( false );
00459 
00460 }
00461 
00462 void KOAttendeeEditor::updateAttendeeInput()
00463 {
00464   setEnableAttendeeInput(!mNameEdit->text().isEmpty());
00465   Attendee* a = currentAttendee();
00466   if ( a ) {
00467     fillAttendeeInput( a );
00468   } else {
00469     clearAttendeeInput();
00470   }
00471 }
00472 
00473 void KOAttendeeEditor::cancelAttendeeEvent( KCal::Incidence *incidence )
00474 {
00475   incidence->clearAttendees();
00476   Attendee * att;
00477   for (att=mdelAttendees.first();att;att=mdelAttendees.next()) {
00478     bool isNewAttendee = false;
00479     for (Attendee *newAtt=mnewAttendees.first();newAtt;newAtt=mnewAttendees.next()) {
00480       if (*att==*newAtt) {
00481         isNewAttendee = true;
00482         break;
00483       }
00484     }
00485     if (!isNewAttendee) {
00486       incidence->addAttendee(new Attendee(*att));
00487     }
00488   }
00489   mdelAttendees.clear();
00490 }
00491 
00492 void KOAttendeeEditor::acceptForMe()
00493 {
00494   changeStatusForMe( Attendee::Accepted );
00495 }
00496 
00497 void KOAttendeeEditor::declineForMe()
00498 {
00499   changeStatusForMe( Attendee::Declined );
00500 }
00501 
00502 bool KOAttendeeEditor::eventFilter(QObject *watched, QEvent *ev)
00503 {
00504   if ( watched && watched == mNameEdit && ev->type() == QEvent::FocusIn &&
00505        currentAttendee() == 0 ) {
00506     addNewAttendee();
00507   }
00508 
00509   return QWidget::eventFilter( watched, ev );
00510 }
00511 
00512 bool KOAttendeeEditor::isExampleAttendee( const KCal::Attendee* attendee ) const
00513 {
00514     if ( !attendee ) return false;
00515     if ( attendee->name() == i18n( "Firstname Lastname" )
00516         && attendee->email().endsWith( "example.net" ) ) {
00517         return true;
00518     }
00519     return false;
00520 }
00521 
00522 #include "koattendeeeditor.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys