Monotone-Parent: 7e4ce901b4c13b7bc91a9cf02ff8ff0946502aaf

Monotone-Revision: e70b402803fd5be6062e9c2357b0a52a293a3440

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2008-03-26T20:30:53
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Wolfgang Sourdeau 2008-03-26 20:30:53 +00:00
parent f8a8a0c6dc
commit de1bd56f2c
8 changed files with 204 additions and 162 deletions

7
NEWS
View File

@ -5,9 +5,12 @@
- pressing enter in the contact edition dialog will perform the creation/update operation
- implemented more of the CalDAV specification for compatibility with Lightning 0.8
- added Italian translation, thanks to Marco Lertora
- improved restoration of drag hanldes state
- improved restoration of drag handles state
- improved contextual menu handling of Address Book module
- fixed various bugs with Safari 3.1
- fixed various bugs occuring with Safari 3.1
- monthly events would not be returned properly
- bi-weekly events would appear every week instead
- weekly events with specified days of week would not appear on the correct days
0.9.0-20080208 (1.0 rc5)
------------------------

View File

@ -1,3 +1,13 @@
2008-03-26 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* iCalRecurrenceRule.m ([iCalRecurrenceRule -byMonthDay]): check
whether the "bymonthday" value is empty and returns an array only if
not, otherwise returns nil.
* iCalRecurrenceCalculator.m ([iCalRecurrenceCalculator
+recurrenceRangesWithinCalendarDateRange:_rfirstInstanceCalendarDateRange:_firrecurrenceRules:_rRulesexceptionRules:_exRulesexceptionDates:_exDates]):
split method in many submethods for clarity.
2008-03-10 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* iCalTimeZonePeriod.m ([iCalTimeZonePeriod

View File

@ -23,6 +23,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import "NSString+NGCards.h"
#import "NGCardsSaxHandler.h"
#import "CardGroup.h"

View File

@ -43,18 +43,21 @@
typedef BOOL NGMonthSet[12];
typedef BOOL NGMonthDaySet[32]; // 0 is unused
static void NGMonthDaySet_clear(NGMonthDaySet *daySet) {
register unsigned i;
for (i = 1; i <= 31; i++)
(*daySet)[i] = NO;
}
static void NGMonthDaySet_copyOrUnion(NGMonthDaySet *base, NGMonthDaySet *new,
BOOL doCopy)
static void
NGMonthDaySet_clear(NGMonthDaySet *daySet)
{
register unsigned i;
for (i = 0; i <= 31; i++)
(*daySet)[i] = NO;
}
static void
NGMonthDaySet_copyOrUnion(NGMonthDaySet *base, NGMonthDaySet *new,
BOOL doCopy)
{
register unsigned i;
if (doCopy)
memcpy(base, new, sizeof(NGMonthDaySet));
else {
@ -265,7 +268,7 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
/* check whether the range to be processed is beyond the 'until' date */
if (until != nil) {
if (until) {
if ([until compare:rStart] == NSOrderedAscending) /* until before start */
return nil;
if ([until compare:rEnd] == NSOrderedDescending) /* end before until */
@ -275,7 +278,7 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
/* precalculate month days (same for all instances) */
if (byMonthDay != nil) {
if (byMonthDay) {
#if HEAVY_DEBUG
NSLog(@"byMonthDay: %@", byMonthDay);
#endif
@ -343,7 +346,7 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
didByFill = NO;
if (byMonthDay != nil) { /* list of days in the month */
if (byMonthDay) { /* list of days in the month */
NGMonthDaySet_copyOrUnion(&monthDays, &byMonthDaySet, !didByFill);
didByFill = YES;
}

View File

@ -48,19 +48,22 @@
@implementation iCalRecurrenceCalculator
static Class NSCalendarDateClass = Nil;
static Class NSStringClass = Nil;
static Class iCalRecurrenceRuleClass = Nil;
static Class dailyCalcClass = Nil;
static Class weeklyCalcClass = Nil;
static Class monthlyCalcClass = Nil;
static Class yearlyCalcClass = Nil;
+ (void)initialize {
+ (void) initialize
{
static BOOL didInit = NO;
if (didInit) return;
didInit = YES;
NSCalendarDateClass = [NSCalendarDate class];
NSStringClass = [NSString class];
iCalRecurrenceRuleClass = [iCalRecurrenceRule class];
dailyCalcClass = NSClassFromString(@"iCalDailyRecurrenceCalculator");
@ -107,98 +110,122 @@ static Class yearlyCalcClass = Nil;
/* complex calculation convenience */
+ (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r
firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir
recurrenceRules:(NSArray *)_rRules
exceptionRules:(NSArray *)_exRules
exceptionDates:(NSArray *)_exDates
+ (void) _fillRanges: (NSMutableArray *) ranges
fromRules: (NSArray *) rrules
withinRange: (NGCalendarDateRange *) limits
startingWithDate: (NGCalendarDateRange *) first
{
id rule;
NSEnumerator *rules;
iCalRecurrenceRule *currentRule;
iCalRecurrenceCalculator *calc;
NSMutableArray *ranges;
NSMutableArray *exDates;
unsigned i, count, rCount;
ranges = [NSMutableArray arrayWithCapacity:64];
for (i = 0, count = [_rRules count]; i < count; i++) {
NSArray *rs;
rule = [_rRules objectAtIndex:i];
if (![rule isKindOfClass:iCalRecurrenceRuleClass])
rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:rule];
calc = [self recurrenceCalculatorForRecurrenceRule:rule
withFirstInstanceCalendarDateRange:_fir];
rules = [rrules objectEnumerator];
while ((currentRule = [rules nextObject]))
{
if ([currentRule isKindOfClass: NSStringClass])
currentRule =
[iCalRecurrenceRule
recurrenceRuleWithICalRepresentation: (NSString *) currentRule];
rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
[ranges addObjectsFromArray:rs];
}
if ([ranges count] == 0)
return nil;
/* test if any exceptions do match */
for (i = 0, count = [_exRules count]; i < count; i++) {
NSArray *rs;
rule = [_exRules objectAtIndex:i];
if (![rule isKindOfClass:iCalRecurrenceRuleClass])
rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:rule];
calc = [self recurrenceCalculatorForRecurrenceRule:rule
withFirstInstanceCalendarDateRange:_fir];
rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
[ranges removeObjectsInArray:rs];
}
if (![ranges isNotEmpty])
return nil;
/* exception dates */
if ((count = [_exDates count]) == 0)
return ranges;
/* sort out exDates not within range */
exDates = [NSMutableArray arrayWithCapacity:count];
for (i = 0; i < count; i++) {
id exDate;
exDate = [_exDates objectAtIndex:i];
if (![exDate isKindOfClass:NSCalendarDateClass])
exDate = [NSCalendarDate calendarDateWithICalRepresentation:exDate];
if ([_r containsDate:exDate])
[exDates addObject:exDate];
}
/* remove matching exDates from ranges */
if ((count = [exDates count]) == 0)
return ranges;
for (i = 0, rCount = [ranges count]; i < count; i++) {
NSCalendarDate *exDate;
NGCalendarDateRange *r;
unsigned k;
exDate = [exDates objectAtIndex:i];
for (k = 0; k < rCount; k++) {
unsigned rIdx;
rIdx = (rCount - k) - 1;
r = [ranges objectAtIndex:rIdx];
if ([r containsDate:exDate]) {
[ranges removeObjectAtIndex:rIdx];
rCount--;
break; /* this is safe because we know that ranges don't overlap */
}
calc = [self recurrenceCalculatorForRecurrenceRule: currentRule
withFirstInstanceCalendarDateRange: first];
[ranges addObjectsFromArray:
[calc recurrenceRangesWithinCalendarDateRange: limits]];
}
}
}
+ (void) _removeExceptionsFromRanges: (NSMutableArray *) ranges
withRules: (NSArray *) exrules
withinRange: (NGCalendarDateRange *) limits
startingWithDate: (NGCalendarDateRange *) first
{
NSEnumerator *rules;
iCalRecurrenceRule *currentRule;
iCalRecurrenceCalculator *calc;
rules = [exrules objectEnumerator];
while ((currentRule = [rules nextObject]))
{
if ([currentRule isKindOfClass: NSStringClass])
currentRule =
[iCalRecurrenceRule
recurrenceRuleWithICalRepresentation: (NSString *) currentRule];
calc = [self recurrenceCalculatorForRecurrenceRule: currentRule
withFirstInstanceCalendarDateRange: first];
[ranges removeObjectsInArray:
[calc recurrenceRangesWithinCalendarDateRange: limits]];
}
}
+ (NSArray *) _dates: (NSArray *) dateList
withinRange: (NGCalendarDateRange *) limits
{
NSMutableArray *newDates;
NSEnumerator *dates;
NSCalendarDate *currentDate;
newDates = [NSMutableArray array];
dates = [dateList objectEnumerator];
while ((currentDate = [dates nextObject]))
{
if ([currentDate isKindOfClass: NSStringClass])
currentDate
= [NSCalendarDate
calendarDateWithICalRepresentation: (NSString *) currentDate];
if ([limits containsDate: currentDate])
[newDates addObject: currentDate];
}
return newDates;
}
+ (void) _removeExceptionDatesFromRanges: (NSMutableArray *) ranges
withDates: (NSArray *) exdates
withinRange: (NGCalendarDateRange *) limits
startingWithDate: (NGCalendarDateRange *) first
{
NSEnumerator *dates;
NSCalendarDate *currentDate;
NGCalendarDateRange *currentRange;
int count, maxRanges;
maxRanges = [ranges count];
dates = [[self _dates: exdates withinRange: limits] objectEnumerator];
while ((currentDate = [dates nextObject]))
for (count = (maxRanges - 1); count > -1; count++)
{
currentRange = [ranges objectAtIndex: count];
if ([currentRange containsDate: currentDate])
{
[ranges removeObjectAtIndex: count];
maxRanges--;
}
}
}
+ (NSArray *)
recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
firstInstanceCalendarDateRange: (NGCalendarDateRange *) _fir
recurrenceRules: (NSArray *) _rRules
exceptionRules: (NSArray *) _exRules
exceptionDates: (NSArray *) _exDates
{
NSMutableArray *ranges;
ranges = [NSMutableArray arrayWithCapacity: 64];
if ([_rRules count] > 0)
{
[self _fillRanges: ranges fromRules: _rRules
withinRange: _r startingWithDate: _fir];
[self _removeExceptionsFromRanges: ranges withRules: _exRules
withinRange: _r startingWithDate: _fir];
[self _removeExceptionDatesFromRanges: ranges withDates: _exDates
withinRange: _r startingWithDate: _fir];
}
return ranges;
}
@ -265,23 +292,12 @@ static Class yearlyCalcClass = Nil;
- (iCalWeekDay) weekDayForJulianNumber: (long)_jn
{
unsigned int day;
iCalWeekDay weekDay;
iCalWeekDay weekDays[] = {iCalWeekDaySunday, iCalWeekDayMonday,
iCalWeekDayTuesday, iCalWeekDayWednesday,
iCalWeekDayThursday, iCalWeekDayFriday,
iCalWeekDaySaturday};
if (day < 7)
weekDay = weekDays[day];
else
{
[self errorWithFormat:
@"got unexpected weekday: %d (falling back on sunday)", day];
weekDay = iCalWeekDaySunday;
}
return weekDay;
return weekDays[[self offsetFromSundayForJulianNumber: _jn]];
}
/* calculation */

View File

@ -325,7 +325,16 @@
- (NSArray *) byMonthDay
{
return [[self namedValue: @"bymonthday"] componentsSeparatedByString: @","];
NSArray *byMonthDay;
NSString *byMonthDayStr;
byMonthDayStr = [self namedValue: @"bymonthday"];
if ([byMonthDayStr length])
byMonthDay = [byMonthDayStr componentsSeparatedByString: @","];
else
byMonthDay = nil;
return byMonthDay;
}
- (BOOL) isInfinite
@ -363,11 +372,13 @@
foundDay = iCalWeekDayTuesday;
else if (chars[1] == 'H')
foundDay = iCalWeekDayThursday;
break;
case 'S':
if (chars[1] == 'A')
foundDay = iCalWeekDaySaturday;
else if (chars[1] == 'U')
foundDay = iCalWeekDaySunday;
break;
}
}

View File

@ -32,13 +32,13 @@
@interface iCalRecurrenceCalculator (PrivateAPI)
- (NSCalendarDate *)lastInstanceStartDate;
- (NSCalendarDate *) lastInstanceStartDate;
- (unsigned)offsetFromSundayForJulianNumber:(long)_jn;
- (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
- (unsigned)offsetFromSundayForCurrentWeekStart;
- (unsigned) offsetFromSundayForJulianNumber:(long)_jn;
- (unsigned) offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
- (unsigned) offsetFromSundayForCurrentWeekStart;
- (iCalWeekDay)weekDayForJulianNumber:(long)_jn;
- (iCalWeekDay) weekDayForJulianNumber:(long)_jn;
@end
@ -48,7 +48,9 @@
*/
@implementation iCalWeeklyRecurrenceCalculator
- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
- (NSArray *)
recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
{
NSMutableArray *ranges;
NSCalendarDate *firStart;
long i, jnFirst, jnStart, jnEnd, startEndCount;

View File

@ -907,10 +907,10 @@ static NSNumber *sharedYes = nil;
forRange: (NGCalendarDateRange *) _r
intoArray: (NSMutableArray *) _ma
{
NSMutableDictionary *row;
NSMutableDictionary *row, *fixedRow;
NSDictionary *cycleinfo;
NSCalendarDate *startDate, *endDate;
NGCalendarDateRange *fir;
NGCalendarDateRange *fir, *rRange;
NSArray *rules, *exRules, *exDates, *ranges;
unsigned i, count;
NSString *content;
@ -918,47 +918,44 @@ static NSNumber *sharedYes = nil;
content = [_row objectForKey: @"c_cycleinfo"];
if (![content isNotNull])
{
[self errorWithFormat:@"cyclic record doesn't have cycleinfo -> %@", _row];
[self errorWithFormat:@"cyclic record doesn't have cycleinfo -> %@",
_row];
return;
}
cycleinfo = [content propertyList];
if (!cycleinfo)
{
[self errorWithFormat:@"cyclic record doesn't have cycleinfo -> %@", _row];
[self errorWithFormat:@"cyclic record doesn't have cycleinfo -> %@",
_row];
return;
}
row = [self fixupRecord:_row fetchRange: _r];
[row removeObjectForKey: @"c_cycleinfo"];
[row setObject: sharedYes forKey:@"isRecurrentEvent"];
[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"];
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];
ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: _r
firstInstanceCalendarDateRange: fir
recurrenceRules: rules
exceptionRules: exRules
exceptionDates: exDates];
count = [ranges count];
for (i = 0; i < count; i++) {
NGCalendarDateRange *rRange;
id fixedRow;
rRange = [ranges objectAtIndex:i];
fixedRow = [self fixupCycleRecord:row cycleRange:rRange];
if (fixedRow != nil)
{
for (i = 0; i < count; i++)
{
rRange = [ranges objectAtIndex:i];
fixedRow = [self fixupCycleRecord: row cycleRange: rRange];
if (fixedRow)
[_ma addObject:fixedRow];
}
}
}
}
- (NSArray *) fixupCyclicRecords: (NSArray *) _records
@ -966,19 +963,18 @@ static NSNumber *sharedYes = nil;
{
// TODO: is the result supposed to be sorted by date?
NSMutableArray *ma;
unsigned i, count;
if (_records == nil) return nil;
if ((count = [_records count]) == 0)
return _records;
ma = [NSMutableArray arrayWithCapacity:count];
for (i = 0; i < count; i++) {
id row; // TODO: what is the type of the record?
row = [_records objectAtIndex:i];
[self _flattenCycleRecord:row forRange:_r intoArray:ma];
}
NSDictionary *row;
unsigned int i, count;
count = [_records count];
ma = [NSMutableArray arrayWithCapacity: count];
if (count > 0)
for (i = 0; i < count; i++)
{
row = [_records objectAtIndex: i];
[self _flattenCycleRecord: row forRange: _r intoArray: ma];
}
return ma;
}