1 /* UIxCalMainView.m - this file is part of SOGo
3 * Copyright (C) 2006, 2007 Inverse groupe conseil
5 * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
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)
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.
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.
23 //#import <OGoContentStore/OCSFolder.h>
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>
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>
40 #import <SOGoUI/SOGoAptFormatter.h>
42 #import "UIxComponent+Scheduler.h"
44 #import "UIxCalView.h"
46 @interface UIxCalView (PrivateAPI)
47 - (NSString *) _userFolderURI;
50 @implementation UIxCalView
52 static BOOL shouldDisplayWeekend = NO;
56 static BOOL didInit = NO;
61 ud = [NSUserDefaults standardUserDefaults];
62 shouldDisplayWeekend = [ud boolForKey: @"SOGoShouldDisplayWeekend"];
71 timeZone = [[context activeUser] timeZone];
74 = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: timeZone];
76 = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: timeZone];
78 = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: timeZone];
79 privateAptTooltipFormatter
80 = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: timeZone];
81 [self configureFormatters];
82 componentsData = [NSMutableDictionary new];
90 [componentsData release];
91 [appointments release];
93 [appointment release];
95 [aptFormatter release];
96 [aptTooltipFormatter release];
97 [privateAptFormatter release];
98 [privateAptTooltipFormatter release];
103 /* subclasses should override this */
104 - (void) configureFormatters
108 [aptFormatter setFullDetails];
109 [aptTooltipFormatter setTooltip];
110 [privateAptFormatter setPrivateDetails];
111 [privateAptTooltipFormatter setPrivateTooltip];
113 title = [self labelForKey: @"empty title"];
114 [aptFormatter setTitlePlaceholder: title];
115 [aptTooltipFormatter setTitlePlaceholder: title];
117 title = [self labelForKey: @"private appointment"];
118 [privateAptFormatter setPrivateTitle: title];
119 [privateAptTooltipFormatter setPrivateTitle: title];
122 - (NSArray *) filterAppointments:(NSArray *) _apts
124 NSMutableArray *filtered;
125 unsigned i, count, p, pCount;
126 NSString *email, *partmailsString, *state, *pEmail;
127 NSDictionary *info, *primaryIdentity;
128 NSArray *partmails, *partstates;
131 if ([self shouldDisplayRejectedAppointments])
134 count = [_apts count];
135 filtered = [[[NSMutableArray alloc] initWithCapacity: count] autorelease];
137 primaryIdentity = [[context activeUser] primaryIdentity];
138 email = [primaryIdentity objectForKey: @"email"];
140 for (i = 0; i < count; i++)
143 info = [_apts objectAtIndex: i];
144 partmailsString = [info objectForKey: @"partmails"];
145 if ([partmailsString isNotNull])
147 partmails = [partmailsString componentsSeparatedByString: @"\n"];
148 pCount = [partmails count];
149 for (p = 0; p < pCount; p++)
151 pEmail = [partmails objectAtIndex: p];
152 if ([pEmail isEqualToString: email])
154 partstates = [[info objectForKey: @"partstates"]
155 componentsSeparatedByString: @"\n"];
156 state = [partstates objectAtIndex: p];
157 if ([state intValue] == iCalPersonPartStatDeclined)
164 [filtered addObject: info];
173 - (void) setAppointments:(NSArray *) _apts
175 _apts = [self filterAppointments: _apts];
176 ASSIGN(appointments, _apts);
179 - (NSArray *) appointments
184 - (void) setAppointment:(id) _apt
186 ASSIGN (appointment, _apt);
189 // - (void) setAppointment:(id) _apt
191 // NSString *mailtoChunk;
192 // NSString *myEmail;
193 // NSString *partmails;
195 // ASSIGN(appointment, _apt);
197 // /* cache some info about apt for faster access */
199 // mailtoChunk = [_apt valueForKey: @"orgmail"];
200 // myEmail = [self emailForUser];
201 // if ([mailtoChunk rangeOfString: myEmail].length > 0)
203 // aptFlags.isMyApt = YES;
204 // aptFlags.canAccessApt = YES;
208 // aptFlags.isMyApt = NO;
210 // partmails = [_apt valueForKey: @"partmails"];
211 // if ([partmails rangeOfString: myEmail].length)
212 // aptFlags.canAccessApt = YES;
214 // aptFlags.canAccessApt
215 // = ([[_apt valueForKey: @"classification"] intValue]
216 // == iCalAccessPublic);
227 return aptFlags.isMyApt ? YES : NO;
230 - (BOOL) canAccessApt
232 return aptFlags.canAccessApt ? YES : NO;
235 - (BOOL) canNotAccessApt
237 return aptFlags.canAccessApt ? NO : YES;
240 - (NSDictionary *) aptTypeDict
244 - (NSString *) aptTypeLabel
248 - (NSString *) aptTypeIcon
253 - (SOGoAptFormatter *) aptFormatter
255 if (aptFlags.canAccessApt)
257 return privateAptFormatter;
260 - (SOGoAptFormatter *) aptTooltipFormatter
262 if (aptFlags.canAccessApt)
263 return aptTooltipFormatter;
264 return privateAptTooltipFormatter;
267 - (void) setTasks: (NSArray *) _tasks
269 ASSIGN(tasks, _tasks);
277 /* TODO: remove this */
278 - (NSString *) shortTextForApt
280 [self warnWithFormat: @"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
281 if (![self canAccessApt])
283 return [[self aptFormatter] stringForObjectValue: appointment];
286 - (NSString *) shortTitleForApt
290 [self warnWithFormat: @"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
292 if (![self canAccessApt])
294 title = [appointment valueForKey: @"title"];
295 if ([title length] > 12)
296 title = [[title substringToIndex: 11] stringByAppendingString: @"..."];
301 - (NSString *) tooltipForApt
303 [self warnWithFormat: @"%s IS DEPRECATED!", __PRETTY_FUNCTION__];
304 return [[self aptTooltipFormatter] stringForObjectValue: appointment
305 referenceDate: [self currentDay]];
308 - (NSString *) aptStyle
313 - (NSCalendarDate *) referenceDateForFormatter
315 return [self selectedDate];
318 - (NSCalendarDate *) thisMonth
320 return [self selectedDate];
323 - (NSCalendarDate *) nextMonth
325 NSCalendarDate *date = [self thisMonth];
326 return [date dateByAddingYears: 0 months: 1 days: 0
327 hours: 0 minutes: 0 seconds: 0];
330 - (NSCalendarDate *) prevMonth
332 NSCalendarDate *date = [self thisMonth];
333 return [date dateByAddingYears: 0 months:-1 days: 0
334 hours: 0 minutes: 0 seconds: 0];
337 - (NSString *) prevMonthAsString
339 return [self dateStringForDate: [self prevMonth]];
342 - (NSString *) nextMonthAsString
344 return [self dateStringForDate: [self nextMonth]];
347 /* current day related */
349 - (void) setCurrentDay:(NSCalendarDate *) _day
351 [_day setTimeZone: timeZone];
352 ASSIGN (currentDay, _day);
355 - (NSCalendarDate *) currentDay
360 - (NSString *) currentDayName
362 return [self localizedNameForDayOfWeek: [currentDay dayOfWeek]];
370 - (NSArray *) allDayApts
373 NSMutableArray *filtered;
379 apts = [self appointments];
380 count = [apts count];
381 filtered = [[NSMutableArray alloc] initWithCapacity: 3];
382 for (i = 0; i < count; i++)
387 apt = [apts objectAtIndex: i];
388 bv = [apt valueForKey: @"isallday"];
390 [filtered addObject: apt];
393 ASSIGN(allDayApts, filtered);
399 /* special appointments */
403 return [self hasHoldidayInfo] || [self hasAllDayApts];
406 - (BOOL) hasHoldidayInfo
408 return [self holidayInfo] != nil;
411 - (BOOL) hasAllDayApts
413 return [[self allDayApts] count] != 0;
419 - (BOOL) showFullNames
424 - (BOOL) showAMPMDates
429 - (unsigned) dayStartHour
434 - (unsigned) dayEndHour
439 - (BOOL) shouldDisplayWeekend
441 return shouldDisplayWeekend;
444 - (BOOL) shouldHideWeekend
446 return ![self shouldDisplayWeekend];
452 - (NSString *) appointmentViewURL
456 if (![(pkey = [[self appointment] valueForKey: @"uid"]) isNotNull])
459 return [[[self clientObject] baseURLForAptWithUID: [pkey stringValue]
460 inContext: [self context]]
461 stringByAppendingString: @"/view"];
466 - (NSCalendarDate *) startDate
468 return [self selectedDate];
471 - (NSCalendarDate *) endDate
473 return [[self startDate] tomorrow];
476 /* query parameters */
478 - (BOOL) shouldDisplayRejectedAppointments
482 bv = [self queryParameterForKey: @"dr"];
484 return [bv boolValue];
487 - (NSDictionary *) toggleShowRejectedAptsQueryParameters
489 NSMutableDictionary *qp;
492 shouldDisplay = ![self shouldDisplayRejectedAppointments];
493 qp = [[[self queryParameters] mutableCopy] autorelease];
494 [qp setObject: shouldDisplay ? @"1" : @"0" forKey: @"dr"];
498 - (NSString *) toggleShowRejectedAptsLabel
500 if (![self shouldDisplayRejectedAppointments])
501 return @"show_rejected_apts";
502 return @"hide_rejected_apts";
505 /* date selection & conversion */
507 - (NSDictionary *) _dateQueryParametersWithOffset: (int) daysOffset
509 NSCalendarDate *date;
511 date = [[self startDate] dateByAddingYears: 0 months: 0
513 hours: 0 minutes: 0 seconds: 0];
514 return [self queryParametersBySettingSelectedDate: date];
517 - (NSDictionary *) todayQueryParameters
519 return [self queryParametersBySettingSelectedDate: [NSCalendarDate date]];
522 - (NSDictionary *) currentDayQueryParameters
524 return [self queryParametersBySettingSelectedDate: currentDay];
529 - (NSString *) _userFolderURI
535 ctx = [self context];
536 obj = [[ctx objectTraversalStack] objectAtIndex: 1];
537 url = [NSURL URLWithString: [obj baseURLInContext: ctx]];
538 return [[url path] stringByUnescapingURL];
541 - (id) redirectForUIDsAction
543 NSMutableString *uri;
544 NSString *uidsString, *loc, *prevMethod, *userFolderID;
545 id <WOActionResults> r;
549 uidsString = [self queryParameterForKey: @"userUIDString"];
550 uidsString = [uidsString stringByTrimmingSpaces];
551 [self setQueryParameter: nil forKey: @"userUIDString"];
553 prevMethod = [self queryParameterForKey: @"previousMethod"];
554 if (prevMethod == nil)
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];
565 uids = [uidsString componentsSeparatedByString: @","];
566 /* guarantee that our id is the first */
567 if (((index = [uids indexOfObject: userFolderID]) != NSNotFound)
570 uids = [[uids mutableCopy] autorelease];
571 [(NSMutableArray *) uids removeObjectAtIndex: index];
572 [(NSMutableArray *) uids insertObject: userFolderID atIndex: 0];
573 uidsString = [uids componentsJoinedByString: @","];
575 [uri appendString: @"Groups/_custom_"];
576 [uri appendString: uidsString];
577 [uri appendString: @"/"];
578 NSLog (@"Group URI = '%@'", uri);
582 /* check if lastPathComponent is the base that we want to have */
583 if ((([uidsString length] != 0)
584 && (![userFolderID isEqualToString: uidsString])))
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
593 r = NSMakeRange(r.location + 1, [uri length] - r.location - 2);
594 [uri replaceCharactersInRange: r withString: uidsString];
597 [uri appendString: @"Calendar/"];
598 [uri appendString: prevMethod];
601 NSLog(@"%s redirect uri:%@",
605 loc = [self completeHrefForMethod: uri]; /* this might return uri! */
606 r = [self redirectToLocation: loc];
611 @end /* UIxCalView */