+2005-02-28 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.5.47
+
+ * iCalRepeatableEntityObject.m: shifted code to
+ iCalRecurrenceCalculator
+
+ * iCalRecurrenceCalculator.[hm]: new class method to calculate
+ complex recurrences. In SOGo this information is stored in quick
+ fields to reduce the complexity of lookups, hence we need to offer
+ a proper API to calculate date ranges from this information.
+ Fixed all calculations to explicitly set timeZone for all newly
+ created startDates - it seems the timeZone information is not
+ properly retained by the hour:minute:second: method from NGExtensions
+ which lead to improper DST related shifts.
+
+ * iCalDateHolder.h: exposed the API
+
+ * NSCalendarDate+ICal.[hm]: new convenience constructor for calendar
+ dates from iCal representations (uses iCalDateHolder internally)
+
+ * iCalRecurrenceRule.m: changed setUntil: to utilize new public
+ NSCalendarDate+ICal category
+
+ * NGiCal.h: added NSCalendarDate+ICal.h to the public headers
+
+ * GNUmakefile: NSCalendarDate+ICal.h is public now
+
2005-02-20 Helge Hess <helge.hess@opengroupware.org>
* NGiCal.xmap: fixed a missing semicolon (did not load on MacOSX)
iCalRenderer.h \
iCalRecurrenceRule.h \
iCalRecurrenceCalculator.h \
+ \
+ NSCalendarDate+ICal.h \
# IcalResponse.h \
#include <NGiCal/iCalRecurrenceRule.h>
#include <NGiCal/iCalRecurrenceCalculator.h>
+#include <NGiCal/NSCalendarDate+ICal.h>
+
#endif /* __NGiCal_H__ */
fileRef = AD770E6707AE627500F5C7A1;
isa = PBXBuildFile;
settings = {
+ ATTRIBUTES = (
+ Public,
+ );
};
};
AD770E6A07AE627500F5C7A1 = {
fileRef = AD77103C07AE8F8500F5C7A1;
isa = PBXBuildFile;
settings = {
+ ATTRIBUTES = (
+ Public,
+ );
};
};
AD77103F07AE8F8500F5C7A1 = {
fileRef = ADAACE6607B3973900FC48D6;
isa = PBXBuildFile;
settings = {
+ ATTRIBUTES = (
+ Public,
+ );
};
};
ADAACE6907B3973900FC48D6 = {
);
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 4.5.44;
+ DYLIB_CURRENT_VERSION = 4.5.47;
FRAMEWORK_SEARCH_PATHS = "\"$(USER_LIBRARY_DIR)/EmbeddedFrameworks\"";
FRAMEWORK_VERSION = A;
GCC_PRECOMPILE_PREFIX_HEADER = NO;
);
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 4.5.44;
+ DYLIB_CURRENT_VERSION = 4.5.47;
FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
FRAMEWORK_VERSION = A;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
isa = PBXBuildFile;
settings = {
ATTRIBUTES = (
+ Public,
);
};
};
02111-1307, USA.
*/
-#ifndef __ICal2_NSCalendarDate_ICal_H__
-#define __ICal2_NSCalendarDate_ICal_H__
+#ifndef __NGiCal_NSCalendarDate_ICal_H__
+#define __NGiCal_NSCalendarDate_ICal_H__
#import <Foundation/NSCalendarDate.h>
@class NSTimeZone;
-@interface NSCalendarDate(ICalValue)
+@interface NSCalendarDate(iCalRepresentation)
+
++ (id)calendarDateWithICalRepresentation:(NSString *)_iCalRep;
/* represention */
- (unsigned)daysBetweenDate:(NSCalendarDate *)_date;
@end
-#endif /* __ICal2_NSCalendarDate_ICal_H__ */
+#endif /* __NGiCal_NSCalendarDate_ICal_H__ */
*/
#include "NSCalendarDate+ICal.h"
+#include "iCalDateHolder.h"
#include "common.h"
static NSTimeZone *gmt = nil;
gmt = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
}
-@implementation NSCalendarDate(ICalValue)
+@interface iCalDateHolder (PrivateAPI)
+- (id)awakeAfterUsingSaxDecoder:(id)_decoder;
+@end
+
+@implementation NSCalendarDate(iCalRepresentation)
/* represention */
static NSString *gmtcalfmt = @"%Y%m%dT%H%M00Z";
++ (id)calendarDateWithICalRepresentation:(NSString *)_iCalRep {
+ iCalDateHolder *dh;
+ NSCalendarDate *date;
+
+ dh = [[iCalDateHolder alloc] init];
+ [dh setString:_iCalRep];
+ date = [dh awakeAfterUsingSaxDecoder:nil];
+ [dh release];
+ return date;
+}
+
- (NSString *)icalStringInGMT {
NSTimeZone *oldtz;
NSString *s;
MAJOR_VERSION=4
MINOR_VERSION=5
-SUBMINOR_VERSION:=46
+SUBMINOR_VERSION:=47
# v4.5.40 requires NGExtensions v4.5.145
# v4.5.37 requires NGExtensions v4.5.140
#import <Foundation/NSObject.h>
-@class NSString;
+@class NSString, NSTimeZone;
@interface iCalDateHolder : NSObject
{
NSString *tag;
}
+- (void)setString:(NSString *)_value;
+- (NSString *)string;
+
+- (void)setTag:(NSString *)_value;
+- (NSString *)tag;
+
+- (void)setTzid:(NSString *)_value;
+- (NSString *)tzid;
+
+- (NSTimeZone *)timeZone;
+
@end
#endif /* __NGiCal_iCalDateHolder_H__ */
iCalRecurrenceRule *rrule;
}
++ (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r
+ firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir
+ recurrenceRules:(NSArray *)_rRules
+ exceptionRules:(NSArray *)_exRules
+ exceptionDates:(NSArray *)_exDates;
+
+ (id)recurrenceCalculatorForRecurrenceRule:(iCalRecurrenceRule *)_rrule
withFirstInstanceCalendarDateRange:(NGCalendarDateRange *)_range;
@implementation iCalRecurrenceCalculator
+static Class NSCalendarDateClass = Nil;
+static Class iCalRecurrenceRuleClass = Nil;
static Class dailyCalcClass = Nil;
static Class weeklyCalcClass = Nil;
static Class monthlyCalcClass = Nil;
if (didInit) return;
didInit = YES;
+ NSCalendarDateClass = [NSCalendarDate class];
+ iCalRecurrenceRuleClass = [iCalRecurrenceRule class];
+
dailyCalcClass = [iCalDailyRecurrenceCalculator class];
weeklyCalcClass = [iCalWeeklyRecurrenceCalculator class];
monthlyCalcClass = [iCalMonthlyRecurrenceCalculator class];
yearlyCalcClass = [iCalYearlyRecurrenceCalculator class];
}
+/* factory */
+
+ (id)recurrenceCalculatorForRecurrenceRule:(iCalRecurrenceRule *)_rrule
withFirstInstanceCalendarDateRange:(NGCalendarDateRange *)_range
{
firstInstanceCalendarDateRange:_range] autorelease];
}
+/* complex calculation convenience */
+
++ (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r
+ firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir
+ recurrenceRules:(NSArray *)_rRules
+ exceptionRules:(NSArray *)_exRules
+ exceptionDates:(NSArray *)_exDates
+{
+ id rule;
+ iCalRecurrenceCalculator *calc;
+ NSMutableArray *ranges;
+ unsigned i, count, rCount;
+
+ ranges = [NSMutableArray array];
+ count = [_rRules count];
+ for (i = 0; i < count; i++) {
+ NSArray *rs;
+
+ rule = [_rRules objectAtIndex:i];
+ if (![rule isKindOfClass:iCalRecurrenceRuleClass])
+ rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:rule];
+
+ calc = [self recurrenceCalculatorForRecurrenceRule:rule
+ withFirstInstanceCalendarDateRange:_fir];
+ rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
+ [ranges addObjectsFromArray:rs];
+ }
+
+ if (![ranges count])
+ return nil;
+
+ /* test if any exceptions do match */
+ count = [_exRules count];
+ for (i = 0; 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 count])
+ return nil;
+
+ /* exception dates are also possible */
+ rCount = [ranges count];
+ count = [_exDates count];
+ for (i = 0; i < count; i++) {
+ id exDate;
+ NGCalendarDateRange *r;
+ unsigned k;
+
+ exDate = [_exDates objectAtIndex:i];
+ if (![exDate isKindOfClass:NSCalendarDateClass]) {
+ exDate = [NSCalendarDate calendarDateWithICalRepresentation:exDate];
+ }
+ for (k = 0; k < rCount; k++) {
+ r = [ranges objectAtIndex:(rCount - k) - 1];
+ if ([r containsDate:exDate]) {
+ [ranges removeObjectAtIndex:k];
+ }
+ }
+ }
+ return ranges;
+}
+
+
+/* init */
+
- (id)initWithRecurrenceRule:(iCalRecurrenceRule *)_rrule
firstInstanceCalendarDateRange:(NGCalendarDateRange *)_range
{
NGCalendarDateRange *r;
start = [NSCalendarDate dateForJulianNumber:jnCurrent];
+ [start setTimeZone:[firStart timeZone]];
start = [start hour: [firStart hourOfDay]
minute:[firStart minuteOfHour]
second:[firStart secondOfMinute]];
NGCalendarDateRange *r;
start = [NSCalendarDate dateForJulianNumber:jnCurrent];
+ [start setTimeZone:[firStart timeZone]];
start = [start hour: [firStart hourOfDay]
minute:[firStart minuteOfHour]
second:[firStart secondOfMinute]];
NGCalendarDateRange *r;
start = [NSCalendarDate dateForJulianNumber:jnCurrent];
+ [start setTimeZone:[firStart timeZone]];
start = [start hour: [firStart hourOfDay]
minute:[firStart minuteOfHour]
second:[firStart secondOfMinute]];
start = [firStart dateByAddingYears:0
months:diff + i
days:0];
+ [start setTimeZone:[firStart timeZone]];
end = [start addTimeInterval:[self->firstRange duration]];
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
endDate:end];
start = [firStart dateByAddingYears:diff + i
months:0
days:0];
+ [start setTimeZone:[firStart timeZone]];
end = [start addTimeInterval:[self->firstRange duration]];
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
endDate:end];
*/
#include "iCalRecurrenceRule.h"
-#include "iCalDateHolder.h"
#include "NSCalendarDate+ICal.h"
#include "common.h"
wkst = rrWeekStart;
*/
-@interface iCalDateHolder (PrivateAPI)
-- (void)setString:(NSString *)_value;
-- (id)awakeAfterUsingSaxDecoder:(id)_decoder;
-@end
-
@interface iCalRecurrenceRule (PrivateAPI)
- (iCalWeekDay)weekDayFromICalRepresentation:(NSString *)_day;
- (NSString *)iCalRepresentationForWeekDay:(iCalWeekDay)_weekDay;
self->repeatCount = [_count unsignedIntValue];
}
- (void)setUntil:(NSString *)_until {
- iCalDateHolder *dh;
NSCalendarDate *date;
- dh = [[iCalDateHolder alloc] init];
- [dh setString:_until];
- date = [dh awakeAfterUsingSaxDecoder:nil];
+ date = [NSCalendarDate calendarDateWithICalRepresentation:_until];
ASSIGN(self->untilDate, date);
- [dh release];
}
- (void)setWkst:(NSString *)_weekStart {
- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r
firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir
{
- iCalRecurrenceRule *rule;
- iCalRecurrenceCalculator *calc;
- NSMutableArray *ranges;
- unsigned i, count, rCount;
-
- ranges = [NSMutableArray array];
- count = [self->rRules count];
- for (i = 0; i < count; i++) {
- NSArray *rs;
-
- rule = [self->rRules objectAtIndex:i];
- calc = [iCalRecurrenceCalculator recurrenceCalculatorForRecurrenceRule:rule
- withFirstInstanceCalendarDateRange:_fir];
- rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
- [ranges addObjectsFromArray:rs];
- }
-
- if (![ranges count])
- return nil;
-
- /* test if any exceptions do match */
- count = [self->exRules count];
- for (i = 0; i < count; i++) {
- NSArray *rs;
-
- rule = [self->exRules objectAtIndex:i];
- calc = [iCalRecurrenceCalculator recurrenceCalculatorForRecurrenceRule:rule
- withFirstInstanceCalendarDateRange:_fir];
- rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
- [ranges removeObjectsInArray:rs];
- }
-
- if (![ranges count])
- return nil;
-
- /* exception dates are also possible */
- rCount = [ranges count];
- count = [self->exDates count];
- for (i = 0; i < count; i++) {
- NSCalendarDate *exDate;
- NGCalendarDateRange *r;
- unsigned k;
-
- exDate = [self->exDates objectAtIndex:i];
- for (k = 0; k < rCount; k++) {
- r = [ranges objectAtIndex:(rCount - k) - 1];
- if ([r containsDate:exDate]) {
- [ranges removeObjectAtIndex:k];
- }
- }
- }
- return ranges;
+ return [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange:_r
+ firstInstanceCalendarDateRange:_fir
+ recurrenceRules:self->rRules
+ exceptionRules:self->exRules
+ exceptionDates:self->exDates];
}