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 ) readEvent( mEvent, mCalendar );
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 //    QBoxLayout *alarmLineLayout = new QHBoxLayout(topLayout);
00133     mGeneral->initAlarm(topFrame,topLayout);
00134     mGeneral->enableAlarm( false );
00135 
00136     topLayout->addStretch( 1 );
00137 
00138     QFrame *topFrame2 = addPage(i18n("Details"));
00139 
00140     QBoxLayout *topLayout2 = new QVBoxLayout(topFrame2);
00141     topLayout2->setSpacing(spacingHint());
00142 
00143     mGeneral->initClass(topFrame2,topLayout2);
00144     mGeneral->initSecrecy( topFrame2, topLayout2 );
00145     mGeneral->initDescription(topFrame2,topLayout2);
00146   } else {
00147     QFrame *topFrame = addPage(i18n("&General"));
00148     QWhatsThis::add( topFrame,
00149                      i18n("The General tab allows you to set the most common "
00150                           "options for the event.") );
00151 
00152     QBoxLayout *topLayout = new QVBoxLayout(topFrame);
00153     topLayout->setSpacing(spacingHint());
00154 
00155     mGeneral->initInvitationBar( topFrame, topLayout );
00156     mGeneral->initHeader( topFrame, topLayout );
00157     mGeneral->initTime(topFrame,topLayout);
00158     mGeneral->initDescription(topFrame,topLayout);
00159     mGeneral->initAttachments(topFrame,topLayout);
00160     connect( mGeneral, SIGNAL( openURL( const KURL& ) ),
00161              this, SLOT( openURL( const KURL& ) ) );
00162     connect( this, SIGNAL( signalAddAttachments( const QStringList&, const QStringList&, bool ) ),
00163              mGeneral, SLOT( addAttachments( const QStringList&, const QStringList&, bool ) ) );
00164   }
00165 
00166   mGeneral->finishSetup();
00167 }
00168 
00169 void KOEventEditor::modified (int /*modification*/)
00170 {
00171   // Play dump, just reload the event. This dialog has become so complicated
00172   // that there is no point in trying to be smart here...
00173   reload();
00174 }
00175 
00176 void KOEventEditor::setupRecurrence()
00177 {
00178 #if 0
00179   QFrame *topFrame = addPage( i18n("Rec&urrence") );
00180 
00181   QWhatsThis::add( topFrame,
00182         i18n("The Recurrence tab allows you to set options on "
00183        "how often this event recurs.") );
00184 
00185   QBoxLayout *topLayout = new QVBoxLayout( topFrame );
00186 
00187   mRecurrence = new KOEditorRecurrence( topFrame );
00188   topLayout->addWidget( mRecurrence );
00189 #endif
00190   mRecurrenceDialog = new KOEditorRecurrenceDialog( this );
00191   mRecurrenceDialog->hide();
00192   mRecurrence = mRecurrenceDialog->editor();
00193 }
00194 
00195 void KOEventEditor::setupFreeBusy()
00196 {
00197   QFrame *freeBusyPage = addPage( i18n("&Attendees") );
00198   QWhatsThis::add( freeBusyPage,
00199         i18n("The Free/Busy tab allows you to see whether "
00200        "other attendees are free or busy during your event.") );
00201 
00202   QBoxLayout *topLayout = new QVBoxLayout( freeBusyPage );
00203 
00204   mAttendeeEditor = mFreeBusy = new KOEditorFreeBusy( spacingHint(), freeBusyPage );
00205   topLayout->addWidget( mFreeBusy );
00206 }
00207 
00208 void KOEventEditor::editIncidence( Incidence *incidence, Calendar *calendar )
00209 {
00210   Event*event = dynamic_cast<Event*>(incidence);
00211   if ( event ) {
00212     init();
00213 
00214     mEvent = event;
00215     mCalendar = calendar;
00216     readEvent( mEvent, mCalendar );
00217   }
00218 
00219   setCaption( i18n("Edit Event") );
00220 }
00221 
00222 void KOEventEditor::newEvent()
00223 {
00224   init();
00225   mEvent = 0;
00226   loadDefaults();
00227   setCaption( i18n("New Event") );
00228 }
00229 
00230 void KOEventEditor::setDates( const QDateTime &from, const QDateTime &to, bool allDay )
00231 {
00232   mGeneral->setDefaults( from, to, allDay );
00233   mRecurrence->setDefaults( from, to, allDay );
00234   if( mFreeBusy ) {
00235     if ( allDay )
00236       mFreeBusy->setDateTimes( from, to.addDays( 1 ) );
00237     else
00238       mFreeBusy->setDateTimes( from, to );
00239   }
00240 }
00241 
00242 void KOEventEditor::setTexts( const QString &summary, const QString &description )
00243 {
00244   if ( description.isEmpty() && summary.contains("\n") ) {
00245     mGeneral->setDescription( summary );
00246     int pos = summary.find( "\n" );
00247     mGeneral->setSummary( summary.left( pos ) );
00248   } else {
00249     mGeneral->setSummary( summary );
00250     mGeneral->setDescription( description );
00251   }
00252 }
00253 
00254 void KOEventEditor::loadDefaults()
00255 {
00256   QDateTime from( QDate::currentDate(), KOPrefs::instance()->mStartTime.time() );
00257   int addSecs = ( KOPrefs::instance()->mDefaultDuration.time().hour()*3600 ) +
00258                 ( KOPrefs::instance()->mDefaultDuration.time().minute()*60 );
00259   QDateTime to( from.addSecs( addSecs ) );
00260 
00261   setDates( from, to, false );
00262 }
00263 
00264 bool KOEventEditor::processInput()
00265 {
00266   kdDebug(5850) << "KOEventEditor::processInput()" << endl;
00267 
00268   if ( !validateInput() || !mChanger ) return false;
00269 
00270   QGuardedPtr<KOEditorFreeBusy> freeBusy( mFreeBusy );
00271 
00272   if ( mEvent ) {
00273     bool rc = true;
00274     Event *oldEvent = mEvent->clone();
00275     Event *event = mEvent->clone();
00276 
00277     kdDebug(5850) << "KOEventEditor::processInput() write event." << endl;
00278     writeEvent( event );
00279     kdDebug(5850) << "KOEventEditor::processInput() event written." << endl;
00280 
00281     if( *event == *mEvent ) {
00282       // Don't do anything
00283       kdDebug(5850) << "Event not changed\n";
00284       if ( mIsCounter )
00285         KMessageBox::information( this, i18n("You didn't change the event, thus no counter proposal has been sent to the organizer."), i18n("No changes") );
00286     } else {
00287       kdDebug(5850) << "Event changed\n";
00288       //IncidenceChanger::assignIncidence( mEvent, event );
00289       writeEvent( mEvent );
00290       if ( mIsCounter ) {
00291         KOGroupware::instance()->sendCounterProposal( mCalendar, oldEvent, mEvent );
00292         // add dummy event at the position of the counter proposal
00293         Event *event = mEvent->clone();
00294         event->clearAttendees();
00295         event->setSummary( i18n("My counter proposal for: %1").arg( mEvent->summary() ) );
00296         mChanger->addIncidence( event );
00297       } else {
00298         mChanger->changeIncidence( oldEvent, mEvent );
00299       }
00300     }
00301     delete event;
00302     delete oldEvent;
00303     return rc;
00304   } else {
00305     mEvent = new Event;
00306     mEvent->setOrganizer( Person( KOPrefs::instance()->fullName(),
00307                           KOPrefs::instance()->email() ) );
00308     writeEvent( mEvent );
00309     // 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.
00310     if ( !mChanger->addIncidence( mEvent, this ) ) {
00311       delete mEvent;
00312       mEvent = 0;
00313       return false;
00314     }
00315   }
00316   // if "this" was deleted, freeBusy is 0 (being a guardedptr)
00317   if ( freeBusy ) freeBusy->cancelReload();
00318 
00319   return true;
00320 }
00321 
00322 void KOEventEditor::processCancel()
00323 {
00324   kdDebug(5850) << "KOEventEditor::processCancel()" << endl;
00325 
00326   if ( mFreeBusy ) mFreeBusy->cancelReload();
00327 }
00328 
00329 void KOEventEditor::deleteEvent()
00330 {
00331   kdDebug(5850) << "Delete event" << endl;
00332 
00333   if ( mEvent )
00334     emit deleteIncidenceSignal( mEvent );
00335   emit dialogClose( mEvent );
00336   reject();
00337 }
00338 
00339 void KOEventEditor::readEvent( Event *event, Calendar *calendar, bool tmpl )
00340 {
00341   mGeneral->readEvent( event, calendar, tmpl );
00342   mRecurrence->readIncidence( event );
00343 //  mAlarms->readIncidence( event );
00344   if ( mFreeBusy ) {
00345     mFreeBusy->readEvent( event );
00346     mFreeBusy->triggerReload();
00347   }
00348 
00349   createEmbeddedURLPages( event );
00350   readDesignerFields( event );
00351 
00352   if ( mIsCounter )
00353     mGeneral->invitationBar()->hide();
00354 }
00355 
00356 void KOEventEditor::writeEvent( Event *event )
00357 {
00358   mGeneral->writeEvent( event );
00359   if ( mFreeBusy )
00360     mFreeBusy->writeEvent( event );
00361 
00362   cancelRemovedAttendees( event );
00363 
00364   mRecurrence->writeIncidence( event );
00365 
00366   writeDesignerFields( event );
00367 }
00368 
00369 bool KOEventEditor::validateInput()
00370 {
00371   if ( !mGeneral->validateInput() ) return false;
00372   if ( !mDetails->validateInput() ) return false;
00373   if ( !mRecurrence->validateInput() ) return false;
00374 
00375   return true;
00376 }
00377 
00378 int KOEventEditor::msgItemDelete()
00379 {
00380   return KMessageBox::warningContinueCancel(this,
00381       i18n("This item will be permanently deleted."),
00382       i18n("KOrganizer Confirmation"),KGuiItem(i18n("Delete"),"editdelete"));
00383 }
00384 
00385 void KOEventEditor::loadTemplate( /*const*/ CalendarLocal& cal )
00386 {
00387   const Event::List events = cal.events();
00388   if ( events.count() == 0 ) {
00389     KMessageBox::error( this,
00390         i18n("Template does not contain a valid event.") );
00391   } else {
00392     kdDebug(5850) << "KOEventEditor::slotLoadTemplate(): readTemplate" << endl;
00393     readEvent( events.first(), 0, true );
00394   }
00395 }
00396 
00397 QStringList& KOEventEditor::templates() const
00398 {
00399   return KOPrefs::instance()->mEventTemplates;
00400 }
00401 
00402 void KOEventEditor::slotSaveTemplate( const QString &templateName )
00403 {
00404   kdDebug(5006) << "SlotSaveTemplate" << endl;
00405   Event *event = new Event;
00406   writeEvent( event );
00407   saveAsTemplate( event, templateName );
00408 }
00409 
00410 QObject *KOEventEditor::typeAheadReceiver() const
00411 {
00412   return mGeneral->typeAheadReceiver();
00413 }
00414 
00415 void KOEventEditor::updateRecurrenceSummary()
00416 {
00417   Event *ev =  new Event();
00418   writeEvent( ev );
00419   mGeneral->updateRecurrenceSummary( IncidenceFormatter::recurrenceString( ev ) );
00420   delete ev;
00421 }
00422 
00423 void KOEventEditor::selectInvitationCounterProposal(bool enable)
00424 {
00425   KOIncidenceEditor::selectInvitationCounterProposal( enable );
00426   if ( enable )
00427     mGeneral->invitationBar()->hide();
00428 }
00429 
00430 #include "koeventeditor.moc"