Monotone-Parent: 4e8caa9222644e6820515bbf312f74dbd372c2fc
Monotone-Revision: 25c172f93ef4ab6ada0aeb6ff4267e98aef8b719 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2008-12-10T18:57:55 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
b8b4c6b5d3
commit
ff33d95a42
|
@ -128,25 +128,22 @@
|
||||||
return ranges;
|
return ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSCalendarDate *) lastInstanceStartDate
|
- (NSCalendarDate *) lastInstanceStartDate
|
||||||
{
|
{
|
||||||
|
NSCalendarDate *firStart, *lastInstanceStartDate;
|
||||||
|
|
||||||
if ([rrule repeatCount] > 0)
|
if ([rrule repeatCount] > 0)
|
||||||
{
|
{
|
||||||
long jnFirst, jnRuleLast;
|
|
||||||
NSCalendarDate *firStart, *until;
|
|
||||||
|
|
||||||
firStart = [firstRange startDate];
|
firStart = [firstRange startDate];
|
||||||
jnFirst = [firStart julianNumber];
|
|
||||||
jnRuleLast = ([rrule repeatInterval] *
|
lastInstanceStartDate = [firStart dateByAddingYears: 0 months: 0
|
||||||
[rrule repeatCount]) +
|
days: ([rrule repeatInterval]
|
||||||
jnFirst;
|
* [rrule repeatCount])];
|
||||||
until = [NSCalendarDate dateForJulianNumber:jnRuleLast];
|
|
||||||
until = [until hour: [firStart hourOfDay]
|
|
||||||
minute: [firStart minuteOfHour]
|
|
||||||
second: [firStart secondOfMinute]];
|
|
||||||
return until;
|
|
||||||
}
|
}
|
||||||
return [super lastInstanceStartDate];
|
else
|
||||||
|
lastInstanceStartDate = [super lastInstanceStartDate];
|
||||||
|
|
||||||
|
return lastInstanceStartDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end /* iCalDailyRecurrenceCalculator */
|
@end /* iCalDailyRecurrenceCalculator */
|
||||||
|
|
|
@ -32,8 +32,10 @@
|
||||||
#import "NSCalendarDate+ICal.h"
|
#import "NSCalendarDate+ICal.h"
|
||||||
#import <string.h>
|
#import <string.h>
|
||||||
|
|
||||||
@interface iCalRecurrenceCalculator(PrivateAPI)
|
@interface iCalRecurrenceCalculator (PrivateAPI)
|
||||||
- (NSCalendarDate *)lastInstanceStartDate;
|
|
||||||
|
- (NSCalendarDate *) lastInstanceStartDate;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
// #define HEAVY_DEBUG 1
|
// #define HEAVY_DEBUG 1
|
||||||
|
@ -44,7 +46,8 @@ typedef BOOL NGMonthSet[12];
|
||||||
typedef BOOL NGMonthDaySet[32]; // 0 is unused
|
typedef BOOL NGMonthDaySet[32]; // 0 is unused
|
||||||
|
|
||||||
static void
|
static void
|
||||||
NGMonthDaySet_clear(NGMonthDaySet *daySet)
|
NGMonthDaySet_clear (NGMonthDaySet *daySet)
|
||||||
|
|
||||||
{
|
{
|
||||||
register unsigned i;
|
register unsigned i;
|
||||||
|
|
||||||
|
@ -53,70 +56,81 @@ NGMonthDaySet_clear(NGMonthDaySet *daySet)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
NGMonthDaySet_copyOrUnion(NGMonthDaySet *base, NGMonthDaySet *new,
|
NGMonthDaySet_copyOrUnion (NGMonthDaySet *base, NGMonthDaySet *new,
|
||||||
BOOL doCopy)
|
BOOL doCopy)
|
||||||
|
|
||||||
{
|
{
|
||||||
register unsigned i;
|
register unsigned i;
|
||||||
|
|
||||||
if (doCopy)
|
if (doCopy)
|
||||||
memcpy(base, new, sizeof(NGMonthDaySet));
|
memcpy (base, new, sizeof (NGMonthDaySet));
|
||||||
else {
|
else
|
||||||
for (i = 1; i <= 31; i++) {
|
{
|
||||||
if (!(*new)[i])
|
for (i = 1; i <= 31; i++)
|
||||||
(*base)[i] = NO;
|
{
|
||||||
|
if (! (*new)[i])
|
||||||
|
(*base)[i] = NO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL NGMonthDaySet_fillWithByMonthDay(NGMonthDaySet *daySet,
|
static BOOL NGMonthDaySet_fillWithByMonthDay (NGMonthDaySet *daySet,
|
||||||
NSArray *byMonthDay)
|
NSArray *byMonthDay)
|
||||||
|
|
||||||
{
|
{
|
||||||
/* list of days in the month */
|
/* list of days in the month */
|
||||||
unsigned i, count;
|
unsigned i, count;
|
||||||
BOOL ok;
|
BOOL ok;
|
||||||
|
|
||||||
NGMonthDaySet_clear(daySet);
|
NGMonthDaySet_clear (daySet);
|
||||||
|
|
||||||
for (i = 0, count = [byMonthDay count], ok = YES; i < count; i++) {
|
for (i = 0, count = [byMonthDay count], ok = YES; i < count; i++)
|
||||||
int dayInMonth; /* -31..-1 and 1..31 */
|
{
|
||||||
|
int dayInMonth; /* -31..-1 and 1..31 */
|
||||||
|
|
||||||
if ((dayInMonth = [[byMonthDay objectAtIndex:i] intValue]) == 0) {
|
if ((dayInMonth = [[byMonthDay objectAtIndex: i] intValue]) == 0)
|
||||||
ok = NO;
|
{
|
||||||
continue; /* invalid value */
|
ok = NO;
|
||||||
}
|
continue; /* invalid value */
|
||||||
if (dayInMonth > 31) {
|
}
|
||||||
ok = NO;
|
if (dayInMonth > 31)
|
||||||
continue; /* error, value to large */
|
{
|
||||||
}
|
ok = NO;
|
||||||
if (dayInMonth < -31) {
|
continue; /* error, value to large */
|
||||||
ok = NO;
|
}
|
||||||
continue; /* error, value to large */
|
if (dayInMonth < -31)
|
||||||
}
|
{
|
||||||
|
ok = NO;
|
||||||
|
continue; /* error, value to large */
|
||||||
|
}
|
||||||
|
|
||||||
/* adjust negative days */
|
/* adjust negative days */
|
||||||
|
|
||||||
if (dayInMonth < 0) {
|
if (dayInMonth < 0)
|
||||||
/* eg: -1 == last day in month, 30 days => 30 */
|
{
|
||||||
dayInMonth = 32 - dayInMonth /* because we count from 1 */;
|
/* eg: -1 == last day in month, 30 days => 30 */
|
||||||
}
|
dayInMonth = 32 - dayInMonth /* because we count from 1 */;
|
||||||
|
}
|
||||||
|
|
||||||
(*daySet)[dayInMonth] = YES;
|
(*daySet)[dayInMonth] = YES;
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned iCalDoWForNSDoW(int dow) {
|
static inline unsigned iCalDoWForNSDoW (int dow)
|
||||||
switch (dow) {
|
{
|
||||||
case 0: return iCalWeekDaySunday;
|
switch (dow)
|
||||||
case 1: return iCalWeekDayMonday;
|
{
|
||||||
case 2: return iCalWeekDayTuesday;
|
case 0: return iCalWeekDaySunday;
|
||||||
case 3: return iCalWeekDayWednesday;
|
case 1: return iCalWeekDayMonday;
|
||||||
case 4: return iCalWeekDayThursday;
|
case 2: return iCalWeekDayTuesday;
|
||||||
case 5: return iCalWeekDayFriday;
|
case 3: return iCalWeekDayWednesday;
|
||||||
case 6: return iCalWeekDaySaturday;
|
case 4: return iCalWeekDayThursday;
|
||||||
case 7: return iCalWeekDaySunday;
|
case 5: return iCalWeekDayFriday;
|
||||||
default: return 0;
|
case 6: return iCalWeekDaySaturday;
|
||||||
}
|
case 7: return iCalWeekDaySunday;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HEAVY_DEBUG
|
#if HEAVY_DEBUG
|
||||||
|
@ -125,11 +139,12 @@ static NSString *dowEN[8] = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
|
static void NGMonthDaySet_fillWithByDayX (NGMonthDaySet *daySet,
|
||||||
unsigned dayMask,
|
unsigned dayMask,
|
||||||
unsigned firstDoWInMonth,
|
unsigned firstDoWInMonth,
|
||||||
unsigned numberOfDaysInMonth,
|
unsigned numberOfDaysInMonth,
|
||||||
int occurrence1)
|
int occurrence1)
|
||||||
|
|
||||||
{
|
{
|
||||||
// TODO: this is called 'X' because the API doesn't allow for full iCalendar
|
// TODO: this is called 'X' because the API doesn't allow for full iCalendar
|
||||||
// functionality. The daymask must be a list of occurence+dow
|
// functionality. The daymask must be a list of occurence+dow
|
||||||
|
@ -137,78 +152,86 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
|
||||||
register int dow; /* current day of the week */
|
register int dow; /* current day of the week */
|
||||||
int occurrences[7] = { 0, 0, 0, 0, 0, 0, 0 } ;
|
int occurrences[7] = { 0, 0, 0, 0, 0, 0, 0 } ;
|
||||||
|
|
||||||
NGMonthDaySet_clear(daySet);
|
NGMonthDaySet_clear (daySet);
|
||||||
|
|
||||||
if (occurrence1 >= 0) {
|
if (occurrence1 >= 0)
|
||||||
for (dayInMonth = 1, dow = firstDoWInMonth; dayInMonth<=31; dayInMonth++) {
|
{
|
||||||
// TODO: complete me
|
for (dayInMonth = 1, dow = firstDoWInMonth; dayInMonth<=31; dayInMonth++)
|
||||||
|
{
|
||||||
|
// TODO: complete me
|
||||||
|
|
||||||
if (dayMask & iCalDoWForNSDoW(dow)) {
|
if (dayMask & iCalDoWForNSDoW (dow))
|
||||||
if (occurrence1 == 0)
|
{
|
||||||
(*daySet)[dayInMonth] = YES;
|
if (occurrence1 == 0)
|
||||||
else { /* occurrence1 > 0 */
|
(*daySet)[dayInMonth] = YES;
|
||||||
occurrences[dow] = occurrences[dow] + 1;
|
else { /* occurrence1 > 0 */
|
||||||
|
occurrences[dow] = occurrences[dow] + 1;
|
||||||
|
|
||||||
if (occurrences[dow] == occurrence1)
|
if (occurrences[dow] == occurrence1)
|
||||||
(*daySet)[dayInMonth] = YES;
|
(*daySet)[dayInMonth] = YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dow = (dow == 6 /* Sat */) ? 0 /* Sun */ : (dow + 1);
|
dow = (dow == 6 /* Sat */) ? 0 /* Sun */ : (dow + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
int lastDoWInMonthSet;
|
{
|
||||||
|
int lastDoWInMonthSet;
|
||||||
/* get the last dow in the set (not necessarily the month!) */
|
|
||||||
for (dayInMonth = 1, dow = firstDoWInMonth;
|
/* get the last dow in the set (not necessarily the month!) */
|
||||||
dayInMonth < numberOfDaysInMonth;dayInMonth++)
|
for (dayInMonth = 1, dow = firstDoWInMonth;
|
||||||
dow = (dow == 6 /* Sat */) ? 0 /* Sun */ : (dow + 1);
|
dayInMonth < numberOfDaysInMonth;dayInMonth++)
|
||||||
lastDoWInMonthSet = dow;
|
dow = (dow == 6 /* Sat */) ? 0 /* Sun */ : (dow + 1);
|
||||||
|
lastDoWInMonthSet = dow;
|
||||||
#if HEAVY_DEBUG
|
|
||||||
NSLog(@"LAST DOW IN SET: %i / %@",
|
#if HEAVY_DEBUG
|
||||||
lastDoWInMonthSet, dowEN[lastDoWInMonthSet]);
|
NSLog (@"LAST DOW IN SET: %i / %@",
|
||||||
#endif
|
lastDoWInMonthSet, dowEN[lastDoWInMonthSet]);
|
||||||
/* start at the end of the set */
|
#endif
|
||||||
for (dayInMonth = numberOfDaysInMonth, dow = lastDoWInMonthSet;
|
/* start at the end of the set */
|
||||||
dayInMonth >= 1; dayInMonth--) {
|
for (dayInMonth = numberOfDaysInMonth, dow = lastDoWInMonthSet;
|
||||||
// TODO: complete me
|
dayInMonth >= 1; dayInMonth--)
|
||||||
|
{
|
||||||
#if HEAVY_DEBUG
|
// TODO: complete me
|
||||||
NSLog(@" CHECK day-of-month %02i, "
|
|
||||||
@" dow=%i/%@ (first=%i/%@, last=%i/%@)",
|
#if HEAVY_DEBUG
|
||||||
dayInMonth,
|
NSLog (@" CHECK day-of-month %02i, "
|
||||||
dow, dowEN[dow],
|
@" dow=%i/%@ (first=%i/%@, last=%i/%@)",
|
||||||
firstDoWInMonth, dowEN[firstDoWInMonth],
|
dayInMonth,
|
||||||
lastDoWInMonthSet, dowEN[lastDoWInMonthSet]
|
dow, dowEN[dow],
|
||||||
);
|
firstDoWInMonth, dowEN[firstDoWInMonth],
|
||||||
#endif
|
lastDoWInMonthSet, dowEN[lastDoWInMonthSet]
|
||||||
|
);
|
||||||
if (dayMask & iCalDoWForNSDoW(dow)) {
|
#endif
|
||||||
occurrences[dow] = occurrences[dow] + 1;
|
|
||||||
#if HEAVY_DEBUG
|
if (dayMask & iCalDoWForNSDoW (dow))
|
||||||
NSLog(@" MATCH %i/%@ count: %i occurences=%i",
|
{
|
||||||
dow, dowEN[dow], occurrences[dow], occurrence1);
|
occurrences[dow] = occurrences[dow] + 1;
|
||||||
#endif
|
#if HEAVY_DEBUG
|
||||||
|
NSLog (@" MATCH %i/%@ count: %i occurences=%i",
|
||||||
if (occurrences[dow] == -occurrence1) {
|
dow, dowEN[dow], occurrences[dow], occurrence1);
|
||||||
#if HEAVY_DEBUG
|
#endif
|
||||||
NSLog(@" COUNT MATCH");
|
|
||||||
#endif
|
if (occurrences[dow] == -occurrence1)
|
||||||
(*daySet)[dayInMonth] = YES;
|
{
|
||||||
|
#if HEAVY_DEBUG
|
||||||
|
NSLog (@" COUNT MATCH");
|
||||||
|
#endif
|
||||||
|
(*daySet)[dayInMonth] = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dow = (dow == 0 /* Sun */) ? 6 /* Sat */ : (dow - 1);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
dow = (dow == 0 /* Sun */) ? 6 /* Sat */ : (dow - 1);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)_addInstanceWithStartDate:(NSCalendarDate *)_startDate
|
- (BOOL) _addInstanceWithStartDate: (NSCalendarDate *)_startDate
|
||||||
limitDate:(NSCalendarDate *)_until
|
limitDate: (NSCalendarDate *)_until
|
||||||
limitRange:(NGCalendarDateRange *)_r
|
limitRange: (NGCalendarDateRange *)_r
|
||||||
toArray:(NSMutableArray *)_ranges
|
toArray: (NSMutableArray *)_ranges
|
||||||
|
|
||||||
{
|
{
|
||||||
NGCalendarDateRange *r;
|
NGCalendarDateRange *r;
|
||||||
NSCalendarDate *end;
|
NSCalendarDate *end;
|
||||||
|
@ -218,29 +241,32 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
|
||||||
// TODO: I think we should check in here whether we succeeded the
|
// TODO: I think we should check in here whether we succeeded the
|
||||||
// repeatCount. Currently we precalculate that info in the
|
// repeatCount. Currently we precalculate that info in the
|
||||||
// -lastInstanceStartDate method.
|
// -lastInstanceStartDate method.
|
||||||
if (_until != nil) {
|
if (_until != nil)
|
||||||
/* Note: the 'until' in the rrule is inclusive as per spec */
|
{
|
||||||
if ([_until compare:_startDate] == NSOrderedAscending)
|
/* Note: the 'until' in the rrule is inclusive as per spec */
|
||||||
/* start after until */
|
if ([_until compare: _startDate] == NSOrderedAscending)
|
||||||
return NO; /* Note: we assume that the algorithm is sequential */
|
/* start after until */
|
||||||
}
|
return NO; /* Note: we assume that the algorithm is sequential */
|
||||||
|
}
|
||||||
|
|
||||||
/* create end date */
|
/* create end date */
|
||||||
|
|
||||||
end = [_startDate addTimeInterval:[self->firstRange duration]];
|
end = [_startDate addTimeInterval: [firstRange duration]];
|
||||||
[end setTimeZone:[_startDate timeZone]];
|
[end setTimeZone: [_startDate timeZone]];
|
||||||
|
|
||||||
/* create range and check whether its in the requested range */
|
/* create range and check whether its in the requested range */
|
||||||
|
|
||||||
r = [[NGCalendarDateRange alloc] initWithStartDate:_startDate endDate:end];
|
r = [[NGCalendarDateRange alloc] initWithStartDate: _startDate endDate: end];
|
||||||
if ([_r containsDateRange:r])
|
if ([_r containsDateRange: r])
|
||||||
[_ranges addObject:r];
|
[_ranges addObject: r];
|
||||||
[r release]; r = nil;
|
[r release]; r = nil;
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{
|
- (NSArray *)
|
||||||
|
recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
|
||||||
|
{
|
||||||
/* main entry */
|
/* main entry */
|
||||||
// TODO: check whether this is OK for multiday-events!
|
// TODO: check whether this is OK for multiday-events!
|
||||||
NSMutableArray *ranges;
|
NSMutableArray *ranges;
|
||||||
|
@ -257,214 +283,225 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
|
||||||
NSArray *byMonthDay; // array of ints (-31..-1 and 1..31)
|
NSArray *byMonthDay; // array of ints (-31..-1 and 1..31)
|
||||||
NGMonthDaySet byMonthDaySet;
|
NGMonthDaySet byMonthDaySet;
|
||||||
|
|
||||||
eventStartDate = [self->firstRange startDate];
|
eventStartDate = [firstRange startDate];
|
||||||
eventDayOfMonth = [eventStartDate dayOfMonth];
|
eventDayOfMonth = [eventStartDate dayOfMonth];
|
||||||
timeZone = [eventStartDate timeZone];
|
timeZone = [eventStartDate timeZone];
|
||||||
rStart = [_r startDate];
|
rStart = [_r startDate];
|
||||||
rEnd = [_r endDate];
|
rEnd = [_r endDate];
|
||||||
interval = [self->rrule repeatInterval];
|
interval = [rrule repeatInterval];
|
||||||
until = [self lastInstanceStartDate]; // TODO: maybe replace
|
until = [self lastInstanceStartDate]; // TODO: maybe replace
|
||||||
byMonthDay = [self->rrule byMonthDay];
|
byMonthDay = [rrule byMonthDay];
|
||||||
|
|
||||||
|
|
||||||
/* check whether the range to be processed is beyond the 'until' date */
|
/* check whether the range to be processed is beyond the 'until' date */
|
||||||
if (until) {
|
if (until)
|
||||||
if ([until compare:rStart] == NSOrderedAscending) /* until before start */
|
{
|
||||||
return nil;
|
if ([until compare: rStart] == NSOrderedAscending) /* until before start */
|
||||||
if ([until compare:rEnd] == NSOrderedDescending) /* end before until */
|
return nil;
|
||||||
rEnd = until; // TODO: why is that? end is _before_ until?
|
if ([until compare: rEnd] == NSOrderedDescending) /* end before until */
|
||||||
}
|
rEnd = until; // TODO: why is that? end is _before_ until?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* precalculate month days (same for all instances) */
|
/* precalculate month days (same for all instances) */
|
||||||
|
|
||||||
if (byMonthDay) {
|
if (byMonthDay)
|
||||||
|
{
|
||||||
#if HEAVY_DEBUG
|
#if HEAVY_DEBUG
|
||||||
NSLog(@"byMonthDay: %@", byMonthDay);
|
NSLog (@"byMonthDay: %@", byMonthDay);
|
||||||
#endif
|
#endif
|
||||||
NGMonthDaySet_fillWithByMonthDay(&byMonthDaySet, byMonthDay);
|
NGMonthDaySet_fillWithByMonthDay (&byMonthDaySet, byMonthDay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: I think the 'diff' is to skip recurrence which are before the
|
// TODO: I think the 'diff' is to skip recurrence which are before the
|
||||||
// requested range. Not sure whether this is actually possible, eg
|
// requested range. Not sure whether this is actually possible, eg
|
||||||
// the repeatCount must be processed from the start.
|
// the repeatCount must be processed from the start.
|
||||||
diff = [eventStartDate monthsBetweenDate:rStart];
|
diff = [eventStartDate monthsBetweenDate: rStart];
|
||||||
if ((diff != 0) && [rStart compare:eventStartDate] == NSOrderedAscending)
|
if ((diff != 0) && [rStart compare: eventStartDate] == NSOrderedAscending)
|
||||||
diff = -diff;
|
diff = -diff;
|
||||||
|
|
||||||
numberOfMonthsInRange = [rStart monthsBetweenDate:rEnd] + 1;
|
numberOfMonthsInRange = [rStart monthsBetweenDate: rEnd] + 1;
|
||||||
ranges = [NSMutableArray arrayWithCapacity:numberOfMonthsInRange];
|
ranges = [NSMutableArray arrayWithCapacity: numberOfMonthsInRange];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Note: we do not add 'eventStartDate', this is intentional, the event date
|
Note: we do not add 'eventStartDate', this is intentional, the event date
|
||||||
itself is _not_ necessarily part of the sequence, eg with monthly
|
itself is _not_ necessarily part of the sequence, eg with monthly
|
||||||
byday recurrences.
|
byday recurrences.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (monthIdxInRange = 0; monthIdxInRange < numberOfMonthsInRange;
|
for (monthIdxInRange = 0; monthIdxInRange < numberOfMonthsInRange;
|
||||||
monthIdxInRange++) {
|
monthIdxInRange++)
|
||||||
NSCalendarDate *cursor;
|
{
|
||||||
unsigned numDaysInMonth;
|
NSCalendarDate *cursor;
|
||||||
int monthIdxInRecurrence, dom;
|
unsigned numDaysInMonth;
|
||||||
NGMonthDaySet monthDays;
|
int monthIdxInRecurrence, dom;
|
||||||
BOOL didByFill, doCont;
|
NGMonthDaySet monthDays;
|
||||||
|
BOOL didByFill, doCont;
|
||||||
|
|
||||||
monthIdxInRecurrence = diff + monthIdxInRange;
|
monthIdxInRecurrence = diff + monthIdxInRange;
|
||||||
|
|
||||||
if (monthIdxInRecurrence < 0)
|
if (monthIdxInRecurrence < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* first check whether we are in the interval */
|
/* first check whether we are in the interval */
|
||||||
|
|
||||||
if ((monthIdxInRecurrence % interval) != 0)
|
if ((monthIdxInRecurrence % interval) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Then the sequence is:
|
Then the sequence is:
|
||||||
- check whether the month is in the BYMONTH list
|
- check whether the month is in the BYMONTH list
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Note: the function below adds exactly a month, eg:
|
Note: the function below adds exactly a month, eg:
|
||||||
2007-01-30 + 1month => 2007-02-*28*!!
|
2007-01-30 + 1month => 2007-02-*28*!!
|
||||||
*/
|
*/
|
||||||
cursor = [eventStartDate dateByAddingYears:0
|
cursor = [eventStartDate dateByAddingYears: 0
|
||||||
months:(diff + monthIdxInRange)
|
months: (diff + monthIdxInRange)
|
||||||
days:0];
|
days: 0];
|
||||||
[cursor setTimeZone:timeZone];
|
[cursor setTimeZone: timeZone];
|
||||||
numDaysInMonth = [cursor numberOfDaysInMonth];
|
numDaysInMonth = [cursor numberOfDaysInMonth];
|
||||||
|
|
||||||
|
|
||||||
/* check whether we match the bymonth specification */
|
/* check whether we match the bymonth specification */
|
||||||
|
|
||||||
if (!byMonthList[[cursor monthOfYear] - 1])
|
if (!byMonthList[[cursor monthOfYear] - 1])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
/* check 'day level' byXYZ rules */
|
/* check 'day level' byXYZ rules */
|
||||||
|
|
||||||
didByFill = NO;
|
didByFill = NO;
|
||||||
|
|
||||||
if (byMonthDay) { /* list of days in the month */
|
if (byMonthDay)
|
||||||
NGMonthDaySet_copyOrUnion(&monthDays, &byMonthDaySet, !didByFill);
|
{ /* list of days in the month */
|
||||||
didByFill = YES;
|
NGMonthDaySet_copyOrUnion (&monthDays, &byMonthDaySet, !didByFill);
|
||||||
}
|
didByFill = YES;
|
||||||
|
}
|
||||||
|
|
||||||
if ([self->rrule byDayMask] != 0) { // TODO: replace the mask with an array
|
if ([rrule byDayMask] != 0)
|
||||||
NGMonthDaySet ruleset;
|
{ // TODO: replace the mask with an array
|
||||||
unsigned firstDoWInMonth;
|
NGMonthDaySet ruleset;
|
||||||
|
unsigned firstDoWInMonth;
|
||||||
|
|
||||||
firstDoWInMonth = [[cursor firstDayOfMonth] dayOfWeek];
|
firstDoWInMonth = [[cursor firstDayOfMonth] dayOfWeek];
|
||||||
|
|
||||||
NGMonthDaySet_fillWithByDayX(&ruleset,
|
NGMonthDaySet_fillWithByDayX (&ruleset,
|
||||||
[self->rrule byDayMask],
|
[rrule byDayMask],
|
||||||
firstDoWInMonth,
|
firstDoWInMonth,
|
||||||
[cursor numberOfDaysInMonth],
|
[cursor numberOfDaysInMonth],
|
||||||
[self->rrule byDayOccurence1]);
|
[rrule byDayOccurence1]);
|
||||||
NGMonthDaySet_copyOrUnion(&monthDays, &ruleset, !didByFill);
|
NGMonthDaySet_copyOrUnion (&monthDays, &ruleset, !didByFill);
|
||||||
didByFill = YES;
|
didByFill = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!didByFill) {
|
if (!didByFill)
|
||||||
/* no rules applied, take the dayOfMonth of the startDate */
|
{
|
||||||
NGMonthDaySet_clear(&monthDays);
|
/* no rules applied, take the dayOfMonth of the startDate */
|
||||||
monthDays[eventDayOfMonth] = YES;
|
NGMonthDaySet_clear (&monthDays);
|
||||||
}
|
monthDays[eventDayOfMonth] = YES;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: add processing of byhour/byminute/bysecond etc
|
// TODO: add processing of byhour/byminute/bysecond etc
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Next step is to create NSCalendarDate instances from our 'monthDays'
|
Next step is to create NSCalendarDate instances from our 'monthDays'
|
||||||
set. We walk over each day of the 'monthDays' set. If its flag isn't
|
set. We walk over each day of the 'monthDays' set. If its flag isn't
|
||||||
set, we continue.
|
set, we continue.
|
||||||
If its set, we add the date to the instance.
|
If its set, we add the date to the instance.
|
||||||
|
|
||||||
The 'cursor' is the *startdate* of the event (not necessarily a
|
The 'cursor' is the *startdate* of the event (not necessarily a
|
||||||
component of the sequence!) plus the currently processed month.
|
component of the sequence!) plus the currently processed month.
|
||||||
Eg:
|
Eg:
|
||||||
startdate: 2007-01-30
|
startdate: 2007-01-30
|
||||||
cursor[1]: 2007-01-30
|
cursor[1]: 2007-01-30
|
||||||
cursor[2]: 2007-02-28 <== Note: we have February!
|
cursor[2]: 2007-02-28 <== Note: we have February!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (dom = 1, doCont = YES; dom <= numDaysInMonth && doCont; dom++) {
|
for (dom = 1, doCont = YES; dom <= numDaysInMonth && doCont; dom++)
|
||||||
NSCalendarDate *start;
|
{
|
||||||
|
NSCalendarDate *start;
|
||||||
|
|
||||||
if (!monthDays[dom])
|
if (!monthDays[dom])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TODO: what is this good for?
|
// TODO: what is this good for?
|
||||||
/*
|
/*
|
||||||
Here we need to correct the date. Remember that the startdate given in
|
Here we need to correct the date. Remember that the startdate given in
|
||||||
the event is not necessarily a date of the sequence!
|
the event is not necessarily a date of the sequence!
|
||||||
|
|
||||||
The 'numDaysInMonth' localvar contains the number of days in the
|
The 'numDaysInMonth' localvar contains the number of days in the
|
||||||
current month (eg 31 for Januar, 28 for most February's, etc)
|
current month (eg 31 for Januar, 28 for most February's, etc)
|
||||||
|
|
||||||
Eg: MONTHLY;BYDAY=-1WE (last wednesday, every month)
|
Eg: MONTHLY;BYDAY=-1WE (last wednesday, every month)
|
||||||
|
|
||||||
cursor: 2007-01-30 (eventDayOfMonth = 30)
|
cursor: 2007-01-30 (eventDayOfMonth = 30)
|
||||||
=>start: 2007-01-31 (dom = 31)
|
=>start: 2007-01-31 (dom = 31)
|
||||||
cursor: 2007-02-28 (eventDayOfMonth = 30)
|
cursor: 2007-02-28 (eventDayOfMonth = 30)
|
||||||
=>start: 2007-02-28 (dom = 28)
|
=>start: 2007-02-28 (dom = 28)
|
||||||
|
|
||||||
Note: in case the cursor already had an event-day overflow, that is the
|
Note: in case the cursor already had an event-day overflow, that is the
|
||||||
'eventDayOfMonth' is bigger than the 'numDaysInMonth', the cursor
|
'eventDayOfMonth' is bigger than the 'numDaysInMonth', the cursor
|
||||||
will already be corrected!
|
will already be corrected!
|
||||||
Eg:
|
Eg:
|
||||||
start was: 2007-01-30
|
start was: 2007-01-30
|
||||||
cursor will be: 2007-02-28
|
cursor will be: 2007-02-28
|
||||||
*/
|
*/
|
||||||
if (eventDayOfMonth == dom) {
|
if (eventDayOfMonth == dom)
|
||||||
start = cursor;
|
{
|
||||||
}
|
start = cursor;
|
||||||
else {
|
}
|
||||||
int maxDay =
|
else
|
||||||
eventDayOfMonth > numDaysInMonth ? numDaysInMonth : eventDayOfMonth;
|
{
|
||||||
|
int maxDay =
|
||||||
|
eventDayOfMonth > numDaysInMonth ? numDaysInMonth : eventDayOfMonth;
|
||||||
|
|
||||||
start = [cursor dateByAddingYears:0 months:0 days:(dom - maxDay)];
|
start = [cursor dateByAddingYears: 0 months: 0 days: (dom - maxDay)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Setup for 2007-02-28, MONTHLY;BYDAY=-1WE.
|
Setup for 2007-02-28, MONTHLY;BYDAY=-1WE.
|
||||||
dom: 28
|
dom: 28
|
||||||
eventDayOfMonth: 31
|
eventDayOfMonth: 31
|
||||||
cursor: 2007-02-28
|
cursor: 2007-02-28
|
||||||
start: 2007-02-25 <== WRONG
|
start: 2007-02-25 <== WRONG
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if HEAVY_DEBUG
|
#if HEAVY_DEBUG
|
||||||
NSLog(@"DOM %i EDOM %i NUMDAYS %i START: %@ CURSOR: %@",
|
NSLog (@"DOM %i EDOM %i NUMDAYS %i START: %@ CURSOR: %@",
|
||||||
dom, eventDayOfMonth, numDaysInMonth,
|
dom, eventDayOfMonth, numDaysInMonth,
|
||||||
start, cursor);
|
start, cursor);
|
||||||
#endif
|
#endif
|
||||||
doCont = [self _addInstanceWithStartDate:start
|
doCont = [self _addInstanceWithStartDate: start
|
||||||
limitDate:until
|
limitDate: until
|
||||||
limitRange:_r
|
limitRange: _r
|
||||||
toArray:ranges];
|
toArray: ranges];
|
||||||
|
}
|
||||||
|
if (!doCont) break; /* reached some limit */
|
||||||
}
|
}
|
||||||
if (!doCont) break; /* reached some limit */
|
|
||||||
}
|
|
||||||
return ranges;
|
return ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSCalendarDate *)lastInstanceStartDate {
|
- (NSCalendarDate *) lastInstanceStartDate
|
||||||
if ([self->rrule repeatCount] > 0) {
|
{
|
||||||
NSCalendarDate *until;
|
if ([rrule repeatCount] > 0)
|
||||||
unsigned months, interval;
|
{
|
||||||
|
NSCalendarDate *until;
|
||||||
|
unsigned months, interval;
|
||||||
|
|
||||||
interval = [self->rrule repeatInterval];
|
interval = [rrule repeatInterval];
|
||||||
months = [self->rrule repeatCount] - 1 /* the first counts as one! */;
|
months = [rrule repeatCount] - 1 /* the first counts as one! */;
|
||||||
|
|
||||||
if (interval > 0)
|
if (interval > 0)
|
||||||
months *= interval;
|
months *= interval;
|
||||||
|
|
||||||
until = [[self->firstRange startDate] dateByAddingYears:0
|
until = [[firstRange startDate] dateByAddingYears: 0
|
||||||
months:months
|
months: months
|
||||||
days:0];
|
days: 0];
|
||||||
return until;
|
return until;
|
||||||
}
|
}
|
||||||
return [super lastInstanceStartDate];
|
return [super lastInstanceStartDate];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||||
|
|
||||||
This file is part of SOPE.
|
This file is part of SOPE.
|
||||||
|
|
||||||
SOPE is free software; you can redistribute it and/or modify it under
|
SOPE 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
|
the terms of the GNU Lesser General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
later version.
|
||||||
|
|
||||||
SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
|
SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
License for more details.
|
License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with SOPE; see the file COPYING. If not, write to the
|
License along with SOPE; see the file COPYING. If not, write to the
|
||||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
02111-1307, USA.
|
02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
@ -34,17 +34,17 @@
|
||||||
|
|
||||||
- (NSCalendarDate *) lastInstanceStartDate;
|
- (NSCalendarDate *) lastInstanceStartDate;
|
||||||
|
|
||||||
- (unsigned) offsetFromSundayForJulianNumber:(long)_jn;
|
- (unsigned) offsetFromSundayForJulianNumber: (long) _jn;
|
||||||
- (unsigned) offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
|
- (unsigned) offsetFromSundayForWeekDay: (iCalWeekDay) _weekDay;
|
||||||
- (unsigned) offsetFromSundayForCurrentWeekStart;
|
- (unsigned) offsetFromSundayForCurrentWeekStart;
|
||||||
|
|
||||||
- (iCalWeekDay) weekDayForJulianNumber:(long)_jn;
|
- (iCalWeekDay) weekDayForJulianNumber: (long) _jn;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: If BYDAY is specified, lastInstanceStartDate and recurrences will
|
TODO: If BYDAY is specified, lastInstanceStartDate and recurrences will
|
||||||
differ significantly!
|
differ significantly!
|
||||||
*/
|
*/
|
||||||
@implementation iCalWeeklyRecurrenceCalculator
|
@implementation iCalWeeklyRecurrenceCalculator
|
||||||
|
|
||||||
|
@ -53,140 +53,156 @@
|
||||||
{
|
{
|
||||||
NSMutableArray *ranges;
|
NSMutableArray *ranges;
|
||||||
NSCalendarDate *firStart;
|
NSCalendarDate *firStart;
|
||||||
long i, jnFirst, jnStart, jnEnd, startEndCount;
|
long i, jnFirst, jnStart, jnEnd, startEndCount;
|
||||||
unsigned interval, byDayMask;
|
unsigned interval, byDayMask;
|
||||||
|
|
||||||
firStart = [self->firstRange startDate];
|
firStart = [firstRange startDate];
|
||||||
jnFirst = [firStart julianNumber];
|
jnFirst = [firStart julianNumber];
|
||||||
jnEnd = [[_r endDate] julianNumber];
|
jnEnd = [[_r endDate] julianNumber];
|
||||||
|
|
||||||
if (jnFirst > jnEnd)
|
if (jnFirst > jnEnd)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
jnStart = [[_r startDate] julianNumber];
|
jnStart = [[_r startDate] julianNumber];
|
||||||
interval = [self->rrule repeatInterval];
|
interval = [rrule repeatInterval];
|
||||||
|
|
||||||
/* if rule is bound, check the bounds */
|
/* if rule is bound, check the bounds */
|
||||||
if (![self->rrule isInfinite]) {
|
if (![rrule isInfinite])
|
||||||
NSCalendarDate *until;
|
{
|
||||||
long jnRuleLast;
|
NSCalendarDate *until;
|
||||||
|
long jnRuleLast;
|
||||||
until = [self->rrule untilDate];
|
|
||||||
if (until) {
|
until = [rrule untilDate];
|
||||||
if ([until compare:[_r startDate]] == NSOrderedAscending)
|
if (until)
|
||||||
return nil;
|
{
|
||||||
jnRuleLast = [until julianNumber];
|
if ([until compare: [_r startDate]] == NSOrderedAscending)
|
||||||
|
return nil;
|
||||||
|
jnRuleLast = [until julianNumber];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jnRuleLast = (interval * [rrule repeatCount] * 7)
|
||||||
|
+ jnFirst;
|
||||||
|
if (jnRuleLast < jnStart)
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
/* jnStart < jnRuleLast < jnEnd ? */
|
||||||
|
if (jnEnd > jnRuleLast)
|
||||||
|
jnEnd = jnRuleLast;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
jnRuleLast = (interval * [self->rrule repeatCount] * 7)
|
|
||||||
+ jnFirst;
|
|
||||||
if (jnRuleLast < jnStart)
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
/* jnStart < jnRuleLast < jnEnd ? */
|
|
||||||
if (jnEnd > jnRuleLast)
|
|
||||||
jnEnd = jnRuleLast;
|
|
||||||
}
|
|
||||||
|
|
||||||
startEndCount = (jnEnd - jnStart) + 1;
|
startEndCount = (jnEnd - jnStart) + 1;
|
||||||
ranges = [NSMutableArray arrayWithCapacity:startEndCount];
|
ranges = [NSMutableArray arrayWithCapacity: startEndCount];
|
||||||
byDayMask = [self->rrule byDayMask];
|
byDayMask = [rrule byDayMask];
|
||||||
if (!byDayMask) {
|
if (!byDayMask)
|
||||||
for (i = 0 ; i < startEndCount; i++) {
|
{
|
||||||
long jnCurrent;
|
for (i = 0 ; i < startEndCount; i++)
|
||||||
|
{
|
||||||
jnCurrent = jnStart + i;
|
long jnCurrent;
|
||||||
if (jnCurrent >= jnFirst) {
|
|
||||||
long jnDiff;
|
jnCurrent = jnStart + i;
|
||||||
|
if (jnCurrent >= jnFirst)
|
||||||
jnDiff = jnCurrent - jnFirst; /* difference in days */
|
{
|
||||||
if ((jnDiff % (interval * 7)) == 0) {
|
long jnDiff;
|
||||||
NSCalendarDate *start, *end;
|
|
||||||
NGCalendarDateRange *r;
|
jnDiff = jnCurrent - jnFirst; /* difference in days */
|
||||||
|
if ((jnDiff % (interval * 7)) == 0)
|
||||||
start = [NSCalendarDate dateForJulianNumber:jnCurrent];
|
{
|
||||||
[start setTimeZone:[firStart timeZone]];
|
NSCalendarDate *start, *end;
|
||||||
start = [start hour: [firStart hourOfDay]
|
NGCalendarDateRange *r;
|
||||||
minute:[firStart minuteOfHour]
|
|
||||||
second:[firStart secondOfMinute]];
|
start = [NSCalendarDate dateForJulianNumber: jnCurrent];
|
||||||
end = [start addTimeInterval:[self->firstRange duration]];
|
[start setTimeZone: [firStart timeZone]];
|
||||||
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
|
start = [start hour: [firStart hourOfDay]
|
||||||
endDate:end];
|
minute: [firStart minuteOfHour]
|
||||||
if ([_r containsDateRange:r])
|
second: [firStart secondOfMinute]];
|
||||||
[ranges addObject:r];
|
end = [start addTimeInterval: [firstRange duration]];
|
||||||
}
|
r = [NGCalendarDateRange calendarDateRangeWithStartDate: start
|
||||||
}
|
endDate: end];
|
||||||
|
if ([_r containsDateRange: r])
|
||||||
|
[ranges addObject: r];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else {
|
{
|
||||||
long jnFirstWeekStart, weekStartOffset;
|
long jnFirstWeekStart, weekStartOffset;
|
||||||
|
|
||||||
/* calculate jnFirst's week start - this depends on our setting of week
|
/* calculate jnFirst's week start - this depends on our setting of week
|
||||||
start */
|
start */
|
||||||
weekStartOffset = [self offsetFromSundayForJulianNumber:jnFirst] -
|
weekStartOffset = [self offsetFromSundayForJulianNumber: jnFirst] -
|
||||||
[self offsetFromSundayForCurrentWeekStart];
|
[self offsetFromSundayForCurrentWeekStart];
|
||||||
|
|
||||||
jnFirstWeekStart = jnFirst - weekStartOffset;
|
jnFirstWeekStart = jnFirst - weekStartOffset;
|
||||||
|
|
||||||
for (i = 0 ; i < startEndCount; i++) {
|
for (i = 0 ; i < startEndCount; i++)
|
||||||
long jnCurrent;
|
{
|
||||||
|
long jnCurrent;
|
||||||
|
|
||||||
jnCurrent = jnStart + i;
|
jnCurrent = jnStart + i;
|
||||||
if (jnCurrent >= jnFirst) {
|
if (jnCurrent >= jnFirst)
|
||||||
long jnDiff;
|
{
|
||||||
|
long jnDiff;
|
||||||
/* we need to calculate a difference in weeks */
|
|
||||||
jnDiff = (jnCurrent - jnFirstWeekStart) % 7;
|
/* we need to calculate a difference in weeks */
|
||||||
if ((jnDiff % interval) == 0) {
|
jnDiff = (jnCurrent - jnFirstWeekStart) % 7;
|
||||||
BOOL isRecurrence = NO;
|
if ((jnDiff % interval) == 0)
|
||||||
|
{
|
||||||
if (jnCurrent == jnFirst) {
|
BOOL isRecurrence = NO;
|
||||||
isRecurrence = YES;
|
|
||||||
}
|
if (jnCurrent == jnFirst)
|
||||||
else {
|
{
|
||||||
iCalWeekDay weekDay;
|
isRecurrence = YES;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iCalWeekDay weekDay;
|
||||||
|
|
||||||
weekDay = [self weekDayForJulianNumber:jnCurrent];
|
weekDay = [self weekDayForJulianNumber: jnCurrent];
|
||||||
isRecurrence = (weekDay & [self->rrule byDayMask]) ? YES : NO;
|
isRecurrence = (weekDay & [rrule byDayMask]) ? YES : NO;
|
||||||
}
|
}
|
||||||
if (isRecurrence) {
|
if (isRecurrence)
|
||||||
NSCalendarDate *start, *end;
|
{
|
||||||
NGCalendarDateRange *r;
|
NSCalendarDate *start, *end;
|
||||||
|
NGCalendarDateRange *r;
|
||||||
start = [NSCalendarDate dateForJulianNumber:jnCurrent];
|
|
||||||
[start setTimeZone:[firStart timeZone]];
|
start = [NSCalendarDate dateForJulianNumber: jnCurrent];
|
||||||
start = [start hour: [firStart hourOfDay]
|
[start setTimeZone: [firStart timeZone]];
|
||||||
minute:[firStart minuteOfHour]
|
start = [start hour: [firStart hourOfDay]
|
||||||
second:[firStart secondOfMinute]];
|
minute: [firStart minuteOfHour]
|
||||||
end = [start addTimeInterval:[self->firstRange duration]];
|
second: [firStart secondOfMinute]];
|
||||||
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
|
end = [start addTimeInterval: [firstRange duration]];
|
||||||
endDate:end];
|
r = [NGCalendarDateRange calendarDateRangeWithStartDate: start
|
||||||
if ([_r containsDateRange:r])
|
endDate: end];
|
||||||
[ranges addObject:r];
|
if ([_r containsDateRange: r])
|
||||||
}
|
[ranges addObject: r];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ranges;
|
return ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSCalendarDate *)lastInstanceStartDate {
|
- (NSCalendarDate *) lastInstanceStartDate
|
||||||
if ([self->rrule repeatCount] > 0) {
|
{
|
||||||
long jnFirst, jnRuleLast;
|
if ([rrule repeatCount] > 0)
|
||||||
NSCalendarDate *firStart, *until;
|
{
|
||||||
|
long jnFirst, jnRuleLast;
|
||||||
firStart = [self->firstRange startDate];
|
NSCalendarDate *firStart, *until;
|
||||||
jnFirst = [firStart julianNumber];
|
|
||||||
jnRuleLast = ([self->rrule repeatInterval] *
|
firStart = [firstRange startDate];
|
||||||
[self->rrule repeatCount] * 7) +
|
jnFirst = [firStart julianNumber];
|
||||||
jnFirst;
|
jnRuleLast = ([rrule repeatInterval] *
|
||||||
until = [NSCalendarDate dateForJulianNumber:jnRuleLast];
|
[rrule repeatCount] * 7) +
|
||||||
until = [until hour: [firStart hourOfDay]
|
jnFirst;
|
||||||
minute:[firStart minuteOfHour]
|
until = [NSCalendarDate dateForJulianNumber: jnRuleLast];
|
||||||
second:[firStart secondOfMinute]];
|
until = [until hour: [firStart hourOfDay]
|
||||||
return until;
|
minute: [firStart minuteOfHour]
|
||||||
}
|
second: [firStart secondOfMinute]];
|
||||||
|
return until;
|
||||||
|
}
|
||||||
return [super lastInstanceStartDate];
|
return [super lastInstanceStartDate];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||||
|
|
||||||
This file is part of SOPE.
|
This file is part of SOPE.
|
||||||
|
|
||||||
SOPE is free software; you can redistribute it and/or modify it under
|
SOPE 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
|
the terms of the GNU Lesser General Public License as published by the
|
||||||
Free Software Foundation; either version 2, or (at your option) any
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
later version.
|
later version.
|
||||||
|
|
||||||
SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
|
SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
License for more details.
|
License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with SOPE; see the file COPYING. If not, write to the
|
License along with SOPE; see the file COPYING. If not, write to the
|
||||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
02111-1307, USA.
|
02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
@ -30,71 +30,78 @@
|
||||||
#import "iCalRecurrenceRule.h"
|
#import "iCalRecurrenceRule.h"
|
||||||
#import "NSCalendarDate+ICal.h"
|
#import "NSCalendarDate+ICal.h"
|
||||||
|
|
||||||
@interface iCalRecurrenceCalculator(PrivateAPI)
|
@interface iCalRecurrenceCalculator (PrivateAPI)
|
||||||
- (NSCalendarDate *)lastInstanceStartDate;
|
- (NSCalendarDate *) lastInstanceStartDate;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation iCalYearlyRecurrenceCalculator
|
@implementation iCalYearlyRecurrenceCalculator
|
||||||
|
|
||||||
- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{
|
- (NSArray *)
|
||||||
|
recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
|
||||||
|
{
|
||||||
NSMutableArray *ranges;
|
NSMutableArray *ranges;
|
||||||
NSCalendarDate *firStart, *rStart, *rEnd, *until;
|
NSCalendarDate *firStart, *rStart, *rEnd, *until;
|
||||||
unsigned i, count, interval;
|
unsigned i, count, interval;
|
||||||
int diff;
|
int diff;
|
||||||
|
|
||||||
firStart = [self->firstRange startDate];
|
firStart = [firstRange startDate];
|
||||||
rStart = [_r startDate];
|
rStart = [_r startDate];
|
||||||
rEnd = [_r endDate];
|
rEnd = [_r endDate];
|
||||||
interval = [self->rrule repeatInterval];
|
interval = [rrule repeatInterval];
|
||||||
until = [self lastInstanceStartDate];
|
until = [self lastInstanceStartDate];
|
||||||
|
|
||||||
if (until) {
|
if (until)
|
||||||
if ([until compare:rStart] == NSOrderedAscending)
|
{
|
||||||
return nil;
|
if ([until compare: rStart] == NSOrderedAscending)
|
||||||
if ([until compare:rEnd] == NSOrderedDescending)
|
return nil;
|
||||||
rEnd = until;
|
if ([until compare: rEnd] == NSOrderedDescending)
|
||||||
}
|
rEnd = until;
|
||||||
|
}
|
||||||
diff = [firStart yearsBetweenDate:rStart];
|
|
||||||
if ((diff != 0) && [rStart compare:firStart] == NSOrderedAscending)
|
diff = [firStart yearsBetweenDate: rStart];
|
||||||
|
if ((diff != 0) && [rStart compare: firStart] == NSOrderedAscending)
|
||||||
diff = -diff;
|
diff = -diff;
|
||||||
|
|
||||||
count = [rStart yearsBetweenDate:rEnd] + 1;
|
count = [rStart yearsBetweenDate: rEnd] + 1;
|
||||||
ranges = [NSMutableArray arrayWithCapacity:count];
|
ranges = [NSMutableArray arrayWithCapacity: count];
|
||||||
for (i = 0 ; i < count; i++) {
|
for (i = 0 ; i < count; i++)
|
||||||
int test;
|
{
|
||||||
|
int test;
|
||||||
|
|
||||||
test = diff + i;
|
test = diff + i;
|
||||||
if ((test >= 0) && (test % interval) == 0) {
|
if ((test >= 0) && (test % interval) == 0)
|
||||||
NSCalendarDate *start, *end;
|
{
|
||||||
NGCalendarDateRange *r;
|
NSCalendarDate *start, *end;
|
||||||
|
NGCalendarDateRange *r;
|
||||||
start = [firStart dateByAddingYears:diff + i
|
|
||||||
months:0
|
start = [firStart dateByAddingYears: diff + i
|
||||||
days:0];
|
months: 0
|
||||||
[start setTimeZone:[firStart timeZone]];
|
days: 0];
|
||||||
end = [start addTimeInterval:[self->firstRange duration]];
|
[start setTimeZone: [firStart timeZone]];
|
||||||
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
|
end = [start addTimeInterval: [firstRange duration]];
|
||||||
endDate:end];
|
r = [NGCalendarDateRange calendarDateRangeWithStartDate: start
|
||||||
if ([_r containsDateRange:r])
|
endDate: end];
|
||||||
[ranges addObject:r];
|
if ([_r containsDateRange: r])
|
||||||
|
[ranges addObject: r];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ranges;
|
return ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSCalendarDate *)lastInstanceStartDate {
|
- (NSCalendarDate *) lastInstanceStartDate
|
||||||
if ([self->rrule repeatCount] > 0) {
|
{
|
||||||
NSCalendarDate *until;
|
if ([rrule repeatCount] > 0)
|
||||||
unsigned years, interval;
|
{
|
||||||
|
NSCalendarDate *until;
|
||||||
interval = [self->rrule repeatInterval];
|
unsigned years, interval;
|
||||||
years = [self->rrule repeatCount] * interval;
|
|
||||||
until = [[self->firstRange startDate] dateByAddingYears:years
|
interval = [rrule repeatInterval];
|
||||||
months:0
|
years = [rrule repeatCount] * interval;
|
||||||
days:0];
|
until = [[firstRange startDate] dateByAddingYears: years
|
||||||
return until;
|
months: 0
|
||||||
}
|
days: 0];
|
||||||
|
return until;
|
||||||
|
}
|
||||||
return [super lastInstanceStartDate];
|
return [super lastInstanceStartDate];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue