korganizer

koincidenceeditor.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     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     As a special exception, permission is given to link this program
00021     with any edition of Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 #include <qtooltip.h>
00026 #include <qframe.h>
00027 #include <qguardedptr.h>
00028 #include <qpixmap.h>
00029 #include <qlayout.h>
00030 #include <qwidgetstack.h>
00031 #include <qdatetime.h>
00032 #include <qwhatsthis.h>
00033 
00034 #include <kdebug.h>
00035 #include <klocale.h>
00036 #include <kstandarddirs.h>
00037 #include <kmessagebox.h>
00038 #include <kinputdialog.h>
00039 #include <kio/netaccess.h>
00040 #include <kabc/addressee.h>
00041 
00042 #include <libkdepim/designerfields.h>
00043 #include <libkdepim/embeddedurlpage.h>
00044 
00045 #include <libkcal/calendarlocal.h>
00046 #include <libkcal/incidence.h>
00047 #include <libkcal/icalformat.h>
00048 
00049 #include "koprefs.h"
00050 #include "koglobals.h"
00051 #include "koeditordetails.h"
00052 #include "koeditorattachments.h"
00053 #include "koeditoralarms.h"
00054 #include "urihandler.h"
00055 #include "koincidenceeditor.h"
00056 #include "templatemanagementdialog.h"
00057 
00058 KOIncidenceEditor::KOIncidenceEditor( const QString &caption,
00059                                       Calendar *calendar, QWidget *parent )
00060   : KDialogBase( Tabbed, caption, Ok | Apply | Cancel | Default, Ok,
00061                  parent, 0, false, false ),
00062     mDetails( 0 ), mAttachments( 0 ), mIsCounter( false )
00063 {
00064   // Set this to be the group leader for all subdialogs - this means
00065   // modal subdialogs will only affect this dialog, not the other windows
00066   setWFlags( getWFlags() | WGroupLeader );
00067 
00068   mCalendar = calendar;
00069 
00070   if ( KOPrefs::instance()->mCompactDialogs ) {
00071     showButton( Apply, false );
00072     showButton( Default, false );
00073   } else {
00074     setButtonText( Default, i18n("&Templates...") );
00075   }
00076 
00077   connect( this, SIGNAL( defaultClicked() ), SLOT( slotManageTemplates() ) );
00078   connect( this, SIGNAL( finished() ), SLOT( delayedDestruct() ) );
00079 }
00080 
00081 KOIncidenceEditor::~KOIncidenceEditor()
00082 {
00083 }
00084 
00085 void KOIncidenceEditor::setupAttendeesTab()
00086 {
00087   QFrame *topFrame = addPage( i18n("Atte&ndees") );
00088   QWhatsThis::add( topFrame,
00089                    i18n("The Attendees tab allows you to Add or Remove "
00090                         "Attendees to/from this event or to-do.") );
00091 
00092   QBoxLayout *topLayout = new QVBoxLayout( topFrame );
00093 
00094   mDetails = new KOEditorDetails( spacingHint(), topFrame );
00095   topLayout->addWidget( mDetails );
00096 }
00097 
00098 void KOIncidenceEditor::setupAttachmentsTab()
00099 {
00100   QFrame *topFrame = addPage( i18n("Attach&ments") );
00101   QWhatsThis::add( topFrame,
00102                    i18n("The Attachments tab allows you to add or remove "
00103                         "files, emails, contacts, and other items "
00104                         "associated with this event or to-do.") );
00105 
00106   QBoxLayout *topLayout = new QVBoxLayout( topFrame );
00107 
00108   mAttachments = new KOEditorAttachments( spacingHint(), topFrame );
00109   connect( mAttachments, SIGNAL( openURL( const KURL & ) ) ,
00110            this, SLOT( openURL( const KURL & ) ) );
00111   topLayout->addWidget( mAttachments );
00112 }
00113 
00114 void KOIncidenceEditor::slotApply()
00115 {
00116   processInput();
00117 }
00118 
00119 void KOIncidenceEditor::slotOk()
00120 {
00121   // "this" can be deleted before processInput() returns (processInput() opens
00122   // a non-modal dialog when Kolab is used). So accept should only be executed
00123   // when "this" is still valid
00124   QGuardedPtr<QWidget> ptr( this );
00125   if ( processInput() && ptr ) accept();
00126 }
00127 
00128 void KOIncidenceEditor::updateCategoryConfig()
00129 {
00130 }
00131 
00132 void KOIncidenceEditor::slotCancel()
00133 {
00134   processCancel();
00135   reject();
00136 }
00137 
00138 void KOIncidenceEditor::cancelRemovedAttendees( Incidence *incidence )
00139 {
00140   if ( !incidence ) return;
00141 
00142   // cancelAttendeeEvent removes all attendees from the incidence,
00143   // and then only adds those that need to be cancelled (i.e. a mail needs to be sent to them).
00144   if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) ) {
00145     Incidence *ev = incidence->clone();
00146     ev->registerObserver( 0 );
00147     mDetails->cancelAttendeeEvent( ev );
00148     if ( ev->attendeeCount() > 0 ) {
00149       emit deleteAttendee( ev );
00150     }
00151     delete( ev );
00152   }
00153 
00154 }
00155 
00156 void KOIncidenceEditor::slotManageTemplates()
00157 {
00158   kdDebug(5850) << "KOIncidenceEditor::manageTemplates()" << endl;
00159 
00160   TemplateManagementDialog * const d = new TemplateManagementDialog( this, templates() );
00161   connect( d, SIGNAL( loadTemplate( const QString& ) ),
00162            this, SLOT( slotLoadTemplate( const QString& ) ) );
00163   connect( d, SIGNAL( templatesChanged( const QStringList& ) ),
00164            this, SLOT( slotTemplatesChanged( const QStringList& ) ) );
00165   connect( d, SIGNAL( saveTemplate( const QString& ) ),
00166            this, SLOT( slotSaveTemplate( const QString& ) ) );
00167   d->exec();
00168   return;
00169 }
00170 
00171 void KOIncidenceEditor::saveAsTemplate( Incidence *incidence,
00172                                         const QString &templateName )
00173 {
00174   if ( !incidence || templateName.isEmpty() ) return;
00175 
00176   QString fileName = "templates/" + incidence->type();
00177   fileName.append( "/" + templateName );
00178   fileName = locateLocal( "data", "korganizer/" + fileName );
00179 
00180   CalendarLocal cal( KOPrefs::instance()->mTimeZoneId );
00181   cal.addIncidence( incidence );
00182   ICalFormat format;
00183   format.save( &cal, fileName );
00184 }
00185 
00186 void KOIncidenceEditor::slotLoadTemplate( const QString& templateName )
00187 {
00188   CalendarLocal cal( KOPrefs::instance()->mTimeZoneId );
00189   QString fileName = locateLocal( "data", "korganizer/templates/" + type() + "/" +
00190       templateName );
00191 
00192   if ( fileName.isEmpty() ) {
00193     KMessageBox::error( this, i18n("Unable to find template '%1'.")
00194         .arg( fileName ) );
00195   } else {
00196     ICalFormat format;
00197     if ( !format.load( &cal, fileName ) ) {
00198       KMessageBox::error( this, i18n("Error loading template file '%1'.")
00199           .arg( fileName ) );
00200       return;
00201     }
00202   }
00203   loadTemplate( cal );
00204 }
00205 
00206 void KOIncidenceEditor::slotTemplatesChanged( const QStringList& newTemplates )
00207 {
00208   templates() = newTemplates;
00209 }
00210 
00211 void KOIncidenceEditor::setupDesignerTabs( const QString &type )
00212 {
00213   QStringList activePages = KOPrefs::instance()->activeDesignerFields();
00214 
00215   QStringList list = KGlobal::dirs()->findAllResources( "data",
00216     "korganizer/designer/" + type + "/*.ui", true, true );
00217   for ( QStringList::iterator it = list.begin(); it != list.end(); ++it ) {
00218     const QString &fn = (*it).mid( (*it).findRev('/') + 1 );
00219     if ( activePages.find( fn ) != activePages.end() ) {
00220       addDesignerTab( *it );
00221     }
00222   }
00223 }
00224 
00225 QWidget *KOIncidenceEditor::addDesignerTab( const QString &uifile )
00226 {
00227   kdDebug(5850) << "Designer tab: " << uifile << endl;
00228 
00229   KPIM::DesignerFields *wid = new KPIM::DesignerFields( uifile, 0 );
00230   mDesignerFields.append( wid );
00231 
00232   QFrame *topFrame = addPage( wid->title() );
00233 
00234   QBoxLayout *topLayout = new QVBoxLayout( topFrame );
00235 
00236   wid->reparent( topFrame, 0, QPoint() );
00237   topLayout->addWidget( wid );
00238   mDesignerFieldForWidget[ topFrame ] = wid;
00239 
00240   return topFrame;
00241 }
00242 
00243 class KCalStorage : public KPIM::DesignerFields::Storage
00244 {
00245   public:
00246     KCalStorage( Incidence *incidence )
00247       : mIncidence( incidence )
00248     {
00249     }
00250 
00251     QStringList keys()
00252     {
00253       QStringList keys;
00254 
00255       QMap<QCString, QString> props = mIncidence->customProperties();
00256       QMap<QCString, QString>::ConstIterator it;
00257       for( it = props.begin(); it != props.end(); ++it ) {
00258         QString customKey = it.key();
00259         QStringList parts = QStringList::split( "-", customKey );
00260         if ( parts.count() != 4 ) continue;
00261         if ( parts[ 2 ] != "KORGANIZER" ) continue;
00262         keys.append( parts[ 3 ] );
00263       }
00264 
00265       return keys;
00266     }
00267 
00268     QString read( const QString &key )
00269     {
00270       return mIncidence->customProperty( "KORGANIZER", key.utf8() );
00271     }
00272 
00273     void write( const QString &key, const QString &value )
00274     {
00275       mIncidence->setCustomProperty( "KORGANIZER", key.utf8(), value );
00276     }
00277 
00278   private:
00279     Incidence *mIncidence;
00280 };
00281 
00282 void KOIncidenceEditor::readDesignerFields( Incidence *i )
00283 {
00284   KCalStorage storage( i );
00285   KPIM::DesignerFields *fields;
00286   for( fields = mDesignerFields.first(); fields;
00287        fields = mDesignerFields.next() ) {
00288     fields->load( &storage );
00289   }
00290 }
00291 
00292 void KOIncidenceEditor::writeDesignerFields( Incidence *i )
00293 {
00294   kdDebug(5850) << "KOIncidenceEditor::writeDesignerFields()" << endl;
00295 
00296   KCalStorage storage( i );
00297   KPIM::DesignerFields *fields;
00298   for( fields = mDesignerFields.first(); fields;
00299        fields = mDesignerFields.next() ) {
00300     kdDebug(5850) << "Write Field " << fields->title() << endl;
00301     fields->save( &storage );
00302   }
00303 }
00304 
00305 
00306 void KOIncidenceEditor::setupEmbeddedURLPage( const QString &label,
00307                                  const QString &url, const QString &mimetype )
00308 {
00309   kdDebug(5850) << "KOIncidenceEditor::setupEmbeddedURLPage()" << endl;
00310   kdDebug(5850) << "label=" << label << ", url=" << url << ", mimetype=" << mimetype << endl;
00311   QFrame *topFrame = addPage( label );
00312   QBoxLayout *topLayout = new QVBoxLayout( topFrame );
00313 
00314   KPIM::EmbeddedURLPage *wid = new KPIM::EmbeddedURLPage( url, mimetype,
00315                                                           topFrame );
00316   topLayout->addWidget( wid );
00317   mEmbeddedURLPages.append( topFrame );
00318   connect( wid, SIGNAL( openURL( const KURL & ) ) ,
00319            this, SLOT( openURL( const KURL & ) ) );
00320   // TODO: Call this method only when the tab is actually activated!
00321   wid->loadContents();
00322 }
00323 
00324 void KOIncidenceEditor::createEmbeddedURLPages( Incidence *i )
00325 {
00326   kdDebug(5850) << "KOIncidenceEditor::createEmbeddedURLPages()" << endl;
00327 
00328   if ( !i ) return;
00329   if ( !mEmbeddedURLPages.isEmpty() ) {
00330     kdDebug(5850) << "mEmbeddedURLPages are not empty, clearing it!" << endl;
00331     mEmbeddedURLPages.setAutoDelete( true );
00332     mEmbeddedURLPages.clear();
00333     mEmbeddedURLPages.setAutoDelete( false );
00334   }
00335   if ( !mAttachedDesignerFields.isEmpty() ) {
00336     for ( QPtrList<QWidget>::Iterator it = mAttachedDesignerFields.begin();
00337           it != mAttachedDesignerFields.end(); ++it ) {
00338       if ( mDesignerFieldForWidget.contains( *it ) ) {
00339         mDesignerFields.remove( mDesignerFieldForWidget[ *it ] );
00340       }
00341     }
00342     mAttachedDesignerFields.setAutoDelete( true );
00343     mAttachedDesignerFields.clear();
00344     mAttachedDesignerFields.setAutoDelete( false );
00345   }
00346 
00347   Attachment::List att = i->attachments();
00348   for ( Attachment::List::Iterator it = att.begin(); it != att.end(); ++it ) {
00349     Attachment *a = (*it);
00350     kdDebug(5850) << "Iterating over the attachments " << endl;
00351     kdDebug(5850) << "label=" << a->label() << ", url=" << a->uri() << ", mimetype=" << a->mimeType() << endl;
00352     if ( a && a->showInline() && a->isUri() ) {
00353       // TODO: Allow more mime-types, but add security checks!
00354 /*      if ( a->mimeType() == "application/x-designer" ) {
00355         QString tmpFile;
00356         if ( KIO::NetAccess::download( a->uri(), tmpFile, this ) ) {
00357           mAttachedDesignerFields.append( addDesignerTab( tmpFile ) );
00358           KIO::NetAccess::removeTempFile( tmpFile );
00359         }
00360       } else*/
00361       // TODO: Enable that check again!
00362       if ( a->mimeType() == "text/html" )
00363       {
00364         setupEmbeddedURLPage( a->label(), a->uri(), a->mimeType() );
00365       }
00366     }
00367   }
00368 }
00369 
00370 void KOIncidenceEditor::openURL( const KURL &url )
00371 {
00372   QString uri = url.url();
00373   UriHandler::process( uri );
00374 }
00375 
00376 void KOIncidenceEditor::addAttachments( const QStringList &attachments,
00377                                         const QStringList &mimeTypes,
00378                                         bool inlineAttachments )
00379 {
00380   QStringList::ConstIterator it;
00381   uint i = 0;
00382   for ( it = attachments.begin(); it != attachments.end(); ++it, ++i ) {
00383     QString mimeType;
00384     if ( mimeTypes.count() > i )
00385       mimeType = mimeTypes[ i ];
00386     mAttachments->addAttachment( *it, mimeType, !inlineAttachments );
00387   }
00388 }
00389 
00390 void KOIncidenceEditor::addAttendees( const QStringList &attendees )
00391 {
00392   QStringList::ConstIterator it;
00393   for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00394     QString name, email;
00395     KABC::Addressee::parseEmailAddress( *it, name, email );
00396     mDetails->insertAttendee( new Attendee( name, email ) );
00397   }
00398 }
00399 
00400 void KOIncidenceEditor::selectInvitationCounterProposal(bool enable)
00401 {
00402   mIsCounter = enable;
00403   if ( mIsCounter ) {
00404     setCaption( i18n( "Counter proposal" ) );
00405     setButtonOK( i18n( "Counter proposal" ) );
00406     enableButtonApply( false );
00407   }
00408 }
00409 
00410 
00411 #include "koincidenceeditor.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys