]> err.no Git - scalable-opengroupware.org/blob - UI/Scheduler/UIxComponentEditor.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1052 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / Scheduler / UIxComponentEditor.m
1 /* UIxComponentEditor.m - this file is part of SOGo
2  *
3  * Copyright (C) 2006 Inverse groupe conseil
4  *
5  * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
6  *
7  * This file 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, or (at your option)
10  * any later version.
11  *
12  * This file 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; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #import <Foundation/NSArray.h>
24 #import <Foundation/NSBundle.h>
25 #import <Foundation/NSException.h>
26 #import <Foundation/NSCalendarDate.h>
27 #import <Foundation/NSKeyValueCoding.h>
28 #import <Foundation/NSString.h>
29 #import <Foundation/NSUserDefaults.h>
30 #import <Foundation/NSURL.h>
31
32 #import <NGCards/iCalPerson.h>
33 #import <NGCards/iCalRepeatableEntityObject.h>
34 #import <NGCards/iCalRecurrenceRule.h>
35 #import <NGCards/NSString+NGCards.h>
36 #import <NGCards/NSCalendarDate+NGCards.h>
37 #import <NGExtensions/NSCalendarDate+misc.h>
38 #import <NGExtensions/NSObject+Logs.h>
39 #import <NGExtensions/NSString+misc.h>
40 #import <NGObjWeb/NSException+HTTP.h>
41 #import <NGObjWeb/WORequest.h>
42
43 #import <SOGo/SOGoUser.h>
44 #import <SOGoUI/SOGoDateFormatter.h>
45 #import <SoObjects/Appointments/SOGoAppointmentFolder.h>
46 #import <SoObjects/Appointments/SOGoAppointmentObject.h>
47 #import <SoObjects/Appointments/SOGoTaskObject.h>
48 #import <SoObjects/SOGo/NSString+Utilities.h>
49
50 #import "UIxComponent+Scheduler.h"
51
52 #import "UIxComponentEditor.h"
53
54 @implementation UIxComponentEditor
55
56 - (id) init
57 {
58   if ((self = [super init]))
59     {
60       component = nil;
61       [self setPrivacy: @"PUBLIC"];
62       [self setIsCycleEndNever];
63       componentOwner = @"";
64       organizer = nil;
65       attendeesNames = nil;
66       attendeesEmails = nil;
67       calendarList = nil;
68     }
69
70   return self;
71 }
72
73 - (void) dealloc
74 {
75   [item release];
76   [cycleUntilDate release];
77   [title release];
78   [location release];
79   [organizer release];
80   [comment release];
81   [priority release];
82   [categories release];
83   [cycle release];
84   [cycleEnd release];
85   [url release];
86   [attendeesNames release];
87   [attendeesEmails release];
88   [calendarList release];
89
90   [super dealloc];
91 }
92
93 - (void) _loadAttendees
94 {
95   NSEnumerator *attendees;
96   iCalPerson *currentAttendee;
97   NSMutableString *names, *emails;
98
99   names = [NSMutableString new];
100   emails = [NSMutableString new];
101
102   attendees = [[component attendees] objectEnumerator];
103   currentAttendee = [attendees nextObject];
104   while (currentAttendee)
105     {
106       NSLog (@"currentCN: %@", [currentAttendee cn]);
107       [names appendFormat: @"%@,", [currentAttendee cn]];
108       [emails appendFormat: @"%@,", [currentAttendee rfc822Email]];
109       currentAttendee = [attendees nextObject];
110     }
111
112   if ([names length] > 0)
113     {
114       ASSIGN (attendeesNames, [names substringToIndex: [names length] - 1]);
115       ASSIGN (attendeesEmails,
116               [emails substringToIndex: [emails length] - 1]);
117     }
118
119   [names release];
120   [emails release];
121 }
122
123 /* warning: we use this method which will be triggered by the template system
124    when the page is instantiated, but we should find another and cleaner way of
125    doing this... for example, when the clientObject is set */
126 - (void) setComponent: (iCalRepeatableEntityObject *) newComponent
127 {
128 //   iCalRecurrenceRule *rrule;
129   SOGoObject *co;
130
131   if (!component)
132     {
133       component = newComponent;
134
135       co = [self clientObject];
136       componentOwner = [co ownerInContext: nil];
137
138       ASSIGN (title, [component summary]);
139       ASSIGN (location, [component location]);
140       ASSIGN (comment, [component comment]);
141       ASSIGN (url, [[component url] absoluteString]);
142       ASSIGN (privacy, [component accessClass]);
143       ASSIGN (priority, [component priority]);
144       ASSIGN (status, [component status]);
145       ASSIGN (categories, [[component categories] commaSeparatedValues]);
146       ASSIGN (organizer, [component organizer]);
147       [self _loadAttendees];
148     }
149 //   /* cycles */
150 //   if ([component isRecurrent])
151 //     {
152 //       rrule = [[component recurrenceRules] objectAtIndex: 0];
153 //       [self adjustCycleControlsForRRule: rrule];
154 //     }
155 }
156
157 - (void) setSaveURL: (NSString *) newSaveURL
158 {
159   saveURL = newSaveURL;
160 }
161
162 - (NSString *) saveURL
163 {
164   return saveURL;
165 }
166
167 /* accessors */
168
169 - (void) setItem: (id) _item
170 {
171   ASSIGN (item, _item);
172 }
173
174 - (id) item
175 {
176   return item;
177 }
178
179 - (NSString *) itemPriorityText
180 {
181   return [self labelForKey: [NSString stringWithFormat: @"prio_%@", item]];
182 }
183
184 - (NSString *) itemPrivacyText
185 {
186   NSString *tag;
187
188   tag = [[self clientObject] componentTag];
189
190   return [self labelForKey: [NSString stringWithFormat: @"%@_%@", item, tag]];
191 }
192
193 - (NSString *) itemStatusText
194 {
195   return [self labelForKey: [NSString stringWithFormat: @"status_%@", item]];
196 }
197
198 - (void) setTitle: (NSString *) _value
199 {
200   ASSIGN (title, _value);
201 }
202
203 - (NSString *) title
204 {
205   return title;
206 }
207
208 - (void) setUrl: (NSString *) _url
209 {
210   ASSIGN (url, _url);
211 }
212
213 - (NSString *) url
214 {
215   return url;
216 }
217
218 - (void) setAttendeesNames: (NSString *) newAttendeesNames
219 {
220   ASSIGN (attendeesNames, newAttendeesNames);
221 }
222
223 - (NSString *) attendeesNames
224 {
225   return attendeesNames;
226 }
227
228 - (void) setAttendeesEmails: (NSString *) newAttendeesEmails
229 {
230   ASSIGN (attendeesEmails, newAttendeesEmails);
231 }
232
233 - (NSString *) attendeesEmails
234 {
235   return attendeesEmails;
236 }
237
238 - (void) setLocation: (NSString *) _value
239 {
240   ASSIGN (location, _value);
241 }
242
243 - (NSString *) location
244 {
245   return location;
246 }
247
248 - (void) setComment: (NSString *) _value
249 {
250   ASSIGN (comment, _value);
251 }
252
253 - (NSString *) comment
254 {
255   return comment;
256 }
257
258 - (NSArray *) categoryList
259 {
260   static NSArray *categoryItems = nil;
261
262   if (!categoryItems)
263     {
264       categoryItems = [NSArray arrayWithObjects: @"ANNIVERSARY",
265                                @"BIRTHDAY",
266                                @"BUSINESS",
267                                @"CALLS", 
268                                @"CLIENTS",
269                                @"COMPETITION",
270                                @"CUSTOMER",
271                                @"FAVORITES",
272                                @"FOLLOW UP",
273                                @"GIFTS",
274                                @"HOLIDAYS",
275                                @"IDEAS",
276                                @"ISSUES",
277                                @"MISCELLANEOUS",
278                                @"PERSONAL",
279                                @"PROJECTS",
280                                @"PUBLIC HOLIDAY",
281                                @"STATUS",
282                                @"SUPPLIERS",
283                                @"TRAVEL",
284                                @"VACATION",
285                               nil];
286       [categoryItems retain];
287     }
288
289   return categoryItems;
290 }
291
292 - (void) setCategories: (NSArray *) _categories
293 {
294   ASSIGN (categories, _categories);
295 }
296
297 - (NSArray *) categories
298 {
299   return categories;
300 }
301
302 - (NSString *) itemCategoryText
303 {
304   return [self labelForKey:
305                  [NSString stringWithFormat: @"category_%@", item]];
306 }
307
308 - (NSArray *) calendarList
309 {
310   SOGoAppointmentFolder *folder;
311   NSEnumerator *allCalendars;
312   NSDictionary *currentCalendar;
313
314   if (!calendarList)
315     {
316       calendarList = [NSMutableArray new];
317       folder = [[self clientObject] container];
318       allCalendars = [[folder calendarFolders] objectEnumerator];
319       currentCalendar = [allCalendars nextObject];
320       while (currentCalendar)
321         {
322           if ([[currentCalendar objectForKey: @"active"] boolValue])
323             [calendarList addObject: currentCalendar];
324           currentCalendar = [allCalendars nextObject];
325         }
326     }
327
328   return calendarList;
329 }
330
331 - (NSString *) calendarsFoldersList
332 {
333   NSArray *calendars;
334
335   calendars = [[self calendarList] valueForKey: @"folder"];
336
337   return [calendars componentsJoinedByString: @","];
338 }
339
340 - (NSString *) componentCalendar
341 {
342   return @"/";
343 }
344
345 /* priorities */
346
347 - (NSArray *) priorities
348 {
349   /* 0 == undefined
350      5 == normal
351      1 == high
352   */
353   static NSArray *priorities = nil;
354
355   if (!priorities)
356     {
357       priorities = [NSArray arrayWithObjects: @"0", @"5", @"1", nil];
358       [priorities retain];
359     }
360
361   return priorities;
362 }
363
364 - (void) setPriority: (NSString *) _priority
365 {
366   ASSIGN (priority, _priority);
367 }
368
369 - (NSString *) priority
370 {
371   return priority;
372 }
373
374 - (NSArray *) privacyClasses
375 {
376   static NSArray *priorities = nil;
377
378   if (!priorities)
379     {
380       priorities = [NSArray arrayWithObjects: @"PUBLIC",
381                             @"CONFIDENTIAL", @"PRIVATE", nil];
382       [priorities retain];
383     }
384
385   return priorities;
386 }
387
388 - (void) setPrivacy: (NSString *) _privacy
389 {
390   ASSIGN (privacy, _privacy);
391 }
392
393 - (NSString *) privacy
394 {
395   return privacy;
396 }
397
398 - (NSArray *) statusTypes
399 {
400   static NSArray *priorities = nil;
401
402   if (!priorities)
403     {
404       priorities = [NSArray arrayWithObjects: @"", @"TENTATIVE", @"CONFIRMED", @"CANCELLED", nil];
405       [priorities retain];
406     }
407
408   return priorities;
409 }
410
411 - (void) setStatus: (NSString *) _status
412 {
413   ASSIGN (status, _status);
414 }
415
416 - (NSString *) status
417 {
418   return status;
419 }
420
421 - (NSArray *) cycles
422 {
423   NSBundle *bundle;
424   NSString *path;
425   static NSArray *cycles = nil;
426   
427   if (!cycles)
428     {
429       bundle = [NSBundle bundleForClass:[self class]];
430       path   = [bundle pathForResource: @"cycles" ofType: @"plist"];
431       NSAssert(path != nil, @"Cannot find cycles.plist!");
432       cycles = [[NSArray arrayWithContentsOfFile:path] retain];
433       NSAssert(cycles != nil, @"Cannot instantiate cycles from cycles.plist!");
434     }
435
436   return cycles;
437 }
438
439 - (void) setCycle: (NSDictionary *) _cycle
440 {
441   ASSIGN (cycle, _cycle);
442 }
443
444 - (NSDictionary *) cycle
445 {
446   return cycle;
447 }
448
449 - (BOOL) hasCycle
450 {
451   return ([cycle objectForKey: @"rule"] != nil);
452 }
453
454 - (NSString *) cycleLabel
455 {
456   NSString *key;
457   
458   key = [(NSDictionary *)item objectForKey: @"label"];
459
460   return [self labelForKey:key];
461 }
462
463 - (void) setCycleUntilDate: (NSCalendarDate *) _cycleUntilDate
464 {
465 //   NSCalendarDate *until;
466
467 //   /* copy hour/minute/second from startDate */
468 //   until = [_cycleUntilDate hour: [startDate hourOfDay]
469 //                            minute: [startDate minuteOfHour]
470 //                            second: [startDate secondOfMinute]];
471 //   [until setTimeZone: [startDate timeZone]];
472 //   ASSIGN (cycleUntilDate, until);
473 }
474
475 - (NSCalendarDate *) cycleUntilDate
476 {
477   return cycleUntilDate;
478 }
479
480 - (iCalRecurrenceRule *) rrule
481 {
482   NSString *ruleRep;
483   iCalRecurrenceRule *rule;
484
485   if (![self hasCycle])
486     return nil;
487   ruleRep = [cycle objectForKey: @"rule"];
488   rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:ruleRep];
489
490   if (cycleUntilDate && [self isCycleEndUntil])
491     [rule setUntilDate:cycleUntilDate];
492
493   return rule;
494 }
495
496 - (void) adjustCycleControlsForRRule: (iCalRecurrenceRule *) _rrule
497 {
498 //   NSDictionary *c;
499 //   NSCalendarDate *until;
500   
501 //   c = [self cycleMatchingRRule:_rrule];
502 //   [self setCycle:c];
503
504 //   until = [[[_rrule untilDate] copy] autorelease];
505 //   if (!until)
506 //     until = startDate;
507 //   else
508 //     [self setIsCycleEndUntil];
509
510 //   [until setTimeZone:[[self clientObject] userTimeZone]];
511 //   [self setCycleUntilDate:until];
512 }
513
514 /*
515  This method is necessary, because we have a fixed sets of cycles in the UI.
516  The model is able to represent arbitrary rules, however.
517  There SHOULD be a different UI, similar to iCal.app, to allow modelling
518  of more complex rules.
519  
520  This method obviously cannot map all existing rules back to the fixed list
521  in cycles.plist. This should be fixed in a future version when interop
522  becomes more important.
523  */
524 - (NSDictionary *) cycleMatchingRRule: (iCalRecurrenceRule *) _rrule
525 {
526   NSString *cycleRep;
527   NSArray *cycles;
528   unsigned i, count;
529
530   if (!_rrule)
531     return [[self cycles] objectAtIndex:0];
532
533   cycleRep = [_rrule versitString];
534   cycles   = [self cycles];
535   count    = [cycles count];
536   for (i = 1; i < count; i++) {
537     NSDictionary *c;
538     NSString *cr;
539
540     c  = [cycles objectAtIndex:i];
541     cr = [c objectForKey: @"rule"];
542     if ([cr isEqualToString:cycleRep])
543       return c;
544   }
545   [self warnWithFormat: @"No default cycle for rrule found! -> %@", _rrule];
546   return nil;
547 }
548
549 /* cycle "ends" - supposed to be 'never', 'COUNT' or 'UNTIL' */
550 - (NSArray *) cycleEnds
551 {
552   static NSArray *ends = nil;
553   
554   if (!ends)
555     {
556       ends = [NSArray arrayWithObjects: @"cycle_end_never",
557                       @"cycle_end_until", nil];
558       [ends retain];
559     }
560
561   return ends;
562 }
563
564 - (void) setCycleEnd: (NSString *) _cycleEnd
565 {
566   ASSIGN (cycleEnd, _cycleEnd);
567 }
568
569 - (NSString *) cycleEnd
570 {
571   return cycleEnd;
572 }
573
574 - (BOOL) isCycleEndUntil
575 {
576   return (cycleEnd && [cycleEnd isEqualToString: @"cycle_end_until"]);
577 }
578
579 - (void) setIsCycleEndUntil
580 {
581   [self setCycleEnd: @"cycle_end_until"];
582 }
583
584 - (void) setIsCycleEndNever
585 {
586   [self setCycleEnd: @"cycle_end_never"];
587 }
588
589 /* helpers */
590 - (NSFormatter *) titleDateFormatter
591 {
592   SOGoDateFormatter *fmt;
593   
594   fmt = [[SOGoDateFormatter alloc] initWithLocale: [self locale]];
595   [fmt autorelease];
596   [fmt setFullWeekdayNameAndDetails];
597
598   return fmt;
599 }
600
601 - (NSString *) completeURIForMethod: (NSString *) _method
602 {
603   NSString *uri;
604   NSRange r;
605     
606   uri = [[[self context] request] uri];
607     
608   /* first: identify query parameters */
609   r = [uri rangeOfString: @"?" options:NSBackwardsSearch];
610   if (r.length > 0)
611     uri = [uri substringToIndex:r.location];
612     
613   /* next: append trailing slash */
614   if (![uri hasSuffix: @"/"])
615     uri = [uri stringByAppendingString: @"/"];
616   
617   /* next: append method */
618   uri = [uri stringByAppendingString:_method];
619     
620   /* next: append query parameters */
621   return [self completeHrefForMethod:uri];
622 }
623
624 - (BOOL) isWriteableClientObject
625 {
626   return [[self clientObject] 
627                 respondsToSelector: @selector(saveContentString:)];
628 }
629
630 - (BOOL) containsConflict: (id) _component
631 {
632   [self subclassResponsibility: _cmd];
633
634   return NO;
635 }
636
637 /* access */
638
639 #if 0
640 - (iCalPerson *) getOrganizer
641 {
642   iCalPerson *p;
643   NSString *emailProp;
644   
645   emailProp = [@"MAILTO:" stringByAppendingString:[self emailForUser]];
646   p = [[[iCalPerson alloc] init] autorelease];
647   [p setEmail:emailProp];
648   [p setCn:[self cnForUser]];
649   return p;
650 }
651 #endif
652
653 - (BOOL) isMyComponent
654 {
655   return ([[context activeUser] hasEmail: [organizer rfc822Email]]);
656 }
657
658 - (BOOL) canEditComponent
659 {
660   return [self isMyComponent];
661 }
662
663 /* response generation */
664
665 - (NSString *) initialCycleVisibility
666 {
667   return ([self hasCycle]
668           ? @"visibility: visible;"
669           : @"visibility: hidden;");
670 }
671
672 - (NSString *) initialCycleEndUntilVisibility {
673   return ([self isCycleEndUntil]
674           ? @"visibility: visible;"
675           : @"visibility: hidden;");
676 }
677
678 // - (NSString *) iCalParticipantsAndResourcesStringFromQueryParameters
679 // {
680 //   NSString *s;
681   
682 //   s = [self iCalParticipantsStringFromQueryParameters];
683 //   return [s stringByAppendingString:
684 //               [self iCalResourcesStringFromQueryParameters]];
685 // }
686
687 // - (NSString *) iCalParticipantsStringFromQueryParameters
688 // {
689 //   static NSString *iCalParticipantString = @"ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;CN=\"%@\":MAILTO:%@\r\n";
690   
691 //   return [self iCalStringFromQueryParameter: @"ps"
692 //                format: iCalParticipantString];
693 // }
694
695 // - (NSString *) iCalResourcesStringFromQueryParameters
696 // {
697 //   static NSString *iCalResourceString = @"ATTENDEE;ROLE=NON-PARTICIPANT;CN=\"%@\":MAILTO:%@\r\n";
698
699 //   return [self iCalStringFromQueryParameter: @"rs"
700 //                format: iCalResourceString];
701 // }
702
703 // - (NSString *) iCalStringFromQueryParameter: (NSString *) _qp
704 //                                      format: (NSString *) _format
705 // {
706 //   AgenorUserManager *um;
707 //   NSMutableString *iCalRep;
708 //   NSString *s;
709
710 //   um = [AgenorUserManager sharedUserManager];
711 //   iCalRep = (NSMutableString *)[NSMutableString string];
712 //   s = [self queryParameterForKey:_qp];
713 //   if(s && [s length] > 0) {
714 //     NSArray *es;
715 //     unsigned i, count;
716     
717 //     es = [s componentsSeparatedByString: @","];
718 //     count = [es count];
719 //     for(i = 0; i < count; i++) {
720 //       NSString *email, *cn;
721       
722 //       email = [es objectAtIndex:i];
723 //       cn = [um getCNForUID:[um getUIDForEmail:email]];
724 //       [iCalRep appendFormat:_format, cn, email];
725 //     }
726 //   }
727 //   return iCalRep;
728 // }
729
730 - (NSException *) validateObjectForStatusChange
731 {
732   id co;
733
734   co = [self clientObject];
735   if (![co respondsToSelector: @selector(changeParticipationStatus:)])
736     return [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
737                         reason:
738                           @"method cannot be invoked on the specified object"];
739
740   return nil;
741 }
742
743 /* contact editor compatibility */
744
745 - (NSString *) urlButtonClasses
746 {
747   NSString *classes;
748
749   if ([url length])
750     classes = @"button";
751   else
752     classes = @"button _disabled";
753
754   return classes;
755 }
756
757 - (void) _handleAttendeesEdition
758 {
759   NSArray *names, *emails;
760   NSMutableArray *newAttendees;
761   unsigned int count, max;
762   NSString *currentEmail;
763   iCalPerson *currentAttendee;
764
765   newAttendees = [NSMutableArray new];
766   if ([attendeesNames length] > 0)
767     {
768       names = [attendeesNames componentsSeparatedByString: @","];
769       emails = [attendeesEmails componentsSeparatedByString: @","];
770       max = [emails count];
771       for (count = 0; count < max; count++)
772         {
773           currentEmail = [emails objectAtIndex: count];
774           currentAttendee = [component findParticipantWithEmail: currentEmail];
775           if (!currentAttendee)
776             {
777               currentAttendee = [iCalPerson elementWithTag: @"attendee"];
778               [currentAttendee setCn: [names objectAtIndex: count]];
779               [currentAttendee setEmail: currentEmail];
780               [currentAttendee setRole: @"REQ-PARTICIPANT"];
781               [currentAttendee
782                 setParticipationStatus: iCalPersonPartStatNeedsAction];
783             }
784           [newAttendees addObject: currentAttendee];
785         }
786     }
787
788   [component setAttendees: newAttendees];
789   [newAttendees release];
790 }
791
792 - (void) _handleOrganizer
793 {
794   NSString *organizerEmail;
795   SOGoUser *activeUser;
796
797   organizerEmail = [[component organizer] email];
798   if ([organizerEmail length] == 0)
799     {
800       if ([[component attendees] count] > 0)
801         {
802           ASSIGN (organizer, [iCalPerson elementWithTag: @"organizer"]);
803           activeUser = [context activeUser];
804           [organizer setCn: [activeUser cn]];
805           [organizer setEmail: [activeUser primaryEmail]];
806           [component setOrganizer: organizer];
807         }
808     }
809   else
810     {
811       if ([[component attendees] count] == 0)
812         {
813           ASSIGN (organizer, [iCalPerson elementWithTag: @"organizer"]);
814           [component setOrganizer: organizer];
815         }
816     }
817 }
818
819 - (void) takeValuesFromRequest: (WORequest *) _rq
820                      inContext: (WOContext *) _ctx
821 {
822   NSCalendarDate *now;
823   SOGoCalendarComponent *clientObject;
824
825   [super takeValuesFromRequest: _rq inContext: _ctx];
826
827   now = [NSCalendarDate calendarDate];
828   [component setSummary: title];
829   [component setLocation: location];
830   [component setComment: comment];
831   [component setUrl: url];
832   [component setAccessClass: privacy];
833   [self _handleAttendeesEdition];
834   [self _handleOrganizer];
835   clientObject = [self clientObject];
836   if ([clientObject isNew])
837     {
838       [component setUid: [clientObject nameInContainer]];
839       [component setCreated: now];
840       [component setTimeStampAsDate: now];
841       [component setPriority: @"0"];
842     }
843   [component setLastModified: now];
844 }
845
846 - (NSString *) toolbar
847 {
848   SOGoUser *currentUser;
849   SOGoCalendarComponent *clientObject;
850   NSString *toolbarFilename;
851   iCalPerson *person;
852   iCalPersonPartStat participationStatus;
853
854   clientObject = [self clientObject];
855   currentUser = [[self context] activeUser];
856   if ([clientObject isOrganizerOrOwner: currentUser])
857     {
858       if ([[clientObject componentTag] isEqualToString: @"vevent"])
859         toolbarFilename = @"SOGoAppointmentObject.toolbar";
860       else
861         toolbarFilename = @"SOGoTaskObject.toolbar";
862     }
863   else
864     {
865       /* Lightning does not manage participation status within tasks */
866       person = [clientObject participant: currentUser];
867       if (person)
868         {
869           participationStatus = [person participationStatus];
870           if (participationStatus == iCalPersonPartStatAccepted)
871             toolbarFilename = @"SOGoAppointmentObjectDecline.toolbar";
872           else if (participationStatus == iCalPersonPartStatDeclined)
873             toolbarFilename = @"SOGoAppointmentObjectAccept.toolbar";
874           else
875             toolbarFilename = @"SOGoAppointmentObjectAcceptOrDecline.toolbar";
876         }
877       else
878         toolbarFilename = @"SOGoComponentClose.toolbar";
879     }
880
881   return toolbarFilename;
882 }
883
884 @end