From 03382298b87a9676d3af993bc8160cb317fb4197 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Tue, 9 Oct 2007 17:19:20 +0000 Subject: [PATCH] Monotone-Parent: fe67bff0ab967ccf03cfe54c248865c9df889c21 Monotone-Revision: 7342d9cd31675160736e0f2db8a83047d9babea9 Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2007-10-09T17:19:20 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 11 +++ .../NGCards/iCalMonthlyRecurrenceCalculator.m | 7 +- SOPE/NGCards/iCalRecurrenceCalculator.m | 4 +- .../Appointments/SOGoAppointmentFolder.m | 30 +++++--- UI/MailerUI/English.lproj/Localizable.strings | 1 + UI/MailerUI/French.lproj/Localizable.strings | 1 + UI/MailerUI/German.lproj/Localizable.strings | 1 + UI/Scheduler/UIxAppointmentEditor.h | 1 + UI/Scheduler/UIxAppointmentEditor.m | 76 ++++++++++++++++++- UI/Scheduler/UIxCalListingActions.m | 38 ++++------ 10 files changed, 128 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index 686d455f4..3eb1a972e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2007-10-05 Ludovic Marcotte + + * UI/WebServerResources/MailerUI.js + We check if at least one message is selected + before performing a Reply/Reply All/Forward + + * SoObjects/Appointments/SOGoAppointmentFolder.m + and others - implemented support for recurring + events (with some known limitations right now, + all soon to be fixed). + 2007-10-04 Francis Lachapelle * Main/SOGo.m ([SOGo -isUserName:_keyinContext:_ctx]): removed diff --git a/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m index 2516534a9..e8a236312 100644 --- a/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m +++ b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m @@ -262,10 +262,9 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet, interval = [self->rrule repeatInterval]; until = [self lastInstanceStartDate]; // TODO: maybe replace byMonthDay = [self->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 != nil) { if ([until compare:rStart] == NSOrderedAscending) /* until before start */ return nil; @@ -314,7 +313,7 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet, continue; /* first check whether we are in the interval */ - + if ((monthIdxInRecurrence % interval) != 0) continue; diff --git a/SOPE/NGCards/iCalRecurrenceCalculator.m b/SOPE/NGCards/iCalRecurrenceCalculator.m index a56eaef38..4923639cb 100644 --- a/SOPE/NGCards/iCalRecurrenceCalculator.m +++ b/SOPE/NGCards/iCalRecurrenceCalculator.m @@ -100,9 +100,10 @@ static Class yearlyCalcClass = Nil; 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]; } @@ -158,6 +159,7 @@ static Class yearlyCalcClass = Nil; unsigned k; exDate = [exDates objectAtIndex:i]; + for (k = 0; k < rCount; k++) { unsigned rIdx; diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index a517d18df..1a2329e51 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -568,13 +568,16 @@ static NSNumber *sharedYes = nil; md = [[_record mutableCopy] autorelease]; - /* cycle is in _r */ + /* 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 */ tmp = [_r startDate]; [tmp setTimeZone: timeZone]; [md setObject:tmp forKey:@"startDate"]; + [md setObject: [NSNumber numberWithInt: [tmp timeIntervalSince1970]] forKey: @"c_startdate"]; tmp = [_r endDate]; [tmp setTimeZone: timeZone]; [md setObject:tmp forKey:@"endDate"]; + [md setObject: [NSNumber numberWithInt: [tmp timeIntervalSince1970]] forKey: @"c_enddate"]; return md; } @@ -633,20 +636,24 @@ static NSNumber *sharedYes = nil; rules = [cycleinfo objectForKey:@"rules"]; exRules = [cycleinfo objectForKey:@"exRules"]; exDates = [cycleinfo objectForKey:@"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) [_ma addObject:fixedRow]; + if (fixedRow != nil) + { + [_ma addObject:fixedRow]; + } } } @@ -845,21 +852,20 @@ static NSNumber *sharedYes = nil; ma = [NSMutableArray arrayWithArray: records]; } - /* fetch recurrent apts now */ - sql = [NSString stringWithFormat: @"(c_iscycle = 1)%@%@%@", - dateSqlString, componentSqlString, privacySqlString]; + /* fetch recurrent apts now. we do NOT consider the date range when doing that + as the c_startdate/c_enddate of a recurring event is always set to the first + recurrence - others are generated on the fly */ + sql = [NSString stringWithFormat: @"(c_iscycle = 1)%@%@", componentSqlString, privacySqlString]; + qualifier = [EOQualifier qualifierWithQualifierFormat: sql]; - [fields addObject: @"c_cycleinfo"]; - records = [_folder fetchFields: fields matchingQualifier: qualifier]; + if (records) { - if (logger) - [self debugWithFormat: @"fetched %i cyclic records: %@", - [records count], records]; - if (r) + if (r) { records = [self fixupCyclicRecords: records fetchRange: r]; + } if (!ma) ma = [NSMutableArray arrayWithCapacity: [records count]]; diff --git a/UI/MailerUI/English.lproj/Localizable.strings b/UI/MailerUI/English.lproj/Localizable.strings index b058b07a1..b8d4e8b9a 100644 --- a/UI/MailerUI/English.lproj/Localizable.strings +++ b/UI/MailerUI/English.lproj/Localizable.strings @@ -153,5 +153,6 @@ "quotasFormat" = "Quotas: %{0} used on %{1} Kb; %{2}%"; +"Please select a message." = "Please select a message."; "Please select a message to print." = "Please select a message to print."; "Please select only one message to print." = "Please select only one message to print."; diff --git a/UI/MailerUI/French.lproj/Localizable.strings b/UI/MailerUI/French.lproj/Localizable.strings index cf34cac37..3fed423bc 100644 --- a/UI/MailerUI/French.lproj/Localizable.strings +++ b/UI/MailerUI/French.lproj/Localizable.strings @@ -203,5 +203,6 @@ "quotasFormat" = "Quotas: %{0} Ko utilisés sur %{1}; %{2}%"; +"Please select a message." = "Veuillez sélectionner un message."; "Please select a message to print." = "Veuillez sélectionner un message à imprimer."; "Please select only one message to print." = "Veuillez ne sélectionner qu'un seul message à imprimer."; diff --git a/UI/MailerUI/German.lproj/Localizable.strings b/UI/MailerUI/German.lproj/Localizable.strings index 9f5b86c3a..ad9ec372c 100644 --- a/UI/MailerUI/German.lproj/Localizable.strings +++ b/UI/MailerUI/German.lproj/Localizable.strings @@ -186,5 +186,6 @@ "quotasFormat" = "Quota: %{0} von %{1} KB verwendet; %{2}%"; +"Please select a message." = "Sie müssen eine Nachricht auswählen."; "Please select a message to print." = "Sie müssen eine Nachricht zum Drucken auswählen."; "Please select only one message to print." = "Bitte wählen Sie nur eine Nachricht zum Drucken aus."; diff --git a/UI/Scheduler/UIxAppointmentEditor.h b/UI/Scheduler/UIxAppointmentEditor.h index e90745500..c3ead6856 100644 --- a/UI/Scheduler/UIxAppointmentEditor.h +++ b/UI/Scheduler/UIxAppointmentEditor.h @@ -35,6 +35,7 @@ NSCalendarDate *aptStartDate; NSCalendarDate *aptEndDate; NSString *item; + NSString *repeat; } /* template values */ diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index a88b3f382..4f4fb0bb3 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -20,6 +20,8 @@ * Boston, MA 02111-1307, USA. */ +#warning WE LEAK IVARS LIKE CRAZY HERE + #include #import @@ -29,6 +31,7 @@ #import #import +#import #import #import @@ -48,12 +51,19 @@ aptEndDate = nil; item = nil; event = nil; + repeat = nil; isAllDay = NO; } return self; } +- (void) dealloc +{ + RELEASE(repeat); + [super dealloc]; +} + /* template values */ - (iCalEvent *) event { @@ -132,6 +142,8 @@ else text = [self labelForKey: [NSString stringWithFormat: @"repeat_%@", item]]; + NSLog(@"itemRepeatText: %@", text); + return text; } @@ -198,11 +210,12 @@ - (NSString *) repeat { - return @""; + return repeat; } - (void) setRepeat: (NSString *) newRepeat { + ASSIGN(repeat, newRepeat); } - (NSString *) reminder @@ -276,8 +289,32 @@ ASSIGN (aptStartDate, startDate); ASSIGN (aptEndDate, endDate); + // We initialize our repeat ivars + if ([event hasRecurrenceRules]) + { + iCalRecurrenceRule *rule; + + repeat = @"CUSTOM"; - /* here comes the code for initializing repeat, reminder and isAllDay... */ + rule = [[event recurrenceRules] lastObject]; + + if ([rule frequency] == iCalRecurrenceFrequenceWeekly) + { + if ([rule repeatInterval] == 1) repeat = @"WEEKLY"; + else if ([rule repeatInterval] == 2) repeat = @"BI-WEEKLY"; + } + else if ([rule frequency] == iCalRecurrenceFrequenceDaily) + { + if ([rule byDayMask] == (iCalWeekDayMonday|iCalWeekDayTuesday|iCalWeekDayWednesday|iCalWeekDayThursday|iCalWeekDayFriday)) repeat = @"EVERY WEEKDAY"; + else if (![rule byDayMask]) repeat = @"DAILY"; + } + else if ([rule frequency] == iCalRecurrenceFrequenceMonthly && [rule repeatInterval] == 1) repeat = @"MONTHLY"; + else if ([rule frequency] == iCalRecurrenceFrequenceYearly && [rule repeatInterval] == 1) repeat = @"YEARLY"; + } + else + { + DESTROY(repeat); + } return self; } @@ -310,7 +347,11 @@ NSString *iCalString; clientObject = [self clientObject]; + NSLog(@"saveAction, clientObject = %@", clientObject); + iCalString = [[clientObject calendar: NO] versitString]; + + NSLog(@"saveAction, iCalString = %@", iCalString); [clientObject saveContentString: iCalString]; return [self jsCloseWithRefreshMethod: @"refreshEventsAndDisplay()"]; @@ -352,6 +393,37 @@ } if ([clientObject isNew]) [event setTransparency: @"OPAQUE"]; + + // We remove any repeat rules + if (!repeat && [event hasRecurrenceRules]) + { + [event removeAllRecurrenceRules]; + } + else if (!([repeat caseInsensitiveCompare: @"-"] == NSOrderedSame || [repeat caseInsensitiveCompare: @"CUSTOM"] == NSOrderedSame)) + { + iCalRecurrenceRule *rule; + + rule = [[iCalRecurrenceRule alloc] init]; + + if ([repeat caseInsensitiveCompare: @"BI-WEEKLY"] == NSOrderedSame) + { + [rule setFrequency: iCalRecurrenceFrequenceWeekly]; + [rule setInterval: @"2"]; + } + else if ([repeat caseInsensitiveCompare: @"EVERY WEEKDAY"] == NSOrderedSame) + { + [rule setByDayMask: (iCalWeekDayMonday|iCalWeekDayTuesday|iCalWeekDayWednesday|iCalWeekDayThursday|iCalWeekDayFriday)]; + [rule setFrequency: iCalRecurrenceFrequenceDaily]; + [rule setInterval: @"1"]; + } + else + { + [rule setFrequency: (iCalRecurrenceFrequency)[rule valueForFrequency: repeat]]; + [rule setInterval: @"1"]; + } + [event setRecurrenceRules: [NSArray arrayWithObject: rule]]; + RELEASE(rule); + } } // TODO: add tentatively diff --git a/UI/Scheduler/UIxCalListingActions.m b/UI/Scheduler/UIxCalListingActions.m index b036060f9..56a608294 100644 --- a/UI/Scheduler/UIxCalListingActions.m +++ b/UI/Scheduler/UIxCalListingActions.m @@ -221,50 +221,42 @@ { NSEnumerator *folders, *currentInfos; SOGoAppointmentFolder *currentFolder; - NSMutableDictionary *infos, *currentInfo, *newInfo; - NSString *owner, *uid; + NSMutableDictionary *newInfo; + NSMutableArray *infos; NSNull *marker; SOGoAppointmentFolders *clientObject; marker = [NSNull null]; - infos = [NSMutableDictionary dictionary]; - clientObject = [self clientObject]; + clientObject = [self clientObject]; folders = [[clientObject subFolders] objectEnumerator]; currentFolder = [folders nextObject]; + + infos = [NSMutableArray array]; while (currentFolder) { if ([currentFolder isActive]) { - owner = [currentFolder ownerInContext: context]; currentInfos = [[currentFolder fetchCoreInfosFrom: startDate to: endDate component: component] objectEnumerator]; - newInfo = [currentInfos nextObject]; - while (newInfo) + + while ((newInfo = [currentInfos nextObject])) { - uid = [newInfo objectForKey: @"c_uid"]; - currentInfo = [infos objectForKey: uid]; - if (!currentInfo - || [owner isEqualToString: userLogin]) - { - [self _updatePrivacyInComponent: newInfo - fromFolder: currentFolder]; - [newInfo setObject: [currentFolder nameInContainer] - forKey: @"c_folder"]; - // [newInfo setObject: owner forKey: @"c_owner"]; - [infos setObject: [newInfo objectsForKeys: fields - notFoundMarker: marker] - forKey: uid]; - } - newInfo = [currentInfos nextObject]; + [self _updatePrivacyInComponent: newInfo + fromFolder: currentFolder]; + [newInfo setObject: [currentFolder nameInContainer] + forKey: @"c_folder"]; + + [infos addObject: [newInfo objectsForKeys: fields + notFoundMarker: marker]]; } } currentFolder = [folders nextObject]; } - return [infos allValues]; + return infos; } - (WOResponse *) _responseWithData: (NSArray *) data