]> err.no Git - scalable-opengroupware.org/blob - SOGo/UI/Scheduler/UIxCalView.m
some code cleanup
[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 = NO;
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 = YES;
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   if (![self isMyApt])
229     return @"apt_other";
230   return nil;
231 }
232
233 - (NSCalendarDate *)referenceDateForFormatter {
234   return [self selectedDate];
235 }
236
237 - (NSCalendarDate *)thisMonth {
238   return [self selectedDate];
239 }
240
241 - (NSCalendarDate *)nextMonth {
242   NSCalendarDate *date = [self thisMonth];
243   return [date dateByAddingYears:0 months:1 days:0
244                hours:0 minutes:0 seconds:0];
245 }
246
247
248 /* current day related */
249
250 - (void)setCurrentDay:(NSCalendarDate *)_day {
251   [_day setTimeZone:[self viewTimeZone]];
252   ASSIGN(self->currentDay, _day);
253 }
254 - (NSCalendarDate *)currentDay {
255   return self->currentDay;
256 }
257
258 - (NSString *)currentDayName {
259   return [self localizedNameForDayOfWeek:[self->currentDay dayOfWeek]];
260 }
261
262 - (id)holidayInfo {
263   return nil;
264 }
265
266 - (NSArray *)allDayApts {
267   NSArray        *apts;
268   NSMutableArray *filtered;
269   unsigned       i, count;
270
271   if (self->allDayApts)
272     return self->allDayApts;
273
274   apts     = [self appointments];
275   count    = [apts count];
276   filtered = [[NSMutableArray alloc] initWithCapacity:3];
277   for (i = 0; i < count; i++) {
278     id       apt;
279     NSNumber *bv;
280
281     apt = [apts objectAtIndex:i];
282     bv  = [apt valueForKey:@"isallday"];
283     if ([bv boolValue])
284       [filtered addObject:apt];
285   }
286     
287   ASSIGN(self->allDayApts, filtered);
288   [filtered release];
289   return self->allDayApts;
290 }
291
292
293 /* special appointments */
294
295 - (BOOL)hasDayInfo {
296   return [self hasHoldidayInfo] || [self hasAllDayApts];
297 }
298
299 - (BOOL)hasHoldidayInfo {
300   return [self holidayInfo] != nil;
301 }
302
303 - (BOOL)hasAllDayApts {
304   return [[self allDayApts] count] != 0;
305 }
306
307
308 /* defaults */
309
310 - (BOOL)showFullNames {
311   return YES;
312 }
313
314 - (BOOL)showAMPMDates {
315   return NO;
316 }
317
318 - (unsigned)dayStartHour {
319   return 8;
320 }
321
322 - (unsigned)dayEndHour {
323   return 18;
324 }
325
326 - (BOOL)shouldDisplayWeekend {
327   return shouldDisplayWeekend;
328 }
329
330 - (BOOL)shouldHideWeekend {
331   return ![self shouldDisplayWeekend];
332 }
333
334
335 /* URLs */
336
337 - (NSString *)appointmentViewURL {
338   id pkey;
339   
340   if (![(pkey = [[self appointment] valueForKey:@"uid"]) isNotNull])
341     return nil;
342   
343   return [[[self clientObject] baseURLForAptWithUID:[pkey stringValue]
344                                inContext:[self context]]
345                                stringByAppendingString:@"/view"];
346 }
347
348 /* fetching */
349
350 - (NSCalendarDate *)startDate {
351   return [self selectedDate];
352 }
353 - (NSCalendarDate *)endDate {
354   return [[self startDate] tomorrow];
355 }
356
357 - (NSArray *)fetchCoreInfos {
358   if (!self->appointments) {
359     id             folder;
360     NSCalendarDate *sd, *ed;
361
362     folder             = [self clientObject];
363     sd                 = [self startDate];
364     ed                 = [self endDate];
365     [self setAppointments:[folder fetchOverviewInfosFrom:sd to:ed]];
366   }
367   return self->appointments;
368 }
369
370 /* query parameters */
371
372 - (BOOL)shouldDisplayRejectedAppointments {
373   NSString *bv;
374   
375   bv = [[[self context] request] formValueForKey:@"dr"];
376   if (!bv) return NO;
377   return [bv boolValue];
378 }
379
380 - (NSDictionary *)toggleShowRejectedAptsQueryParameters {
381   NSMutableDictionary *qp;
382   BOOL                shouldDisplay;
383   
384   shouldDisplay = ![self shouldDisplayRejectedAppointments];
385   qp = [[[self queryParameters] mutableCopy] autorelease];
386   [qp setObject:shouldDisplay ? @"1" : @"0" forKey:@"dr"];
387   return qp;
388 }
389
390 - (NSString *)toggleShowRejectedAptsLabel {
391   if (![self shouldDisplayRejectedAppointments])
392     return @"show_rejected_apts";
393   return @"hide_rejected_apts";
394 }
395
396 /* date selection & conversion */
397
398 - (NSDictionary *)todayQueryParameters {
399   NSCalendarDate *date;
400     
401   date = [NSCalendarDate date]; /* today */
402   return [self queryParametersBySettingSelectedDate:date];
403 }
404
405 - (NSDictionary *)currentDayQueryParameters {
406   return [self queryParametersBySettingSelectedDate:self->currentDay];
407 }
408
409 /* calendarUIDs */
410
411 - (NSString *)formattedCalendarUIDs {
412     return [[[self clientObject] calendarUIDs]
413                                  componentsJoinedByString:@", "];
414 }
415
416 /* Actions */
417
418 - (NSString *)_userFolderURI {
419   WOContext *ctx;
420   id        obj;
421   NSURL     *url;
422
423   ctx = [self context];
424   obj = [[ctx objectTraversalStack] objectAtIndex:1];
425   url = [NSURL URLWithString:[obj baseURLInContext:ctx]];
426   return [[url path] stringByUnescapingURL];
427 }
428
429 - (id)redirectForUIDsAction {
430   NSMutableString *uri;
431   NSString   *uidsString, *loc, *prevMethod, *userFolderID;
432   WORequest  *req;
433   id <WOActionResults> r;
434   BOOL useGroups;
435   unsigned index;
436
437   req = [[self context] request];
438
439   uidsString = [req formValueForKey:@"anaisUIDString"];
440   uidsString = [uidsString stringByTrimmingWhiteSpaces];
441
442   prevMethod = [req formValueForKey:@"previousMethod"];
443   if(prevMethod == nil)
444     prevMethod = @"";
445
446   uri = [[NSMutableString alloc] initWithString:[self _userFolderURI]];
447   /* if we have more than one entry, use groups - otherwise don't */
448   useGroups = [uidsString rangeOfString:@","].length > 0;
449   userFolderID = [uri lastPathComponent];
450   if(useGroups) {
451     NSArray *uids;
452
453     uids = [uidsString componentsSeparatedByString:@","];
454     /* guarantee that our id is the first */
455     if(((index = [uids indexOfObject:userFolderID]) != NSNotFound) &&
456        (index != 0)) {
457         uids = [[uids mutableCopy] autorelease];
458         [(NSMutableArray *)uids removeObjectAtIndex:index];
459         [(NSMutableArray *)uids insertObject:userFolderID atIndex:0];
460         uidsString = [uids componentsJoinedByString:@","];
461     }
462     [uri appendString:@"Groups/_custom_"];
463     [uri appendString:uidsString];
464     [uri appendString:@"/"];
465   }
466   else {
467       /* check if lastPathComponent is the base that we want to have */
468       if((([uidsString length] != 0) &&
469           (![userFolderID isEqualToString:uidsString]))) {
470           NSRange r;
471           
472           /* uri ends with an '/', so we have to adjust the range a little */
473           r = NSMakeRange(0, [uri length] - 1);
474           r = [uri rangeOfString:@"/"
475                          options:NSBackwardsSearch
476                            range:r];
477           r = NSMakeRange(r.location + 1, [uri length] - r.location - 2);
478           [uri replaceCharactersInRange:r withString:uidsString];
479       }
480   }
481   [uri appendString:@"Calendar/"];
482   [uri appendString:prevMethod];
483
484 #if 0
485   NSLog(@"%s redirect uri:%@",
486           __PRETTY_FUNCTION__,
487           uri);
488 #endif
489   loc = [self completeHrefForMethod:uri]; /* this might return uri! */
490   r = [self redirectToLocation:loc];
491   [uri release];
492   return r;
493 }
494
495 @end /* UIxCalView */