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 TQt, and distribute the resulting executable,
00023     without including the source code for TQt in the source distribution.
00024 */
00025 
00026 #include <tqtooltip.h>
00027 #include <tqframe.h>
00028 #include <tqpixmap.h>
00029 #include <tqlayout.h>
00030 #include <tqwidgetstack.h>
00031 #include <tqwhatsthis.h>
00032 
00033 #include <kiconloader.h>
00034 #include <kdebug.h>
00035 #include <tdelocale.h>
00036 #include <tdemessagebox.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, TQWidget *parent )
00054   : KOIncidenceEditor( TQString(), 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, TQT_SIGNAL( dateTimesChanged( const TQDateTime &, const TQDateTime & ) ),
00074            mRecurrence, TQT_SLOT( setDateTimes( const TQDateTime &, const TQDateTime &) ) );
00075   connect( mGeneral, TQT_SIGNAL( dateTimeStrChanged( const TQString & ) ),
00076            mRecurrence, TQT_SLOT( setDateTimeStr( const TQString & ) ) );
00077   connect( mFreeBusy, TQT_SIGNAL( dateTimesChanged( const TQDateTime &, const TQDateTime & ) ),
00078            mRecurrence, TQT_SLOT( setDateTimes( const TQDateTime &, const TQDateTime & ) ) );
00079 
00080   // Propagate date time settings to gantt tab and back
00081   connect( mGeneral, TQT_SIGNAL( dateTimesChanged( const TQDateTime &, const TQDateTime & ) ),
00082            mFreeBusy, TQT_SLOT( slotUpdateGanttView( const TQDateTime &, const TQDateTime & ) ) );
00083   connect( mFreeBusy, TQT_SIGNAL( dateTimesChanged( const TQDateTime &, const TQDateTime & ) ),
00084            mGeneral, TQT_SLOT( setDateTimes( const TQDateTime &, const TQDateTime & ) ) );
00085 
00086   connect( mGeneral, TQT_SIGNAL( focusReceivedSignal() ),
00087            TQT_SIGNAL( focusReceivedSignal() ) );
00088 
00089   connect( mGeneral, TQT_SIGNAL( openCategoryDialog() ),
00090            TQT_SIGNAL( editCategories() ) );
00091   connect( this, TQT_SIGNAL( updateCategoryConfig() ),
00092            mGeneral, TQT_SIGNAL( updateCategoryConfig() ) );
00093 
00094   connect( mFreeBusy, TQT_SIGNAL(updateAttendeeSummary(int)),
00095            mGeneral, TQT_SLOT(updateAttendeeSummary(int)) );
00096 
00097   connect( mGeneral, TQT_SIGNAL(editRecurrence()),
00098            mRecurrenceDialog, TQT_SLOT(show()) );
00099   connect( mRecurrenceDialog, TQT_SIGNAL(okClicked()),
00100            TQT_SLOT(updateRecurrenceSummary()) );
00101 
00102   connect( mGeneral, TQT_SIGNAL(acceptInvitation()),
00103            mFreeBusy, TQT_SLOT(acceptForMe()) );
00104   connect( mGeneral, TQT_SIGNAL(declineInvitation()),
00105            mFreeBusy, TQT_SLOT(declineForMe()) );
00106 }
00107 
00108 void KOEventEditor::reload()
00109 {
00110   kdDebug(5850) << "KOEventEditor::reload()" << endl;
00111 
00112   if ( mEvent ) {
00113     readEvent( mEvent, mCalendar, TQDate() );
00114   }
00115 }
00116 
00117 void KOEventEditor::setupGeneral()
00118 {
00119   mGeneral = new KOEditorGeneralEvent( TQT_TQOBJECT(this) );
00120 
00121   if( KOPrefs::instance()->mCompactDialogs ) {
00122     TQFrame *topFrame = addPage(i18n("General"));
00123     TQWhatsThis::add( topFrame,
00124                      i18n("The General tab allows you to set the most common "
00125                           "options for the event.") );
00126 
00127     TQBoxLayout *topLayout = new TQVBoxLayout(topFrame);
00128     topLayout->setSpacing(spacingHint());
00129 
00130     mGeneral->initHeader( topFrame, topLayout );
00131     mGeneral->initTime(topFrame,topLayout);
00132 
00133     topLayout->addStretch( 1 );
00134 
00135     TQFrame *topFrame2 = addPage(i18n("Details"));
00136 
00137     TQBoxLayout *topLayout2 = new TQVBoxLayout(topFrame2);
00138     topLayout2->setSpacing(spacingHint());
00139 
00140     mGeneral->initClass(topFrame2,topLayout2);
00141     mGeneral->initSecrecy( topFrame2, topLayout2 );
00142     mGeneral->initDescription(topFrame2,topLayout2);
00143   } else {
00144     TQFrame *topFrame = addPage(i18n("&General"));
00145     TQWhatsThis::add( topFrame,
00146                      i18n("The General tab allows you to set the most common "
00147                           "options for the event.") );
00148 
00149     TQBoxLayout *topLayout = new TQVBoxLayout(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, TQT_SIGNAL( openURL( const KURL& ) ),
00158              this, TQT_SLOT( openURL( const KURL& ) ) );
00159     connect( this, TQT_SIGNAL( signalAddAttachments( const TQStringList&, const TQStringList&, bool ) ),
00160              mGeneral, TQT_SLOT( addAttachments( const TQStringList&, const TQStringList&, 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   TQFrame *freeBusyPage = addPage( i18n("&Attendees") );
00183   TQWhatsThis::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   TQBoxLayout *topLayout = new TQVBoxLayout( freeBusyPage );
00188 
00189   mAttendeeEditor = mFreeBusy = new KOEditorFreeBusy( spacingHint(), freeBusyPage );
00190   topLayout->addWidget( mFreeBusy );
00191 }
00192 
00193 void KOEventEditor::editIncidence( Incidence *incidence,
00194                                    const TQDate &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 TQDate &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 TQDateTime &from, const TQDateTime &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 TQString &summary, const TQString &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   TQDateTime from( TQDate::currentDate(), KOPrefs::instance()->mStartTime.time() );
00246   int addSecs = ( KOPrefs::instance()->mDefaultDuration.time().hour()*3600 ) +
00247                 ( KOPrefs::instance()->mDefaultDuration.time().minute()*60 );
00248   TQDateTime to( from.addSecs( addSecs ) );
00249 
00250   setDates( from, to, false );
00251 }
00252 
00253 bool KOEventEditor::processInput()
00254 {
00255   kdDebug(5850) << "KOEventEditor::processInput(); event is " << mEvent << endl;
00256 
00257   if ( !validateInput() || !mChanger ) {
00258     kdDebug(5850) << " mChanger is " << mChanger << endl;
00259     return false;
00260   }
00261 
00262   TQGuardedPtr<KOEditorFreeBusy> freeBusy( mFreeBusy );
00263 
00264   if ( mEvent ) {
00265     bool rc = true;
00266     Event *oldEvent = mEvent->clone();
00267     Event *event = mEvent->clone();
00268 
00269     kdDebug(5850) << "KOEventEditor::processInput() write event." << endl;
00270     writeEvent( event );
00271     kdDebug(5850) << "KOEventEditor::processInput() event written." << endl;
00272 
00273     if( *event == *mEvent ) {
00274       // Don't do anything
00275       kdDebug(5850) << "Event not changed" << endl;
00276       if ( mIsCounter ) {
00277         KMessageBox::information( this, i18n("You didn't change the event, thus no counter proposal has been sent to the organizer."), i18n("No changes") );
00278       }
00279     } else {
00280       kdDebug(5850) << "Event changed" << endl;
00281       //IncidenceChanger::assignIncidence( mEvent, event );
00282       writeEvent( mEvent );
00283       if ( mIsCounter ) {
00284         KOGroupware::instance()->sendCounterProposal( mCalendar, oldEvent, mEvent );
00285         // add dummy event at the position of the counter proposal
00286         Event *event = mEvent->clone();
00287         event->clearAttendees();
00288         event->setSummary( i18n("My counter proposal for: %1").arg( mEvent->summary() ) );
00289         mChanger->addIncidence( event, mResource, mSubResource, this );
00290       } else {
00291         if ( mRecurIncidence && mRecurIncidenceAfterDissoc ) {
00292           mChanger->addIncidence( mEvent, mResource, mSubResource, this );
00293 
00294           mChanger->changeIncidence( mRecurIncidence, mRecurIncidenceAfterDissoc,
00295                                      KOGlobals::RECURRENCE_MODIFIED_ALL_FUTURE, this );
00296 
00297         } else {
00298           mChanger->changeIncidence( oldEvent, mEvent, KOGlobals::NOTHING_MODIFIED, this );
00299         }
00300       }
00301     }
00302     delete event;
00303     delete oldEvent;
00304     return rc;
00305   } else {
00306     mEvent = new Event;
00307     mEvent->setOrganizer( Person( KOPrefs::instance()->fullName(),
00308                           KOPrefs::instance()->email() ) );
00309     writeEvent( mEvent );
00310     // 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.
00311     if ( !mChanger->addIncidence( mEvent, mResource, mSubResource, this ) ) {
00312       delete mEvent;
00313       mEvent = 0;
00314       return false;
00315     }
00316   }
00317   // if "this" was deleted, freeBusy is 0 (being a guardedptr)
00318   if ( freeBusy ) {
00319     freeBusy->cancelReload();
00320   }
00321 
00322   return true;
00323 }
00324 
00325 void KOEventEditor::processCancel()
00326 {
00327   kdDebug(5850) << "KOEventEditor::processCancel()" << endl;
00328 
00329   if ( mFreeBusy ) mFreeBusy->cancelReload();
00330 
00331   if ( mRecurIncidence && mRecurIncidenceAfterDissoc ) {
00332     *mRecurIncidenceAfterDissoc = *mRecurIncidence;
00333   }
00334 
00335 }
00336 
00337 void KOEventEditor::deleteEvent()
00338 {
00339   kdDebug(5850) << "Delete event" << endl;
00340 
00341   if ( mEvent )
00342     emit deleteIncidenceSignal( mEvent );
00343   emit dialogClose( mEvent );
00344   reject();
00345 }
00346 
00347 void KOEventEditor::readEvent( Event *event, Calendar *calendar, const TQDate &date, bool tmpl )
00348 {
00349   mGeneral->readEvent( event, calendar, date, tmpl );
00350   mRecurrence->readIncidence( event );
00351 
00352   if ( mFreeBusy ) {
00353     mFreeBusy->readEvent( event );
00354     mFreeBusy->triggerReload();
00355   }
00356 
00357   createEmbeddedURLPages( event );
00358   readDesignerFields( event );
00359 
00360   if ( mIsCounter )
00361     mGeneral->invitationBar()->hide();
00362 }
00363 
00364 void KOEventEditor::writeEvent( Event *event )
00365 {
00366   mGeneral->writeEvent( event );
00367   if ( mFreeBusy )
00368     mFreeBusy->writeEvent( event );
00369 
00370   cancelRemovedAttendees( event );
00371 
00372   mRecurrence->writeIncidence( event );
00373 
00374   writeDesignerFields( event );
00375 }
00376 
00377 bool KOEventEditor::validateInput()
00378 {
00379   if ( !mGeneral->validateInput() ||
00380        !mDetails->validateInput() ||
00381        !mRecurrence->validateInput() ) {
00382     kdDebug(5850) << "ValidateInput returns false" << endl;
00383     return false;
00384   } else {
00385     return true;
00386   }
00387 }
00388 
00389 int KOEventEditor::msgItemDelete()
00390 {
00391   return KMessageBox::warningContinueCancel(this,
00392       i18n("This item will be permanently deleted."),
00393       i18n("KOrganizer Confirmation"),KGuiItem(i18n("Delete"),"edit-delete"));
00394 }
00395 
00396 void KOEventEditor::loadTemplate( /*const*/ CalendarLocal& cal )
00397 {
00398   const Event::List events = cal.events();
00399   if ( events.count() == 0 ) {
00400     KMessageBox::error( this,
00401         i18n("Template does not contain a valid event.") );
00402   } else {
00403     kdDebug(5850) << "KOEventEditor::slotLoadTemplate(): readTemplate" << endl;
00404     readEvent( events.first(), 0, TQDate(), true );
00405   }
00406 }
00407 
00408 TQStringList& KOEventEditor::templates() const
00409 {
00410   return KOPrefs::instance()->mEventTemplates;
00411 }
00412 
00413 void KOEventEditor::slotSaveTemplate( const TQString &templateName )
00414 {
00415   kdDebug(5006) << "SlotSaveTemplate" << endl;
00416   Event *event = new Event;
00417   writeEvent( event );
00418   saveAsTemplate( event, templateName );
00419 }
00420 
00421 TQObject *KOEventEditor::typeAheadReceiver() const
00422 {
00423   return mGeneral->typeAheadReceiver();
00424 }
00425 
00426 void KOEventEditor::updateRecurrenceSummary()
00427 {
00428   Event *ev = new Event();
00429   writeEvent( ev );
00430   mGeneral->updateRecurrenceSummary( ev );
00431   delete ev;
00432 }
00433 
00434 void KOEventEditor::selectInvitationCounterProposal(bool enable)
00435 {
00436   KOIncidenceEditor::selectInvitationCounterProposal( enable );
00437   if ( enable )
00438     mGeneral->invitationBar()->hide();
00439 }
00440 
00441 #include "koeventeditor.moc"