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