Fix exceptions of recurring all-day events

pull/8/head
Francis Lachapelle 2013-01-21 14:11:38 -05:00
parent ddc9a1b3f5
commit 5bbb5df2a8
5 changed files with 42 additions and 65 deletions

View File

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2007-2012 Inverse inc. Copyright (C) 2007-2013 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of SOGo. This file is part of SOGo.
@ -697,8 +697,10 @@ static NSNumber *sharedYes = nil;
unsigned int count; unsigned int count;
NSCalendarDate *date; NSCalendarDate *date;
NSNumber *dateValue; NSNumber *dateValue;
BOOL isAllDay;
unsigned int offset; unsigned int offset;
isAllDay = [[theRecord objectForKey: @"c_isallday"] boolValue];
record = [[theRecord mutableCopy] autorelease]; record = [[theRecord mutableCopy] autorelease];
for (count = 0; count < 2; count++) for (count = 0; count < 2; count++)
{ {
@ -709,7 +711,7 @@ static NSNumber *sharedYes = nil;
if (date) if (date)
{ {
[date setTimeZone: timeZone]; [date setTimeZone: timeZone];
if ([[theRecord objectForKey: @"c_isallday"] boolValue]) if (isAllDay)
{ {
// Since there's no timezone associated to all-day events, // Since there's no timezone associated to all-day events,
// their time must be adjusted for the user's timezone. // their time must be adjusted for the user's timezone.
@ -788,6 +790,15 @@ static NSNumber *sharedYes = nil;
[record setObject: date forKey: @"startDate"]; [record setObject: date forKey: @"startDate"];
dateSecs = [NSNumber numberWithInt: [date timeIntervalSince1970]]; dateSecs = [NSNumber numberWithInt: [date timeIntervalSince1970]];
[record setObject: dateSecs forKey: @"c_startdate"]; [record setObject: dateSecs forKey: @"c_startdate"];
if ([[record valueForKey: @"c_isallday"] boolValue])
{
// Refer to all-day recurrence id by their GMT-based start date
date = [theCycle startDate];
secondsOffsetFromGMT = (int) [[date timeZone] secondsFromGMTForDate: date];
date = [date dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: secondsOffsetFromGMT];
dateSecs = [NSNumber numberWithInt: [date timeIntervalSince1970]];
}
[record setObject: dateSecs forKey: @"c_recurrence_id"]; [record setObject: dateSecs forKey: @"c_recurrence_id"];
date = [theCycle endDate]; date = [theCycle endDate];
@ -851,18 +862,18 @@ static NSNumber *sharedYes = nil;
firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
fromRow: (NSDictionary *) row fromRow: (NSDictionary *) row
forRange: (NGCalendarDateRange *) dateRange forRange: (NGCalendarDateRange *) dateRange
withTimeZone: (NSTimeZone *) tz withTimeZone: (NSTimeZone *) tz
toArray: (NSMutableArray *) ma toArray: (NSMutableArray *) ma
{ {
NSCalendarDate *startDate, *recurrenceId; NSCalendarDate *recurrenceId;
NSMutableDictionary *newRecord; NSMutableDictionary *newRecord;
NSDictionary *oldRecord; NSDictionary *oldRecord;
NGCalendarDateRange *newRecordRange; NGCalendarDateRange *newRecordRange;
NSComparisonResult compare;
int recordIndex, secondsOffsetFromGMT; int recordIndex, secondsOffsetFromGMT;
newRecord = nil; newRecord = nil;
recurrenceId = [component recurrenceId]; recurrenceId = [component recurrenceId];
if (!recurrenceId) if (!recurrenceId)
{ {
[self errorWithFormat: @"ignored component with an empty EXCEPTION-ID"]; [self errorWithFormat: @"ignored component with an empty EXCEPTION-ID"];
@ -877,40 +888,32 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
secondsOffsetFromGMT = [tz secondsFromGMTForDate: recurrenceId]; secondsOffsetFromGMT = [tz secondsFromGMTForDate: recurrenceId];
recurrenceId = (NSCalendarDate *) [recurrenceId dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 recurrenceId = (NSCalendarDate *) [recurrenceId dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-secondsOffsetFromGMT]; seconds:-secondsOffsetFromGMT];
[recurrenceId setTimeZone: tz];
} }
compare = [[dateRange startDate] compare: recurrenceId]; if ([dateRange containsDate: [component startDate]] ||
if ((compare == NSOrderedAscending || compare == NSOrderedSame) && [dateRange containsDate: [component endDate]])
[[dateRange endDate] compare: recurrenceId] == NSOrderedDescending)
{ {
recordIndex = [self _indexOfRecordMatchingDate: recurrenceId recordIndex = [self _indexOfRecordMatchingDate: recurrenceId
inArray: ma]; inArray: ma];
if (recordIndex > -1) if (recordIndex > -1)
{ {
startDate = [component startDate]; newRecord = [self fixupRecord: [component quickRecord]];
if ([dateRange containsDate: startDate]) [newRecord setObject: [NSNumber numberWithInt: 1]
{ forKey: @"c_iscycle"];
newRecord = [self fixupRecord: [component quickRecord]]; oldRecord = [ma objectAtIndex: recordIndex];
[newRecord setObject: [NSNumber numberWithInt: 1] [newRecord setObject: [oldRecord objectForKey: @"c_recurrence_id"]
forKey: @"c_iscycle"]; forKey: @"c_recurrence_id"];
oldRecord = [ma objectAtIndex: recordIndex];
[newRecord setObject: [oldRecord objectForKey: @"c_recurrence_id"]
forKey: @"c_recurrence_id"];
// [newRecord setObject: [NSNumber numberWithInt: [recurrenceId timeIntervalSince1970]]
// forKey: @"c_recurrence_id"];
// The first instance date is added to the dictionary so it can // The first instance date is added to the dictionary so it can
// be used by UIxCalListingActions to compute the DST offset. // be used by UIxCalListingActions to compute the DST offset.
[newRecord setObject: [fir startDate] forKey: @"cycleStartDate"]; [newRecord setObject: [fir startDate] forKey: @"cycleStartDate"];
// We identified the record as an exception. // We identified the record as an exception.
[newRecord setObject: [NSNumber numberWithInt: 1] [newRecord setObject: [NSNumber numberWithInt: 1]
forKey: @"isException"]; forKey: @"isException"];
[ma replaceObjectAtIndex: recordIndex withObject: newRecord]; [ma replaceObjectAtIndex: recordIndex withObject: newRecord];
}
else
[ma removeObjectAtIndex: recordIndex];
} }
else else
[self errorWithFormat: [self errorWithFormat:
@ -1030,14 +1033,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
// Retrieve the range of the first/master event // Retrieve the range of the first/master event
component = [components objectAtIndex: 0]; component = [components objectAtIndex: 0];
dtstart = (iCalDateTime *) [component uniqueChildWithTag: @"dtstart"]; dtstart = (iCalDateTime *) [component uniqueChildWithTag: @"dtstart"];
firstStartDate = [[[[dtstart valuesForKey: @""] firstRange = [component firstOccurenceRange]; // ignores timezone
lastObject]
lastObject]
asCalendarDate];
firstEndDate = [firstStartDate addTimeInterval: [component occurenceInterval]];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate
endDate: firstEndDate];
eventTimeZone = [dtstart timeZone]; eventTimeZone = [dtstart timeZone];
if (eventTimeZone) if (eventTimeZone)

View File

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2007-2012 Inverse inc. Copyright (C) 2007-2013 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of SOGo This file is part of SOGo
@ -107,7 +107,7 @@
timeIntervalSinceDate: firstDate]; timeIntervalSinceDate: firstDate];
if ([newOccurence isAllDay]) if ([newOccurence isAllDay])
{ {
nbrDays = ((float) abs (interval) / 86400) + 1; nbrDays = ((float) abs (interval) / 86400);
[newOccurence setAllDayWithStartDate: date [newOccurence setAllDayWithStartDate: date
duration: nbrDays]; duration: nbrDays];
} }

View File

@ -1,6 +1,6 @@
/* iCalEvent+SOGo.m - this file is part of SOGo /* iCalEvent+SOGo.m - this file is part of SOGo
* *
* Copyright (C) 2007-2011 Inverse inc. * Copyright (C) 2007-2013 Inverse inc.
* *
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca> * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca> * Francis Lachapelle <flachapelle@inverse.ca>
@ -282,7 +282,7 @@
dates = [[[self uniqueChildWithTag: @"dtstart"] valuesForKey: @""] lastObject]; dates = [[[self uniqueChildWithTag: @"dtstart"] valuesForKey: @""] lastObject];
if ([dates count] > 0) if ([dates count] > 0)
{ {
start = [[dates lastObject] asCalendarDate]; start = [[dates lastObject] asCalendarDate]; // ignores timezone
end = [start addTimeInterval: [self occurenceInterval]]; end = [start addTimeInterval: [self occurenceInterval]];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: start firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: start

View File

@ -1,6 +1,6 @@
/* iCalRepeatableEntityObject+SOGo.h - this file is part of SOGo /* iCalRepeatableEntityObject+SOGo.h - this file is part of SOGo
Copyright (C) 2004-2005 SKYRIX Software AG Copyright (C) 2004-2005 SKYRIX Software AG
Copyright (C) 2008 Inverse inc. Copyright (C) 2008-2013 Inverse inc.
This file is part of OpenGroupware.org. This file is part of OpenGroupware.org.
@ -29,6 +29,7 @@
@interface iCalRepeatableEntityObject (SOGoExtensions) @interface iCalRepeatableEntityObject (SOGoExtensions)
- (NSString *) cycleInfo; - (NSString *) cycleInfo;
- (NGCalendarDateRange *) firstOccurenceRange;
- (BOOL) doesOccurOnDate: (NSCalendarDate *) occurenceDate; - (BOOL) doesOccurOnDate: (NSCalendarDate *) occurenceDate;
@end @end

View File

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2008-2011 Inverse inc. Copyright (C) 2008-2013 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of OpenGroupware.org. This file is part of OpenGroupware.org.
@ -133,35 +133,15 @@
if (doesOccur) if (doesOccur)
{ {
// Retrieve the range of the first event // Retrieve the range of the first event
firstRange = [self firstOccurenceRange]; firstRange = [self firstOccurenceRange]; // returns GMT dates
// Set the range to check with respect to the event timezone (extracted from the start date) // Set the range to check with respect to the event timezone (extracted from the start date)
firstStartDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"]; firstStartDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"];
timeZone = [(iCalDateTime *)firstStartDate timeZone]; timeZone = [(iCalDateTime *)firstStartDate timeZone];
if (timeZone) if (timeZone)
{
startDate = [(iCalTimeZone *)timeZone computedDateForDate: theOccurenceDate]; startDate = [(iCalTimeZone *)timeZone computedDateForDate: theOccurenceDate];
}
else else
{
startDate = theOccurenceDate; startDate = theOccurenceDate;
if ([self isKindOfClass: [iCalEvent class]] && [(iCalEvent *) self isAllDay])
{
// The event lasts all-day and has no timezone (floating); we convert the range of the first event
// to the occurence's timezone.
timeZone = [theOccurenceDate timeZone];
offset = [(NSTimeZone *)timeZone secondsFromGMTForDate: [firstRange startDate]];
firstStartDate = (NSCalendarDate *)[[firstRange startDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
firstEndDate = (NSCalendarDate *)[[firstRange endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
[(NSCalendarDate *)firstStartDate setTimeZone: timeZone];
[(NSCalendarDate *)firstEndDate setTimeZone: timeZone];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate
endDate: firstEndDate];
}
}
endDate = [startDate addTimeInterval: [self occurenceInterval]]; endDate = [startDate addTimeInterval: [self occurenceInterval]];
checkRange = [NGCalendarDateRange calendarDateRangeWithStartDate: startDate checkRange = [NGCalendarDateRange calendarDateRangeWithStartDate: startDate
endDate: endDate]; endDate: endDate];