See ChangeLog.

Monotone-Parent: 5768aec2a733241a4cb94db69e98b57603adb638
Monotone-Revision: 553f303f1f7a6910069af8e49e3926e86bece4b7

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2011-03-29T23:25:40
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Francis Lachapelle
2011-03-29 23:25:40 +00:00
parent eea9b8b91d
commit 6b3d99424a
8 changed files with 135 additions and 55 deletions
+19 -1
View File
@@ -1,3 +1,21 @@
2011-03-29 francis <flachapelle@inverse.ca>
* SoObjects/Appointments/iCalEvent+SOGo.m
(-updateRecurrenceRulesUntilDate:): shifts the "until dates" of
the recurrence rules of the event with respect to the previous end
date of the event.
* SoObjects/Appointments/SOGoCalendarComponent.m
(-updateComponent: ): splitted method "saveComponent:" to avoid
saving the component multiple times during the same session.
* SoObjects/Appointments/SOGoAppointmentObject.m (-saveComponent):
make use of the new "updateComponent" method mentioned above.
* SoObjects/Appointments/SOGoAppointmentFolder.m
(-_flattenCycleRecord:forRange:intoArray:): when the event has a
timezone, the "until dates" of recurrence rules must be adjusted.
2011-03-28 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Tools/SOGoToolRemoveDoubles.m
@@ -134,7 +152,7 @@
* SoObjects/Appointments/iCalEvent+SOGo.m (-quickRecord): an all-day
event usually doesn't have a timezone. However, if it does, we must
convert its dates to GMT. All-day events are "floating", in the
sense that are timezone-independant.
sense that they are timezone-independant.
2011-03-17 Francis Lachapelle <flachapelle@inverse.ca>
+40 -37
View File
@@ -45,6 +45,7 @@
#import <NGCards/iCalDateTime.h>
#import <NGCards/iCalPerson.h>
#import <NGCards/iCalRecurrenceCalculator.h>
#import <NGCards/iCalRecurrenceRule.h>
#import <NGCards/iCalTimeZone.h>
#import <NGCards/iCalTimeZonePeriod.h>
#import <NGCards/NSString+NGCards.h>
@@ -748,24 +749,14 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
NSDictionary *oldRecord;
NGCalendarDateRange *newRecordRange;
int recordIndex;
signed int daylightOffset;
newRecord = nil;
recurrenceId = [component recurrenceId];
if ([timeZone isDaylightSavingTimeForDate: recurrenceId] != [timeZone isDaylightSavingTimeForDate: [fir startDate]])
{
// For the event's recurrence id, compute the daylight saving time
// offset with respect to the first occurrence of the recurring event.
daylightOffset = (signed int)[timeZone secondsFromGMTForDate: [fir startDate]]
- (signed int)[timeZone secondsFromGMTForDate: recurrenceId];
recurrenceId = [recurrenceId dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:daylightOffset];
}
if ([dateRange containsDate: recurrenceId])
{
recordIndex = [self _indexOfRecordMatchingDate: recurrenceId
inArray: ma];
inArray: ma];
if (recordIndex > -1)
{
startDate = [component startDate];
@@ -793,8 +784,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
}
else
[self errorWithFormat:
@"missing exception record for recurrence-id: %@",
recurrenceId];
@"missing exception record for recurrence-id %@ (uid %@)",
recurrenceId, [component uid]];
}
else
{
@@ -822,6 +813,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
content = [row objectForKey: @"c_content"];
if ([content length])
{
// TODO : c_content could have already been parsed.
// @see _flattenCycleRecord:forRange:intoArray:
elements = [iCalCalendar parseFromSource: content];
if ([elements count])
{
@@ -830,9 +823,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
for (count = 1; count < max; count++)
[self _appendCycleException: [components objectAtIndex: count]
firstInstanceCalendarDateRange: fir
fromRow: row
forRange: dateRange
toArray: ma];
fromRow: row
forRange: dateRange
toArray: ma];
}
}
}
@@ -852,7 +845,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
NSMutableDictionary *row, *fixedRow;
NSMutableArray *records;
NSDictionary *cycleinfo;
NGCalendarDateRange *firstRange, *oneRange;
NGCalendarDateRange *firstRange, *recurrenceRange, *oneRange;
NSArray *rules, *exRules, *exDates, *ranges;
NSArray *elements, *components;
NSString *content;
@@ -860,7 +853,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
id firstStartDate, firstEndDate;
NSCalendarDate *checkStartDate, *checkEndDate;
iCalTimeZone *eventTimeZone;
unsigned i, count, offset;
unsigned count, max, offset;
records = [NSMutableArray array];
ranges = nil;
@@ -883,7 +876,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
rules = [cycleinfo objectForKey: @"rules"];
exRules = [cycleinfo objectForKey: @"exRules"];
exDates = [cycleinfo objectForKey: @"exDates"];
row = [self fixupRecord: theRecord];
[row removeObjectForKey: @"c_cycleinfo"];
[row setObject: sharedYes forKey: @"isRecurrentEvent"];
@@ -897,7 +890,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
components = [[elements objectAtIndex: 0] events];
if ([components count])
{
// Retrieve the range of the first event
// Retrieve the range of the first/master event
component = [components objectAtIndex: 0];
firstStartDate = [component uniqueChildWithTag: @"dtstart"];
firstEndDate = [component uniqueChildWithTag: @"dtend"];
@@ -910,27 +903,37 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
// Adjust the range to check with respect to the event timezone (extracted from the start date)
checkStartDate = [eventTimeZone computedDateForDate: [theRange startDate]];
checkEndDate = [eventTimeZone computedDateForDate: [theRange endDate]];
theRange = [NGCalendarDateRange calendarDateRangeWithStartDate: checkStartDate
endDate: checkEndDate];
recurrenceRange = [NGCalendarDateRange calendarDateRangeWithStartDate: checkStartDate
endDate: checkEndDate];
// Adjust the exception dates
exDates = [eventTimeZone computedDatesForStrings: exDates];
// Adjust the recurrence rules "until" dates
rules = [component recurrenceRulesWithTimeZone: eventTimeZone];
exRules = [component exceptionRulesWithTimeZone: eventTimeZone];
}
else if ([[theRecord objectForKey: @"c_isallday"] boolValue])
else
{
// The event lasts all-day and has no timezone (floating); we convert the range of the first event
// to the user's timezone
offset = [timeZone secondsFromGMTForDate: [firstRange startDate]];
firstStartDate = (NSCalendarDate*)[[firstRange startDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
recurrenceRange = theRange;
if ([[theRecord objectForKey: @"c_isallday"] boolValue])
{
// The event lasts all-day and has no timezone (floating); we convert the range of the first event
// to the user's timezone
offset = [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];
firstEndDate = (NSCalendarDate*)[[firstRange endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
[firstStartDate setTimeZone: timeZone];
[firstEndDate setTimeZone: timeZone];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate
endDate: firstEndDate];
[firstStartDate setTimeZone: timeZone];
[firstEndDate setTimeZone: timeZone];
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate
endDate: firstEndDate];
}
}
// Calculate the occurrences for the given range
ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: theRange
ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: recurrenceRange
firstInstanceCalendarDateRange: firstRange
recurrenceRules: rules
exceptionRules: exRules
@@ -939,10 +942,10 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
}
}
count = [ranges count];
for (i = 0; i < count; i++)
max = [ranges count];
for (count = 0; count < max; count++)
{
oneRange = [ranges objectAtIndex: i];
oneRange = [ranges objectAtIndex: count];
fixedRow = [self fixupCycleRecord: row
cycleRange: oneRange
firstInstanceCalendarDateRange: firstRange
+7 -10
View File
@@ -564,9 +564,9 @@
[self expandGroupsInEvent: newEvent];
// We first save the event. It is important to this initially
// as the event's UID might get modified in SOGoCalendarComponent: -saveComponent:
[super saveComponent: newEvent];
// We first update the event. It is important to this initially
// as the event's UID might get modified.
[super updateComponent: newEvent];
if ([self isNew])
{
@@ -606,15 +606,12 @@
hasOrganizer = [[[oldMasterEvent organizer] email] length];
if (!hasOrganizer || [oldMasterEvent userIsOrganizer: ownerUser])
{
// The owner is the organizer of the event; handle the modifications
[self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent];
// The sequence has possibly been increased -- resave the event.
[super saveComponent: newEvent];
}
// The owner is the organizer of the event; handle the modifications
[self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent];
}
[super saveComponent: newEvent];
[fullCalendar release];
fullCalendar = nil;
[safeCalendar release];
@@ -1,8 +1,9 @@
/* SOGoCalendarComponent.h - this file is part of SOGo
*
* Copyright (C) 2006-2009 Inverse inc.
* Copyright (C) 2006-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -58,6 +59,7 @@
- (NSException *) copyComponent: (iCalCalendar *) calendar
toFolder: (SOGoGCSFolder *) newFolder;
- (void) updateComponent: (iCalRepeatableEntityObject *) newObject;
- (void) saveComponent: (iCalRepeatableEntityObject *) newObject;
/* mail notifications */
@@ -593,9 +593,9 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
}
}
- (void) saveComponent: (iCalRepeatableEntityObject *) newObject
- (void) updateComponent: (iCalRepeatableEntityObject *) newObject
{
NSString *newiCalString, *newUid;
NSString *newUid;
if (!isNew
&& [newObject isRecurrent])
@@ -625,6 +625,11 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence,
[eaMgr handleAlarmsInCalendar: [newObject parent]
fromComponent: self];
}
}
- (void) saveComponent: (iCalRepeatableEntityObject *) newObject
{
NSString *newiCalString;
newiCalString = [[newObject parent] versitString];
+3 -1
View File
@@ -1,8 +1,9 @@
/* iCalEvent+SOGo.h - this file is part of SOGo
*
* Copyright (C) 2007-2009 Inverse inc.
* Copyright (C) 2007-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,6 +32,7 @@
- (BOOL) isStillRelevant;
- (NSMutableDictionary *) quickRecord;
- (void) updateRecurrenceRulesUntilDate: (NSCalendarDate *) previousEndDate;
@end
+53
View File
@@ -24,6 +24,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSValue.h>
#import <NGExtensions/NGCalendarDateRange.h>
@@ -35,6 +36,7 @@
#import <NGCards/iCalTimeZone.h>
#import <NGCards/iCalEvent.h>
#import <NGCards/iCalPerson.h>
#import <NGCards/iCalRecurrenceRule.h>
#import <NGCards/iCalTrigger.h>
#import <NGCards/NSString+NGCards.h>
@@ -286,4 +288,55 @@
return [[self endDate] timeIntervalSinceDate: [self startDate]];
}
/**
* Shift the "until dates" of the recurrence rules of the event
* with respect to the previous end date of the event.
* @param previousEndDate the previous end date of the event
*/
- (void) updateRecurrenceRulesUntilDate: (NSCalendarDate *) previousEndDate
{
iCalRecurrenceRule *rule;
NSEnumerator *rules;
NSCalendarDate *untilDate;
int offset;
// Recurrence rules
rules = [[self recurrenceRules] objectEnumerator];
while ((rule = [rules nextObject]))
{
untilDate = [rule untilDate];
if (untilDate)
{
// The until date must match the time of the end date
offset = [[self endDate] timeIntervalSinceDate: previousEndDate];
untilDate = [untilDate dateByAddingYears:0
months:0
days:0
hours:0
minutes:0
seconds:offset];
[rule setUntilDate: untilDate];
}
}
// Exception rules
rules = [[self exceptionRules] objectEnumerator];
while ((rule = [rules nextObject]))
{
untilDate = [rule untilDate];
if (untilDate)
{
// The until date must match the time of the end date
offset = [[self endDate] timeIntervalSinceDate: previousEndDate];
untilDate = [untilDate dateByAddingYears:0
months:0
days:0
hours:0
minutes:0
seconds:offset];
[rule setUntilDate: untilDate];
}
}
}
@end
@@ -161,9 +161,9 @@
// Calculate the occurrences for the given date
ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: checkRange
firstInstanceCalendarDateRange: firstRange
recurrenceRules: [self recurrenceRules]
exceptionRules: [self exceptionRules]
exceptionDates: [self exceptionDatesWithEventTimeZone: eventTimeZone]];
recurrenceRules: [self recurrenceRulesWithTimeZone: eventTimeZone]
exceptionRules: [self exceptionRulesWithTimeZone: eventTimeZone]
exceptionDates: [self exceptionDatesWithTimeZone: eventTimeZone]];
doesOccur = [ranges dateRangeArrayContainsDate: startDate];
}