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 "koeditoralarms.h"
00045 #include "koeditorrecurrence.h"
00046 #include "koeditordetails.h"
00047 #include "koeditorfreebusy.h"
00048 #include "kogroupware.h"
00049 #include "kodialogmanager.h"
00050 #include "incidencechanger.h"
00051 
00052 #include "koeventeditor.h"
00053 
00054 KOEventEditor::KOEventEditor( Calendar *calendar, QWidget *parent )
00055   : KOIncidenceEditor( QString::null, calendar, parent ),
00056     mEvent( 0 ), mCalendar( 0 ), mGeneral( 0 ), mRecurrence( 0 ), mFreeBusy( 0 )
00057 {
00058 }
00059 
00060 KOEventEditor::~KOEventEditor()
00061 {
00062   if ( !mIsCounter )
00063     emit dialogClose( mEvent );
00064 }
00065 
00066 void KOEventEditor::init()
00067 {
00068   setupGeneral();
00069 //  setupAlarmsTab();
00070   setupRecurrence();
00071   setupFreeBusy();
00072   setupDesignerTabs( "event" );
00073 
00074   // Propagate date time settings to recurrence tab
00075   connect( mGeneral, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ),
00076            mRecurrence, SLOT( setDateTimes( const QDateTime &, const QDateTime &) ) );
00077   connect( mGeneral, SIGNAL( dateTimeStrChanged( const QString & ) ),
00078            mRecurrence, SLOT( setDateTimeStr( const QString & ) ) );
00079   connect( mFreeBusy, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ),
00080            mRecurrence, SLOT( setDateTimes( const QDateTime &, const QDateTime & ) ) );
00081 
00082   // Propagate date time settings to gantt tab and back
00083   connect( mGeneral, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ),
00084            mFreeBusy, SLOT( slotUpdateGanttView( const QDateTime &, const QDateTime & ) ) );
00085   connect( mFreeBusy, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ),
00086            mGeneral, SLOT( setDateTimes( const QDateTime &, const QDateTime & ) ) );
00087 
00088   connect( mGeneral, SIGNAL( focusReceivedSignal() ),
00089            SIGNAL( focusReceivedSignal() ) );
00090 
00091   connect( mGeneral, SIGNAL( openCategoryDialog() ),
00092            SIGNAL( editCategories() ) );
00093   connect( this, SIGNAL( updateCategoryConfig() ),
00094            mGeneral, SIGNAL( updateCategoryConfig() ) );
00095 
00096   connect( mFreeBusy, SIGNAL(updateAttendeeSummary(int)),
00097            mGeneral, SLOT(updateAttendeeSummary(int)) );
00098 
00099   connect( mGeneral, SIGNAL(editRecurrence()),
00100            mRecurrenceDialog, SLOT(show()) );
00101   connect( mRecurrenceDialog, SIGNAL(okClicked()),
00102            SLOT(updateRecurrenceSummary()) );
00103 
00104   connect( mGeneral, SIGNAL(acceptInvitation()),
00105            mFreeBusy, SLOT(acceptForMe()) );
00106   connect( mGeneral, SIGNAL(declineInvitation()),
00107            mFreeBusy, SLOT(declineForMe()) );
00108 }
00109 
00110 void KOEventEditor::reload()
00111 {
00112   kdDebug(5850) << "KOEventEditor::reload()" << endl;
00113 
00114   if ( mEvent ) {
00115     readEvent( mEvent, mCalendar, QDate() );
00116   }
00117 }
00118 
00119 void KOEventEditor::setupGeneral()
00120 {
00121   mGeneral = new KOEditorGeneralEvent( this );
00122 
00123   if( KOPrefs::instance()->mCompactDialogs ) {
00124     QFrame *topFrame = addPage(i18n("General"));
00125     QWhatsThis::add( topFrame,
00126                      i18n("The General tab allows you to set the most common "
00127                           "options for the event.") );
00128 
00129     QBoxLayout *topLayout = new QVBoxLayout(topFrame);
00130     topLayout->setSpacing(spacingHint());
00131 
00132     mGeneral->initHeader( topFrame, topLayout );
00133     mGeneral->initTime(topFrame,topLayout);
00134 //    QBoxLayout *alarmLineLayout = new QHBoxLayout(topLayout);
00135     mGeneral->initAlarm(topFrame,topLayout);
00136     mGeneral->enableAlarm( false );
00137 
00138     topLayout->addStretch( 1 );
00139 
00140     QFrame *topFrame2 = addPage(i18n("Details"));
00141 
00142     QBoxLayout *topLayout2 = new QVBoxLayout(topFrame2);
00143     topLayout2->setSpacing(spacingHint());
00144 
00145     mGeneral->initClass(topFrame2,topLayout2);
00146     mGeneral->initSecrecy( topFrame2, topLayout2 );
00147     mGeneral->initDescription(topFrame2,topLayout2);
00148   } else {
00149     QFrame *topFrame = addPage(i18n("&General"));
00150     QWhatsThis::add( topFrame,
00151                      i18n("The General tab allows you to set the most common "
00152                           "options for the event.") );
00153 
00154     QBoxLayout *topLayout = new QVBoxLayout(topFrame);
00155     topLayout->setSpacing(spacingHint());
00156 
00157     mGeneral->initInvitationBar( topFrame, topLayout );
00158     mGeneral->initHeader( topFrame, topLayout );
00159     mGeneral->initTime(topFrame,topLayout);
00160     mGeneral->initDescription(topFrame,topLayout);
00161     mGeneral->initAttachments(topFrame,topLayout);
00162     connect( mGeneral, SIGNAL( openURL( const KURL& ) ),
00163              this, SLOT( openURL( const KURL& ) ) );
00164     connect( this, SIGNAL( signalAddAttachments( const QStringList&, const QStringList&, bool ) ),
00165              mGeneral, SLOT( addAttachments( const QStringList&, const QStringList&, bool ) ) );
00166   }
00167 
00168   mGeneral->finishSetup();
00169 }
00170 
00171 void KOEventEditor::modified()
00172 {
00173   // Play dump, just reload the event. This dialog has become so complicated
00174   // that there is no point in trying to be smart here...
00175   reload();
00176 }
00177 
00178 void KOEventEditor::setupRecurrence()
00179 {
00180 #if 0
00181   QFrame *topFrame = addPage( i18n("Rec&urrence") );
00182 
00183   QWhatsThis::add( topFrame,
00184         i18n("The Recurrence tab allows you to set options on "
00185        "how often this event recurs.") );
00186 
00187   QBoxLayout *topLayout = new QVBoxLayout( topFrame );
00188 
00189   mRecurrence = new KOEditorRecurrence( topFrame );
00190   topLayout->addWidget( mRecurrence );
00191 #endif
00192   mRecurrenceDialog = new KOEditorRecurrenceDialog( this );
00193   mRecurrenceDialog->hide();
00194   mRecurrence = mRecurrenceDialog->editor();
00195 }
00196 
00197 void KOEventEditor::setupFreeBusy()
00198 {
00199   QFrame *freeBusyPage = addPage( i18n("&Attendees") );
00200   QWhatsThis::add( freeBusyPage,
00201         i18n("The Free/Busy tab allows you to see whether "
00202        "other attendees are free or busy during your event.") );
00203 
00204   QBoxLayout *topLayout = new QVBoxLayout( freeBusyPage );
00205 
00206   mAttendeeEditor = mFreeBusy = new KOEditorFreeBusy( spacingHint(), freeBusyPage );
00207   topLayout->addWidget( mFreeBusy );
00208 }
00209 
00210 void KOEventEditor::editIncidence( Incidence *incidence, const QDate &date, Calendar *calendar )
00211 {
00212   Event*event = dynamic_cast<Event*>(incidence);
00213   if ( event ) {
00214     init();
00215 
00216     mEvent = event;
00217     mCalendar = calendar;
00218     readEvent( mEvent, mCalendar, date );
00219   }
00220 
00221   setCaption( i18n("Edit Event") );
00222 }
00223 
00224 void KOEventEditor::newEvent()
00225 {
00226   init();
00227   mEvent = 0;
00228   loadDefaults();
00229   setCaption( i18n("New Event") );
00230 }
00231 
00232 void KOEventEditor::setDates( const QDateTime &from, const QDateTime &to, bool allDay )
00233 {
00234   mGeneral->setDefaults( from, to, allDay );
00235   mRecurrence->setDefaults( from, to, allDay );
00236   if( mFreeBusy ) {
00237     if ( allDay )
00238       mFreeBusy->setDateTimes( from, to.addDays( 1 ) );
00239     else
00240       mFreeBusy->setDateTimes( from, to );
00241   }
00242 }
00243 
00244 void KOEventEditor::setTexts( const QString &summary, const QString &description )
00245 {
00246   if ( description.isEmpty() && summary.contains("\n") ) {
00247     mGeneral->setDescription( summary );
00248     int pos = summary.find( "\n" );
00249     mGeneral->setSummary( summary.left( pos ) );
00250   } else {
00251     mGeneral->setSummary( summary );
00252     mGeneral->setDescription( description );
00253   }
00254 }
00255 
00256 void KOEventEditor::loadDefaults()
00257 {
00258   QDateTime from( QDate::currentDate(), KOPrefs::instance()->mStartTime.time() );
00259   int addSecs = ( KOPrefs::instance()->mDefaultDuration.time().hour()*3600 ) +
00260                 ( KOPrefs::instance()->mDefaultDuration.time().minute()*60 );
00261   QDateTime to( from.addSecs( addSecs ) );
00262 
00263   setDates( from, to, false );
00264 }
00265 
00266 bool KOEventEditor::processInput()
00267 {
00268   kdDebug(5850) << "KOEventEditor::processInput()" << endl;
00269 
00270   if ( !validateInput() || !mChanger ) return false;
00271 
00272   QGuardedPtr<KOEditorFreeBusy> freeBusy( mFreeBusy );
00273 
00274   if ( mEvent ) {
00275     bool rc = true;
00276     Event *oldEvent = mEvent->clone();
00277     Event *event = mEvent->clone();
00278 
00279     kdDebug(5850) << "KOEventEditor::processInput() write event." << endl;
00280     writeEvent( event );
00281     kdDebug(5850) << "KOEventEditor::processInput() event written." << endl;
00282 
00283     if( *event == *mEvent ) {
00284       // Don't do anything
00285       kdDebug(5850) << "Event not changed\n";
00286       if ( mIsCounter )
00287         KMessageBox::information( this, i18n("You didn't change the event, thus no counter proposal has been sent to the organizer."), i18n("No changes") );
00288     } else {
00289       kdDebug(5850) << "Event changed\n";
00290       //IncidenceChanger::assignIncidence( mEvent, event );
00291       writeEvent( mEvent );
00292       if ( mIsCounter ) {
00293         KOGroupware::instance()->sendCounterProposal( mCalendar, oldEvent, mEvent );
00294         // add dummy event at the position of the counter proposal
00295         Event *event = mEvent->clone();
00296         event->clearAttendees();
00297         event->setSummary( i18n("My counter proposal for: %1").arg( mEvent->summary() ) );
00298         mChanger->addIncidence( event, this );
00299       } else {
00300         mChanger->changeIncidence( oldEvent, mEvent, KOGlobals::NOTHING_MODIFIED, this );
00301       }
00302     }
00303     delete event;
00304     delete oldEvent;
00305     return rc;
00306   } else {
00307     mEvent = new Event;
00308     mEvent->setOrganizer( Person( KOPrefs::instance()->fullName(),
00309                           KOPrefs::instance()->email() ) );
00310     writeEvent( mEvent );
00311     // 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.
00312     if ( !mChanger->addIncidence( mEvent, this ) ) {
00313       delete mEvent;
00314       mEvent = 0;
00315       return false;
00316     }
00317   }
00318   // if "this" was deleted, freeBusy is 0 (being a guardedptr)
00319   if ( freeBusy ) freeBusy->cancelReload();
00320 
00321   return true;
00322 }
00323 
00324 void KOEventEditor::processCancel()
00325 {
00326   kdDebug(5850) << "KOEventEditor::processCancel()" << endl;
00327 
00328   if ( mFreeBusy ) mFreeBusy->cancelReload();
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 //  mAlarms->readIncidence( event );
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( IncidenceFormatter::recurrenceString( 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"