sogo/UI/Scheduler/UIxTaskProposal.m
Wolfgang Sourdeau 6d95a55549 Monotone-Parent: a5370a41693bc2294eb25921c8e19dda7570a063
Monotone-Revision: d236b4faef46342731f423fa93d09e1139cc312e

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2007-07-12T15:37:14
Monotone-Branch: ca.inverse.sogo
2007-07-12 15:37:14 +00:00

516 lines
14 KiB
Objective-C

/*
Copyright (C) 2004 SKYRIX Software AG
This file is part of OpenGroupware.org.
OGo is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
// $Id: UIxTaskEditor.m 181 2004-08-11 15:13:25Z helge $
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSNull.h>
#import <Foundation/NSValue.h>
#import <NGExtensions/NGCalendarDateRange.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGCards/iCalPerson.h>
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
#import <SoObjects/Appointments/SOGoFreeBusyObject.h>
#import <SOGoUI/UIxComponent.h>
@interface UIxTaskProposal : UIxComponent
{
id item;
id currentDay;
/* individual values */
id startDateHour;
id startDateMinute;
id endDateHour;
id endDateMinute;
id startDateDay;
id startDateMonth;
id startDateYear;
id endDateDay;
id endDateMonth;
id endDateYear;
NSArray *participants; /* array of iCalPerson's */
NSArray *resources; /* array of iCalPerson's */
id duration;
NSArray *blockedRanges;
NSMutableDictionary *currentQueryParameters;
}
- (NSMutableDictionary *)currentQueryParameters;
- (NSDictionary *)currentHourQueryParametersForFirstHalf:(BOOL)_first;
- (void)setICalPersons:(NSArray *)_ps asQueryParameter:(NSString *)_qp;
@end
@implementation UIxTaskProposal
- (void)dealloc {
[self->blockedRanges release];
[self->startDateHour release];
[self->startDateMinute release];
[self->startDateDay release];
[self->startDateMonth release];
[self->startDateYear release];
[self->endDateHour release];
[self->endDateMinute release];
[self->endDateDay release];
[self->endDateMonth release];
[self->endDateYear release];
[self->duration release];
[self->participants release];
[self->resources release];
[self->currentQueryParameters release];
[super dealloc];
}
/* notifications */
- (void)sleep {
[self->currentDay release]; self->currentDay = nil;
[self->item release]; self->item = nil;
[super sleep];
}
/* accessors */
- (void)setItem:(id)_item {
ASSIGN(self->item, _item);
}
- (id)item {
return self->item;
}
- (void)setStartDateHour:(id)_startDateHour {
ASSIGN(self->startDateHour, _startDateHour);
}
- (id)startDateHour {
return self->startDateHour;
}
- (void)setStartDateMinute:(id)_startDateMinute {
ASSIGN(self->startDateMinute, _startDateMinute);
}
- (id)startDateMinute {
return self->startDateMinute;
}
- (void)setStartDateDay:(id)_startDateDay {
ASSIGN(self->startDateDay, _startDateDay);
}
- (id)startDateDay {
return self->startDateDay;
}
- (void)setStartDateMonth:(id)_startDateMonth {
ASSIGN(self->startDateMonth, _startDateMonth);
}
- (id)startDateMonth {
return self->startDateMonth;
}
- (void)setStartDateYear:(id)_startDateYear {
ASSIGN(self->startDateYear, _startDateYear);
}
- (id)startDateYear {
return self->startDateYear;
}
- (void)setEndDateHour:(id)_endDateHour {
ASSIGN(self->endDateHour, _endDateHour);
}
- (id)endDateHour {
return self->endDateHour;
}
- (void)setEndDateMinute:(id)_endDateMinute {
ASSIGN(self->endDateMinute, _endDateMinute);
}
- (id)endDateMinute {
return self->endDateMinute;
}
- (void)setEndDateDay:(id)_endDateDay {
ASSIGN(self->endDateDay, _endDateDay);
}
- (id)endDateDay {
return self->endDateDay;
}
- (void)setEndDateMonth:(id)_endDateMonth {
ASSIGN(self->endDateMonth, _endDateMonth);
}
- (id)endDateMonth {
return self->endDateMonth;
}
- (void)setEndDateYear:(id)_endDateYear {
ASSIGN(self->endDateYear, _endDateYear);
}
- (id)endDateYear {
return self->endDateYear;
}
- (void)setStartDate:(NSCalendarDate *)_date {
[self setStartDateHour:[NSNumber numberWithInt:[_date hourOfDay]]];
[self setStartDateMinute:[NSNumber numberWithInt:[_date minuteOfHour]]];
[self setStartDateDay:[NSNumber numberWithInt:[_date dayOfMonth]]];
[self setStartDateMonth:[NSNumber numberWithInt:[_date monthOfYear]]];
[self setStartDateYear:[NSNumber numberWithInt:[_date yearOfCommonEra]]];
}
- (NSCalendarDate *) startDate
{
NSTimeZone *timeZone;
timeZone = [[context activeUser] timeZone];
return [NSCalendarDate dateWithYear:[[self startDateYear] intValue]
month:[[self startDateMonth] intValue]
day:[[self startDateDay] intValue]
hour:[[self startDateHour] intValue]
minute:[[self startDateMinute] intValue]
second:0
timeZone: timeZone];
}
- (void) setEndDate: (NSCalendarDate *) _date
{
[self setEndDateHour:[NSNumber numberWithInt:[_date hourOfDay]]];
[self setEndDateMinute:[NSNumber numberWithInt:[_date minuteOfHour]]];
[self setEndDateDay:[NSNumber numberWithInt:[_date dayOfMonth]]];
[self setEndDateMonth:[NSNumber numberWithInt:[_date monthOfYear]]];
[self setEndDateYear:[NSNumber numberWithInt:[_date yearOfCommonEra]]];
}
- (NSCalendarDate *) endDate
{
NSTimeZone *timeZone;
timeZone = [[context activeUser] timeZone];
return [NSCalendarDate dateWithYear:[[self endDateYear] intValue]
month:[[self endDateMonth] intValue]
day:[[self endDateDay] intValue]
hour:[[self endDateHour] intValue]
minute:[[self endDateMinute] intValue]
second:59
timeZone: timeZone];
}
- (void)setDuration:(id)_duration {
ASSIGN(self->duration, _duration);
}
- (id)duration {
return self->duration;
}
- (int)durationInMinutes {
return [[self duration] intValue];
}
- (NSTimeInterval)durationAsTimeInterval {
return [self durationInMinutes] * 60;
}
- (NSString *)itemDurationText {
// TODO: use a formatter
// TODO: localize
switch ([[self item] intValue]) {
case 30: return @"30 minutes";
case 60: return @"1 hour";
case 120: return @"2 hours";
case 240: return @"4 hours";
case 480: return @"8 hours";
default:
return [NSString stringWithFormat:@"%@ minutes", [self item]];
}
}
- (void)setParticipants:(NSArray *)_parts {
ASSIGN(self->participants, _parts);
}
- (NSArray *)participants {
return self->participants;
}
- (void)setResources:(NSArray *)_res {
ASSIGN(self->resources, _res);
}
- (NSArray *)resources {
return self->resources;
}
- (NSArray *)attendees {
NSArray *a, *b;
a = [self participants];
b = [self resources];
if ([b count] == 0) return a;
if ([a count] == 0) return b;
return [a arrayByAddingObjectsFromArray:b];
}
- (void)setCurrentDay:(id)_day {
ASSIGN(self->currentDay, _day);
}
- (id)currentDay {
return self->currentDay;
}
- (NSArray *)hours {
// TODO: from 'earliest start' to 'latest endtime'
unsigned lStartHour = 9, lEndHour = 17, i;
NSMutableArray *ma;
lStartHour = [[self startDateHour] intValue];
lEndHour = [[self endDateHour] intValue];
if (lStartHour < 1) lStartHour = 1;
if (lEndHour < lStartHour) lEndHour = lStartHour + 1;
ma = [NSMutableArray arrayWithCapacity:lEndHour - lStartHour + 2];
for (i = lStartHour; i <= lEndHour; i++)
[ma addObject:[NSNumber numberWithInt:i]];
return ma;
}
- (NSArray *) days
{
// TODO: from startdate to enddate
NSMutableArray *ma;
NSCalendarDate *base, *stop, *current;
NSTimeZone *timeZone;
timeZone = [[context activeUser] timeZone];
base = [NSCalendarDate dateWithYear: [[self startDateYear] intValue]
month: [[self startDateMonth] intValue]
day: [[self startDateDay] intValue]
hour: 12 minute: 0 second: 0
timeZone: timeZone];
stop = [NSCalendarDate dateWithYear: [[self endDateYear] intValue]
month: [[self endDateMonth] intValue]
day: [[self endDateDay] intValue]
hour: 12 minute: 0 second: 0
timeZone: timeZone];
ma = [NSMutableArray arrayWithCapacity:16];
current = base;
while ([current compare:stop] != NSOrderedDescending) {
[current setTimeZone: timeZone];
[ma addObject:current];
/* Note: remember the timezone behaviour of the method below! */
current = [current dateByAddingYears:0 months:0 days:1];
}
return ma;
}
- (NSArray *)durationSteps {
// TODO: make configurable
return [NSArray arrayWithObjects:
@"30", @"60", @"120", @"240", @"480", nil];
}
/* slots */
- (BOOL)isRangeGreen:(NGCalendarDateRange *)_range {
unsigned idx;
idx = [self->blockedRanges indexOfFirstIntersectingDateRange:_range];
if (idx != NSNotFound) {
[self debugWithFormat:@"blocked range:\n range: %@\n block: %@\nintersection:%@",
_range,
[self->blockedRanges objectAtIndex:idx],
[_range intersectionDateRange:[self->blockedRanges objectAtIndex:idx]]];
}
return idx == NSNotFound ? YES : NO;
}
- (BOOL)isSlotRangeGreen: (NGCalendarDateRange *) _slotRange
{
NGCalendarDateRange *aptRange;
NSCalendarDate *aptStartDate, *aptEndDate;
NSTimeZone *timeZone;
if (_slotRange == nil)
return NO;
timeZone = [[context activeUser] timeZone];
/* calculate the interval requested by the user (can be larger) */
aptStartDate = [_slotRange startDate];
// TODO: gives warning on MacOSX
aptEndDate
= [[NSCalendarDate alloc]
initWithTimeIntervalSince1970: ([aptStartDate timeIntervalSince1970]
+ [self durationAsTimeInterval])];
[aptStartDate setTimeZone: timeZone];
[aptEndDate setTimeZone: timeZone];
aptRange = [NGCalendarDateRange calendarDateRangeWithStartDate: aptStartDate
endDate: aptEndDate];
[aptEndDate release];
aptEndDate = nil;
return [self isRangeGreen: aptRange];
}
- (BOOL)isFirstHalfGreen {
/* currentday is the date, self->item the hour */
NSCalendarDate *from, *to;
NGCalendarDateRange *range;
from = [self->currentDay hour:[[self item] intValue] minute:0];
to = [self->currentDay hour:[[self item] intValue] minute:30];
range = [NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:to];
return [self isSlotRangeGreen:range];
}
- (BOOL)isSecondHalfGreen {
/* currentday is the date, self->item the hour */
NSCalendarDate *from, *to;
NGCalendarDateRange *range;
from = [self->currentDay hour:[[self item] intValue] minute:30];
to = [self->currentDay hour:[[self item] intValue] + 1 minute:0];
range = [NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:to];
return [self isSlotRangeGreen:range];
}
- (BOOL)isFirstHalfBlocked {
return [self isFirstHalfGreen] ? NO : YES;
}
- (BOOL)isSecondHalfBlocked {
return [self isSecondHalfGreen] ? NO : YES;
}
/* actions */
- (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
return YES;
}
- (id<WOActionResults>)defaultAction {
NSCalendarDate *now;
now = [NSCalendarDate date];
[self setDuration:@"120"]; /* 1 hour as default */
[self setStartDate:[now hour:9 minute:0]];
[self setEndDate:[now hour:18 minute:0]];
return self;
}
- (id)proposalSearchAction {
NSArray *attendees, *uids, *fbos, *ranges;
unsigned i, count;
NSMutableArray *allInfos;
[self logWithFormat:@"search from %@ to %@",
[self startDate], [self endDate]];
attendees = [self attendees];
uids = [[self clientObject] uidsFromICalPersons:attendees];
if ([uids count] == 0) {
[self logWithFormat:@"Note: no UIDs selected."];
return self;
}
fbos = [[self clientObject] lookupFreeBusyObjectsForUIDs:uids
inContext:[self context]];
count = [fbos count];
// wild guess at capacity
allInfos = [[[NSMutableArray alloc] initWithCapacity:count * 10] autorelease];
for (i = 0; i < count; i++) {
SOGoFreeBusyObject *fb;
NSArray *infos;
fb = [fbos objectAtIndex:i];
if (fb != (SOGoFreeBusyObject *)[NSNull null]) {
infos = [fb fetchFreeBusyInfosFrom:[self startDate] to:[self endDate]];
[allInfos addObjectsFromArray:infos];
}
}
[self debugWithFormat:@" processing: %d infos", [allInfos count]];
ranges = [allInfos arrayByCreatingDateRangesFromObjectsWithStartDateKey:
@"startDate"
andEndDateKey:@"endDate"];
ranges = [ranges arrayByCompactingContainedDateRanges];
[self debugWithFormat:@" ranges: %@", ranges];
ASSIGNCOPY(self->blockedRanges, ranges);
return self;
}
/* URLs */
- (NSMutableDictionary *)currentQueryParameters {
if(!self->currentQueryParameters) {
self->currentQueryParameters = [[self queryParameters] mutableCopy];
[self->currentQueryParameters setObject:[self duration] forKey:@"dur"];
[self setICalPersons:[self resources] asQueryParameter:@"rs"];
[self setICalPersons:[self participants] asQueryParameter:@"ps"];
}
return self->currentQueryParameters;
}
- (void)setICalPersons:(NSArray *)_ps asQueryParameter:(NSString *)_qp {
NSMutableString *s;
unsigned i, count;
s = [[NSMutableString alloc] init];
count = [_ps count];
for(i = 0; i < count; i++) {
iCalPerson *p = [_ps objectAtIndex:i];
[s appendString:[p rfc822Email]];
if(i != (count - 1))
[s appendString:@","];
}
[[self currentQueryParameters] setObject:s forKey:_qp];
[s release];
}
- (NSDictionary *)currentHourQueryParametersForFirstHalf:(BOOL)_first {
NSMutableDictionary *qp;
NSString *hmString;
NSCalendarDate *date;
unsigned minute;
minute = _first ? 0 : 30;
qp = [self currentQueryParameters];
date = [self currentDay];
hmString = [NSString stringWithFormat:@"%02d%02d",
[item intValue], minute];
[self setSelectedDateQueryParameter:date inDictionary:qp];
[qp setObject:hmString forKey:@"hm"];
return qp;
}
- (NSDictionary *)currentFirstHalfQueryParameters {
return [self currentHourQueryParametersForFirstHalf:YES];
}
- (NSDictionary *)currentSecondHalfQueryParameters {
return [self currentHourQueryParametersForFirstHalf:NO];
}
@end /* UIxTaskProposal */