]> err.no Git - scalable-opengroupware.org/blob - UI/Scheduler/UIxCalView.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1304 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / Scheduler / UIxCalView.m
1 /* UIxCalMainView.m - this file is part of SOGo
2  *
3  * Copyright (C) 2006, 2007 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 <OGoContentStore/OCSFolder.h>
24
25 #import <NGObjWeb/SoSecurityManager.h>
26 #import <NGObjWeb/SoUser.h>
27 #import <NGObjWeb/WOResponse.h>
28 #import <NGExtensions/NGCalendarDateRange.h>
29 #import <NGExtensions/NSCalendarDate+misc.h>
30 #import <NGExtensions/NSNull+misc.h>
31 #import <NGExtensions/NSObject+Logs.h>
32 #import <NGExtensions/NSString+misc.h>
33 #import <NGCards/NGCards.h>
34
35 #import <SoObjects/Appointments/SOGoAppointmentFolder.h>
36 #import <SoObjects/SOGo/NSArray+Utilities.h>
37 #import <SoObjects/SOGo/SOGoUser.h>
38 #import <SoObjects/SOGo/SOGoObject.h>
39
40 #import <SOGoUI/SOGoAptFormatter.h>
41
42 #import "UIxComponent+Scheduler.h"
43
44 #import "UIxCalView.h"
45
46 @interface UIxCalView (PrivateAPI)
47 - (NSString *) _userFolderURI;
48 @end
49
50 @implementation UIxCalView
51
52 static BOOL shouldDisplayWeekend = NO;
53
54 + (void) initialize
55 {
56   static BOOL didInit = NO;
57   NSUserDefaults *ud;
58
59   if (didInit) return;
60
61   ud = [NSUserDefaults standardUserDefaults];
62   shouldDisplayWeekend = [ud boolForKey: @"SOGoShouldDisplayWeekend"];
63   didInit = YES;
64 }
65
66 - (id) init
67 {
68   self = [super init];
69   if (self)
70     {
71       timeZone = [[context activeUser] timeZone];
72       [timeZone retain];
73       aptFormatter
74         = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: timeZone];
75       aptTooltipFormatter
76         = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: timeZone];
77       privateAptFormatter
78         = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: timeZone];
79       privateAptTooltipFormatter
80         = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: timeZone];
81       [self configureFormatters];
82       componentsData = [NSMutableDictionary new];
83     }
84
85   return self;
86 }
87
88 - (void) dealloc
89 {
90   [componentsData release];
91   [appointments release];
92   [allDayApts release];
93   [appointment release];
94   [currentDay release];
95   [aptFormatter release];
96   [aptTooltipFormatter release];
97   [privateAptFormatter release];
98   [privateAptTooltipFormatter release];
99   [timeZone release];
100   [super dealloc];
101 }
102
103 /* subclasses should override this */
104 - (void) configureFormatters
105 {
106   NSString *title;
107
108   [aptFormatter setFullDetails];
109   [aptTooltipFormatter setTooltip];
110   [privateAptFormatter setPrivateDetails];
111   [privateAptTooltipFormatter setPrivateTooltip];
112
113   title = [self labelForKey: @"empty title"];
114   [aptFormatter setTitlePlaceholder: title];
115   [aptTooltipFormatter setTitlePlaceholder: title];
116
117   title = [self labelForKey: @"private appointment"];
118   [privateAptFormatter setPrivateTitle: title];
119   [privateAptTooltipFormatter setPrivateTitle: title];
120 }
121
122 - (NSArray *) filterAppointments:(NSArray *) _apts
123 {
124   NSMutableArray *filtered;
125   unsigned i, count, p, pCount;
126   NSString *email, *partmailsString, *state, *pEmail;
127   NSDictionary *info, *primaryIdentity;
128   NSArray *partmails, *partstates;
129   BOOL shouldAdd;
130
131   if ([self shouldDisplayRejectedAppointments])
132     return _apts;
133   {
134     count = [_apts count];
135     filtered = [[[NSMutableArray alloc] initWithCapacity: count] autorelease];
136
137     primaryIdentity = [[context activeUser] primaryIdentity];
138     email = [primaryIdentity objectForKey: @"email"];
139
140     for (i = 0; i < count; i++)
141       {
142         shouldAdd = YES;
143         info = [_apts objectAtIndex: i];
144         partmailsString = [info objectForKey: @"partmails"];
145         if ([partmailsString isNotNull])
146           {
147             partmails = [partmailsString componentsSeparatedByString: @"\n"];
148             pCount = [partmails count];
149             for (p = 0; p < pCount; p++)
150               {
151                 pEmail = [partmails objectAtIndex: p];
152                 if ([pEmail isEqualToString: email])
153                   {
154                     partstates = [[info objectForKey: @"partstates"]
155                                    componentsSeparatedByString: @"\n"];
156                     state = [partstates objectAtIndex: p];
157                     if ([state intValue] == iCalPersonPartStatDeclined)
158                       shouldAdd = NO;
159                     break;
160                   }
161               }
162           }
163         if (shouldAdd)
164           [filtered addObject: info];
165       }
166   }
167
168   return filtered;
169 }
170
171 /* accessors */
172
173 - (void) setAppointments:(NSArray *) _apts
174 {
175   _apts = [self filterAppointments: _apts];
176   ASSIGN(appointments, _apts);
177 }
178
179 - (NSArray *) appointments
180 {
181   return appointments;
182 }
183
184 - (void) setAppointment:(id) _apt
185 {
186   ASSIGN (appointment, _apt);
187 }
188
189 // - (void) setAppointment:(id) _apt
190 // {
191 //   NSString *mailtoChunk;
192 //   NSString *myEmail;
193 //   NSString *partmails;
194
195 //   ASSIGN(appointment, _apt);
196
197 //   /* cache some info about apt for faster access */
198   
199 //   mailtoChunk = [_apt valueForKey: @"orgmail"];
200 //   myEmail = [self emailForUser];
201 //   if ([mailtoChunk rangeOfString: myEmail].length > 0)
202 //     {
203 //       aptFlags.isMyApt = YES;
204 //       aptFlags.canAccessApt = YES;
205 //     }
206 //   else
207 //     {
208 //       aptFlags.isMyApt = NO;
209
210 //       partmails = [_apt valueForKey: @"partmails"];
211 //       if ([partmails rangeOfString: myEmail].length)
212 //         aptFlags.canAccessApt = YES;
213 //       else
214 //         aptFlags.canAccessApt
215 //           = ([[_apt valueForKey: @"classification"] intValue]
216 //              == iCalAccessPublic);
217 //     }
218 // }
219
220 - (id) appointment
221 {
222   return appointment;
223 }
224
225 - (BOOL) isMyApt
226 {
227   return aptFlags.isMyApt ? YES : NO;
228 }
229
230 - (BOOL) canAccessApt
231 {
232   return aptFlags.canAccessApt ? YES : NO;
233 }
234
235 - (BOOL) canNotAccessApt
236 {
237   return aptFlags.canAccessApt ? NO : YES;
238 }
239
240 - (NSDictionary *) aptTypeDict
241 {
242   return nil;
243 }
244 - (NSString *) aptTypeLabel
245 {
246   return @"aptLabel";
247 }
248 - (NSString *) aptTypeIcon
249 {
250   return @"";
251 }
252
253 - (SOGoAptFormatter *) aptFormatter
254 {
255   if (aptFlags.canAccessApt)
256     return aptFormatter;
257   return privateAptFormatter;
258 }
259
260 - (SOGoAptFormatter *) aptTooltipFormatter
261 {
262   if (aptFlags.canAccessApt)
263     return aptTooltipFormatter;
264   return privateAptTooltipFormatter;
265 }
266
267 - (void) setTasks: (NSArray *) _tasks
268 {
269   ASSIGN(tasks, _tasks);
270 }
271
272 - (NSArray *) tasks
273 {
274   return tasks;
275 }
276
277 /* TODO: remove this */
278 - (NSString *) shortTextForApt
279 {
280   [self warnWithFormat: @"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
281   if (![self canAccessApt])
282     return @"";
283   return [[self aptFormatter] stringForObjectValue: appointment];
284 }
285
286 - (NSString *) shortTitleForApt
287 {
288   NSString *title;
289
290   [self warnWithFormat: @"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
291
292   if (![self canAccessApt])
293     return @"";
294   title = [appointment valueForKey: @"title"];
295   if ([title length] > 12)
296     title = [[title substringToIndex: 11] stringByAppendingString: @"..."];
297   
298   return title;
299 }
300
301 - (NSString *) tooltipForApt
302 {
303   [self warnWithFormat: @"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
304   return [[self aptTooltipFormatter] stringForObjectValue: appointment
305                                      referenceDate: [self currentDay]];
306 }
307
308 - (NSString *) aptStyle
309 {
310   return nil;
311 }
312
313 - (NSCalendarDate *) referenceDateForFormatter
314 {
315   return [self selectedDate];
316 }
317
318 - (NSCalendarDate *) thisMonth
319 {
320   return [self selectedDate];
321 }
322
323 - (NSCalendarDate *) nextMonth
324 {
325   NSCalendarDate *date = [self thisMonth];
326   return [date dateByAddingYears: 0 months: 1 days: 0
327                hours: 0 minutes: 0 seconds: 0];
328 }
329
330 - (NSCalendarDate *) prevMonth
331 {
332   NSCalendarDate *date = [self thisMonth];
333   return [date dateByAddingYears: 0 months:-1 days: 0
334                hours: 0 minutes: 0 seconds: 0];
335 }
336
337 - (NSString *) prevMonthAsString
338 {
339   return [self dateStringForDate: [self prevMonth]];
340 }
341
342 - (NSString *) nextMonthAsString
343 {
344   return [self dateStringForDate: [self nextMonth]];
345 }
346
347 /* current day related */
348
349 - (void) setCurrentDay:(NSCalendarDate *) _day
350 {
351   [_day setTimeZone: timeZone];
352   ASSIGN (currentDay, _day);
353 }
354
355 - (NSCalendarDate *) currentDay
356 {
357   return currentDay;
358 }
359
360 - (NSString *) currentDayName
361 {
362   return [self localizedNameForDayOfWeek: [currentDay dayOfWeek]];
363 }
364
365 - (id) holidayInfo
366 {
367   return nil;
368 }
369
370 - (NSArray *) allDayApts
371 {
372   NSArray        *apts;
373   NSMutableArray *filtered;
374   unsigned       i, count;
375
376   if (allDayApts)
377     return allDayApts;
378
379   apts = [self appointments];
380   count = [apts count];
381   filtered = [[NSMutableArray alloc] initWithCapacity: 3];
382   for (i = 0; i < count; i++)
383     {
384       id       apt;
385       NSNumber *bv;
386
387       apt = [apts objectAtIndex: i];
388       bv = [apt valueForKey: @"isallday"];
389       if ([bv boolValue])
390         [filtered addObject: apt];
391     }
392     
393   ASSIGN(allDayApts, filtered);
394   [filtered release];
395   return allDayApts;
396 }
397
398
399 /* special appointments */
400
401 - (BOOL) hasDayInfo
402 {
403   return [self hasHoldidayInfo] || [self hasAllDayApts];
404 }
405
406 - (BOOL) hasHoldidayInfo
407 {
408   return [self holidayInfo] != nil;
409 }
410
411 - (BOOL) hasAllDayApts
412 {
413   return [[self allDayApts] count] != 0;
414 }
415
416
417 /* defaults */
418
419 - (BOOL) showFullNames
420 {
421   return YES;
422 }
423
424 - (BOOL) showAMPMDates
425 {
426   return NO;
427 }
428
429 - (unsigned) dayStartHour
430 {
431   return 0;
432 }
433
434 - (unsigned) dayEndHour
435 {
436   return 23;
437 }
438
439 - (BOOL) shouldDisplayWeekend
440 {
441   return shouldDisplayWeekend;
442 }
443
444 - (BOOL) shouldHideWeekend
445 {
446   return ![self shouldDisplayWeekend];
447 }
448
449
450 /* URLs */
451
452 - (NSString *) appointmentViewURL
453 {
454   id pkey;
455   
456   if (![(pkey = [[self appointment] valueForKey: @"uid"]) isNotNull])
457     return nil;
458   
459   return [[[self clientObject] baseURLForAptWithUID: [pkey stringValue]
460                                inContext: [self context]]
461            stringByAppendingString: @"/view"];
462 }
463
464 /* fetching */
465
466 - (NSCalendarDate *) startDate
467 {
468   return [self selectedDate];
469 }
470
471 - (NSCalendarDate *) endDate
472 {
473   return [[self startDate] tomorrow];
474 }
475
476 /* query parameters */
477
478 - (BOOL) shouldDisplayRejectedAppointments
479 {
480   NSString *bv;
481   
482   bv = [self queryParameterForKey: @"dr"];
483   if (!bv) return NO;
484   return [bv boolValue];
485 }
486
487 - (NSDictionary *) toggleShowRejectedAptsQueryParameters
488 {
489   NSMutableDictionary *qp;
490   BOOL                shouldDisplay;
491   
492   shouldDisplay = ![self shouldDisplayRejectedAppointments];
493   qp = [[[self queryParameters] mutableCopy] autorelease];
494   [qp setObject: shouldDisplay ? @"1" : @"0" forKey: @"dr"];
495   return qp;
496 }
497
498 - (NSString *) toggleShowRejectedAptsLabel
499 {
500   if (![self shouldDisplayRejectedAppointments])
501     return @"show_rejected_apts";
502   return @"hide_rejected_apts";
503 }
504
505 /* date selection & conversion */
506
507 - (NSDictionary *) _dateQueryParametersWithOffset: (int) daysOffset
508 {
509   NSCalendarDate *date;
510   
511   date = [[self startDate] dateByAddingYears: 0 months: 0
512                            days: daysOffset
513                            hours: 0 minutes: 0 seconds: 0];
514   return [self queryParametersBySettingSelectedDate: date];
515 }
516
517 - (NSDictionary *) todayQueryParameters
518 {
519   return [self queryParametersBySettingSelectedDate: [NSCalendarDate date]];
520 }
521
522 - (NSDictionary *) currentDayQueryParameters
523 {
524   return [self queryParametersBySettingSelectedDate: currentDay];
525 }
526
527 /* Actions */
528
529 - (NSString *) _userFolderURI
530 {
531   WOContext *ctx;
532   id        obj;
533   NSURL     *url;
534
535   ctx = [self context];
536   obj = [[ctx objectTraversalStack] objectAtIndex: 1];
537   url = [NSURL URLWithString: [obj baseURLInContext: ctx]];
538   return [[url path] stringByUnescapingURL];
539 }
540
541 - (id) redirectForUIDsAction
542 {
543   NSMutableString *uri;
544   NSString *uidsString, *loc, *prevMethod, *userFolderID;
545   id <WOActionResults> r;
546   BOOL useGroups;
547   unsigned index;
548
549   uidsString = [self queryParameterForKey: @"userUIDString"];
550   uidsString = [uidsString stringByTrimmingSpaces];
551   [self setQueryParameter: nil forKey: @"userUIDString"];
552
553   prevMethod = [self queryParameterForKey: @"previousMethod"];
554   if (prevMethod == nil)
555     prevMethod = @"";
556
557   uri = [[NSMutableString alloc] initWithString: [self _userFolderURI]];
558   /* if we have more than one entry, use groups - otherwise don't */
559   useGroups = [uidsString rangeOfString: @","].length > 0;
560   userFolderID = [uri lastPathComponent];
561   if (useGroups)
562     {
563       NSArray *uids;
564
565       uids = [uidsString componentsSeparatedByString: @","];
566       /* guarantee that our id is the first */
567       if (((index = [uids indexOfObject: userFolderID]) != NSNotFound)
568           && (index != 0))
569         {
570           uids = [[uids mutableCopy] autorelease];
571           [(NSMutableArray *) uids removeObjectAtIndex: index];
572           [(NSMutableArray *) uids insertObject: userFolderID atIndex: 0];
573           uidsString = [uids componentsJoinedByString: @","];
574         }
575       [uri appendString: @"Groups/_custom_"];
576       [uri appendString: uidsString];
577       [uri appendString: @"/"];
578       NSLog (@"Group URI = '%@'", uri);
579     }
580   else
581     {
582       /* check if lastPathComponent is the base that we want to have */
583       if ((([uidsString length] != 0)
584            && (![userFolderID isEqualToString: uidsString])))
585         {
586           NSRange r;
587           
588           /* uri ends with an '/', so we have to adjust the range a little */
589           r = NSMakeRange(0, [uri length] - 1);
590           r = [uri rangeOfString: @"/"
591                    options: NSBackwardsSearch
592                    range: r];
593           r = NSMakeRange(r.location + 1, [uri length] - r.location - 2);
594           [uri replaceCharactersInRange: r withString: uidsString];
595         }
596     }
597   [uri appendString: @"Calendar/"];
598   [uri appendString: prevMethod];
599
600 #if 0
601   NSLog(@"%s redirect uri:%@",
602         __PRETTY_FUNCTION__,
603         uri);
604 #endif
605   loc = [self completeHrefForMethod: uri]; /* this might return uri! */
606   r = [self redirectToLocation: loc];
607   [uri release];
608   return r;
609 }
610
611 @end /* UIxCalView */