korganizer

koeventeditor.cpp

00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 2001, 2002, 2003 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 <qtooltip.h>
00027 #include <qframe.h>
00028 #include <qpixmap.h>
00029 #include <qlayout.h>
00030 #include <qwidgetstack.h>
00031 #include <qwhatsthis.h>
00032 
00033 #include <kiconloader.h>
00034 #include <kdebug.h>
00035 #include <klocale.h>
00036 #include <kmessagebox.h>
00037 #include <libkcal/calendarresources.h>
00038 #include <libkcal/resourcecalendar.h>
00039 #include <libkcal/incidenceformatter.h>
00040 #include <libkcal/calendarlocal.h>
00041 
00042 #include "koprefs.h"
00043 #include "koeditorgeneralevent.h"
00044 #include "koeditorrecurrence.h"
00045 #include "koeditordetails.h"
00046 #include "koeditorfreebusy.h"
00047 #include "kogroupware.h"
00048 #include "kodialogmanager.h"
00049 #include "incidencechanger.h"
00050 
00051 #include "koeventeditor.h"
00052 
00053 KOEventEditor::KOEventEditor( Calendar *calendar, QWidget *parent )
00054   : KOIncidenceEditor( QString::null, calendar, parent ),
00055     mEvent( 0 ), mCalendar( 0 ), mGeneral( 0 ), mRecurrence( 0 ), mFreeBusy( 0 )
00056 {
00057 }
00058 
00059 KOEventEditor::~KOEventEditor()
00060 {
00061   if ( !mIsCounter )
00062     emit dialogClose( mEvent );
00063 }
00064 
00065 void KOEventEditor::init()
00066 {
00067   setupGeneral();
00068   setupRecurrence();
00069   setupFreeBusy();
00070   setupDesignerTabs( "event" );
00071 
00072   // Propagate date time settings to recurrence tab
00073   connect( mGeneral, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ),
00074            mRecurrence, SLOT( setDateTimes( const QDateTime &, const QDateTime &) ) );
00075   connect( mGeneral, SIGNAL( dateTimeStrChanged( const QString & ) ),
00076            mRecurrence, SLOT( setDateTimeStr( const QString & ) ) );
00077   connect( mFreeBusy, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ),
00078            mRecurrence, SLOT( setDateTimes( const QDateTime &, const QDateTime & ) ) );
00079 
00080   // Propagate date time settings to gantt tab and back
00081   connect( mGeneral, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ),
00082            mFreeBusy, SLOT( slotUpdateGanttView( const QDateTime &, const QDateTime & ) ) );
00083   connect( mFreeBusy, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ),
00084            mGeneral, SLOT( setDateTimes( const QDateTime &, const QDateTime & ) ) );
00085 
00086   connect( mGeneral, SIGNAL( focusReceivedSignal() ),
00087            SIGNAL( focusReceivedSignal() ) );
00088 
00089   connect( mGeneral, SIGNAL( openCategoryDialog() ),
00090            SIGNAL( editCategories() ) );
00091   connect( this, SIGNAL( updateCategoryConfig() ),
00092            mGeneral, SIGNAL( updateCategoryConfig() ) );
00093 
00094   connect( mFreeBusy, SIGNAL(updateAttendeeSummary(int)),
00095            mGeneral, SLOT(updateAttendeeSummary(int)) );
00096 
00097   connect( mGeneral, SIGNAL(editRecurrence()),
00098            mRecurrenceDialog, SLOT(show()) );
00099   connect( mRecurrenceDialog, SIGNAL(okClicked()),
00100            SLOT(updateRecurrenceSummary()) );
00101 
00102   connect( mGeneral, SIGNAL(acceptInvitation()),
00103            mFreeBusy, SLOT(acceptForMe()) );
00104   connect( mGeneral, SIGNAL(declineInvitation()),
00105            mFreeBusy, SLOT(declineForMe()) );
00106 }
00107 
00108 void KOEventEditor::reload()
00109 {
00110   kdDebug(5850) << "KOEventEditor::reload()" << endl;
00111 
00112   if ( mEvent ) {
00113     readEvent( mEvent, mCalendar, QDate() );
00114   }
00115 }
00116 
00117 void KOEventEditor::setupGeneral()
00118 {
00119   mGeneral = new KOEditorGeneralEvent( this );
00120 
00121   if( KOPrefs::instance()->mCompactDialogs ) {
00122     QFrame *topFrame = addPage(i18n("General"));
00123     QWhatsThis::add( topFrame,
00124                      i18n("The General tab allows you to set the most common "
00125                           "options for the event.") );
00126 
00127     QBoxLayout *topLayout = new QVBoxLayout(topFrame);
00128     topLayout->setSpacing(spacingHint());
00129 
00130     mGeneral->initHeader( topFrame, topLayout );
00131     mGeneral->initTime(topFrame,topLayout);
00132 
00133     topLayout->addStretch( 1 );
00134 
00135     QFrame *topFrame2 = addPage(i18n("Details"));
00136 
00137     QBoxLayout *topLayout2 = new QVBoxLayout(topFrame2);
00138     topLayout2->setSpacing(spacingHint());
00139 
00140     mGeneral->initClass(topFrame2,topLayout2);
00141     mGeneral->initSecrecy( topFrame2, topLayout2 );
00142     mGeneral->initDescription(topFrame2,topLayout2);
00143   } else {
00144     QFrame *topFrame = addPage(i18n("&General"));
00145     QWhatsThis::add( topFrame,
00146                      i18n("The General tab allows you to set the most common "
00147                           "options for the event.") );
00148 
00149     QBoxLayout *topLayout = new QVBoxLayout(topFrame);
00150     topLayout->setSpacing(spacingHint());
00151 
00152     mGeneral->initInvitationBar( topFrame, topLayout );
00153     mGeneral->initHeader( topFrame, topLayout );
00154     mGeneral->initTime(topFrame,topLayout);
00155     mGeneral->initDescription(topFrame,topLayout);
00156     mGeneral->initAttachments(topFrame,topLayout);
00157     connect( mGeneral, SIGNAL( openURL( const KURL& ) ),
00158              this, SLOT( openURL( const KURL& ) ) );
00159     connect( this, SIGNAL( signalAddAttachments( const QStringList&, const QStringList&, bool ) ),
00160              mGeneral, SLOT( addAttachments( const QStringList&, const QStringList&, bool ) ) );
00161   }
00162 
00163   mGeneral->finishSetup();
00164 }
00165 
00166 void KOEventEditor::modified()
00167 {
00168   // Play dumb, just reload the event. This dialog has become so complicated
00169   // that there is no point in trying to be smart here...
00170   reload();
00171 }
00172 
00173 void KOEventEditor::setupRecurrence()
00174 {
00175   mRecurrenceDialog = new KOEditorRecurrenceDialog( this );
00176   mRecurrenceDialog->hide();
00177   mRecurrence = mRecurrenceDialog->editor();
00178 }
00179 
00180 void KOEventEditor::setupFreeBusy()
00181 {
00182   QFrame *freeBusyPage = addPage( i18n("&Attendees") );
00183   QWhatsThis::add( freeBusyPage,
00184         i18n("The Free/Busy tab allows you to see whether "
00185        "other attendees are free or busy during your event.") );
00186 
00187   QBoxLayout *topLayout = new QVBoxLayout( freeBusyPage );
00188 
00189   mAttendeeEditor = mFreeBusy = new KOEditorFreeBusy( spacingHint(), freeBusyPage );
00190   topLayout->addWidget( mFreeBusy );
00191 }
00192 
00193 void KOEventEditor::editIncidence( Incidence *incidence,
00194                                    const QDate &date,
00195                                    Calendar *calendar )
00196 {
00197   Event*event = dynamic_cast<Event*>(incidence);
00198   if ( event ) {
00199     init();
00200 
00201     mEvent = event;
00202     mCalendar = calendar;
00203 
00204     const QDate &dt = mRecurIncidence && date.isValid() ? date : incidence->dtStart().date();
00205     readEvent( mEvent, mCalendar, dt );
00206   }
00207 
00208   setCaption( i18n("Edit Event") );
00209 }
00210 
00211 void KOEventEditor::newEvent()
00212 {
00213   init();
00214   mEvent = 0;
00215   loadDefaults();
00216   setCaption( i18n("New Event") );
00217 }
00218 
00219 void KOEventEditor::setDates( const QDateTime &from, const QDateTime &to, bool allDay )
00220 {
00221   mGeneral->setDefaults( from, to, allDay );
00222   mRecurrence->setDefaults( from, to, allDay );
00223   if( mFreeBusy ) {
00224     if ( allDay )
00225       mFreeBusy->setDateTimes( from, to.addDays( 1 ) );
00226     else
00227       mFreeBusy->setDateTimes( from, to );
00228   }
00229 }
00230 
00231 void KOEventEditor::setTexts( const QString &summary, const QString &description )
00232 {
00233   if ( description.isEmpty() && summary.contains("\n") ) {
00234     mGeneral->setDescription( summary );
00235     int pos = summary.find( "\n" );
00236     mGeneral->setSummary( summary.left( pos ) );
00237   } else {
00238     mGeneral->setSummary( summary );
00239     mGeneral->setDescription( description );
00240   }
00241 }
00242 
00243 void KOEventEditor::loadDefaults()
00244 {
00245   QDateTime from( QDate::currentDate(), KOPrefs::instance()->mStartTime.time() );
00246   int addSecs = ( KOPrefs::instance()->mDefaultDuration.time().hour()*3600 ) +
00247                 ( KOPrefs::instance()->mDefaultDuration.time().minute()*60 );
00248   QDateTime to( from.addSecs( addSecs ) );
00249 
00250   setDates( from, to, false );
00251 }
00252 
00253 bool KOEventEditor::processInput()
00254 {
00255   kdDebug(5850) << "KOEventEditor::processInput()" << endl;
00256 
00257   if ( !validateInput() || !mChanger ) return false;
00258 
00259   QGuardedPtr<KOEditorFreeBusy> freeBusy( mFreeBusy );
00260 
00261   if ( mEvent ) {
00262     bool rc = true;
00263     Event *oldEvent = mEvent->clone();
00264     Event *event = mEvent->clone();
00265 
00266     kdDebug(5850) << "KOEventEditor::processInput() write event." << endl;
00267     writeEvent( event );
00268     kdDebug(5850) << "KOEventEditor::processInput() event written." << endl;
00269 
00270     if( *event == *mEvent ) {
00271       // Don't do anything
00272       kdDebug(5850) << "Event not changed\n";
00273       if ( mIsCounter )
00274         KMessageBox::information( this, i18n("You didn't change the event, thus no counter proposal has been sent to the organizer."), i18n("No changes") );
00275     } else {
00276       kdDebug(5850) << "Event changed\n";
00277       //IncidenceChanger::assignIncidence( mEvent, event );
00278       writeEvent( mEvent );
00279       if ( mIsCounter ) {
00280         KOGroupware::instance()->sendCounterProposal( mCalendar, oldEvent, mEvent );
00281         // add dummy event at the position of the counter proposal
00282         Event *event = mEvent->clone();
00283         event->clearAttendees();
00284         event->setSummary( i18n("My counter proposal for: %1").arg( mEvent->summary() ) );
00285         mChanger->addIncidence( event, mResource, mSubResource, this );
00286       } else {
00287         if ( mRecurIncidence && mRecurIncidenceAfterDissoc ) {
00288           mChanger->addIncidence( mEvent, mResource, mSubResource, this );
00289 
00290           mChanger->changeIncidence( mRecurIncidence, mRecurIncidenceAfterDissoc,
00291                                      KOGlobals::RECURRENCE_MODIFIED_ALL_FUTURE, this );
00292 
00293         } else {
00294           mChanger->changeIncidence( oldEvent, mEvent, KOGlobals::NOTHING_MODIFIED, this );
00295         }
00296       }
00297     }
00298     delete event;
00299     delete oldEvent;
00300     return rc;
00301   } else {
00302     mEvent = new Event;
00303     mEvent->setOrganizer( Person( KOPrefs::instance()->fullName(),
00304                           KOPrefs::instance()->email() ) );
00305     writeEvent( mEvent );
00306     // NOTE: triggered by addIncidence, the kolab resource might open a non-modal dialog (parent is not available in the resource) to select a resource folder. Thus the user can close this dialog before addIncidence() returns.
00307     if ( !mChanger->addIncidence( mEvent, mResource, mSubResource, this ) ) {
00308       delete mEvent;
00309       mEvent = 0;
00310       return false;
00311     }
00312   }
00313   // if "this" was deleted, freeBusy is 0 (being a guardedptr)
00314   if ( freeBusy ) freeBusy->cancelReload();
00315 
00316   return true;
00317 }
00318 
00319 void KOEventEditor::processCancel()
00320 {
00321   kdDebug(5850) << "KOEventEditor::processCancel()" << endl;
00322 
00323   if ( mFreeBusy ) mFreeBusy->cancelReload();
00324 
00325   if ( mRecurIncidence && mRecurIncidenceAfterDissoc ) {
00326     *mRecurIncidenceAfterDissoc = *mRecurIncidence;
00327   }
00328 
00329 }
00330 
00331 void KOEventEditor::deleteEvent()
00332 {
00333   kdDebug(5850) << "Delete event" << endl;
00334 
00335   if ( mEvent )
00336     emit deleteIncidenceSignal( mEvent );
00337   emit dialogClose( mEvent );
00338   reject();
00339 }
00340 
00341 void KOEventEditor::readEvent( Event *event, Calendar *calendar, const QDate &date, bool tmpl )
00342 {
00343   mGeneral->readEvent( event, calendar, date, tmpl );
00344   mRecurrence->readIncidence( event );
00345 
00346   if ( mFreeBusy ) {
00347     mFreeBusy->readEvent( event );
00348     mFreeBusy->triggerReload();
00349   }
00350 
00351   createEmbeddedURLPages( event );
00352   readDesignerFields( event );
00353 
00354   if ( mIsCounter )
00355     mGeneral->invitationBar()->hide();
00356 }
00357 
00358 void KOEventEditor::writeEvent( Event *event )
00359 {
00360   mGeneral->writeEvent( event );
00361   if ( mFreeBusy )
00362     mFreeBusy->writeEvent( event );
00363 
00364   cancelRemovedAttendees( event );
00365 
00366   mRecurrence->writeIncidence( event );
00367 
00368   writeDesignerFields( event );
00369 }
00370 
00371 bool KOEventEditor::validateInput()
00372 {
00373   if ( !mGeneral->validateInput() ) return false;
00374   if ( !mDetails->validateInput() ) return false;
00375   if ( !mRecurrence->validateInput() ) return false;
00376 
00377   return true;
00378 }
00379 
00380 int KOEventEditor::msgItemDelete()
00381 {
00382   return KMessageBox::warningContinueCancel(this,
00383       i18n("This item will be permanently deleted."),
00384       i18n("KOrganizer Confirmation"),KGuiItem(i18n("Delete"),"editdelete"));
00385 }
00386 
00387 void KOEventEditor::loadTemplate( /*const*/ CalendarLocal& cal )
00388 {
00389   const Event::List events = cal.events();
00390   if ( events.count() == 0 ) {
00391     KMessageBox::error( this,
00392         i18n("Template does not contain a valid event.") );
00393   } else {
00394     kdDebug(5850) << "KOEventEditor::slotLoadTemplate(): readTemplate" << endl;
00395     readEvent( events.first(), 0, QDate(), true );
00396   }
00397 }
00398 
00399 QStringList& KOEventEditor::templates() const
00400 {
00401   return KOPrefs::instance()->mEventTemplates;
00402 }
00403 
00404 void KOEventEditor::slotSaveTemplate( const QString &templateName )
00405 {
00406   kdDebug(5006) << "SlotSaveTemplate" << endl;
00407   Event *event = new Event;
00408   writeEvent( event );
00409   saveAsTemplate( event, templateName );
00410 }
00411 
00412 QObject *KOEventEditor::typeAheadReceiver() const
00413 {
00414   return mGeneral->typeAheadReceiver();
00415 }
00416 
00417 void KOEventEditor::updateRecurrenceSummary()
00418 {
00419   Event *ev = new Event();
00420   writeEvent( ev );
00421   mGeneral->updateRecurrenceSummary( ev );
00422   delete ev;
00423 }
00424 
00425 void KOEventEditor::selectInvitationCounterProposal(bool enable)
00426 {
00427   KOIncidenceEditor::selectInvitationCounterProposal( enable );
00428   if ( enable )
00429     mGeneral->invitationBar()->hide();
00430 }
00431 
00432 #include "koeventeditor.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys