See Changelog.
Monotone-Parent: 8f58a8aa696d8fbbb82f1cd571800676a04b96af Monotone-Revision: b593ce96638476fad98d678453ca6af6112169fb Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2011-01-14T02:54:33 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
b6bc06b163
commit
64081b8fa7
23
ChangeLog
23
ChangeLog
|
@ -1,3 +1,26 @@
|
|||
2011-01-13 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* SoObjects/Appointments/iCalRepeatableEntityObject+SOGo.m
|
||||
(-doesOccurOnDate:): the date to verify must be adjusted to the
|
||||
event's timezone before performing the calculation of the
|
||||
recurrence rule.
|
||||
|
||||
* SoObjects/Appointments/iCalEvent+SOGo.m (-firstOccurenceRange):
|
||||
extract the original start and end dates from the event, based on
|
||||
the event's timezone.
|
||||
|
||||
* SoObjects/Appointments/SOGoAppointmentFolder.m
|
||||
(-fixupCycleRecord:cycleRange:firstInstanceCalendarDateRange:withEventTimeZone:):
|
||||
the event dates must be first be adjusted to the event's timezone
|
||||
before being adjusted to the user's timezone.
|
||||
(-_flattenCycleRecord:forRange:intoArray:): the calculation of the
|
||||
occurrences must be performed with respect to the event's
|
||||
timezone, not the user's timezone.
|
||||
|
||||
* SoObjects/Appointments/SOGoAppointmentObject.m
|
||||
(-newOccurenceWithID:): new occurrences are now independant of the
|
||||
user's timezone.
|
||||
|
||||
2011-01-11 Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
|
||||
* OpenChange/MAPIStoreContactsMessageTable.m
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
2011-01-13 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* iCalTimeZone.m (-computedDateForDate:): Was
|
||||
_computedDateTimeForDate. Adjusts a date with respect to this
|
||||
vTimeZone.
|
||||
|
||||
* iCalDateTime.m (-dateTimes): when there's no timezone defined
|
||||
(which is the case when parsing a vTimeZone!), don't fallback to
|
||||
the system timezone.
|
||||
|
||||
2010-11-18 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* NGVCard.m (-setVName, vName): removed useless and non-standard
|
||||
|
|
|
@ -161,6 +161,7 @@
|
|||
currentEndDate = [currentStartDate addTimeInterval: [firstRange duration]];
|
||||
r = [NGCalendarDateRange calendarDateRangeWithStartDate: currentStartDate
|
||||
endDate: currentEndDate];
|
||||
|
||||
if ([_r containsDateRange: r])
|
||||
[ranges addObject: r];
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* iCalDateTime.m - this file is part of SOPE
|
||||
*
|
||||
* Copyright (C) 2006 Inverse inc.
|
||||
* Copyright (C) 2006-2011 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
|
@ -161,7 +161,7 @@
|
|||
NSString *date;
|
||||
NSCalendarDate *initialDate, *dateTime;
|
||||
NSMutableArray *dates;
|
||||
NSTimeZone *tz;
|
||||
//NSTimeZone *tz;
|
||||
unsigned count, i;
|
||||
|
||||
count = [[self values] count];
|
||||
|
@ -170,24 +170,28 @@
|
|||
{
|
||||
date = [self value: i];
|
||||
iTZ = [self timeZone];
|
||||
|
||||
if (iTZ)
|
||||
dateTime = [iTZ dateForDateTimeString: date];
|
||||
else
|
||||
{
|
||||
initialDate = [date asCalendarDate];
|
||||
if (initialDate)
|
||||
dateTime = initialDate;
|
||||
/*
|
||||
{
|
||||
if ([date hasSuffix: @"Z"] || [date hasSuffix: @"z"])
|
||||
dateTime = initialDate;
|
||||
else
|
||||
{
|
||||
/* same TODO as above */
|
||||
// same TODO as above
|
||||
tz = [NSTimeZone defaultTimeZone];
|
||||
dateTime = [initialDate addYear: 0 month: 0 day: 0
|
||||
hour: 0 minute: 0
|
||||
second: -[tz secondsFromGMTForDate: initialDate]];
|
||||
}
|
||||
}
|
||||
*/
|
||||
else
|
||||
dateTime = nil;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* iCalTimeZone.h - this file is part of SOPE
|
||||
*
|
||||
* Copyright (C) 2006-2009 Inverse inc.
|
||||
* Copyright (C) 2006-2011 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
|
@ -28,10 +28,14 @@
|
|||
|
||||
#import "CardGroup.h"
|
||||
|
||||
@class iCalTimeZonePeriod;
|
||||
|
||||
@interface iCalTimeZone : CardGroup
|
||||
|
||||
+ (iCalTimeZone *) timeZoneForName: (NSString *) theName;
|
||||
- (NSString *) tzId;
|
||||
- (iCalTimeZonePeriod *) periodForDate: (NSCalendarDate *) date;
|
||||
- (NSCalendarDate *) computedDateForDate: (NSCalendarDate *) theDate;
|
||||
- (NSString *) dateTimeStringForDate: (NSCalendarDate *) date;
|
||||
- (NSString *) dateStringForDate: (NSCalendarDate *) date;
|
||||
- (NSCalendarDate *) dateForDateTimeString: (NSString *) string;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
/* iCalTimeZone.m - this file is part of SOPE
|
||||
*
|
||||
* Copyright (C) 2006-2009 Inverse inc.
|
||||
* Copyright (C) 2006-2011 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Ludovic Marcotte <lmarcotte@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
|
||||
|
@ -185,35 +186,38 @@ static NSMutableDictionary *cache;
|
|||
period = (iCalTimeZonePeriod *) [self uniqueChildWithTag: @"daylight"];
|
||||
}
|
||||
|
||||
// NSLog (@"chosen period: '%@'", [period tag]);
|
||||
|
||||
return period;
|
||||
}
|
||||
|
||||
- (NSCalendarDate *) _computedDateTimeForDate: (NSCalendarDate *) date
|
||||
/**
|
||||
* Adjust a date with respect to this vTimeZone.
|
||||
* @param theDate the date to adjust to the timezone.
|
||||
* @return a new GMT date adjusted with the offset of the timezone.
|
||||
*/
|
||||
- (NSCalendarDate *) computedDateForDate: (NSCalendarDate *) theDate
|
||||
{
|
||||
NSCalendarDate *tmpDate;
|
||||
NSTimeZone *utc;
|
||||
|
||||
utc = [NSTimeZone timeZoneWithName: @"GMT"];
|
||||
tmpDate = [date copy];
|
||||
tmpDate = [theDate copy];
|
||||
[tmpDate autorelease];
|
||||
[tmpDate setTimeZone: utc];
|
||||
|
||||
return [tmpDate addYear: 0 month: 0 day: 0
|
||||
hour: 0 minute: 0
|
||||
second: [[self periodForDate: date] secondsOffsetFromGMT]];
|
||||
second: [[self periodForDate: theDate] secondsOffsetFromGMT]];
|
||||
}
|
||||
|
||||
- (NSString *) dateTimeStringForDate: (NSCalendarDate *) date
|
||||
{
|
||||
return [[self _computedDateTimeForDate: date]
|
||||
return [[self computedDateForDate: date]
|
||||
iCalFormattedDateTimeString];
|
||||
}
|
||||
|
||||
- (NSString *) dateStringForDate: (NSCalendarDate *) date
|
||||
{
|
||||
return [[self _computedDateTimeForDate: date]
|
||||
return [[self computedDateForDate: date]
|
||||
iCalFormattedDateString];
|
||||
}
|
||||
|
||||
|
|
|
@ -137,6 +137,7 @@
|
|||
}
|
||||
|
||||
tzStart = [self startDate];
|
||||
|
||||
[tzStart setTimeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
|
||||
tmpDate = [NSCalendarDate dateWithYear: [refDate yearOfCommonEra]
|
||||
month: [[rrule namedValue: @"bymonth"] intValue]
|
||||
|
|
|
@ -186,6 +186,7 @@
|
|||
currentEndDate = [currentStartDate addTimeInterval: [firstRange duration]];
|
||||
r = [NGCalendarDateRange calendarDateRangeWithStartDate: currentStartDate
|
||||
endDate: currentEndDate];
|
||||
|
||||
if ([_r containsDateRange: r])
|
||||
[ranges addObject: r];
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2007-2009 Inverse inc.
|
||||
Copyright (C) 2007-2011 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
@ -46,6 +46,7 @@
|
|||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalRecurrenceCalculator.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
#import <NGCards/iCalTimeZonePeriod.h>
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
#import <NGExtensions/NGCalendarDateRange.h>
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
|
@ -576,33 +577,38 @@ static NSNumber *sharedYes = nil;
|
|||
forKey: [currentRecord objectForKey: @"c_name"]];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) fixupRecord: (NSDictionary *) _record
|
||||
/**
|
||||
* Set the timezone of the event start and end dates to the user's timezone.
|
||||
* @param theRecord an dictionnary with the attributes of the event.
|
||||
* @return a copy of theRecord with adjusted dates.
|
||||
*/
|
||||
- (NSMutableDictionary *) fixupRecord: (NSDictionary *) theRecord
|
||||
{
|
||||
NSMutableDictionary *md;
|
||||
NSMutableDictionary *record;
|
||||
static NSString *fields[] = { @"c_startdate", @"startDate",
|
||||
@"c_enddate", @"endDate" };
|
||||
unsigned int count;
|
||||
NSCalendarDate *date;
|
||||
NSNumber *dateValue;
|
||||
|
||||
md = [[_record mutableCopy] autorelease];
|
||||
record = [[theRecord mutableCopy] autorelease];
|
||||
for (count = 0; count < 2; count++)
|
||||
{
|
||||
dateValue = [_record objectForKey: fields[count * 2]];
|
||||
dateValue = [theRecord objectForKey: fields[count * 2]];
|
||||
if (dateValue)
|
||||
{
|
||||
date = [NSCalendarDate dateWithTimeIntervalSince1970: [dateValue unsignedIntValue]];
|
||||
if (date)
|
||||
{
|
||||
[date setTimeZone: timeZone];
|
||||
[md setObject: date forKey: fields[count * 2 + 1]];
|
||||
[record setObject: date forKey: fields[count * 2 + 1]];
|
||||
}
|
||||
}
|
||||
else
|
||||
[self logWithFormat: @"missing '%@' in record?", fields[count * 2]];
|
||||
}
|
||||
|
||||
return md;
|
||||
return record;
|
||||
}
|
||||
|
||||
- (NSArray *) fixupRecords: (NSArray *) theRecords
|
||||
|
@ -629,42 +635,52 @@ static NSNumber *sharedYes = nil;
|
|||
return ma;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) fixupCycleRecord: (NSDictionary *) _record
|
||||
cycleRange: (NGCalendarDateRange *) _r
|
||||
firstInstanceCalendarDateRange: (NGCalendarDateRange *) _fir
|
||||
forViewRange: (NGCalendarDateRange *) _viewRange
|
||||
/**
|
||||
* Adjust the timezone of the start and end dates to the user's timezone.
|
||||
* The event is recurrent and the dates must first be adjusted with respect to
|
||||
* the event's timezone.
|
||||
* @param theRecord
|
||||
* @param theCycle
|
||||
* @param theFirstCycle
|
||||
* @param theEventTimeZone
|
||||
* @see fixupRecord:
|
||||
* @return a copy of theRecord with adjusted dates.
|
||||
*/
|
||||
- (NSMutableDictionary *) fixupCycleRecord: (NSDictionary *) theRecord
|
||||
cycleRange: (NGCalendarDateRange *) theCycle
|
||||
firstInstanceCalendarDateRange: (NGCalendarDateRange *) theFirstCycle
|
||||
withEventTimeZone: (iCalTimeZone *) theEventTimeZone
|
||||
{
|
||||
NSMutableDictionary *md;
|
||||
NSMutableDictionary *record;
|
||||
NSNumber *dateSecs;
|
||||
id tmp;
|
||||
|
||||
md = [[_record mutableCopy] autorelease];
|
||||
id date;
|
||||
int secondsOffsetFromGMT;
|
||||
|
||||
/* cycle is in _r. We also have to override the c_startdate/c_enddate with the date values of
|
||||
the reccurence since we use those when displaying events in SOGo Web */
|
||||
record = [[theRecord mutableCopy] autorelease];
|
||||
|
||||
tmp = [_r startDate];
|
||||
[tmp setTimeZone: timeZone];
|
||||
[md setObject: tmp forKey: @"startDate"];
|
||||
dateSecs = [NSNumber numberWithInt: [tmp timeIntervalSince1970]];
|
||||
[md setObject: dateSecs forKey: @"c_startdate"];
|
||||
date = [theCycle startDate];
|
||||
secondsOffsetFromGMT = (int) [[theEventTimeZone periodForDate: date] secondsOffsetFromGMT];
|
||||
date = [date dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: -secondsOffsetFromGMT];
|
||||
[date setTimeZone: timeZone];
|
||||
[record setObject: date forKey: @"startDate"];
|
||||
dateSecs = [NSNumber numberWithInt: [date timeIntervalSince1970]];
|
||||
[record setObject: dateSecs forKey: @"c_startdate"];
|
||||
[record setObject: dateSecs forKey: @"c_recurrence_id"];
|
||||
|
||||
tmp = [_r endDate];
|
||||
[tmp setTimeZone: timeZone];
|
||||
[md setObject: tmp forKey: @"endDate"];
|
||||
dateSecs = [NSNumber numberWithInt: [tmp timeIntervalSince1970]];
|
||||
[md setObject: dateSecs forKey: @"c_enddate"];
|
||||
|
||||
tmp = [_r startDate];
|
||||
dateSecs = [NSNumber numberWithInt: [tmp timeIntervalSince1970]];
|
||||
[md setObject: dateSecs forKey: @"c_recurrence_id"];
|
||||
date = [theCycle endDate];
|
||||
secondsOffsetFromGMT = (int) [[theEventTimeZone periodForDate: date] secondsOffsetFromGMT];
|
||||
date = [date dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: -secondsOffsetFromGMT];
|
||||
[date setTimeZone: timeZone];
|
||||
[record setObject: date forKey: @"endDate"];
|
||||
dateSecs = [NSNumber numberWithInt: [date timeIntervalSince1970]];
|
||||
[record setObject: dateSecs forKey: @"c_enddate"];
|
||||
|
||||
// The first instance date is added to the dictionary so it can
|
||||
// be used by UIxCalListingActions to compute the DST offset.
|
||||
tmp = [_fir startDate];
|
||||
[md setObject: tmp forKey: @"cycleStartDate"];
|
||||
date = [theFirstCycle startDate];
|
||||
[record setObject: date forKey: @"cycleStartDate"];
|
||||
|
||||
return md;
|
||||
return record;
|
||||
}
|
||||
|
||||
- (int) _indexOfRecordMatchingDate: (NSCalendarDate *) matchDate
|
||||
|
@ -805,26 +821,39 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
|||
}
|
||||
}
|
||||
|
||||
- (void) _flattenCycleRecord: (NSDictionary *) _row
|
||||
forRange: (NGCalendarDateRange *) _r
|
||||
intoArray: (NSMutableArray *) _ma
|
||||
/**
|
||||
* Calculate and return the occurrences of the recurrent event for the given
|
||||
* period.
|
||||
* @param theRecord the event definition.
|
||||
* @param theRange the period to look in.
|
||||
* @param theRecords the array into which are copied the resulting occurrences.
|
||||
*/
|
||||
- (void) _flattenCycleRecord: (NSDictionary *) theRecord
|
||||
forRange: (NGCalendarDateRange *) theRange
|
||||
intoArray: (NSMutableArray *) theRecords
|
||||
{
|
||||
NSMutableDictionary *row, *fixedRow;
|
||||
NSMutableArray *recordArray;
|
||||
NSDictionary *cycleinfo;
|
||||
NSCalendarDate *startDate, *endDate;
|
||||
NGCalendarDateRange *fir, *rRange;
|
||||
NSArray *rules, *exRules, *exDates, *ranges;
|
||||
unsigned i, count;
|
||||
NSMutableArray *records;
|
||||
NSDictionary *cycleinfo;
|
||||
NSCalendarDate *startDate, *endDate;
|
||||
NGCalendarDateRange *firstRange, *oneRange;
|
||||
NSArray *rules, *exRules, *exDates, *ranges;
|
||||
NSArray *elements, *components;
|
||||
NSString *content;
|
||||
iCalRepeatableEntityObject *component;
|
||||
iCalDateTime *firstStartDate, *firstEndDate;
|
||||
NSCalendarDate *checkStartDate, *checkEndDate;
|
||||
iCalTimeZone *eventTimeZone;
|
||||
unsigned i, count;
|
||||
|
||||
recordArray = [NSMutableArray array];
|
||||
records = [NSMutableArray array];
|
||||
ranges = nil;
|
||||
|
||||
content = [_row objectForKey: @"c_cycleinfo"];
|
||||
content = [theRecord objectForKey: @"c_cycleinfo"];
|
||||
if (![content isNotNull])
|
||||
{
|
||||
[self errorWithFormat:@"cyclic record doesn't have cycleinfo -> %@",
|
||||
_row];
|
||||
theRecord];
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -832,45 +861,72 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
|||
if (!cycleinfo)
|
||||
{
|
||||
[self errorWithFormat:@"cyclic record doesn't have cycleinfo -> %@",
|
||||
_row];
|
||||
theRecord];
|
||||
return;
|
||||
}
|
||||
|
||||
row = [self fixupRecord: _row];
|
||||
row = [self fixupRecord: theRecord];
|
||||
[row removeObjectForKey: @"c_cycleinfo"];
|
||||
[row setObject: sharedYes forKey: @"isRecurrentEvent"];
|
||||
|
||||
startDate = [row objectForKey: @"startDate"];
|
||||
endDate = [row objectForKey: @"endDate"];
|
||||
fir = [NGCalendarDateRange calendarDateRangeWithStartDate: startDate
|
||||
endDate: endDate];
|
||||
rules = [cycleinfo objectForKey: @"rules"];
|
||||
exRules = [cycleinfo objectForKey: @"exRules"];
|
||||
exDates = [cycleinfo objectForKey: @"exDates"];
|
||||
|
||||
ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: _r
|
||||
firstInstanceCalendarDateRange: fir
|
||||
recurrenceRules: rules
|
||||
exceptionRules: exRules
|
||||
exceptionDates: exDates];
|
||||
|
||||
content = [theRecord objectForKey: @"c_content"];
|
||||
if ([content length])
|
||||
{
|
||||
elements = [iCalCalendar parseFromSource: content];
|
||||
if ([elements count])
|
||||
{
|
||||
components = [[elements objectAtIndex: 0] events];
|
||||
if ([components count])
|
||||
{
|
||||
// Retrieve the range of the first event
|
||||
component = [components objectAtIndex: 0];
|
||||
firstStartDate = (iCalDateTime*)[component uniqueChildWithTag: @"dtstart"];
|
||||
firstEndDate = (iCalDateTime*)[component uniqueChildWithTag: @"dtend"];
|
||||
eventTimeZone = [firstStartDate timeZone];
|
||||
startDate = [eventTimeZone computedDateForDate: startDate];
|
||||
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: [[[firstStartDate values] lastObject] asCalendarDate]
|
||||
endDate: [[[firstEndDate values] lastObject] asCalendarDate]];
|
||||
|
||||
// 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];
|
||||
|
||||
// Calculate the occurrences for the given range
|
||||
rules = [cycleinfo objectForKey: @"rules"];
|
||||
exRules = [cycleinfo objectForKey: @"exRules"];
|
||||
exDates = [cycleinfo objectForKey: @"exDates"];
|
||||
ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: theRange
|
||||
firstInstanceCalendarDateRange: firstRange
|
||||
recurrenceRules: rules
|
||||
exceptionRules: exRules
|
||||
exceptionDates: exDates];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count = [ranges count];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
rRange = [ranges objectAtIndex: i];
|
||||
fixedRow = [self fixupCycleRecord: row
|
||||
cycleRange: rRange
|
||||
firstInstanceCalendarDateRange: fir
|
||||
forViewRange: _r];
|
||||
oneRange = [ranges objectAtIndex: i];
|
||||
fixedRow = [self fixupCycleRecord: row
|
||||
cycleRange: oneRange
|
||||
firstInstanceCalendarDateRange: firstRange
|
||||
withEventTimeZone: eventTimeZone];
|
||||
if (fixedRow)
|
||||
[recordArray addObject: fixedRow];
|
||||
[records addObject: fixedRow];
|
||||
}
|
||||
|
||||
[self _appendCycleExceptionsFromRow: row
|
||||
firstInstanceCalendarDateRange: fir
|
||||
forRange: _r
|
||||
toArray: recordArray];
|
||||
firstInstanceCalendarDateRange: firstRange
|
||||
forRange: theRange
|
||||
toArray: records];
|
||||
|
||||
[_ma addObjectsFromArray: recordArray];
|
||||
[theRecords addObjectsFromArray: records];
|
||||
}
|
||||
|
||||
- (NSArray *) _flattenCycleRecords: (NSArray *) _records
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Copyright (C) 2007-2011 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
Copyright (C) 2007-2009 Inverse inc.
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
|
@ -80,33 +80,28 @@
|
|||
inContainer: self];
|
||||
}
|
||||
|
||||
- (iCalRepeatableEntityObject *) newOccurenceWithID: (NSString *) recID
|
||||
/**
|
||||
* Return a new exception in a the recurrent event.
|
||||
* @param theRecurrenceID the ID of the occurence.
|
||||
* @return a new occurence.
|
||||
*/
|
||||
- (iCalRepeatableEntityObject *) newOccurenceWithID: (NSString *) theRecurrenceID
|
||||
{
|
||||
iCalEvent *newOccurence, *master;
|
||||
NSCalendarDate *date, *firstDate;
|
||||
unsigned int interval, nbrDays;
|
||||
SOGoUserDefaults *ud;
|
||||
NSTimeZone *timeZone;
|
||||
int daylightOffset;
|
||||
|
||||
ud = [[SOGoUser userWithLogin: owner] userDefaults];
|
||||
timeZone = [ud timeZone];
|
||||
|
||||
newOccurence = (iCalEvent *) [super newOccurenceWithID: recID];
|
||||
newOccurence = (iCalEvent *) [super newOccurenceWithID: theRecurrenceID];
|
||||
date = [newOccurence recurrenceId];
|
||||
|
||||
master = [self component: NO secure: NO];
|
||||
firstDate = [master startDate];
|
||||
|
||||
// We are creating a new exception in a recurrent event -- compute the daylight
|
||||
// saving time with respect to the first occurrence of the recurrent event.
|
||||
daylightOffset = (int) ([timeZone secondsFromGMTForDate: firstDate]
|
||||
- [timeZone secondsFromGMTForDate: date]);
|
||||
if (daylightOffset)
|
||||
date = [date dateByAddingYears: 0 months: 0 days: 0
|
||||
hours:0 minutes: 0 seconds: daylightOffset];
|
||||
[date setTimeZone: timeZone];
|
||||
|
||||
interval = [[master endDate]
|
||||
timeIntervalSinceDate: firstDate];
|
||||
if ([newOccurence isAllDay])
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/* iCalEvent+SOGo.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007 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
|
||||
|
@ -30,6 +31,7 @@
|
|||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
|
@ -240,10 +242,22 @@
|
|||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the start and end dates from the event, from which all recurrence
|
||||
* calculations will be based on.
|
||||
* @return the range of the first occurrence.
|
||||
*/
|
||||
- (NGCalendarDateRange *) firstOccurenceRange
|
||||
{
|
||||
return [NGCalendarDateRange calendarDateRangeWithStartDate: [self startDate]
|
||||
endDate: [self endDate]];
|
||||
iCalDateTime *firstStartDate, *firstEndDate;
|
||||
NGCalendarDateRange *firstRange;
|
||||
|
||||
firstStartDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"];
|
||||
firstEndDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtend"];
|
||||
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: [[[firstStartDate values] lastObject] asCalendarDate]
|
||||
endDate: [[[firstEndDate values] lastObject] asCalendarDate]];
|
||||
|
||||
return firstRange;
|
||||
}
|
||||
|
||||
- (unsigned int) occurenceInterval
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* iCalRepeatableEntityObject+SOGo.m - this file is part of SOGo
|
||||
/*
|
||||
Copyright (C) 2008-2011 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
Copyright (C) 2008 Inverse inc.
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
|
@ -26,8 +26,11 @@
|
|||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
#import <NGCards/iCalRecurrenceCalculator.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
#import <NGExtensions/NGCalendarDateRange.h>
|
||||
|
||||
#import "iCalRepeatableEntityObject+SOGo.h"
|
||||
|
@ -104,25 +107,39 @@
|
|||
return 0;
|
||||
}
|
||||
|
||||
- (BOOL) doesOccurOnDate: (NSCalendarDate *) occurenceDate
|
||||
/**
|
||||
* Checks if a date is part of the recurring entity.
|
||||
* @param theOccurrenceDate the date to verify.
|
||||
* @return true if the occurence date is part of the recurring entity.
|
||||
*/
|
||||
- (BOOL) doesOccurOnDate: (NSCalendarDate *) theOccurenceDate
|
||||
{
|
||||
NSArray *ranges;
|
||||
NGCalendarDateRange *checkRange;
|
||||
NSCalendarDate *endDate;
|
||||
NGCalendarDateRange *checkRange, *firstRange;
|
||||
NSCalendarDate *startDate, *endDate;
|
||||
iCalDateTime *firstStartDate;
|
||||
BOOL doesOccur;
|
||||
|
||||
doesOccur = [self isRecurrent];
|
||||
if (doesOccur)
|
||||
{
|
||||
endDate = [occurenceDate addTimeInterval: [self occurenceInterval]];
|
||||
checkRange = [NGCalendarDateRange calendarDateRangeWithStartDate: occurenceDate
|
||||
endDate: endDate];
|
||||
// Retrieve the range of the first event
|
||||
firstRange = [self firstOccurenceRange];
|
||||
|
||||
// Set the range to check with respect to the event timezone (extracted from the start date)
|
||||
firstStartDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"];
|
||||
startDate = [[firstStartDate timeZone] computedDateForDate: theOccurenceDate];
|
||||
endDate = [startDate addTimeInterval: [self occurenceInterval]];
|
||||
checkRange = [NGCalendarDateRange calendarDateRangeWithStartDate: startDate
|
||||
endDate: endDate];
|
||||
|
||||
// Calculate the occurrences for the given date
|
||||
ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: checkRange
|
||||
firstInstanceCalendarDateRange: [self firstOccurenceRange]
|
||||
recurrenceRules: [self recurrenceRules]
|
||||
exceptionRules: [self exceptionRules]
|
||||
exceptionDates: [self exceptionDates]];
|
||||
doesOccur = [ranges dateRangeArrayContainsDate: occurenceDate];
|
||||
firstInstanceCalendarDateRange: firstRange
|
||||
recurrenceRules: [self recurrenceRules]
|
||||
exceptionRules: [self exceptionRules]
|
||||
exceptionDates: [self exceptionDates]];
|
||||
doesOccur = [ranges dateRangeArrayContainsDate: startDate];
|
||||
}
|
||||
|
||||
return doesOccur;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/* UIxCalListingActions.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2006-2010 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
|
||||
|
@ -34,6 +35,8 @@
|
|||
#import <NGObjWeb/WOResponse.h>
|
||||
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
|
||||
#import <NGExtensions/NGCalendarDateRange.h>
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
|
@ -246,8 +249,12 @@ static NSArray *tasksFields = nil;
|
|||
forKey: @"c_title"];
|
||||
}
|
||||
|
||||
/* TODO: shouldn't this be handled when creating the quick records ? */
|
||||
- (void) _fixDates: (NSMutableDictionary *) aRecord
|
||||
/*
|
||||
* Adjust the event start and end dates when there's a time change
|
||||
* in the period covering the view for the user's timezone.
|
||||
* @param theRecord the attributes of the event.
|
||||
*/
|
||||
- (void) _fixDates: (NSMutableDictionary *) theRecord
|
||||
{
|
||||
NSCalendarDate *aDate, *aStartDate;
|
||||
NSNumber *aDateValue;
|
||||
|
@ -272,41 +279,25 @@ static NSArray *tasksFields = nil;
|
|||
http://www.sogo.nu/bugs/view.php?id=678
|
||||
...
|
||||
*/
|
||||
if (dayBasedView || [[aRecord objectForKey: @"c_isallday"] boolValue])
|
||||
|
||||
if (dayBasedView || [[theRecord objectForKey: @"c_isallday"] boolValue])
|
||||
{
|
||||
for (count = 0; count < 2; count++)
|
||||
{
|
||||
aDateField = fields[count * 2];
|
||||
aDate = [aRecord objectForKey: aDateField];
|
||||
daylightOffset = (int) ([userTimeZone secondsFromGMTForDate: aDate]
|
||||
- [userTimeZone secondsFromGMTForDate: startDate]);
|
||||
aDate = [theRecord objectForKey: aDateField];
|
||||
daylightOffset = (int) ([userTimeZone secondsFromGMTForDate: aDate]
|
||||
- [userTimeZone secondsFromGMTForDate: startDate]);
|
||||
if (daylightOffset)
|
||||
{
|
||||
aDate = [aDate dateByAddingYears: 0 months: 0 days: 0 hours: 0
|
||||
minutes: 0 seconds: daylightOffset];
|
||||
[aRecord setObject: aDate forKey: aDateField];
|
||||
[theRecord setObject: aDate forKey: aDateField];
|
||||
aDateValue = [NSNumber numberWithInt: [aDate timeIntervalSince1970]];
|
||||
[aRecord setObject: aDateValue forKey: fields[count * 2 + 1]];
|
||||
[theRecord setObject: aDateValue forKey: fields[count * 2 + 1]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aDateValue = [aRecord objectForKey: @"c_recurrence_id"];
|
||||
aDate = [aRecord objectForKey: @"cycleStartDate"];
|
||||
if (aDateValue && aDate)
|
||||
{
|
||||
aStartDate = [aRecord objectForKey: @"startDate"];
|
||||
if ([userTimeZone isDaylightSavingTimeForDate: aStartDate] !=
|
||||
[userTimeZone isDaylightSavingTimeForDate: aDate])
|
||||
{
|
||||
// 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)[userTimeZone secondsFromGMTForDate: aStartDate]
|
||||
- (signed int)[userTimeZone secondsFromGMTForDate: aDate];
|
||||
aDateValue = [NSNumber numberWithInt: [aDateValue intValue] + daylightOffset];
|
||||
[aRecord setObject: aDateValue forKey: @"c_recurrence_id"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *) _fetchFields: (NSArray *) fields
|
||||
|
@ -341,7 +332,6 @@ static NSArray *tasksFields = nil;
|
|||
component: component] objectEnumerator];
|
||||
owner = [currentFolder ownerInContext: context];
|
||||
ownerUser = [SOGoUser userWithLogin: owner];
|
||||
/* TODO: this should be handled per-folder rather than per-event. */
|
||||
isErasable = ([owner isEqualToString: userLogin]
|
||||
|| [[currentFolder aclsForUser: userLogin] containsObject: SOGoRole_ObjectEraser]);
|
||||
while ((newInfo = [currentInfos nextObject]))
|
||||
|
@ -349,10 +339,12 @@ static NSArray *tasksFields = nil;
|
|||
if ([fields containsObject: @"editable"])
|
||||
{
|
||||
if (folderIsRemote)
|
||||
// .ics subscriptions are not editable
|
||||
[newInfo setObject: [NSNumber numberWithInt: 0]
|
||||
forKey: @"editable"];
|
||||
else
|
||||
{
|
||||
// Identifies whether the active user can edit the event.
|
||||
role =
|
||||
[currentFolder roleForComponentsWithAccessClass:
|
||||
[[newInfo objectForKey: @"c_classification"] intValue]
|
||||
|
|
Loading…
Reference in New Issue