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( nullptr, 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;
117 kdDebug(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 == nullptr;
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{
340 kdDebug(5850) << "IncidenceChanger::changeIncidence for incidence \""
341 << newinc->summary() << "\" (old one was \"" << oldinc->summary() << "\")" << endl;
342 if ( incidencesEqual( newinc, oldinc ) ) {
343 // Don't do anything
344 kdDebug(5850) << "Incidence not changed" << endl;
345 } else {
346 kdDebug(5850) << "Incidence changed" << endl;
347 bool attendeeStatusChanged = myAttendeeStatusChanged( oldinc, newinc );
348 int revision = newinc->revision();
349 newinc->setRevision( revision + 1 );
350 // FIXME: Use a generic method for this! Ideally, have an interface class
351 // for group scheduling. Each implementation could then just do what
352 // it wants with the event. If no groupware is used,use the null
353 // pattern...
354 bool success = true;
355 if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
356 success = KOGroupware::instance()->sendICalMessage(
357 parent,
358 KCal::Scheduler::Request,
359 newinc, KOGlobals::INCIDENCEEDITED, attendeeStatusChanged, dontAskForGroupware );
360 }
361
362 if ( success ) {
363 // Accept the event changes
364 emit incidenceChanged( oldinc, newinc, action );
365 } else {
366 // revert changes
367 assignIncidence( newinc, oldinc );
368 return false;
369 }
370 }
371 return true;
372}
373
374bool IncidenceChanger::addIncidence( Incidence *incidence,
375 ResourceCalendar *res, const TQString &subRes,
376 TQWidget *parent )
377{
378 return addIncidence( incidence, res, subRes, parent, 0 );
379}
380
381bool IncidenceChanger::addIncidence( Incidence *incidence,
382 ResourceCalendar *res, const TQString &subRes,
383 TQWidget *parent, int dontAskForGroupware )
384{
385 CalendarResources *stdcal = dynamic_cast<CalendarResources *>( mCalendar );
386 if( stdcal && !stdcal->hasCalendarResources() ) {
387 KMessageBox::sorry(
388 parent,
389 i18n( "No calendars found, unable to save %1 \"%2\"." ).
390 arg( i18n( incidence->type() ) ).
391 arg( incidence->summary() ) );
392 kdDebug(5850) << "IncidenceChanger: No calendars found" << endl;
393 return false;
394 }
395
396 // FIXME: This is a nasty hack, since we need to set a parent for the
397 // resource selection dialog. However, we don't have any UI methods
398 // in the calendar, only in the CalendarResources::DestinationPolicy
399 // So we need to type-cast it and extract it from the CalendarResources
400 TQWidget *tmpparent = nullptr;
401 if ( stdcal ) {
402 tmpparent = stdcal->dialogParentWidget();
403 stdcal->setDialogParentWidget( parent );
404 }
405
406 // If a ResourceCalendar isn't provided, then try to compute one
407 // along with any subResource from the incidence.
408 ResourceCalendar *pRes = res;
409 TQString pSubRes = subRes;
410 TQString pResName;
411 if ( !pRes ) {
412 if ( stdcal ) {
413 pRes = stdcal->resource( incidence );
414 if ( pRes ) {
415 pResName = pRes->resourceName();
416 if ( pRes->canHaveSubresources() ) {
417 pSubRes = pRes->subresourceIdentifier( incidence );
418 pResName = pRes->labelForSubresource( pSubRes );
419 }
420 }
421 }
422 }
423
424 bool success = false;
425 if ( stdcal && pRes && !pRes->readOnly() && pRes->subresourceWritable( pSubRes ) ) {
426 success = stdcal->addIncidence( incidence, pRes, pSubRes );
427 } else {
428 success = mCalendar->addIncidence( incidence );
429 }
430
431 if ( !success ) {
432 // We can have a failure if the user pressed [cancel] in the resource
433 // selectdialog, so check the exception.
434 ErrorFormat *e = stdcal ? stdcal->exception() : nullptr;
435 if ( !e ||
436 ( e && ( e->errorCode() != KCal::ErrorFormat::UserCancel &&
438 TQString errMessage;
439 if ( pResName.isEmpty() ) {
440 errMessage = i18n( "Unable to save %1 \"%2\"." ).
441 arg( i18n( incidence->type() ) ).
442 arg( incidence->summary() );
443 } else {
444 errMessage = i18n( "Unable to save %1 \"%2\" to calendar %3." ).
445 arg( i18n( incidence->type() ) ).
446 arg( incidence->summary() ).
447 arg( pResName );
448 }
449 KMessageBox::sorry( parent, errMessage );
450 }
451 kdDebug(5850) << "IncidenceChanger: Can't add incidence" << endl;
452 return false;
453 }
454
455 if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
456 if ( !KOGroupware::instance()->sendICalMessage(
457 parent,
458 KCal::Scheduler::Request,
459 incidence, KOGlobals::INCIDENCEADDED, false, dontAskForGroupware ) ) {
460 KMessageBox::sorry(
461 parent,
462 i18n( "Attempt to send the scheduling message failed. "
463 "Please check your Group Scheduling settings. "
464 "Contact your system administrator for more help.") );
465 }
466 }
467
468 emit incidenceAdded( incidence );
469 return true;
470}
471
472
473#include "incidencechanger.moc"
474#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