]> err.no Git - scalable-opengroupware.org/blob - SOGo/UI/Scheduler/UIxCalView.m
git-svn-id: http://svn.opengroupware.org/SOGo/trunk@900 d1b88da0-ebda-0310-925b-ed51d...
[scalable-opengroupware.org] / SOGo / UI / Scheduler / UIxCalView.m
1 // $Id$
2
3 #include "UIxCalView.h"
4 #include "common.h"
5 //#include <OGoContentStore/OCSFolder.h>
6 #include "SoObjects/Appointments/SOGoAppointmentFolder.h"
7 #include <NGObjWeb/SoUser.h>
8 #include <SOGoUI/SOGoAptFormatter.h>
9 #include <NGExtensions/NGCalendarDateRange.h>
10 #include <NGiCal/NGiCal.h>
11 #include "UIxComponent+Agenor.h"
12
13 @interface UIxCalView (PrivateAPI)
14 - (NSString *)_userFolderURI;
15 @end
16
17 @implementation UIxCalView
18
19 static BOOL shouldDisplayWeekend = NO;
20
21 + (void)initialize {
22   static BOOL    didInit = NO;
23   NSUserDefaults *ud;
24
25   if (didInit) return;
26
27   ud                   = [NSUserDefaults standardUserDefaults];
28   shouldDisplayWeekend = [ud boolForKey:@"SOGoShouldDisplayWeekend"];
29 }
30
31 - (id)init {
32   self = [super init];
33   if(self) {
34     NSTimeZone *tz;
35
36     tz = [self viewTimeZone];
37     self->aptFormatter =
38       [[SOGoAptFormatter alloc] initWithDisplayTimeZone:tz];
39     self->aptTooltipFormatter =
40       [[SOGoAptFormatter alloc] initWithDisplayTimeZone:tz];
41     self->privateAptFormatter =
42       [[SOGoAptFormatter alloc] initWithDisplayTimeZone:tz];
43     self->privateAptTooltipFormatter =
44       [[SOGoAptFormatter alloc] initWithDisplayTimeZone:tz];
45     [self configureFormatters];
46   }
47   return self;
48 }
49
50 - (void)dealloc {
51   [self->appointments               release];
52   [self->allDayApts                 release];
53   [self->appointment                release];
54   [self->currentDay                 release];
55   [self->aptFormatter               release];
56   [self->aptTooltipFormatter        release];
57   [self->privateAptFormatter        release];
58   [self->privateAptTooltipFormatter release];
59   [super dealloc];
60 }
61
62 /* subclasses should override this */
63 - (void)configureFormatters {
64   NSString *title;
65
66   [self->aptFormatter setFullDetails];
67   [self->aptTooltipFormatter setTooltip];
68   [self->privateAptFormatter setPrivateDetails];
69   [self->privateAptTooltipFormatter setPrivateTooltip];
70
71   title = [self labelForKey:@"empty title"];
72   [self->aptFormatter setTitlePlaceholder:title];
73   [self->aptTooltipFormatter setTitlePlaceholder:title];
74
75   title = [self labelForKey:@"private appointment"];
76   [self->privateAptFormatter setPrivateTitle:title];
77   [self->privateAptTooltipFormatter setPrivateTitle:title];
78 }
79
80 - (NSArray *)filterAppointments:(NSArray *)_apts {
81   NSMutableArray *filtered;
82   unsigned       i, count;
83   NSString       *email;
84
85   count    = [_apts count];
86   if (!count) return _apts;
87   if ([self shouldDisplayRejectedAppointments]) return _apts;
88
89   filtered = [[[NSMutableArray alloc] initWithCapacity:count] autorelease];
90   email    = [self emailForUser];
91
92   for (i = 0; i < count; i++) {
93     NSDictionary *info;
94     NSArray      *partmails;
95     unsigned     p, pCount;
96     BOOL         shouldAdd;
97     
98     shouldAdd = YES;
99     info      = [_apts objectAtIndex:i];
100     partmails = [[info objectForKey:@"partmails"]
101                        componentsSeparatedByString:@"\n"];
102     pCount     = [partmails count];
103     for (p = 0; p < pCount; p++) {
104       NSString *pEmail;
105
106       pEmail = [partmails objectAtIndex:p];
107       if ([pEmail isEqualToString:email]) {
108         NSArray  *partstates;
109         NSString *state;
110
111         partstates = [[info objectForKey:@"partstates"]
112                             componentsSeparatedByString:@"\n"];
113         state      = [partstates objectAtIndex:p];
114         if ([state intValue] == iCalPersonPartStatDeclined)
115           shouldAdd = NO;
116         break;
117       }
118     }
119     if (shouldAdd)
120       [filtered addObject:info];
121   }
122   return filtered;
123 }
124
125 /* accessors */
126
127 - (void)setAppointments:(NSArray *)_apts {
128   _apts = [self filterAppointments:_apts];
129   ASSIGN(self->appointments, _apts);
130 }
131 - (NSArray *)appointments {
132   return self->appointments;
133 }
134
135 - (void)setAppointment:(id)_apt {
136   NSString *mailtoChunk;
137   NSString *myEmail;
138
139   ASSIGN(self->appointment, _apt);
140
141   /* cache some info about apt for faster access */
142   
143   mailtoChunk = [_apt valueForKey:@"orgmail"];
144   myEmail     = [self emailForUser];
145   if ([mailtoChunk rangeOfString:myEmail].length > 0) {
146     self->aptFlags.isMyApt      = YES;
147     self->aptFlags.canAccessApt = YES;
148   }
149   else {
150     NSString *partmails;
151
152     self->aptFlags.isMyApt = NO;
153
154     partmails = [_apt valueForKey:@"partmails"];
155     if ([partmails rangeOfString:myEmail].length)
156       self->aptFlags.canAccessApt = YES;
157     else
158       self->aptFlags.canAccessApt = [[_apt valueForKey:@"ispublic"] boolValue];
159   }
160 }
161 - (id)appointment {
162   return self->appointment;
163 }
164
165 - (BOOL)isMyApt {
166   return self->aptFlags.isMyApt ? YES : NO;
167 }
168
169 - (BOOL)canAccessApt {
170   return self->aptFlags.canAccessApt ? YES : NO;
171 }
172
173 - (BOOL)canNotAccessApt {
174   return self->aptFlags.canAccessApt ? NO : YES;
175 }
176
177 - (NSDictionary *)aptTypeDict {
178   return nil;
179 }
180 - (NSString *)aptTypeLabel {
181   return @"aptLabel";
182 }
183 - (NSString *)aptTypeIcon {
184   return @"";
185 }
186
187 - (SOGoAptFormatter *)aptFormatter {
188   if(self->aptFlags.canAccessApt)
189     return self->aptFormatter;
190   return self->privateAptFormatter;
191 }
192
193 - (SOGoAptFormatter *)aptTooltipFormatter {
194   if(self->aptFlags.canAccessApt)
195     return self->aptTooltipFormatter;
196   return self->privateAptTooltipFormatter;
197 }
198
199 /* TODO: remove this */
200 - (NSString *)shortTextForApt {
201   [self warnWithFormat:@"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
202   if (![self canAccessApt])
203     return @"";
204   return [[self aptFormatter] stringForObjectValue:self->appointment];
205 }
206
207 - (NSString *)shortTitleForApt {
208   NSString *title;
209
210   [self warnWithFormat:@"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
211
212   if (![self canAccessApt])
213     return @"";
214   title = [self->appointment valueForKey:@"title"];
215   if ([title length] > 12)
216     title = [[title substringToIndex:11] stringByAppendingString:@"..."];
217   
218   return title;
219 }
220
221 - (NSString *)tooltipForApt {
222   [self warnWithFormat:@"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
223   return [[self aptTooltipFormatter] stringForObjectValue:self->appointment
224                                      referenceDate:[self currentDay]];
225 }
226
227 - (NSString *)aptStyle {
228   return nil;
229 }
230
231 - (NSCalendarDate *)referenceDateForFormatter {
232   return [self selectedDate];
233 }
234
235 - (NSCalendarDate *)thisMonth {
236   return [self selectedDate];
237 }
238
239 - (NSCalendarDate *)nextMonth {
240   NSCalendarDate *date = [self thisMonth];
241   return [date dateByAddingYears:0 months:1 days:0
242                hours:0 minutes:0 seconds:0];
243 }
244
245
246 /* current day related */
247
248 - (void)setCurrentDay:(NSCalendarDate *)_day {
249   [_day setTimeZone:[self viewTimeZone]];
250   ASSIGN(self->currentDay, _day);
251 }
252 - (NSCalendarDate *)currentDay {
253   return self->currentDay;
254 }
255
256 - (NSString *)currentDayName {
257   return [self localizedNameForDayOfWeek:[self->currentDay dayOfWeek]];
258 }
259
260 - (id)holidayInfo {
261   return nil;
262 }
263
264 - (NSArray *)allDayApts {
265   NSArray        *apts;
266   NSMutableArray *filtered;
267   unsigned       i, count;
268
269   if (self->allDayApts)
270     return self->allDayApts;
271
272   apts     = [self appointments];
273   count    = [apts count];
274   filtered = [[NSMutableArray alloc] initWithCapacity:3];
275   for (i = 0; i < count; i++) {
276     id       apt;
277     NSNumber *bv;
278
279     apt = [apts objectAtIndex:i];
280     bv  = [apt valueForKey:@"isallday"];
281     if ([bv boolValue])
282       [filtered addObject:apt];
283   }
284     
285   ASSIGN(self->allDayApts, filtered);
286   [filtered release];
287   return self->allDayApts;
288 }
289
290
291 /* special appointments */
292
293 - (BOOL)hasDayInfo {
294   return [self hasHoldidayInfo] || [self hasAllDayApts];
295 }
296
297 - (BOOL)hasHoldidayInfo {
298   return [self holidayInfo] != nil;
299 }
300
301 - (BOOL)hasAllDayApts {
302   return [[self allDayApts] count] != 0;
303 }
304
305
306 /* defaults */
307
308 - (BOOL)showFullNames {
309   return YES;
310 }
311
312 - (BOOL)showAMPMDates {
313   return NO;
314 }
315
316 - (unsigned)dayStartHour {
317   return 8;
318 }
319
320 - (unsigned)dayEndHour {
321   return 18;
322 }
323
324 - (BOOL)shouldDisplayWeekend {
325   return shouldDisplayWeekend;
326 }
327
328 - (BOOL)shouldHideWeekend {
329   return ![self shouldDisplayWeekend];
330 }
331
332
333 /* URLs */
334
335 - (NSString *)appointmentViewURL {
336   id pkey;
337   
338   if (![(pkey = [[self appointment] valueForKey:@"uid"]) isNotNull])
339     return nil;
340   
341   return [[[self clientObject] baseURLForAptWithUID:[pkey stringValue]
342                                inContext:[self context]]
343                                stringByAppendingString:@"/view"];
344 }
345
346 /* fetching */
347
348 - (NSCalendarDate *)startDate {
349   return [self selectedDate];
350 }
351 - (NSCalendarDate *)endDate {
352   return [[self startDate] tomorrow];
353 }
354
355 - (NSArray *)fetchCoreInfos {
356   if (!self->appointments) {
357     id             folder;
358     NSCalendarDate *sd, *ed;
359
360     folder             = [self clientObject];
361     sd                 = [self startDate];
362     ed                 = [self endDate];
363     [self setAppointments:[folder fetchOverviewInfosFrom:sd to:ed]];
364   }
365   return self->appointments;
366 }
367
368 /* query parameters */
369
370 - (BOOL)shouldDisplayRejectedAppointments {
371   NSString *bv;
372   
373   bv = [[[self context] request] formValueForKey:@"dr"];
374   if (!bv) return NO;
375   return [bv boolValue];
376 }
377
378 - (NSDictionary *)toggleShowRejectedAptsQueryParameters {
379   NSMutableDictionary *qp;
380   BOOL                shouldDisplay;
381   
382   shouldDisplay = ![self shouldDisplayRejectedAppointments];
383   qp = [[[self queryParameters] mutableCopy] autorelease];
384   [qp setObject:shouldDisplay ? @"1" : @"0" forKey:@"dr"];
385   return qp;
386 }
387
388 - (NSString *)toggleShowRejectedAptsLabel {
389   if (![self shouldDisplayRejectedAppointments])
390     return @"show_rejected_apts";
391   return @"hide_rejected_apts";
392 }
393
394 /* date selection & conversion */
395
396 - (NSDictionary *)todayQueryParameters {
397   NSCalendarDate *date;
398     
399   date = [NSCalendarDate date]; /* today */
400   return [self queryParametersBySettingSelectedDate:date];
401 }
402
403 - (NSDictionary *)currentDayQueryParameters {
404   return [self queryParametersBySettingSelectedDate:self->currentDay];
405 }
406
407 /* calendarUIDs */
408
409 - (NSString *)formattedCalendarUIDs {
410     return [[[self clientObject] calendarUIDs]
411                                  componentsJoinedByString:@", "];
412 }
413
414 /* Actions */
415
416 - (NSString *)_userFolderURI {
417   WOContext *ctx;
418   id        obj;
419   NSURL     *url;
420
421   ctx = [self context];
422   obj = [[ctx objectTraversalStack] objectAtIndex:1];
423   url = [NSURL URLWithString:[obj baseURLInContext:ctx]];
424   return [[url path] stringByUnescapingURL];
425 }
426
427 - (id)redirectForUIDsAction {
428   NSMutableString *uri;
429   NSString   *uidsString, *loc, *prevMethod, *userFolderID;
430   WORequest  *req;
431   id <WOActionResults> r;
432   BOOL useGroups;
433   unsigned index;
434
435   req = [[self context] request];
436
437   uidsString = [req formValueForKey:@"userUIDString"];
438   uidsString = [uidsString stringByTrimmingWhiteSpaces];
439
440   prevMethod = [req formValueForKey:@"previousMethod"];
441   if(prevMethod == nil)
442     prevMethod = @"";
443
444   uri = [[NSMutableString alloc] initWithString:[self _userFolderURI]];
445   /* if we have more than one entry, use groups - otherwise don't */
446   useGroups = [uidsString rangeOfString:@","].length > 0;
447   userFolderID = [uri lastPathComponent];
448   if(useGroups) {
449     NSArray *uids;
450
451     uids = [uidsString componentsSeparatedByString:@","];
452     /* guarantee that our id is the first */
453     if(((index = [uids indexOfObject:userFolderID]) != NSNotFound) &&
454        (index != 0)) {
455         uids = [[uids mutableCopy] autorelease];
456         [(NSMutableArray *)uids removeObjectAtIndex:index];
457         [(NSMutableArray *)uids insertObject:userFolderID atIndex:0];
458         uidsString = [uids componentsJoinedByString:@","];
459     }
460     [uri appendString:@"Groups/_custom_"];
461     [uri appendString:uidsString];
462     [uri appendString:@"/"];
463   }
464   else {
465       /* check if lastPathComponent is the base that we want to have */
466       if((([uidsString length] != 0) &&
467           (![userFolderID isEqualToString:uidsString]))) {
468           NSRange r;
469           
470           /* uri ends with an '/', so we have to adjust the range a little */
471           r = NSMakeRange(0, [uri length] - 1);
472           r = [uri rangeOfString:@"/"
473                          options:NSBackwardsSearch
474                            range:r];
475           r = NSMakeRange(r.location + 1, [uri length] - r.location - 2);
476           [uri replaceCharactersInRange:r withString:uidsString];
477       }
478   }
479   [uri appendString:@"Calendar/"];
480   [uri appendString:prevMethod];
481
482 #if 0
483   NSLog(@"%s redirect uri:%@",
484           __PRETTY_FUNCTION__,
485           uri);
486 #endif
487   loc = [self completeHrefForMethod:uri]; /* this might return uri! */
488   r = [self redirectToLocation:loc];
489   [uri release];
490   return r;
491 }
492
493 @end /* UIxCalView */