]> err.no Git - scalable-opengroupware.org/blob - UI/Scheduler/UIxCalScheduleOverview.m
some more work on the Kolab viewers
[scalable-opengroupware.org] / UI / Scheduler / UIxCalScheduleOverview.m
1 /*
2  Copyright (C) 2004 SKYRIX Software AG
3  
4  This file is part of OpenGroupware.org
5  
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
9  later version.
10  
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.
15  
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
19  02111-1307, USA.
20  */
21
22 #include <SOGoUI/UIxComponent.h>
23
24 @class NSMutableArray;
25
26 @interface UIxCalScheduleOverview : UIxComponent
27 {
28   NSMutableArray *userApts;
29   NSMutableArray *foreignApts;
30   id             item;
31   NSMutableArray *partNames;
32   NSMutableArray *partStates;
33   NSString       *userParticipationStatus;
34   unsigned       participantIndex;
35   unsigned       userIndex;
36 }
37
38 - (NSCalendarDate *)startDate;
39 - (NSCalendarDate *)endDate;
40
41 - (NSArray *)userAppointments;
42 - (NSArray *)foreignAppointments;
43
44 - (BOOL)hasUserAppointments;
45 - (BOOL)hasForeignAppointments;
46 - (BOOL)hasAnyAppointments;
47
48 - (void)fetchInfos;
49
50 - (NSString *)appointmentBaseURL;
51
52 - (unsigned)participantsCount;
53 - (unsigned)maxRenderedParticipantsCount;
54 - (unsigned)renderedParticipantsCount;
55 - (unsigned)truncatedParticipantsCount;
56 - (BOOL)didTruncateParticipants;
57
58 - (NSString *)getUserPartStateFromApt:(id)_apt;
59
60 - (BOOL)shouldIgnoreRejectedAppointments;
61 - (BOOL)shouldIgnoreAcceptedAppointments;
62 - (BOOL)shouldShowRejectedAndAcceptedAppointments;
63   
64 @end
65
66 #include <NGObjWeb/SoComponent.h>
67 #include "UIxComponent+Agenor.h"
68 #include "SoObjects/Appointments/SOGoAppointmentFolder.h"
69 #include "common.h"
70
71 @implementation UIxCalScheduleOverview
72
73 - (void)dealloc {
74   [self->userApts                release];
75   [self->foreignApts             release];
76   [self->item                    release];
77   [self->partNames               release];
78   [self->partStates              release];
79   [self->userParticipationStatus release];
80   [super dealloc];
81 }
82
83
84 /* accessors */
85
86 - (void)setItem:(id)_item {
87   NSString *ps, *email;
88   NSArray  *partmails;
89   unsigned idx;
90   
91   ASSIGN(self->item, _item);
92
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"];
101
102   /* reorder partNames/partStates */
103   
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) {
109       id obj;
110
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];
117     }
118   }
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) {
124     id obj;
125
126     self->userIndex = 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];
133   }
134   else {
135     self->userIndex = idx;
136   }
137   if (self->userIndex != NSNotFound)
138     self->userParticipationStatus =
139       [[self->partStates objectAtIndex:self->userIndex] retain];
140   else
141     self->userParticipationStatus = nil;
142 }
143 - (id)item {
144   return self->item;
145 }
146
147 - (void)setParticipantIndex:(unsigned)_participantIndex {
148   self->participantIndex = _participantIndex;
149 }
150 - (unsigned)participantIndex {
151   return self->participantIndex;
152 }
153
154 - (unsigned)userIndex {
155   return self->userIndex;
156 }
157
158 - (BOOL)isFirstParticipant {
159   return self->participantIndex == 0 ? YES : NO;
160 }
161
162 - (BOOL)hasUserAppointments {
163   // NOTE: this has been disabled for Agenor 0.8 on client's request
164 #if 1
165   return NO;
166 #else
167   return [[self userAppointments] count] > 0;
168 #endif
169 }
170 - (BOOL)hasForeignAppointments {
171   return [[self foreignAppointments] count] > 0;
172 }
173 - (BOOL)hasAnyAppointments {
174   return ([self hasUserAppointments] ||
175           [self hasForeignAppointments]) ? YES : NO;
176 }
177
178 - (unsigned)participantsCount {
179   return [self->partNames count];
180 }
181
182 - (NSString *)participant {
183   return [self->partNames objectAtIndex:self->participantIndex];
184 }
185
186 - (NSString *)participationStatus {
187   return [self->partStates objectAtIndex:self->participantIndex];
188 }
189
190 - (unsigned)maxRenderedParticipantsCount {
191   return 3;
192 }
193
194 - (unsigned)renderedParticipantsCount {
195   if ([self didTruncateParticipants])
196     return [self maxRenderedParticipantsCount];
197   return [self participantsCount];
198 }
199
200 - (unsigned)truncatedParticipantsCount {
201   return [self participantsCount] - [self renderedParticipantsCount];
202 }
203
204 - (BOOL)didTruncateParticipants {
205   return [self participantsCount] >
206          ([self maxRenderedParticipantsCount] + 1) ? YES : NO;
207 }
208
209 - (unsigned)rowspan {
210   unsigned count;
211   
212   count = [self renderedParticipantsCount];
213   if ([self didTruncateParticipants])
214     count += 1;
215   return count;
216 }
217
218 - (NSString *)userParticipationStatus {
219   return self->userParticipationStatus;
220 }
221
222 - (BOOL)shouldIgnoreRejectedAppointments {
223   return ![self shouldShowRejectedAndAcceptedAppointments];
224 }
225
226 - (BOOL)shouldIgnoreAcceptedAppointments {
227   return ![self shouldShowRejectedAndAcceptedAppointments];
228 }
229
230 - (BOOL)shouldShowRejectedAndAcceptedAppointments {
231   NSString *value;
232   
233   value = [[[self context] request] formValueForKey:@"dr"];
234   if (!value) return NO;
235   return [value boolValue];
236 }
237
238 - (NSString *)toggleShowHideAptsQueryParameter {
239   BOOL shouldShow;
240   
241   shouldShow = [self shouldShowRejectedAndAcceptedAppointments];
242   return shouldShow ? @"0" : @"1";
243 }
244
245 - (NSString *)toggleShowHideAptsText {
246   if ([self shouldShowRejectedAndAcceptedAppointments])
247     return @"Hide already accepted and rejected appointments";
248   return @"Show already accepted and rejected appointments";
249 }
250
251
252 - (NSString *)getUserPartStateFromApt:(id)_apt {
253   NSString *email;
254   NSArray  *ps, *pms;
255   unsigned idx;
256
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];
265 }
266
267
268 /* fetching */
269
270 - (NSCalendarDate *)startDate {
271   return [[NSCalendarDate date] beginOfDay];
272 }
273
274 /* ZNeK: is a month ok? */
275 - (NSCalendarDate *)endDate {
276   NSCalendarDate *date;
277   
278   date = [NSCalendarDate date];
279   date = [date dateByAddingYears:0 months:1 days:0
280                            hours:0 minutes:0 seconds:0];
281   date = [date endOfDay];
282   return date;
283 }
284
285 - (NSArray *)userAppointments {
286   if (!self->userApts) {
287     [self fetchInfos];
288   }
289   return self->userApts;
290 }
291
292 - (NSArray *)foreignAppointments {
293   if (!self->foreignApts) {
294     [self fetchInfos];
295   }
296   return self->foreignApts;
297 }
298
299 - (void)fetchInfos {
300   static NSArray *orders = nil;
301   id       aptFolder;
302   NSArray  *apts;
303   NSString *userEmail;
304   unsigned i, count;
305
306   if (!orders) {
307     EOSortOrdering *so;
308     so     = [EOSortOrdering sortOrderingWithKey:@"startDate"
309                              selector:EOCompareAscending];
310     orders = [[NSArray alloc] initWithObjects:so, nil];
311   }
312
313   aptFolder = [self clientObject];
314   apts      = [aptFolder fetchCoreInfosFrom:[self startDate]
315                          to:[self endDate]];
316   userEmail = [self emailForUser];
317   count     = [apts count];
318
319   self->userApts    = [[NSMutableArray alloc] initWithCapacity:count];
320   self->foreignApts = [[NSMutableArray alloc] initWithCapacity:count];
321
322   for (i = 0; i < count; i++) {
323     id       apt;
324     NSString *orgEmail;
325
326     apt      = [apts objectAtIndex:i];
327     orgEmail = [(NSDictionary *)apt objectForKey:@"orgmail"];
328     if (orgEmail && [orgEmail isEqualToString:userEmail]) {
329       [self->userApts addObject:apt];
330     }
331     else {
332       BOOL shouldAdd = YES;
333
334       if ([self shouldIgnoreAcceptedAppointments] ||
335           [self shouldIgnoreRejectedAppointments])
336       {
337         NSString *userPartStat;
338
339         userPartStat = [self getUserPartStateFromApt:apt];
340         if (userPartStat) {
341           if ([self shouldIgnoreAcceptedAppointments] &&
342               [userPartStat isEqualToString:@"1"])
343             shouldAdd = NO;
344           else if ([self shouldIgnoreRejectedAppointments] &&
345                    [userPartStat isEqualToString:@"2"])
346             shouldAdd = NO;
347         }
348       }
349       if (shouldAdd)
350         [self->foreignApts addObject:apt];
351     }
352   }
353   [self->userApts    sortUsingKeyOrderArray:orders];
354   [self->foreignApts sortUsingKeyOrderArray:orders];
355 }
356
357
358 /* URLs */
359
360 - (NSString *)appointmentBaseURL {
361   id pkey;
362   
363   if (![(pkey = [self->item valueForKey:@"uid"]) isNotNull])
364     return nil;
365   
366   return [[self clientObject] baseURLForAptWithUID:[pkey stringValue]
367                               inContext:[self context]];
368 }
369 - (NSString *)appointmentViewURL {
370   return [[self appointmentBaseURL] stringByAppendingPathComponent:@"view"];
371 }
372 - (NSString *)acceptAppointmentURL {
373   return [[self appointmentBaseURL] stringByAppendingPathComponent:@"accept"];
374 }
375 - (NSString *)declineAppointmentURL {
376   return [[self appointmentBaseURL] stringByAppendingPathComponent:@"decline"];
377 }
378
379
380 /* access protection */
381
382 - (BOOL)canAccess {
383   NSString *owner;
384   
385   owner = [[self clientObject] ownerInContext:[self context]];
386   if (!owner)
387     return NO;
388   return [[[[self context] activeUser] login] isEqualToString:owner];
389 }
390
391 @end