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