2 Copyright (C) 2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include <SOGoUI/UIxComponent.h>
24 @class NSMutableArray;
26 @interface UIxCalScheduleOverview : UIxComponent
28 NSMutableArray *userApts;
29 NSMutableArray *foreignApts;
31 NSMutableArray *partNames;
32 NSMutableArray *partStates;
33 NSString *userParticipationStatus;
34 unsigned participantIndex;
38 - (NSCalendarDate *)startDate;
39 - (NSCalendarDate *)endDate;
41 - (NSArray *)userAppointments;
42 - (NSArray *)foreignAppointments;
44 - (BOOL)hasUserAppointments;
45 - (BOOL)hasForeignAppointments;
46 - (BOOL)hasAnyAppointments;
50 - (NSString *)appointmentBaseURL;
52 - (unsigned)participantsCount;
53 - (unsigned)maxRenderedParticipantsCount;
54 - (unsigned)renderedParticipantsCount;
55 - (unsigned)truncatedParticipantsCount;
56 - (BOOL)didTruncateParticipants;
58 - (NSString *)getUserPartStateFromApt:(id)_apt;
60 - (BOOL)shouldIgnoreRejectedAppointments;
61 - (BOOL)shouldIgnoreAcceptedAppointments;
62 - (BOOL)shouldShowRejectedAndAcceptedAppointments;
66 #include <NGObjWeb/SoComponent.h>
67 #include "UIxComponent+Agenor.h"
68 #include "SoObjects/Appointments/SOGoAppointmentFolder.h"
71 @implementation UIxCalScheduleOverview
74 [self->userApts release];
75 [self->foreignApts release];
77 [self->partNames release];
78 [self->partStates release];
79 [self->userParticipationStatus release];
86 - (void)setItem:(id)_item {
91 ASSIGN(self->item, _item);
93 [self->partNames release];
94 [self->partStates release];
95 ps = [self->item valueForKey:@"participants"];
96 self->partNames = [[ps componentsSeparatedByString:@"\n"] mutableCopy];
97 ps = [self->item valueForKey:@"partstates"];
98 self->partStates = [[ps componentsSeparatedByString:@"\n"] mutableCopy];
99 ps = [self->item valueForKey:@"partmails"];
100 partmails = [ps componentsSeparatedByString:@"\n"];
102 /* reorder partNames/partStates */
104 /* ensure organizer is first entry */
105 email = [self->item valueForKey:@"orgmail"];
106 if ([email isNotNull]) {
107 idx = [partmails indexOfObject:email];
108 if (idx != NSNotFound && idx != 0) {
111 obj = [self->partNames objectAtIndex:idx];
112 [self->partNames insertObject:obj atIndex:0]; /* frontmost */
113 [self->partNames removeObjectAtIndex:idx + 1];
114 obj = [self->partStates objectAtIndex:idx];
115 [self->partStates insertObject:obj atIndex:0]; /* frontmost */
116 [self->partStates removeObjectAtIndex:idx + 1];
119 /* user is either second, first or none at all */
120 [self->userParticipationStatus release];
121 email = [self emailForUser];
122 idx = [partmails indexOfObject:email];
123 if (idx != NSNotFound && idx != 0 && idx != 1) {
127 obj = [self->partNames objectAtIndex:idx];
128 [self->partNames insertObject:obj atIndex:self->userIndex]; /* second */
129 [self->partNames removeObjectAtIndex:idx + 1];
130 obj = [self->partStates objectAtIndex:idx];
131 [self->partStates insertObject:obj atIndex:self->userIndex]; /* second */
132 [self->partStates removeObjectAtIndex:idx + 1];
135 self->userIndex = idx;
137 if (self->userIndex != NSNotFound)
138 self->userParticipationStatus =
139 [[self->partStates objectAtIndex:self->userIndex] retain];
141 self->userParticipationStatus = nil;
147 - (void)setParticipantIndex:(unsigned)_participantIndex {
148 self->participantIndex = _participantIndex;
150 - (unsigned)participantIndex {
151 return self->participantIndex;
154 - (unsigned)userIndex {
155 return self->userIndex;
158 - (BOOL)isFirstParticipant {
159 return self->participantIndex == 0 ? YES : NO;
162 - (BOOL)hasUserAppointments {
163 // NOTE: this has been disabled for Agenor 0.8 on client's request
167 return [[self userAppointments] count] > 0;
170 - (BOOL)hasForeignAppointments {
171 return [[self foreignAppointments] count] > 0;
173 - (BOOL)hasAnyAppointments {
174 return ([self hasUserAppointments] ||
175 [self hasForeignAppointments]) ? YES : NO;
178 - (unsigned)participantsCount {
179 return [self->partNames count];
182 - (NSString *)participant {
183 return [self->partNames objectAtIndex:self->participantIndex];
186 - (NSString *)participationStatus {
187 return [self->partStates objectAtIndex:self->participantIndex];
190 - (unsigned)maxRenderedParticipantsCount {
194 - (unsigned)renderedParticipantsCount {
195 if ([self didTruncateParticipants])
196 return [self maxRenderedParticipantsCount];
197 return [self participantsCount];
200 - (unsigned)truncatedParticipantsCount {
201 return [self participantsCount] - [self renderedParticipantsCount];
204 - (BOOL)didTruncateParticipants {
205 return [self participantsCount] >
206 ([self maxRenderedParticipantsCount] + 1) ? YES : NO;
209 - (unsigned)rowspan {
212 count = [self renderedParticipantsCount];
213 if ([self didTruncateParticipants])
218 - (NSString *)userParticipationStatus {
219 return self->userParticipationStatus;
222 - (BOOL)shouldIgnoreRejectedAppointments {
223 return ![self shouldShowRejectedAndAcceptedAppointments];
226 - (BOOL)shouldIgnoreAcceptedAppointments {
227 return ![self shouldShowRejectedAndAcceptedAppointments];
230 - (BOOL)shouldShowRejectedAndAcceptedAppointments {
233 value = [[[self context] request] formValueForKey:@"dr"];
234 if (!value) return NO;
235 return [value boolValue];
238 - (NSString *)toggleShowHideAptsQueryParameter {
241 shouldShow = [self shouldShowRejectedAndAcceptedAppointments];
242 return shouldShow ? @"0" : @"1";
245 - (NSString *)toggleShowHideAptsText {
246 if ([self shouldShowRejectedAndAcceptedAppointments])
247 return @"Hide already accepted and rejected appointments";
248 return @"Show already accepted and rejected appointments";
252 - (NSString *)getUserPartStateFromApt:(id)_apt {
257 email = [self emailForUser];
258 pms = [[_apt valueForKey:@"partmails"]
259 componentsSeparatedByString:@"\n"];
260 idx = [pms indexOfObject:email];
261 if (idx == NSNotFound) return nil;
262 ps = [[_apt valueForKey:@"partstates"]
263 componentsSeparatedByString:@"\n"];
264 return [ps objectAtIndex:idx];
270 - (NSCalendarDate *)startDate {
271 return [[NSCalendarDate date] beginOfDay];
274 /* ZNeK: is a month ok? */
275 - (NSCalendarDate *)endDate {
276 NSCalendarDate *date;
278 date = [NSCalendarDate date];
279 date = [date dateByAddingYears:0 months:1 days:0
280 hours:0 minutes:0 seconds:0];
281 date = [date endOfDay];
285 - (NSArray *)userAppointments {
286 if (!self->userApts) {
289 return self->userApts;
292 - (NSArray *)foreignAppointments {
293 if (!self->foreignApts) {
296 return self->foreignApts;
300 static NSArray *orders = nil;
308 so = [EOSortOrdering sortOrderingWithKey:@"startDate"
309 selector:EOCompareAscending];
310 orders = [[NSArray alloc] initWithObjects:so, nil];
313 aptFolder = [self clientObject];
314 apts = [aptFolder fetchCoreInfosFrom:[self startDate]
316 userEmail = [self emailForUser];
317 count = [apts count];
319 self->userApts = [[NSMutableArray alloc] initWithCapacity:count];
320 self->foreignApts = [[NSMutableArray alloc] initWithCapacity:count];
322 for (i = 0; i < count; i++) {
326 apt = [apts objectAtIndex:i];
327 orgEmail = [(NSDictionary *)apt objectForKey:@"orgmail"];
328 if (orgEmail && [orgEmail isEqualToString:userEmail]) {
329 [self->userApts addObject:apt];
332 BOOL shouldAdd = YES;
334 if ([self shouldIgnoreAcceptedAppointments] ||
335 [self shouldIgnoreRejectedAppointments])
337 NSString *userPartStat;
339 userPartStat = [self getUserPartStateFromApt:apt];
341 if ([self shouldIgnoreAcceptedAppointments] &&
342 [userPartStat isEqualToString:@"1"])
344 else if ([self shouldIgnoreRejectedAppointments] &&
345 [userPartStat isEqualToString:@"2"])
350 [self->foreignApts addObject:apt];
353 [self->userApts sortUsingKeyOrderArray:orders];
354 [self->foreignApts sortUsingKeyOrderArray:orders];
360 - (NSString *)appointmentBaseURL {
363 if (![(pkey = [self->item valueForKey:@"uid"]) isNotNull])
366 return [[self clientObject] baseURLForAptWithUID:[pkey stringValue]
367 inContext:[self context]];
369 - (NSString *)appointmentViewURL {
370 return [[self appointmentBaseURL] stringByAppendingPathComponent:@"view"];
372 - (NSString *)acceptAppointmentURL {
373 return [[self appointmentBaseURL] stringByAppendingPathComponent:@"accept"];
375 - (NSString *)declineAppointmentURL {
376 return [[self appointmentBaseURL] stringByAppendingPathComponent:@"decline"];
380 /* access protection */
385 owner = [[self clientObject] ownerInContext:[self context]];
388 return [[[[self context] activeUser] login] isEqualToString:owner];