korganizer

koeventeditor.cpp
1/*
2 This file is part of KOrganizer.
3
4 Copyright (c) 2001, 2002, 2003 Cornelius Schumacher <schumacher@kde.org>
5 Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21 As a special exception, permission is given to link this program
22 with any edition of TQt, and distribute the resulting executable,
23 without including the source code for TQt in the source distribution.
24*/
25
26#include <tqtooltip.h>
27#include <tqframe.h>
28#include <tqpixmap.h>
29#include <tqlayout.h>
30#include <tqwidgetstack.h>
31#include <tqwhatsthis.h>
32
33#include <kiconloader.h>
34#include <kdebug.h>
35#include <tdelocale.h>
36#include <tdemessagebox.h>
38#include <libkcal/resourcecalendar.h>
39#include <libkcal/incidenceformatter.h>
40#include <libkcal/calendarlocal.h>
41
42#include "koprefs.h"
43#include "koeditorgeneralevent.h"
44#include "koeditorrecurrence.h"
45#include "koeditordetails.h"
46#include "koeditorfreebusy.h"
47#include "kogroupware.h"
48#include "kodialogmanager.h"
49#include "incidencechanger.h"
50
51#include "koeventeditor.h"
52
53KOEventEditor::KOEventEditor( Calendar *calendar, TQWidget *parent )
54 : KOIncidenceEditor( TQString(), calendar, parent ),
55 mEvent( 0 ), mCalendar( 0 ), mGeneral( 0 ), mRecurrence( 0 ), mFreeBusy( 0 )
56{
57}
58
59KOEventEditor::~KOEventEditor()
60{
61 if ( !mIsCounter )
62 emit dialogClose( mEvent );
63}
64
66{
67 setupGeneral();
68 setupRecurrence();
69 setupFreeBusy();
70 setupDesignerTabs( "event" );
71
72 // Propagate date time settings to recurrence tab
73 connect( mGeneral, TQ_SIGNAL( dateTimesChanged( const TQDateTime &, const TQDateTime & ) ),
74 mRecurrence, TQ_SLOT( setDateTimes( const TQDateTime &, const TQDateTime &) ) );
75 connect( mGeneral, TQ_SIGNAL( dateTimeStrChanged( const TQString & ) ),
76 mRecurrence, TQ_SLOT( setDateTimeStr( const TQString & ) ) );
77 connect( mFreeBusy, TQ_SIGNAL( dateTimesChanged( const TQDateTime &, const TQDateTime & ) ),
78 mRecurrence, TQ_SLOT( setDateTimes( const TQDateTime &, const TQDateTime & ) ) );
79
80 // Propagate date time settings to gantt tab and back
81 connect( mGeneral, TQ_SIGNAL( dateTimesChanged( const TQDateTime &, const TQDateTime & ) ),
82 mFreeBusy, TQ_SLOT( slotUpdateGanttView( const TQDateTime &, const TQDateTime & ) ) );
83 connect( mFreeBusy, TQ_SIGNAL( dateTimesChanged( const TQDateTime &, const TQDateTime & ) ),
84 mGeneral, TQ_SLOT( setDateTimes( const TQDateTime &, const TQDateTime & ) ) );
85
86 connect( mGeneral, TQ_SIGNAL( focusReceivedSignal() ),
87 TQ_SIGNAL( focusReceivedSignal() ) );
88
89 connect( mGeneral, TQ_SIGNAL( openCategoryDialog() ),
90 TQ_SIGNAL( editCategories() ) );
91 connect( this, TQ_SIGNAL( updateCategoryConfig() ),
92 mGeneral, TQ_SIGNAL( updateCategoryConfig() ) );
93
94 connect( mFreeBusy, TQ_SIGNAL(updateAttendeeSummary(int)),
95 mGeneral, TQ_SLOT(updateAttendeeSummary(int)) );
96
97 connect( mGeneral, TQ_SIGNAL(editRecurrence()),
98 mRecurrenceDialog, TQ_SLOT(show()) );
99 connect( mRecurrenceDialog, TQ_SIGNAL(okClicked()),
100 TQ_SLOT(updateRecurrenceSummary()) );
101
102 connect( mGeneral, TQ_SIGNAL(acceptInvitation()),
103 mFreeBusy, TQ_SLOT(acceptForMe()) );
104 connect( mGeneral, TQ_SIGNAL(declineInvitation()),
105 mFreeBusy, TQ_SLOT(declineForMe()) );
106}
107
108void KOEventEditor::reload()
109{
110 kdDebug(5850) << "KOEventEditor::reload()" << endl;
111
112 if ( mEvent ) {
113 readEvent( mEvent, mCalendar, TQDate() );
114 }
115}
116
117void KOEventEditor::setupGeneral()
118{
119 mGeneral = new KOEditorGeneralEvent( this );
120
121 if( KOPrefs::instance()->mCompactDialogs ) {
122 TQFrame *topFrame = addPage(i18n("General"));
123 TQWhatsThis::add( topFrame,
124 i18n("The General tab allows you to set the most common "
125 "options for the event.") );
126
127 TQBoxLayout *topLayout = new TQVBoxLayout(topFrame);
128 topLayout->setSpacing(spacingHint());
129
130 mGeneral->initHeader( topFrame, topLayout );
131 mGeneral->initTime(topFrame,topLayout);
132
133 topLayout->addStretch( 1 );
134
135 TQFrame *topFrame2 = addPage(i18n("Details"));
136
137 TQBoxLayout *topLayout2 = new TQVBoxLayout(topFrame2);
138 topLayout2->setSpacing(spacingHint());
139
140 mGeneral->initClass(topFrame2,topLayout2);
141 mGeneral->initSecrecy( topFrame2, topLayout2 );
142 mGeneral->initDescription(topFrame2,topLayout2);
143 } else {
144 TQFrame *topFrame = addPage(i18n("&General"));
145 TQWhatsThis::add( topFrame,
146 i18n("The General tab allows you to set the most common "
147 "options for the event.") );
148
149 TQBoxLayout *topLayout = new TQVBoxLayout(topFrame);
150 topLayout->setSpacing(spacingHint());
151
152 mGeneral->initInvitationBar( topFrame, topLayout );
153 mGeneral->initHeader( topFrame, topLayout );
154 mGeneral->initTime(topFrame,topLayout);
155 mGeneral->initDescription(topFrame,topLayout);
156 mGeneral->initAttachments(topFrame,topLayout);
157 connect( mGeneral, TQ_SIGNAL( openURL( const KURL& ) ),
158 this, TQ_SLOT( openURL( const KURL& ) ) );
159 connect( this, TQ_SIGNAL( signalAddAttachments( const TQStringList&, const TQStringList&, bool ) ),
160 mGeneral, TQ_SLOT( addAttachments( const TQStringList&, const TQStringList&, bool ) ) );
161 }
162
163 mGeneral->finishSetup();
164}
165
167{
168 // Play dumb, just reload the event. This dialog has become so complicated
169 // that there is no point in trying to be smart here...
170 reload();
171}
172
173void KOEventEditor::setupRecurrence()
174{
175 mRecurrenceDialog = new KOEditorRecurrenceDialog( this );
176 mRecurrenceDialog->hide();
177 mRecurrence = mRecurrenceDialog->editor();
178}
179
180void KOEventEditor::setupFreeBusy()
181{
182 TQFrame *freeBusyPage = addPage( i18n("&Attendees") );
183 TQWhatsThis::add( freeBusyPage,
184 i18n("The Free/Busy tab allows you to see whether "
185 "other attendees are free or busy during your event.") );
186
187 TQBoxLayout *topLayout = new TQVBoxLayout( freeBusyPage );
188
189 mAttendeeEditor = mFreeBusy = new KOEditorFreeBusy( spacingHint(), freeBusyPage );
190 topLayout->addWidget( mFreeBusy );
191}
192
194 const TQDate &date,
195 Calendar *calendar )
196{
197 Event*event = dynamic_cast<Event*>(incidence);
198 if ( event ) {
199 init();
200
201 mEvent = event;
202 mCalendar = calendar;
203
204 const TQDate &dt = mRecurIncidence && date.isValid() ? date : incidence->dtStart().date();
205 readEvent( mEvent, mCalendar, dt );
206 }
207
208 setCaption( i18n("Edit Event") );
209}
210
212{
213 init();
214 mEvent = 0;
215 loadDefaults();
216 setCaption( i18n("New Event") );
217}
218
219void KOEventEditor::setDates( const TQDateTime &from, const TQDateTime &to, bool allDay )
220{
221 mGeneral->setDefaults( from, to, allDay );
222 mRecurrence->setDefaults( from, to, allDay );
223 if( mFreeBusy ) {
224 if ( allDay )
225 mFreeBusy->setDateTimes( from, to.addDays( 1 ) );
226 else
227 mFreeBusy->setDateTimes( from, to );
228 }
229}
230
231void KOEventEditor::setTexts( const TQString &summary, const TQString &description )
232{
233 if ( description.isEmpty() && summary.contains("\n") ) {
234 mGeneral->setDescription( summary );
235 int pos = summary.find( "\n" );
236 mGeneral->setSummary( summary.left( pos ) );
237 } else {
238 mGeneral->setSummary( summary );
239 mGeneral->setDescription( description );
240 }
241}
242
243void KOEventEditor::loadDefaults()
244{
245 TQDateTime from( TQDate::currentDate(), KOPrefs::instance()->mStartTime.time() );
246 int addSecs = ( KOPrefs::instance()->mDefaultDuration.time().hour()*3600 ) +
247 ( KOPrefs::instance()->mDefaultDuration.time().minute()*60 );
248 TQDateTime to( from.addSecs( addSecs ) );
249
250 setDates( from, to, false );
251}
252
254{
255 kdDebug(5850) << "KOEventEditor::processInput(); event is " << mEvent << endl;
256
257 if ( !validateInput() || !mChanger ) {
258 kdDebug(5850) << " mChanger is " << mChanger << endl;
259 return false;
260 }
261
262 TQGuardedPtr<KOEditorFreeBusy> freeBusy( mFreeBusy );
263
264 if ( mEvent ) {
265 bool rc = true;
266 Event *oldEvent = mEvent->clone();
267 Event *event = mEvent->clone();
268
269 kdDebug(5850) << "KOEventEditor::processInput() write event." << endl;
270 writeEvent( event );
271 kdDebug(5850) << "KOEventEditor::processInput() event written." << endl;
272
273 if( *event == *mEvent ) {
274 // Don't do anything
275 kdDebug(5850) << "Event not changed" << endl;
276 if ( mIsCounter ) {
277 KMessageBox::information( this, i18n("You didn't change the event, thus no counter proposal has been sent to the organizer."), i18n("No changes") );
278 }
279 } else {
280 kdDebug(5850) << "Event changed" << endl;
281 //IncidenceChanger::assignIncidence( mEvent, event );
282 writeEvent( mEvent );
283 if ( mIsCounter ) {
284 KOGroupware::instance()->sendCounterProposal( mCalendar, oldEvent, mEvent );
285 // add dummy event at the position of the counter proposal
286 Event *event = mEvent->clone();
287 event->clearAttendees();
288 event->setSummary( i18n("My counter proposal for: %1").arg( mEvent->summary() ) );
289 mChanger->addIncidence( event, mResource, mSubResource, this );
290 } else {
291 if ( mRecurIncidence && mRecurIncidenceAfterDissoc ) {
292 mChanger->addIncidence( mEvent, mResource, mSubResource, this );
293
294 mChanger->changeIncidence( mRecurIncidence, mRecurIncidenceAfterDissoc,
295 KOGlobals::RECURRENCE_MODIFIED_ALL_FUTURE, this );
296
297 } else {
298 mChanger->changeIncidence( oldEvent, mEvent, KOGlobals::NOTHING_MODIFIED, this );
299 }
300 }
301 }
302 delete event;
303 delete oldEvent;
304 return rc;
305 } else {
306 mEvent = new Event;
307 mEvent->setOrganizer( Person( KOPrefs::instance()->fullName(),
308 KOPrefs::instance()->email() ) );
309 writeEvent( mEvent );
310 // 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.
311 if ( !mChanger->addIncidence( mEvent, mResource, mSubResource, this ) ) {
312 delete mEvent;
313 mEvent = 0;
314 return false;
315 }
316 }
317 // if "this" was deleted, freeBusy is 0 (being a guardedptr)
318 if ( freeBusy ) {
319 freeBusy->cancelReload();
320 }
321
322 return true;
323}
324
325void KOEventEditor::processCancel()
326{
327 kdDebug(5850) << "KOEventEditor::processCancel()" << endl;
328
329 if ( mFreeBusy ) mFreeBusy->cancelReload();
330
331 if ( mRecurIncidence && mRecurIncidenceAfterDissoc ) {
332 *mRecurIncidenceAfterDissoc = *mRecurIncidence;
333 }
334
335}
336
337void KOEventEditor::deleteEvent()
338{
339 kdDebug(5850) << "Delete event" << endl;
340
341 if ( mEvent )
342 emit deleteIncidenceSignal( mEvent );
343 emit dialogClose( mEvent );
344 reject();
345}
346
347void KOEventEditor::readEvent( Event *event, Calendar *calendar, const TQDate &date, bool tmpl )
348{
349 mGeneral->readEvent( event, calendar, date, tmpl );
350 mRecurrence->readIncidence( event );
351
352 if ( mFreeBusy ) {
353 mFreeBusy->readEvent( event );
354 mFreeBusy->triggerReload();
355 }
356
357 createEmbeddedURLPages( event );
358 readDesignerFields( event );
359
360 if ( mIsCounter )
361 mGeneral->invitationBar()->hide();
362}
363
365{
366 mGeneral->writeEvent( event );
367 if ( mFreeBusy )
368 mFreeBusy->writeEvent( event );
369
370 cancelRemovedAttendees( event );
371
372 mRecurrence->writeIncidence( event );
373
374 writeDesignerFields( event );
375}
376
378{
379 if ( !mGeneral->validateInput() ||
380 !mDetails->validateInput() ||
381 !mRecurrence->validateInput() ) {
382 kdDebug(5850) << "ValidateInput returns false" << endl;
383 return false;
384 } else {
385 return true;
386 }
387}
388
389int KOEventEditor::msgItemDelete()
390{
391 return KMessageBox::warningContinueCancel(this,
392 i18n("This item will be permanently deleted."),
393 i18n("KOrganizer Confirmation"),KGuiItem(i18n("Delete"),"edit-delete"));
394}
395
396void KOEventEditor::loadTemplate( /*const*/ CalendarLocal& cal )
397{
398 const Event::List events = cal.events();
399 if ( events.count() == 0 ) {
400 KMessageBox::error( this,
401 i18n("Template does not contain a valid event.") );
402 } else {
403 kdDebug(5850) << "KOEventEditor::slotLoadTemplate(): readTemplate" << endl;
404 readEvent( events.first(), 0, TQDate(), true );
405 }
406}
407
408TQStringList& KOEventEditor::templates() const
409{
410 return KOPrefs::instance()->mEventTemplates;
411}
412
413void KOEventEditor::slotSaveTemplate( const TQString &templateName )
414{
415 kdDebug(5006) << "SlotSaveTemplate" << endl;
416 Event *event = new Event;
417 writeEvent( event );
418 saveAsTemplate( event, templateName );
419}
420
421TQObject *KOEventEditor::typeAheadReceiver() const
422{
423 return mGeneral->typeAheadReceiver();
424}
425
426void KOEventEditor::updateRecurrenceSummary()
427{
428 Event *ev = new Event();
429 writeEvent( ev );
430 mGeneral->updateRecurrenceSummary( ev );
431 delete ev;
432}
433
434void KOEventEditor::selectInvitationCounterProposal(bool enable)
435{
436 KOIncidenceEditor::selectInvitationCounterProposal( enable );
437 if ( enable )
438 mGeneral->invitationBar()->hide();
439}
440
441#include "koeventeditor.moc"
virtual Event::List events(EventSortField sortField=EventSortUnsorted, SortDirection sortDirection=SortDirectionAscending)
Event * clone()
void setOrganizer(const Person &o)
virtual TQDateTime dtStart() const
TQString summary() const
bool validateInput()
Check if the input is valid.
void modified()
This event has been modified externally.
void setDates(const TQDateTime &from, const TQDateTime &to, bool allDay)
Set widgets to the given date/time values.
void writeEvent(Event *)
Write event settings to event object.
void init()
Initialize editor.
void setTexts(const TQString &summary, const TQString &description=TQString())
Sets the given summary and description.
bool processInput()
Process user input and create or update event.
void readEvent(Event *event, Calendar *calendar, const TQDate &date, bool tmpl=false)
Read event object and setup widgets accordingly.
KOEventEditor(Calendar *calendar, TQWidget *parent)
Construct new event editor.
void newEvent()
Clear event win for new event.
void editIncidence(Incidence *incidence, const TQDate &date, Calendar *calendar)
Edit an existing event.
This is the base class for the calendar component editors.
void addAttachments(const TQStringList &attachments, const TQStringList &mimeTypes=TQStringList(), bool inlineAttachment=false)
Adds attachments to the editor.