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