korganizer

koeditordetails.cpp

00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
00005     Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020 
00021     As a special exception, permission is given to link this program
00022     with any edition of Qt, and distribute the resulting executable,
00023     without including the source code for Qt in the source distribution.
00024 */
00025 
00026 #include "koeditordetails.h"
00027 
00028 #include <qbuttongroup.h>
00029 #include <qcheckbox.h>
00030 #include <qcombobox.h>
00031 #include <qdatetime.h>
00032 #include <qdragobject.h>
00033 #include <qfiledialog.h>
00034 #include <qgroupbox.h>
00035 #include <qlabel.h>
00036 #include <qlayout.h>
00037 #include <qlineedit.h>
00038 #include <qpushbutton.h>
00039 #include <qradiobutton.h>
00040 #include <qregexp.h>
00041 #include <qtooltip.h>
00042 #include <qvbox.h>
00043 #include <qvgroupbox.h>
00044 #include <qwhatsthis.h>
00045 #include <qwidgetstack.h>
00046 #include <qvaluevector.h>
00047 
00048 #include <kdebug.h>
00049 #include <klocale.h>
00050 #include <kiconloader.h>
00051 #include <kmessagebox.h>
00052 #ifndef KORG_NOKABC
00053 #include <kabc/addresseedialog.h>
00054 #include <kabc/vcardconverter.h>
00055 #include <libkdepim/addressesdialog.h>
00056 #include <libkdepim/addresseelineedit.h>
00057 #include <libkdepim/distributionlist.h>
00058 #include <kabc/stdaddressbook.h>
00059 #endif
00060 #include <libkdepim/kvcarddrag.h>
00061 #include <libemailfunctions/email.h>
00062 
00063 #include <libkcal/incidence.h>
00064 
00065 #include "koprefs.h"
00066 #include "koglobals.h"
00067 
00068 #include "koeditorfreebusy.h"
00069 
00070 #include "kocore.h"
00071 
00072 template <>
00073 CustomListViewItem<KCal::Attendee *>::~CustomListViewItem()
00074 {
00075   delete mData;
00076 }
00077 
00078 template <>
00079 void CustomListViewItem<KCal::Attendee *>::updateItem()
00080 {
00081   setText(0,mData->name());
00082   setText(1,mData->email());
00083   setText(2,mData->roleStr());
00084   setText(3,mData->statusStr());
00085   if (mData->RSVP() && !mData->email().isEmpty())
00086     setPixmap(4,KOGlobals::self()->smallIcon("mailappt"));
00087   else
00088     setPixmap(4,KOGlobals::self()->smallIcon("nomailappt"));
00089   setText(5, mData->delegate());
00090   setText(6, mData->delegator());
00091 }
00092 
00093 KOAttendeeListView::KOAttendeeListView ( QWidget *parent, const char *name )
00094   : KListView(parent, name)
00095 {
00096   setAcceptDrops( true );
00097   setAllColumnsShowFocus( true );
00098   setSorting( -1 );
00099 }
00100 
00106 KOAttendeeListView::~KOAttendeeListView()
00107 {
00108 }
00109 
00110 void KOAttendeeListView::contentsDragEnterEvent( QDragEnterEvent *e )
00111 {
00112   dragEnterEvent(e);
00113 }
00114 
00115 void KOAttendeeListView::contentsDragMoveEvent( QDragMoveEvent *e )
00116 {
00117 #ifndef KORG_NODND
00118   if ( KVCardDrag::canDecode( e ) || QTextDrag::canDecode( e ) ) {
00119     e->accept();
00120   } else {
00121     e->ignore();
00122   }
00123 #endif
00124 }
00125 
00126 void KOAttendeeListView::dragEnterEvent( QDragEnterEvent *e )
00127 {
00128 #ifndef KORG_NODND
00129   if ( KVCardDrag::canDecode( e ) || QTextDrag::canDecode( e ) ) {
00130     e->accept();
00131   } else {
00132     e->ignore();
00133   }
00134 #endif
00135 }
00136 
00137 void KOAttendeeListView::addAttendee( const QString &newAttendee )
00138 {
00139   kdDebug(5850) << " Email: " << newAttendee << endl;
00140   QString name;
00141   QString email;
00142   KPIM::getNameAndMail( newAttendee, name, email );
00143   emit dropped( new Attendee( name, email, true ) );
00144 }
00145 
00146 void KOAttendeeListView::contentsDropEvent( QDropEvent *e )
00147 {
00148   dropEvent(e);
00149 }
00150 
00151 void KOAttendeeListView::dropEvent( QDropEvent *e )
00152 {
00153 #ifndef KORG_NODND
00154   QString text;
00155   QString vcards;
00156 
00157 #ifndef KORG_NOKABC
00158   if ( KVCardDrag::decode( e, vcards ) ) {
00159     KABC::VCardConverter converter;
00160 
00161     KABC::Addressee::List list = converter.parseVCards( vcards );
00162     KABC::Addressee::List::Iterator it;
00163     for ( it = list.begin(); it != list.end(); ++it ) {
00164       QString em( (*it).fullEmail() );
00165       if (em.isEmpty()) {
00166         em=(*it).realName();
00167       }
00168       addAttendee( em );
00169     }
00170   } else
00171 #endif // KORG_NOKABC
00172   if (QTextDrag::decode(e,text)) {
00173     kdDebug(5850) << "Dropped : " << text << endl;
00174     QStringList emails = QStringList::split(",",text);
00175     for(QStringList::ConstIterator it = emails.begin();it!=emails.end();++it) {
00176       addAttendee(*it);
00177     }
00178   }
00179 #endif //KORG_NODND
00180 }
00181 
00182 
00183 KOEditorDetails::KOEditorDetails( int spacing, QWidget *parent,
00184                                   const char *name )
00185   : KOAttendeeEditor( parent, name), mDisableItemUpdate( false )
00186 {
00187   QBoxLayout *topLayout = new QVBoxLayout( this );
00188   topLayout->setSpacing( spacing );
00189 
00190   initOrganizerWidgets( this, topLayout );
00191 
00192   mListView = new KOAttendeeListView( this, "mListView" );
00193   QWhatsThis::add( mListView,
00194            i18n("Displays information about current attendees. "
00195             "To edit an attendee, select it in this list "
00196             "and modify the values in the area below. "
00197             "Clicking on a column title will sort the list "
00198             "according to that column. The RSVP column "
00199             "indicates whether or not a response is requested "
00200             "from the attendee.") );
00201   mListView->addColumn( i18n("Name"), 200 );
00202   mListView->addColumn( i18n("Email"), 200 );
00203   mListView->addColumn( i18n("Role"), 80 );
00204   mListView->addColumn( i18n("Status"), 100 );
00205   mListView->addColumn( i18n("RSVP"), 55 );
00206   mListView->addColumn( i18n("Delegated to"), 120 );
00207   mListView->addColumn( i18n("Delegated from" ), 120 );
00208   mListView->setResizeMode( QListView::LastColumn );
00209   if ( KOPrefs::instance()->mCompactDialogs ) {
00210     mListView->setFixedHeight( 78 );
00211   }
00212 
00213   connect( mListView, SIGNAL( selectionChanged( QListViewItem * ) ),
00214            SLOT( updateAttendeeInput() ) );
00215 #ifndef KORG_NODND
00216   connect( mListView, SIGNAL( dropped( Attendee * ) ),
00217            SLOT( slotInsertAttendee( Attendee * ) ) );
00218 #endif
00219   topLayout->addWidget( mListView );
00220 
00221   initEditWidgets( this, topLayout );
00222 
00223   connect( mRemoveButton, SIGNAL(clicked()), SLOT(removeAttendee()) );
00224 
00225   updateAttendeeInput();
00226 }
00227 
00228 KOEditorDetails::~KOEditorDetails()
00229 {
00230 }
00231 
00232 bool KOEditorDetails::hasAttendees()
00233 {
00234   return mListView->childCount() > 0;
00235 }
00236 
00237 void KOEditorDetails::removeAttendee()
00238 {
00239   AttendeeListItem *aItem =
00240       static_cast<AttendeeListItem *>( mListView->selectedItem() );
00241   if ( !aItem ) return;
00242 
00243   AttendeeListItem *nextSelectedItem = static_cast<AttendeeListItem*>( aItem->nextSibling() );
00244   if( mListView->childCount() == 1 )
00245       nextSelectedItem = 0;
00246   if( mListView->childCount() > 1 && aItem == mListView->lastItem() )
00247       nextSelectedItem = static_cast<AttendeeListItem*>(  mListView->firstChild() );
00248 
00249   Attendee *delA = new Attendee( aItem->data()->name(), aItem->data()->email(),
00250                                  aItem->data()->RSVP(), aItem->data()->status(),
00251                                  aItem->data()->role(), aItem->data()->uid() );
00252   mdelAttendees.append( delA );
00253 
00254   delete aItem;
00255 
00256   if( nextSelectedItem )
00257       mListView->setSelected( nextSelectedItem, true );
00258   updateAttendeeInput();
00259   emit updateAttendeeSummary( mListView->childCount() );
00260 }
00261 
00262 
00263 void KOEditorDetails::insertAttendee( Attendee *a, bool goodEmailAddress )
00264 {
00265   Q_UNUSED( goodEmailAddress );
00266 
00267   // lastItem() is O(n), but for n very small that should be fine
00268   AttendeeListItem *item = new AttendeeListItem( a, mListView,
00269       static_cast<KListViewItem*>( mListView->lastItem() ) );
00270   mListView->setSelected( item, true );
00271   emit updateAttendeeSummary( mListView->childCount() );
00272 }
00273 
00274 void KOEditorDetails::setDefaults()
00275 {
00276   mRsvpButton->setChecked( true );
00277 }
00278 
00279 void KOEditorDetails::readEvent( Incidence *event )
00280 {
00281   mListView->clear();
00282   KOAttendeeEditor::readEvent( event );
00283 
00284   mListView->setSelected( mListView->firstChild(), true );
00285 
00286   emit updateAttendeeSummary( mListView->childCount() );
00287 }
00288 
00289 void KOEditorDetails::writeEvent(Incidence *event)
00290 {
00291   event->clearAttendees();
00292   QValueVector<QListViewItem*> toBeDeleted;
00293   QListViewItem *item;
00294   AttendeeListItem *a;
00295   for (item = mListView->firstChild(); item;
00296        item = item->nextSibling()) {
00297     a = (AttendeeListItem *)item;
00298     Attendee *attendee = a->data();
00299     Q_ASSERT( attendee );
00300     /* Check if the attendee is a distribution list and expand it */
00301     if ( attendee->email().isEmpty() ) {
00302       KPIM::DistributionList list =
00303         KPIM::DistributionList::findByName( KABC::StdAddressBook::self(), attendee->name() );
00304       if ( !list.isEmpty() ) {
00305         toBeDeleted.push_back( item ); // remove it once we are done expanding
00306         KPIM::DistributionList::Entry::List entries = list.entries( KABC::StdAddressBook::self() );
00307         KPIM::DistributionList::Entry::List::Iterator it( entries.begin() );
00308         while ( it != entries.end() ) {
00309           KPIM::DistributionList::Entry &e = ( *it );
00310           ++it;
00311           // this calls insertAttendee, which appends
00312           insertAttendeeFromAddressee( e.addressee, attendee );
00313           // TODO: duplicate check, in case it was already added manually
00314         }
00315       }
00316     } else {
00317       bool skip = false;
00318       if ( attendee->email().endsWith( "example.net" ) ) {
00319         if ( KMessageBox::warningYesNo( this, i18n("%1 does not look like a valid email address. "
00320                 "Are you sure you want to invite this participant?").arg( attendee->email() ),
00321               i18n("Invalid email address") ) != KMessageBox::Yes ) {
00322           skip = true;
00323         }
00324       }
00325       if ( !skip ) {
00326         event->addAttendee( new Attendee( *attendee ) );
00327       }
00328     }
00329   }
00330 
00331   KOAttendeeEditor::writeEvent( event );
00332 
00333   // cleanup
00334   QValueVector<QListViewItem*>::iterator it;
00335   for( it = toBeDeleted.begin(); it != toBeDeleted.end(); ++it ) {
00336     delete *it;
00337   }
00338 }
00339 
00340 bool KOEditorDetails::validateInput()
00341 {
00342   return true;
00343 }
00344 
00345 KCal::Attendee * KOEditorDetails::currentAttendee() const
00346 {
00347   QListViewItem *item = mListView->selectedItem();
00348   AttendeeListItem *aItem = static_cast<AttendeeListItem *>( item );
00349   if ( !aItem )
00350     return 0;
00351   return aItem->data();
00352 }
00353 
00354 void KOEditorDetails::updateCurrentItem()
00355 {
00356   AttendeeListItem *item = static_cast<AttendeeListItem*>( mListView->selectedItem() );
00357   if ( item )
00358     item->updateItem();
00359 }
00360 
00361 void KOEditorDetails::slotInsertAttendee(Attendee * a)
00362 {
00363   insertAttendee( a );
00364 }
00365 
00366 void KOEditorDetails::changeStatusForMe(Attendee::PartStat status)
00367 {
00368   const QStringList myEmails = KOPrefs::instance()->allEmails();
00369   for ( QListViewItemIterator it( mListView ); it.current(); ++it ) {
00370     AttendeeListItem *item = static_cast<AttendeeListItem*>( it.current() );
00371     for ( QStringList::ConstIterator it2( myEmails.begin() ), end( myEmails.end() ); it2 != end; ++it2 ) {
00372       if ( item->data()->email() == *it2 ) {
00373         item->data()->setStatus( status );
00374         item->updateItem();
00375       }
00376     }
00377   }
00378 }
00379 
00380 QListViewItem* KOEditorDetails::hasExampleAttendee() const
00381 {
00382   for ( QListViewItemIterator it( mListView ); it.current(); ++it ) {
00383     AttendeeListItem *item = static_cast<AttendeeListItem*>( it.current() );
00384     Attendee *attendee = item->data();
00385     Q_ASSERT( attendee );
00386     if ( isExampleAttendee( attendee ) )
00387         return item;
00388   }
00389   return 0;
00390 }
00391 
00392 #include "koeditordetails.moc"