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
21 // $Id: UIxAppointmentEditor.m 181 2004-08-11 15:13:25Z helge $
23 #include <SOGoUI/UIxComponent.h>
25 @interface UIxAppointmentProposal : UIxComponent
30 /* individual values */
43 NSArray *participants; /* array of iCalPerson's */
44 NSArray *resources; /* array of iCalPerson's */
47 NSArray *blockedRanges;
52 #include <SoObjects/Appointments/SOGoAppointmentFolder.h>
53 #include <NGExtensions/NGCalendarDateRange.h>
56 @implementation UIxAppointmentProposal
59 [self->blockedRanges release];
61 [self->startDateHour release];
62 [self->startDateMinute release];
63 [self->startDateDay release];
64 [self->startDateMonth release];
65 [self->startDateYear release];
67 [self->endDateHour release];
68 [self->endDateMinute release];
69 [self->endDateDay release];
70 [self->endDateMonth release];
71 [self->endDateYear release];
72 [self->duration release];
74 [self->participants release];
75 [self->resources release];
82 [self->currentDay release]; self->currentDay = nil;
83 [self->item release]; self->item = nil;
89 - (void)setItem:(id)_item {
90 ASSIGN(self->item, _item);
96 - (void)setStartDateHour:(id)_startDateHour {
97 ASSIGN(self->startDateHour, _startDateHour);
100 return self->startDateHour;
102 - (void)setStartDateMinute:(id)_startDateMinute {
103 ASSIGN(self->startDateMinute, _startDateMinute);
105 - (id)startDateMinute {
106 return self->startDateMinute;
108 - (void)setStartDateDay:(id)_startDateDay {
109 ASSIGN(self->startDateDay, _startDateDay);
112 return self->startDateDay;
114 - (void)setStartDateMonth:(id)_startDateMonth {
115 ASSIGN(self->startDateMonth, _startDateMonth);
117 - (id)startDateMonth {
118 return self->startDateMonth;
120 - (void)setStartDateYear:(id)_startDateYear {
121 ASSIGN(self->startDateYear, _startDateYear);
123 - (id)startDateYear {
124 return self->startDateYear;
126 - (void)setEndDateHour:(id)_endDateHour {
127 ASSIGN(self->endDateHour, _endDateHour);
130 return self->endDateHour;
132 - (void)setEndDateMinute:(id)_endDateMinute {
133 ASSIGN(self->endDateMinute, _endDateMinute);
135 - (id)endDateMinute {
136 return self->endDateMinute;
138 - (void)setEndDateDay:(id)_endDateDay {
139 ASSIGN(self->endDateDay, _endDateDay);
142 return self->endDateDay;
144 - (void)setEndDateMonth:(id)_endDateMonth {
145 ASSIGN(self->endDateMonth, _endDateMonth);
148 return self->endDateMonth;
150 - (void)setEndDateYear:(id)_endDateYear {
151 ASSIGN(self->endDateYear, _endDateYear);
154 return self->endDateYear;
157 - (void)setStartDate:(NSCalendarDate *)_date {
158 [self setStartDateHour:[NSNumber numberWithInt:[_date hourOfDay]]];
159 [self setStartDateMinute:[NSNumber numberWithInt:[_date minuteOfHour]]];
160 [self setStartDateDay:[NSNumber numberWithInt:[_date dayOfMonth]]];
161 [self setStartDateMonth:[NSNumber numberWithInt:[_date monthOfYear]]];
162 [self setStartDateYear:[NSNumber numberWithInt:[_date yearOfCommonEra]]];
164 - (NSCalendarDate *)startDate {
165 return [NSCalendarDate dateWithYear:[[self startDateYear] intValue]
166 month:[[self startDateMonth] intValue]
167 day:[[self startDateDay] intValue]
168 hour:[[self startDateHour] intValue]
169 minute:[[self startDateMinute] intValue]
171 timeZone:[self viewTimeZone]];
173 - (void)setEndDate:(NSCalendarDate *)_date {
174 [self setEndDateHour:[NSNumber numberWithInt:[_date hourOfDay]]];
175 [self setEndDateMinute:[NSNumber numberWithInt:[_date minuteOfHour]]];
176 [self setEndDateDay:[NSNumber numberWithInt:[_date dayOfMonth]]];
177 [self setEndDateMonth:[NSNumber numberWithInt:[_date monthOfYear]]];
178 [self setEndDateYear:[NSNumber numberWithInt:[_date yearOfCommonEra]]];
180 - (NSCalendarDate *)endDate {
181 return [NSCalendarDate dateWithYear:[[self endDateYear] intValue]
182 month:[[self endDateMonth] intValue]
183 day:[[self endDateDay] intValue]
184 hour:[[self endDateHour] intValue]
185 minute:[[self endDateMinute] intValue]
187 timeZone:[self viewTimeZone]];
190 - (void)setDuration:(id)_duration {
191 ASSIGN(self->duration, _duration);
194 return self->duration;
196 - (int)durationInMinutes {
197 return [[self duration] intValue];
199 - (NSTimeInterval)durationAsTimeInterval {
200 return [self durationInMinutes] * 60;
203 - (NSString *)itemDurationText {
204 // TODO: use a formatter
206 switch ([[self item] intValue]) {
207 case 30: return @"30 minutes";
208 case 60: return @"1 hour";
209 case 120: return @"2 hours";
210 case 240: return @"4 hours";
211 case 480: return @"8 hours";
213 return [NSString stringWithFormat:@"%@ minutes", [self item]];
217 - (void)setParticipants:(NSArray *)_parts {
218 ASSIGN(self->participants, _parts);
220 - (NSArray *)participants {
221 return self->participants;
223 - (void)setResources:(NSArray *)_res {
224 ASSIGN(self->resources, _res);
226 - (NSArray *)resources {
227 return self->resources;
230 - (NSArray *)attendees {
233 a = [self participants];
234 b = [self resources];
235 if ([b count] == 0) return a;
236 if ([a count] == 0) return b;
237 return [a arrayByAddingObjectsFromArray:b];
240 - (void)setCurrentDay:(id)_day {
241 ASSIGN(self->currentDay, _day);
244 return self->currentDay;
248 // TODO: from 'earliest start' to 'latest endtime'
249 unsigned lStartHour = 9, lEndHour = 17, i;
252 lStartHour = [[self startDateHour] intValue];
253 lEndHour = [[self endDateHour] intValue];
254 if (lStartHour < 1) lStartHour = 1;
255 if (lEndHour < lStartHour) lEndHour = lStartHour + 1;
257 ma = [NSMutableArray arrayWithCapacity:lEndHour - lStartHour + 2];
258 for (i = lStartHour; i <= lEndHour; i++)
259 [ma addObject:[NSNumber numberWithInt:i]];
264 // TODO: from startdate to enddate
266 NSCalendarDate *base, *stop, *current;
268 base = [NSCalendarDate dateWithYear:[[self startDateYear] intValue]
269 month:[[self startDateMonth] intValue]
270 day:[[self startDateDay] intValue]
271 hour:12 minute:0 second:0
272 timeZone:[self viewTimeZone]];
273 stop = [NSCalendarDate dateWithYear:[[self endDateYear] intValue]
274 month:[[self endDateMonth] intValue]
275 day:[[self endDateDay] intValue]
276 hour:12 minute:0 second:0
277 timeZone:[self viewTimeZone]];
279 ma = [NSMutableArray arrayWithCapacity:16];
282 while ([current compare:stop] != NSOrderedDescending) {
283 [current setTimeZone:[self viewTimeZone]];
284 [ma addObject:current];
286 /* Note: remember the timezone behaviour of the method below! */
287 current = [current dateByAddingYears:0 months:0 days:1];
292 - (NSArray *)durationSteps {
293 // TODO: make configurable
294 return [NSArray arrayWithObjects:
295 @"30", @"60", @"120", @"240", @"480", nil];
300 - (BOOL)isRangeGreen:(NGCalendarDateRange *)_range {
303 idx = [self->blockedRanges indexOfFirstIntersectingDateRange:_range];
304 if (idx != NSNotFound) {
305 [self debugWithFormat:@"blocked range:\n range: %@\n block: %@",
307 [self->blockedRanges objectAtIndex:idx]];
310 return idx == NSNotFound ? YES : NO;
313 - (BOOL)isSlotRangeGreen:(NGCalendarDateRange *)_slotRange {
314 NGCalendarDateRange *aptRange;
315 NSCalendarDate *aptStartDate, *aptEndDate;
317 if (_slotRange == nil)
320 /* calculate the interval requested by the user (can be larger) */
322 aptStartDate = [_slotRange startDate];
323 aptEndDate = [[NSCalendarDate alloc] initWithTimeIntervalSince1970:
324 [aptStartDate timeIntervalSince1970]
325 + [self durationAsTimeInterval] - 1];
326 [aptStartDate setTimeZone:[self viewTimeZone]];
327 [aptEndDate setTimeZone:[self viewTimeZone]];
328 aptRange = [NGCalendarDateRange calendarDateRangeWithStartDate:aptStartDate
330 [aptEndDate release]; aptEndDate = nil;
332 return [self isRangeGreen:aptRange];
335 - (BOOL)isFirstHalfGreen {
336 /* currentday is the date, self->item the hour */
337 NSCalendarDate *from, *to;
338 NGCalendarDateRange *range;
340 from = [self->currentDay hour:[[self item] intValue] minute:0];
341 to = [self->currentDay hour:[[self item] intValue] minute:30];
342 range = [NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:to];
343 return [self isSlotRangeGreen:range];
345 - (BOOL)isSecondHalfGreen {
346 /* currentday is the date, self->item the hour */
347 NSCalendarDate *from, *to;
348 NGCalendarDateRange *range;
350 from = [self->currentDay hour:[[self item] intValue] minute:30];
351 to = [self->currentDay hour:[[self item] intValue] minute:59];
352 range = [NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:to];
353 return [self isSlotRangeGreen:range];
356 - (BOOL)isFirstHalfBlocked {
357 return [self isFirstHalfGreen] ? NO : YES;
359 - (BOOL)isSecondHalfBlocked {
360 return [self isSecondHalfGreen] ? NO : YES;
365 - (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
369 - (id)defaultAction {
372 now = [NSCalendarDate date];
374 [self setDuration:@"120"]; /* 1 hour as default */
375 [self setStartDate:[now hour:9 minute:0]];
376 [self setEndDate:[now hour:18 minute:0]];
381 - (id)proposalSearchAction {
382 NSArray *attendees, *uids;
383 SOGoAppointmentFolder *groupCalendar;
387 [self logWithFormat:@"search from %@ to %@",
388 [self startDate], [self endDate]];
390 attendees = [self attendees];
391 uids = [[self clientObject] uidsFromICalPersons:attendees];
392 if ([uids count] == 0) {
393 [self logWithFormat:@"Note: no UIDs selected."];
397 groupCalendar = [[self clientObject] lookupGroupCalendarFolderForUIDs:uids
398 inContext:[self context]];
399 [self debugWithFormat:@"group calendar: %@", groupCalendar];
401 if (![groupCalendar respondsToSelector:@selector(fetchCoreInfosFrom:to:)]) {
402 return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
403 reason:@"invalid folder to run proposal query on!"];
406 // TODO: just query startdate and enddate ... (freebusy)
407 coreInfos = [groupCalendar fetchCoreInfosFrom:[self startDate]
409 [self debugWithFormat:@" process: %d events", [coreInfos count]];
411 ranges = [coreInfos arrayByCreatingDateRangesFromObjectsWithStartDateKey:
413 andEndDateKey:@"endDate"];
414 ranges = [ranges arrayByCompactingContainedDateRanges];
415 [self debugWithFormat:@" ranges: %@", ranges];
417 ASSIGNCOPY(self->blockedRanges, ranges);
422 @end /* UIxAppointmentProposal */