korganizer

incidencechanger.cpp
1/*
2 This file is part of KOrganizer.
3
4 Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
20 As a special exception, permission is given to link this program
21 with any edition of TQt, and distribute the resulting executable,
22 without including the source code for TQt in the source distribution.
23*/
24
25#include "incidencechanger.h"
26#include "koglobals.h"
27#include "koprefs.h"
28#include "kogroupware.h"
29#include "mailscheduler.h"
30
31#include <libkcal/freebusy.h>
32#include <libkcal/dndfactory.h>
33#include <kdebug.h>
34#include <tdemessagebox.h>
35#include <tdelocale.h>
36
37bool IncidenceChanger::beginChange( Incidence *incidence,
38 ResourceCalendar *res, const TQString &subRes )
39{
40 if ( !incidence ) {
41 return false;
42 }
43
44 kdDebug(5850) << "IncidenceChanger::beginChange for incidence \""
45 << incidence->summary() << "\"" << endl;
46
47 CalendarResources *calRes = dynamic_cast<CalendarResources*>( mCalendar );
48 if ( !calRes ) {
49 return false;
50 }
51
52 return calRes->beginChange( incidence, res, subRes );
53}
54
55bool IncidenceChanger::sendGroupwareMessage( Incidence *incidence,
57 KOGlobals::HowChanged action,
58 TQWidget *parent )
59{
60 if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) && incidence->attendeeCount()>0
61 && !KOPrefs::instance()->mUseGroupwareCommunication ) {
62 emit schedule( method, incidence );
63 return true;
64 } else if( KOPrefs::instance()->mUseGroupwareCommunication ) {
65 return
66 KOGroupware::instance()->sendICalMessage( parent, method, incidence, action, false );
67 }
68 return true;
69}
70
71void IncidenceChanger::cancelAttendees( Incidence *incidence )
72{
73 if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
74 if ( KMessageBox::questionYesNo( 0, i18n("Some attendees were removed "
75 "from the incidence. Shall cancel messages be sent to these attendees?"),
76 i18n( "Attendees Removed" ), i18n("Send Messages"), i18n("Do Not Send") ) == KMessageBox::Yes ) {
77 // don't use KOGroupware::sendICalMessage here, because that asks just
78 // a very general question "Other people are involved, send message to
79 // them?", which isn't helpful at all in this situation. Afterwards, it
80 // would only call the MailScheduler::performTransaction, so do this
81 // manually.
82 // FIXME: Groupware scheduling should be factored out to it's own class
83 // anyway
84 KCal::MailScheduler scheduler( mCalendar );
85 scheduler.performTransaction( incidence, Scheduler::Cancel );
86 }
87 }
88}
89
90bool IncidenceChanger::endChange( Incidence *incidence,
91 ResourceCalendar *res, const TQString &subRes )
92{
93 // FIXME: if that's a groupware incidence, and I'm not the organizer,
94 // send out a mail to the organizer with a counterproposal instead
95 // of actually changing the incidence. Then no locking is needed.
96 // FIXME: if that's a groupware incidence, and the incidence was
97 // never locked, we can't unlock it with endChange().
98
99 if ( !incidence ) {
100 return false;
101 }
102
103 kdDebug(5850) << "IncidenceChanger::endChange for incidence \""
104 << incidence->summary() << "\"" << endl;
105
106 CalendarResources *calRes = dynamic_cast<CalendarResources*>( mCalendar );
107 if ( !calRes ) {
108 return false;
109 }
110
111 return calRes->endChange( incidence, res, subRes );
112}
113
114bool IncidenceChanger::deleteIncidence( Incidence *incidence, TQWidget *parent )
115{
116 if ( !incidence ) return true;
117kdDebug(5850)<<"IncidenceChanger::deleteIncidence for incidence \""<<incidence->summary()<<"\""<<endl;
118 bool doDelete = sendGroupwareMessage( incidence, KCal::Scheduler::Cancel,
119 KOGlobals::INCIDENCEDELETED, parent );
120 if( doDelete ) {
121 // @TODO: let Calendar::deleteIncidence do the locking...
122 Incidence* tmp = incidence->clone();
123 emit incidenceToBeDeleted( incidence );
124 doDelete = mCalendar->deleteIncidence( incidence );
125 if ( !KOPrefs::instance()->thatIsMe( tmp->organizer().email() ) ) {
126 const TQStringList myEmails = KOPrefs::instance()->allEmails();
127 bool notifyOrganizer = false;
128 for ( TQStringList::ConstIterator it = myEmails.begin(); it != myEmails.end(); ++it ) {
129 TQString email = *it;
130 Attendee *me = tmp->attendeeByMail(email);
131 if ( me ) {
132 if ( me->status() == KCal::Attendee::Accepted || me->status() == KCal::Attendee::Delegated )
133 notifyOrganizer = true;
134 Attendee *newMe = new Attendee( *me );
135 newMe->setStatus( KCal::Attendee::Declined );
136 tmp->clearAttendees();
137 tmp->addAttendee( newMe );
138 break;
139 }
140 }
141
142 if ( !KOGroupware::instance()->doNotNotify() && notifyOrganizer ) {
143 KCal::MailScheduler scheduler( mCalendar );
144 scheduler.performTransaction( tmp, Scheduler::Reply );
145 }
146 //reset the doNotNotify flag
147 KOGroupware::instance()->setDoNotNotify( false );
148 }
149 emit incidenceDeleted( incidence );
150 }
151 return doDelete;
152}
153
154bool IncidenceChanger::cutIncidences( const Incidence::List &incidences,
155 TQWidget *parent )
156{
157 Incidence::List::ConstIterator it;
158 bool doDelete = true;
159 Incidence::List incsToCut;
160 for ( it = incidences.constBegin(); it != incidences.constEnd(); ++it ) {
161 if ( *it ) {
162 doDelete = sendGroupwareMessage( *it, KCal::Scheduler::Cancel,
163 KOGlobals::INCIDENCEDELETED, parent );
164 if ( doDelete ) {
165 emit incidenceToBeDeleted( *it );
166 incsToCut.append( *it );
167 }
168 }
169 }
170
171 DndFactory factory( mCalendar );
172
173 if ( factory.cutIncidences( incsToCut ) ) {
174 for ( it = incsToCut.constBegin(); it != incsToCut.constEnd(); ++it ) {
175 emit incidenceDeleted( *it );
176 }
177 return !incsToCut.isEmpty();
178 } else {
179 return false;
180 }
181}
182
183bool IncidenceChanger::cutIncidence( Incidence *incidence, TQWidget *parent )
184{
185 Incidence::List incidences;
186 incidences.append( incidence );
187 return cutIncidences( incidences, parent );
188}
189
190class IncidenceChanger::ComparisonVisitor : public IncidenceBase::Visitor
191{
192 public:
194 bool act( IncidenceBase *incidence, IncidenceBase *inc2 )
195 {
196 mIncidence2 = inc2;
197 if ( incidence )
198 return incidence->accept( *this );
199 else
200 return (inc2 == 0);
201 }
202 protected:
203 bool visit( Event *event )
204 {
205 Event *ev2 = dynamic_cast<Event*>(mIncidence2);
206 if ( event && ev2 ) {
207 return *event == *ev2;
208 } else {
209 // either both 0, or return false;
210 return ( ev2 == event );
211 }
212 }
213 bool visit( Todo *todo )
214 {
215 Todo *to2 = dynamic_cast<Todo*>( mIncidence2 );
216 if ( todo && to2 ) {
217 return *todo == *to2;
218 } else {
219 // either both 0, or return false;
220 return ( todo == to2 );
221 }
222 }
223 bool visit( Journal *journal )
224 {
225 Journal *j2 = dynamic_cast<Journal*>( mIncidence2 );
226 if ( journal && j2 ) {
227 return *journal == *j2;
228 } else {
229 // either both 0, or return false;
230 return ( journal == j2 );
231 }
232 }
233 bool visit( FreeBusy *fb )
234 {
235 FreeBusy *fb2 = dynamic_cast<FreeBusy*>( mIncidence2 );
236 if ( fb && fb2 ) {
237 return *fb == *fb2;
238 } else {
239 // either both 0, or return false;
240 return ( fb2 == fb );
241 }
242 }
243
244 protected:
245 IncidenceBase *mIncidence2;
246};
247
248class IncidenceChanger::AssignmentVisitor : public IncidenceBase::Visitor
249{
250 public:
252 bool act( IncidenceBase *incidence, IncidenceBase *inc2 )
253 {
254 mIncidence2 = inc2;
255 if ( incidence )
256 return incidence->accept( *this );
257 else
258 return false;
259 }
260 protected:
261 bool visit( Event *event )
262 {
263 Event *ev2 = dynamic_cast<Event*>( mIncidence2 );
264 if ( event && ev2 ) {
265 *event = *ev2;
266 return true;
267 } else {
268 return false;
269 }
270 }
271 bool visit( Todo *todo )
272 {
273 Todo *to2 = dynamic_cast<Todo*>( mIncidence2 );
274 if ( todo && to2 ) {
275 *todo = *to2;
276 return true;
277 } else {
278 return false;
279 }
280 }
281 bool visit( Journal *journal )
282 {
283 Journal *j2 = dynamic_cast<Journal*>(mIncidence2);
284 if ( journal && j2 ) {
285 *journal = *j2;
286 return true;
287 } else {
288 return false;
289 }
290 }
291 bool visit( FreeBusy *fb )
292 {
293 FreeBusy *fb2 = dynamic_cast<FreeBusy*>( mIncidence2 );
294 if ( fb && fb2 ) {
295 *fb = *fb2;
296 return true;
297 } else {
298 return false;
299 }
300 }
301
302 protected:
303 IncidenceBase *mIncidence2;
304};
305
306bool IncidenceChanger::incidencesEqual( Incidence *inc1, Incidence *inc2 )
307{
309 return ( v.act( inc1, inc2 ) );
310}
311
312bool IncidenceChanger::assignIncidence( Incidence *inc1, Incidence *inc2 )
313{
315 return v.act( inc1, inc2 );
316}
317
318bool IncidenceChanger::myAttendeeStatusChanged( Incidence *oldInc, Incidence *newInc )
319{
320 Attendee *oldMe = oldInc->attendeeByMails( KOPrefs::instance()->allEmails() );
321 Attendee *newMe = newInc->attendeeByMails( KOPrefs::instance()->allEmails() );
322 if ( oldMe && newMe && ( oldMe->status() != newMe->status() ) )
323 return true;
324
325 return false;
326}
327
328bool IncidenceChanger::changeIncidence( Incidence *oldinc, Incidence *newinc,
329 KOGlobals::WhatChanged action,
330 TQWidget *parent )
331{
332 return changeIncidence( oldinc, newinc, action, parent, 0 );
333}
334
335bool IncidenceChanger::changeIncidence( Incidence *oldinc, Incidence *newinc,
336 KOGlobals::WhatChanged action,
337 TQWidget *parent,
338 int dontAskForGroupware )
339{
340kdDebug(5850)<<"IncidenceChanger::changeIncidence for incidence \""<<newinc->summary()<<"\" ( old one was \""<<oldinc->summary()<<"\")"<<endl;
341 if ( incidencesEqual( newinc, oldinc ) ) {
342 // Don't do anything
343 kdDebug(5850) << "Incidence not changed\n";
344 } else {
345 kdDebug(5850) << "Incidence changed\n";
346 bool attendeeStatusChanged = myAttendeeStatusChanged( oldinc, newinc );
347 int revision = newinc->revision();
348 newinc->setRevision( revision + 1 );
349 // FIXME: Use a generic method for this! Ideally, have an interface class
350 // for group scheduling. Each implementation could then just do what
351 // it wants with the event. If no groupware is used,use the null
352 // pattern...
353 bool success = true;
354 if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
355 success = KOGroupware::instance()->sendICalMessage(
356 parent,
357 KCal::Scheduler::Request,
358 newinc, KOGlobals::INCIDENCEEDITED, attendeeStatusChanged, dontAskForGroupware );
359 }
360
361 if ( success ) {
362 // Accept the event changes
363 emit incidenceChanged( oldinc, newinc, action );
364 } else {
365 // revert changes
366 assignIncidence( newinc, oldinc );
367 return false;
368 }
369 }
370 return true;
371}
372
373bool IncidenceChanger::addIncidence( Incidence *incidence,
374 ResourceCalendar *res, const TQString &subRes,
375 TQWidget *parent )
376{
377 return addIncidence( incidence, res, subRes, parent, 0 );
378}
379
380bool IncidenceChanger::addIncidence( Incidence *incidence,
381 ResourceCalendar *res, const TQString &subRes,
382 TQWidget *parent, int dontAskForGroupware )
383{
384 CalendarResources *stdcal = dynamic_cast<CalendarResources *>( mCalendar );
385 if( stdcal && !stdcal->hasCalendarResources() ) {
386 KMessageBox::sorry(
387 parent,
388 i18n( "No calendars found, unable to save %1 \"%2\"." ).
389 arg( i18n( incidence->type() ) ).
390 arg( incidence->summary() ) );
391 kdDebug(5850) << "IncidenceChanger: No calendars found" << endl;
392 return false;
393 }
394
395 // FIXME: This is a nasty hack, since we need to set a parent for the
396 // resource selection dialog. However, we don't have any UI methods
397 // in the calendar, only in the CalendarResources::DestinationPolicy
398 // So we need to type-cast it and extract it from the CalendarResources
399 TQWidget *tmpparent = 0;
400 if ( stdcal ) {
401 tmpparent = stdcal->dialogParentWidget();
402 stdcal->setDialogParentWidget( parent );
403 }
404
405 // If a ResourceCalendar isn't provided, then try to compute one
406 // along with any subResource from the incidence.
407 ResourceCalendar *pRes = res;
408 TQString pSubRes = subRes;
409 TQString pResName;
410 if ( !pRes ) {
411 if ( stdcal ) {
412 pRes = stdcal->resource( incidence );
413 if ( pRes ) {
414 pResName = pRes->resourceName();
415 if ( pRes->canHaveSubresources() ) {
416 pSubRes = pRes->subresourceIdentifier( incidence );
417 pResName = pRes->labelForSubresource( pSubRes );
418 }
419 }
420 }
421 }
422
423 bool success = false;
424 if ( stdcal && pRes && !pRes->readOnly() && pRes->subresourceWritable( pSubRes ) ) {
425 success = stdcal->addIncidence( incidence, pRes, pSubRes );
426 } else {
427 success = mCalendar->addIncidence( incidence );
428 }
429
430 if ( !success ) {
431 // We can have a failure if the user pressed [cancel] in the resource
432 // selectdialog, so check the exception.
433 ErrorFormat *e = stdcal ? stdcal->exception() : 0;
434 if ( !e ||
435 ( e && ( e->errorCode() != KCal::ErrorFormat::UserCancel &&
437 TQString errMessage;
438 if ( pResName.isEmpty() ) {
439 errMessage = i18n( "Unable to save %1 \"%2\"." ).
440 arg( i18n( incidence->type() ) ).
441 arg( incidence->summary() );
442 } else {
443 errMessage = i18n( "Unable to save %1 \"%2\" to calendar %3." ).
444 arg( i18n( incidence->type() ) ).
445 arg( incidence->summary() ).
446 arg( pResName );
447 }
448 KMessageBox::sorry( parent, errMessage );
449 }
450 kdDebug(5850) << "IncidenceChanger: Can't add incidence" << endl;
451 return false;
452 }
453
454 if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
455 if ( !KOGroupware::instance()->sendICalMessage(
456 parent,
457 KCal::Scheduler::Request,
458 incidence, KOGlobals::INCIDENCEADDED, false, dontAskForGroupware ) ) {
459 KMessageBox::sorry(
460 parent,
461 i18n( "Attempt to send the scheduling message failed. "
462 "Please check your Group Scheduling settings. "
463 "Contact your system administrator for more help.") );
464 }
465 }
466
467 emit incidenceAdded( incidence );
468 return true;
469}
470
471
472#include "incidencechanger.moc"
473#include "incidencechangerbase.moc"
void setStatus(PartStat s)
PartStat status() const
ResourceCalendar * resource(Incidence *incidence)
void setDialogParentWidget(TQWidget *parent)
bool addIncidence(Incidence *incidence)
TDE_DEPRECATED bool beginChange(Incidence *incidence)
TQWidget * dialogParentWidget()
TDE_DEPRECATED bool endChange(Incidence *incidence)
ErrorFormat * exception() const
ErrorCodeFormat errorCode()
virtual bool visit(Event *)
int attendeeCount() const
Attendee * attendeeByMail(const TQString &) const
Attendee * attendeeByMails(const TQStringList &, const TQString &email=TQString()) const
virtual bool accept(Visitor &)
void addAttendee(Attendee *attendee, bool doUpdate=true)
int revision() const
virtual Incidence * clone()=0
TQString summary() const
void setRevision(int rev)
virtual TQString subresourceIdentifier(Incidence *incidence)
virtual bool subresourceWritable(const TQString &) const
virtual bool canHaveSubresources() const
virtual const TQString labelForSubresource(const TQString &resource) const