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: UIxTaskEditor.m 181 2004-08-11 15:13:25Z helge $
23 #import <Foundation/NSCalendarDate.h>
24 #import <Foundation/NSNull.h>
25 #import <Foundation/NSValue.h>
27 #import <NGExtensions/NGCalendarDateRange.h>
28 #import <NGExtensions/NSCalendarDate+misc.h>
29 #import <NGCards/iCalPerson.h>
31 #import <SoObjects/Appointments/SOGoAppointmentFolder.h>
32 #import <SoObjects/Appointments/SOGoFreeBusyObject.h>
33 #import <SOGoUI/UIxComponent.h>
35 @interface UIxTaskProposal : UIxComponent
40 /* individual values */
53 NSArray *participants; /* array of iCalPerson's */
54 NSArray *resources; /* array of iCalPerson's */
57 NSArray *blockedRanges;
58 NSMutableDictionary *currentQueryParameters;
61 - (NSMutableDictionary *)currentQueryParameters;
62 - (NSDictionary *)currentHourQueryParametersForFirstHalf:(BOOL)_first;
64 - (void)setICalPersons:(NSArray *)_ps asQueryParameter:(NSString *)_qp;
67 @implementation UIxTaskProposal
70 [self->blockedRanges release];
72 [self->startDateHour release];
73 [self->startDateMinute release];
74 [self->startDateDay release];
75 [self->startDateMonth release];
76 [self->startDateYear release];
78 [self->endDateHour release];
79 [self->endDateMinute release];
80 [self->endDateDay release];
81 [self->endDateMonth release];
82 [self->endDateYear release];
83 [self->duration release];
85 [self->participants release];
86 [self->resources release];
88 [self->currentQueryParameters release];
95 [self->currentDay release]; self->currentDay = nil;
96 [self->item release]; self->item = nil;
102 - (void)setItem:(id)_item {
103 ASSIGN(self->item, _item);
109 - (void)setStartDateHour:(id)_startDateHour {
110 ASSIGN(self->startDateHour, _startDateHour);
112 - (id)startDateHour {
113 return self->startDateHour;
115 - (void)setStartDateMinute:(id)_startDateMinute {
116 ASSIGN(self->startDateMinute, _startDateMinute);
118 - (id)startDateMinute {
119 return self->startDateMinute;
121 - (void)setStartDateDay:(id)_startDateDay {
122 ASSIGN(self->startDateDay, _startDateDay);
125 return self->startDateDay;
127 - (void)setStartDateMonth:(id)_startDateMonth {
128 ASSIGN(self->startDateMonth, _startDateMonth);
130 - (id)startDateMonth {
131 return self->startDateMonth;
133 - (void)setStartDateYear:(id)_startDateYear {
134 ASSIGN(self->startDateYear, _startDateYear);
136 - (id)startDateYear {
137 return self->startDateYear;
139 - (void)setEndDateHour:(id)_endDateHour {
140 ASSIGN(self->endDateHour, _endDateHour);
143 return self->endDateHour;
145 - (void)setEndDateMinute:(id)_endDateMinute {
146 ASSIGN(self->endDateMinute, _endDateMinute);
148 - (id)endDateMinute {
149 return self->endDateMinute;
151 - (void)setEndDateDay:(id)_endDateDay {
152 ASSIGN(self->endDateDay, _endDateDay);
155 return self->endDateDay;
157 - (void)setEndDateMonth:(id)_endDateMonth {
158 ASSIGN(self->endDateMonth, _endDateMonth);
161 return self->endDateMonth;
163 - (void)setEndDateYear:(id)_endDateYear {
164 ASSIGN(self->endDateYear, _endDateYear);
167 return self->endDateYear;
170 - (void)setStartDate:(NSCalendarDate *)_date {
171 [self setStartDateHour:[NSNumber numberWithInt:[_date hourOfDay]]];
172 [self setStartDateMinute:[NSNumber numberWithInt:[_date minuteOfHour]]];
173 [self setStartDateDay:[NSNumber numberWithInt:[_date dayOfMonth]]];
174 [self setStartDateMonth:[NSNumber numberWithInt:[_date monthOfYear]]];
175 [self setStartDateYear:[NSNumber numberWithInt:[_date yearOfCommonEra]]];
178 - (NSCalendarDate *) startDate
180 NSTimeZone *timeZone;
182 timeZone = [[context activeUser] timeZone];
184 return [NSCalendarDate dateWithYear:[[self startDateYear] intValue]
185 month:[[self startDateMonth] intValue]
186 day:[[self startDateDay] intValue]
187 hour:[[self startDateHour] intValue]
188 minute:[[self startDateMinute] intValue]
193 - (void) setEndDate: (NSCalendarDate *) _date
195 [self setEndDateHour:[NSNumber numberWithInt:[_date hourOfDay]]];
196 [self setEndDateMinute:[NSNumber numberWithInt:[_date minuteOfHour]]];
197 [self setEndDateDay:[NSNumber numberWithInt:[_date dayOfMonth]]];
198 [self setEndDateMonth:[NSNumber numberWithInt:[_date monthOfYear]]];
199 [self setEndDateYear:[NSNumber numberWithInt:[_date yearOfCommonEra]]];
202 - (NSCalendarDate *) endDate
204 NSTimeZone *timeZone;
206 timeZone = [[context activeUser] timeZone];
208 return [NSCalendarDate dateWithYear:[[self endDateYear] intValue]
209 month:[[self endDateMonth] intValue]
210 day:[[self endDateDay] intValue]
211 hour:[[self endDateHour] intValue]
212 minute:[[self endDateMinute] intValue]
217 - (void)setDuration:(id)_duration {
218 ASSIGN(self->duration, _duration);
221 return self->duration;
223 - (int)durationInMinutes {
224 return [[self duration] intValue];
226 - (NSTimeInterval)durationAsTimeInterval {
227 return [self durationInMinutes] * 60;
230 - (NSString *)itemDurationText {
231 // TODO: use a formatter
233 switch ([[self item] intValue]) {
234 case 30: return @"30 minutes";
235 case 60: return @"1 hour";
236 case 120: return @"2 hours";
237 case 240: return @"4 hours";
238 case 480: return @"8 hours";
240 return [NSString stringWithFormat:@"%@ minutes", [self item]];
244 - (void)setParticipants:(NSArray *)_parts {
245 ASSIGN(self->participants, _parts);
247 - (NSArray *)participants {
248 return self->participants;
250 - (void)setResources:(NSArray *)_res {
251 ASSIGN(self->resources, _res);
253 - (NSArray *)resources {
254 return self->resources;
257 - (NSArray *)attendees {
260 a = [self participants];
261 b = [self resources];
262 if ([b count] == 0) return a;
263 if ([a count] == 0) return b;
264 return [a arrayByAddingObjectsFromArray:b];
267 - (void)setCurrentDay:(id)_day {
268 ASSIGN(self->currentDay, _day);
271 return self->currentDay;
275 // TODO: from 'earliest start' to 'latest endtime'
276 unsigned lStartHour = 9, lEndHour = 17, i;
279 lStartHour = [[self startDateHour] intValue];
280 lEndHour = [[self endDateHour] intValue];
281 if (lStartHour < 1) lStartHour = 1;
282 if (lEndHour < lStartHour) lEndHour = lStartHour + 1;
284 ma = [NSMutableArray arrayWithCapacity:lEndHour - lStartHour + 2];
285 for (i = lStartHour; i <= lEndHour; i++)
286 [ma addObject:[NSNumber numberWithInt:i]];
292 // TODO: from startdate to enddate
294 NSCalendarDate *base, *stop, *current;
295 NSTimeZone *timeZone;
297 timeZone = [[context activeUser] timeZone];
298 base = [NSCalendarDate dateWithYear: [[self startDateYear] intValue]
299 month: [[self startDateMonth] intValue]
300 day: [[self startDateDay] intValue]
301 hour: 12 minute: 0 second: 0
303 stop = [NSCalendarDate dateWithYear: [[self endDateYear] intValue]
304 month: [[self endDateMonth] intValue]
305 day: [[self endDateDay] intValue]
306 hour: 12 minute: 0 second: 0
309 ma = [NSMutableArray arrayWithCapacity:16];
312 while ([current compare:stop] != NSOrderedDescending) {
313 [current setTimeZone: timeZone];
314 [ma addObject:current];
316 /* Note: remember the timezone behaviour of the method below! */
317 current = [current dateByAddingYears:0 months:0 days:1];
323 - (NSArray *)durationSteps {
324 // TODO: make configurable
325 return [NSArray arrayWithObjects:
326 @"30", @"60", @"120", @"240", @"480", nil];
331 - (BOOL)isRangeGreen:(NGCalendarDateRange *)_range {
334 idx = [self->blockedRanges indexOfFirstIntersectingDateRange:_range];
335 if (idx != NSNotFound) {
336 [self debugWithFormat:@"blocked range:\n range: %@\n block: %@\nintersection:%@",
338 [self->blockedRanges objectAtIndex:idx],
339 [_range intersectionDateRange:[self->blockedRanges objectAtIndex:idx]]];
342 return idx == NSNotFound ? YES : NO;
345 - (BOOL)isSlotRangeGreen: (NGCalendarDateRange *) _slotRange
347 NGCalendarDateRange *aptRange;
348 NSCalendarDate *aptStartDate, *aptEndDate;
349 NSTimeZone *timeZone;
351 if (_slotRange == nil)
354 timeZone = [[context activeUser] timeZone];
355 /* calculate the interval requested by the user (can be larger) */
357 aptStartDate = [_slotRange startDate];
358 // TODO: gives warning on MacOSX
360 = [[NSCalendarDate alloc]
361 initWithTimeIntervalSince1970: ([aptStartDate timeIntervalSince1970]
362 + [self durationAsTimeInterval])];
363 [aptStartDate setTimeZone: timeZone];
364 [aptEndDate setTimeZone: timeZone];
365 aptRange = [NGCalendarDateRange calendarDateRangeWithStartDate: aptStartDate
366 endDate: aptEndDate];
367 [aptEndDate release];
370 return [self isRangeGreen: aptRange];
373 - (BOOL)isFirstHalfGreen {
374 /* currentday is the date, self->item the hour */
375 NSCalendarDate *from, *to;
376 NGCalendarDateRange *range;
378 from = [self->currentDay hour:[[self item] intValue] minute:0];
379 to = [self->currentDay hour:[[self item] intValue] minute:30];
380 range = [NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:to];
381 return [self isSlotRangeGreen:range];
383 - (BOOL)isSecondHalfGreen {
384 /* currentday is the date, self->item the hour */
385 NSCalendarDate *from, *to;
386 NGCalendarDateRange *range;
388 from = [self->currentDay hour:[[self item] intValue] minute:30];
389 to = [self->currentDay hour:[[self item] intValue] + 1 minute:0];
390 range = [NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:to];
391 return [self isSlotRangeGreen:range];
394 - (BOOL)isFirstHalfBlocked {
395 return [self isFirstHalfGreen] ? NO : YES;
397 - (BOOL)isSecondHalfBlocked {
398 return [self isSecondHalfGreen] ? NO : YES;
403 - (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
407 - (id<WOActionResults>)defaultAction {
410 now = [NSCalendarDate date];
412 [self setDuration:@"120"]; /* 1 hour as default */
413 [self setStartDate:[now hour:9 minute:0]];
414 [self setEndDate:[now hour:18 minute:0]];
419 - (id)proposalSearchAction {
420 NSArray *attendees, *uids, *fbos, *ranges;
422 NSMutableArray *allInfos;
424 [self logWithFormat:@"search from %@ to %@",
425 [self startDate], [self endDate]];
427 attendees = [self attendees];
428 uids = [[self clientObject] uidsFromICalPersons:attendees];
429 if ([uids count] == 0) {
430 [self logWithFormat:@"Note: no UIDs selected."];
434 fbos = [[self clientObject] lookupFreeBusyObjectsForUIDs:uids
435 inContext:[self context]];
436 count = [fbos count];
437 // wild guess at capacity
438 allInfos = [[[NSMutableArray alloc] initWithCapacity:count * 10] autorelease];
440 for (i = 0; i < count; i++) {
441 SOGoFreeBusyObject *fb;
444 fb = [fbos objectAtIndex:i];
445 if (fb != (SOGoFreeBusyObject *)[NSNull null]) {
446 infos = [fb fetchFreeBusyInfosFrom:[self startDate] to:[self endDate]];
447 [allInfos addObjectsFromArray:infos];
450 [self debugWithFormat:@" processing: %d infos", [allInfos count]];
451 ranges = [allInfos arrayByCreatingDateRangesFromObjectsWithStartDateKey:
453 andEndDateKey:@"endDate"];
454 ranges = [ranges arrayByCompactingContainedDateRanges];
455 [self debugWithFormat:@" ranges: %@", ranges];
457 ASSIGNCOPY(self->blockedRanges, ranges);
464 - (NSMutableDictionary *)currentQueryParameters {
465 if(!self->currentQueryParameters) {
466 self->currentQueryParameters = [[self queryParameters] mutableCopy];
467 [self->currentQueryParameters setObject:[self duration] forKey:@"dur"];
468 [self setICalPersons:[self resources] asQueryParameter:@"rs"];
469 [self setICalPersons:[self participants] asQueryParameter:@"ps"];
471 return self->currentQueryParameters;
474 - (void)setICalPersons:(NSArray *)_ps asQueryParameter:(NSString *)_qp {
478 s = [[NSMutableString alloc] init];
480 for(i = 0; i < count; i++) {
481 iCalPerson *p = [_ps objectAtIndex:i];
482 [s appendString:[p rfc822Email]];
484 [s appendString:@","];
486 [[self currentQueryParameters] setObject:s forKey:_qp];
490 - (NSDictionary *)currentHourQueryParametersForFirstHalf:(BOOL)_first {
491 NSMutableDictionary *qp;
493 NSCalendarDate *date;
496 minute = _first ? 0 : 30;
497 qp = [self currentQueryParameters];
499 date = [self currentDay];
500 hmString = [NSString stringWithFormat:@"%02d%02d",
501 [item intValue], minute];
502 [self setSelectedDateQueryParameter:date inDictionary:qp];
503 [qp setObject:hmString forKey:@"hm"];
507 - (NSDictionary *)currentFirstHalfQueryParameters {
508 return [self currentHourQueryParametersForFirstHalf:YES];
511 - (NSDictionary *)currentSecondHalfQueryParameters {
512 return [self currentHourQueryParametersForFirstHalf:NO];
515 @end /* UIxTaskProposal */