4 //#import <OGoContentStore/OCSFolder.h>
6 #import <NGObjWeb/SoSecurityManager.h>
7 #import <NGObjWeb/SoUser.h>
8 #import <NGExtensions/NGCalendarDateRange.h>
9 #import <NGCards/NGCards.h>
11 #import <SOGoUI/SOGoAptFormatter.h>
12 #import "UIxComponent+Agenor.h"
14 #import "SoObjects/Appointments/SOGoAppointmentFolder.h"
15 #import <SOGo/SOGoUser.h>
16 #import <SOGo/SOGoObject.h>
18 #import "UIxCalView.h"
20 @interface UIxCalView (PrivateAPI)
21 - (NSString *) _userFolderURI;
24 @implementation UIxCalView
26 static BOOL shouldDisplayWeekend = NO;
30 static BOOL didInit = NO;
35 ud = [NSUserDefaults standardUserDefaults];
36 shouldDisplayWeekend = [ud boolForKey: @"SOGoShouldDisplayWeekend"];
47 tz = [[self clientObject] userTimeZone];
49 = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: tz];
51 = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: tz];
53 = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: tz];
54 privateAptTooltipFormatter
55 = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: tz];
56 [self configureFormatters];
57 componentsData = [NSMutableDictionary new];
64 [componentsData release];
65 [appointments release];
67 [appointment release];
69 [aptFormatter release];
70 [aptTooltipFormatter release];
71 [privateAptFormatter release];
72 [privateAptTooltipFormatter release];
76 /* subclasses should override this */
77 - (void) configureFormatters
81 [aptFormatter setFullDetails];
82 [aptTooltipFormatter setTooltip];
83 [privateAptFormatter setPrivateDetails];
84 [privateAptTooltipFormatter setPrivateTooltip];
86 title = [self labelForKey: @"empty title"];
87 [aptFormatter setTitlePlaceholder: title];
88 [aptTooltipFormatter setTitlePlaceholder: title];
90 title = [self labelForKey: @"private appointment"];
91 [privateAptFormatter setPrivateTitle: title];
92 [privateAptTooltipFormatter setPrivateTitle: title];
95 - (NSArray *) filterAppointments:(NSArray *) _apts
97 NSMutableArray *filtered;
101 count = [_apts count];
102 if (!count) return _apts;
103 if ([self shouldDisplayRejectedAppointments]) return _apts;
105 filtered = [[[NSMutableArray alloc] initWithCapacity: count] autorelease];
106 email = [self emailForUser];
108 for (i = 0; i < count; i++)
116 info = [_apts objectAtIndex: i];
117 partmails = [[info objectForKey: @"partmails"]
118 componentsSeparatedByString: @"\n"];
119 pCount = [partmails count];
120 for (p = 0; p < pCount; p++)
124 pEmail = [partmails objectAtIndex: p];
125 if ([pEmail isEqualToString: email])
130 partstates = [[info objectForKey: @"partstates"]
131 componentsSeparatedByString: @"\n"];
132 state = [partstates objectAtIndex: p];
133 if ([state intValue] == iCalPersonPartStatDeclined)
139 [filtered addObject: info];
146 - (void) setAppointments:(NSArray *) _apts
148 _apts = [self filterAppointments: _apts];
149 ASSIGN(appointments, _apts);
152 - (NSArray *) appointments
157 - (void) setAppointment:(id) _apt
159 NSString *mailtoChunk;
162 ASSIGN(appointment, _apt);
164 /* cache some info about apt for faster access */
166 mailtoChunk = [_apt valueForKey: @"orgmail"];
167 myEmail = [self emailForUser];
168 if ([mailtoChunk rangeOfString: myEmail].length > 0)
170 aptFlags.isMyApt = YES;
171 aptFlags.canAccessApt = YES;
177 aptFlags.isMyApt = NO;
179 partmails = [_apt valueForKey: @"partmails"];
180 if ([partmails rangeOfString: myEmail].length)
181 aptFlags.canAccessApt = YES;
183 aptFlags.canAccessApt = [[_apt valueForKey: @"ispublic"] boolValue];
187 - (void) setTasks: (NSArray *) _tasks
189 ASSIGN(tasks, _tasks);
204 return aptFlags.isMyApt ? YES : NO;
207 - (BOOL) canAccessApt
209 return aptFlags.canAccessApt ? YES : NO;
212 - (BOOL) canNotAccessApt
214 return aptFlags.canAccessApt ? NO : YES;
217 - (NSDictionary *) aptTypeDict
221 - (NSString *) aptTypeLabel
225 - (NSString *) aptTypeIcon
230 - (SOGoAptFormatter *) aptFormatter
232 if (aptFlags.canAccessApt)
234 return privateAptFormatter;
237 - (SOGoAptFormatter *) aptTooltipFormatter
239 if (aptFlags.canAccessApt)
240 return aptTooltipFormatter;
241 return privateAptTooltipFormatter;
244 /* TODO: remove this */
245 - (NSString *) shortTextForApt
247 [self warnWithFormat: @"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
248 if (![self canAccessApt])
250 return [[self aptFormatter] stringForObjectValue: appointment];
253 - (NSString *) shortTitleForApt
257 [self warnWithFormat: @"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
259 if (![self canAccessApt])
261 title = [appointment valueForKey: @"title"];
262 if ([title length] > 12)
263 title = [[title substringToIndex: 11] stringByAppendingString: @"..."];
268 - (NSString *) tooltipForApt
270 [self warnWithFormat: @"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
271 return [[self aptTooltipFormatter] stringForObjectValue: appointment
272 referenceDate: [self currentDay]];
275 - (NSString *) aptStyle
280 - (NSCalendarDate *) referenceDateForFormatter
282 return [self selectedDate];
285 - (NSCalendarDate *) thisMonth
287 return [self selectedDate];
290 - (NSCalendarDate *) nextMonth
292 NSCalendarDate *date = [self thisMonth];
293 return [date dateByAddingYears: 0 months: 1 days: 0
294 hours: 0 minutes: 0 seconds: 0];
297 - (NSCalendarDate *) prevMonth
299 NSCalendarDate *date = [self thisMonth];
300 return [date dateByAddingYears: 0 months:-1 days: 0
301 hours: 0 minutes: 0 seconds: 0];
304 - (NSString *) prevMonthAsString
306 return [self dateStringForDate: [self prevMonth]];
309 - (NSString *) nextMonthAsString
311 return [self dateStringForDate: [self nextMonth]];
314 /* current day related */
316 - (void) setCurrentDay:(NSCalendarDate *) _day
318 [_day setTimeZone: [[self clientObject] userTimeZone]];
319 ASSIGN(currentDay, _day);
322 - (NSCalendarDate *) currentDay
327 - (NSString *) currentDayName
329 return [self localizedNameForDayOfWeek: [currentDay dayOfWeek]];
337 - (NSArray *) allDayApts
340 NSMutableArray *filtered;
346 apts = [self appointments];
347 count = [apts count];
348 filtered = [[NSMutableArray alloc] initWithCapacity: 3];
349 for (i = 0; i < count; i++)
354 apt = [apts objectAtIndex: i];
355 bv = [apt valueForKey: @"isallday"];
357 [filtered addObject: apt];
360 ASSIGN(allDayApts, filtered);
366 /* special appointments */
370 return [self hasHoldidayInfo] || [self hasAllDayApts];
373 - (BOOL) hasHoldidayInfo
375 return [self holidayInfo] != nil;
378 - (BOOL) hasAllDayApts
380 return [[self allDayApts] count] != 0;
386 - (BOOL) showFullNames
391 - (BOOL) showAMPMDates
396 - (unsigned) dayStartHour
401 - (unsigned) dayEndHour
406 - (BOOL) shouldDisplayWeekend
408 return shouldDisplayWeekend;
411 - (BOOL) shouldHideWeekend
413 return ![self shouldDisplayWeekend];
419 - (NSString *) appointmentViewURL
423 if (![(pkey = [[self appointment] valueForKey: @"uid"]) isNotNull])
426 return [[[self clientObject] baseURLForAptWithUID: [pkey stringValue]
427 inContext: [self context]]
428 stringByAppendingString: @"/view"];
433 - (NSCalendarDate *) startDate
435 return [self selectedDate];
438 - (NSCalendarDate *) endDate
440 return [[self startDate] tomorrow];
443 - (NSArray *) activeCalendarFolders
446 NSEnumerator *calendarUIDs;
447 SOGoAppointmentFolder *currentFolder;
448 NSMutableArray *folders;
449 NSString *currentUID;
450 SoSecurityManager *securityManager;
452 securityManager = [SoSecurityManager sharedSecurityManager];
454 folders = [NSMutableArray array];
455 ud = [[context activeUser] userDefaults];
456 calendarUIDs = [[[ud stringForKey: @"calendaruids"]
457 componentsSeparatedByString: @","] objectEnumerator];
458 currentUID = [calendarUIDs nextObject];
461 if (![currentUID hasPrefix: @"-"])
463 currentFolder = [[self clientObject] lookupCalendarFolderForUID: currentUID];
465 && ![securityManager validatePermission: SoPerm_AccessContentsInformation
466 onObject: currentFolder
468 [folders addObject: currentFolder];
470 currentUID = [calendarUIDs nextObject];
476 - (NSArray *) _fetchCoreInfosForComponent: (NSString *) component
478 NSArray *currentInfos;
479 NSMutableArray *infos;
480 NSEnumerator *folders;
481 SOGoAppointmentFolder *currentFolder;
483 infos = [componentsData objectForKey: component];
486 infos = [NSMutableArray array];
487 folders = [[self activeCalendarFolders] objectEnumerator];
488 currentFolder = [folders nextObject];
489 while (currentFolder)
491 currentInfos = [currentFolder fetchCoreInfosFrom: [[self startDate] beginOfDay]
492 to: [[self endDate] endOfDay]
493 component: component];
494 [currentInfos makeObjectsPerform: @selector (setObject:forKey:)
495 withObject: [currentFolder ownerInContext: nil]
496 withObject: @"owner"];
497 [infos addObjectsFromArray: currentInfos];
498 currentFolder = [folders nextObject];
500 [componentsData setObject: infos forKey: component];
506 - (NSArray *) fetchCoreAppointmentsInfos
509 [self setAppointments: [self _fetchCoreInfosForComponent: @"vevent"]];
514 - (NSArray *) fetchCoreTasksInfos
517 [self setTasks: [self _fetchCoreInfosForComponent: @"vtodo"]];
522 /* query parameters */
524 - (BOOL) shouldDisplayRejectedAppointments
528 bv = [self queryParameterForKey: @"dr"];
530 return [bv boolValue];
533 - (NSDictionary *) toggleShowRejectedAptsQueryParameters
535 NSMutableDictionary *qp;
538 shouldDisplay = ![self shouldDisplayRejectedAppointments];
539 qp = [[[self queryParameters] mutableCopy] autorelease];
540 [qp setObject: shouldDisplay ? @"1" : @"0" forKey: @"dr"];
544 - (NSString *) toggleShowRejectedAptsLabel
546 if (![self shouldDisplayRejectedAppointments])
547 return @"show_rejected_apts";
548 return @"hide_rejected_apts";
551 /* date selection & conversion */
553 - (NSDictionary *) _dateQueryParametersWithOffset: (int) daysOffset
555 NSCalendarDate *date;
557 date = [[self startDate] dateByAddingYears: 0 months: 0
559 hours: 0 minutes: 0 seconds: 0];
560 return [self queryParametersBySettingSelectedDate: date];
563 - (NSDictionary *) todayQueryParameters
565 return [self queryParametersBySettingSelectedDate: [NSCalendarDate date]];
568 - (NSDictionary *) currentDayQueryParameters
570 return [self queryParametersBySettingSelectedDate: currentDay];
575 - (NSString *) formattedCalendarUIDs
577 return [[[self clientObject] calendarUIDs]
578 componentsJoinedByString: @", "];
583 - (NSString *) _userFolderURI
589 ctx = [self context];
590 obj = [[ctx objectTraversalStack] objectAtIndex: 1];
591 url = [NSURL URLWithString: [obj baseURLInContext: ctx]];
592 return [[url path] stringByUnescapingURL];
595 - (id) redirectForUIDsAction
597 NSMutableString *uri;
598 NSString *uidsString, *loc, *prevMethod, *userFolderID;
599 id <WOActionResults> r;
603 uidsString = [self queryParameterForKey: @"userUIDString"];
604 uidsString = [uidsString stringByTrimmingWhiteSpaces];
605 [self setQueryParameter: nil forKey: @"userUIDString"];
607 prevMethod = [self queryParameterForKey: @"previousMethod"];
608 if (prevMethod == nil)
611 uri = [[NSMutableString alloc] initWithString: [self _userFolderURI]];
612 /* if we have more than one entry, use groups - otherwise don't */
613 useGroups = [uidsString rangeOfString: @","].length > 0;
614 userFolderID = [uri lastPathComponent];
619 uids = [uidsString componentsSeparatedByString: @","];
620 /* guarantee that our id is the first */
621 if (((index = [uids indexOfObject: userFolderID]) != NSNotFound)
624 uids = [[uids mutableCopy] autorelease];
625 [(NSMutableArray *) uids removeObjectAtIndex: index];
626 [(NSMutableArray *) uids insertObject: userFolderID atIndex: 0];
627 uidsString = [uids componentsJoinedByString: @","];
629 [uri appendString: @"Groups/_custom_"];
630 [uri appendString: uidsString];
631 [uri appendString: @"/"];
632 NSLog (@"Group URI = '%@'", uri);
636 /* check if lastPathComponent is the base that we want to have */
637 if ((([uidsString length] != 0)
638 && (![userFolderID isEqualToString: uidsString])))
642 /* uri ends with an '/', so we have to adjust the range a little */
643 r = NSMakeRange(0, [uri length] - 1);
644 r = [uri rangeOfString: @"/"
645 options: NSBackwardsSearch
647 r = NSMakeRange(r.location + 1, [uri length] - r.location - 2);
648 [uri replaceCharactersInRange: r withString: uidsString];
651 [uri appendString: @"Calendar/"];
652 [uri appendString: prevMethod];
655 NSLog(@"%s redirect uri:%@",
659 loc = [self completeHrefForMethod: uri]; /* this might return uri! */
660 r = [self redirectToLocation: loc];
665 @end /* UIxCalView */