From a40357f9c48a4b96e89b2832bf16de6599674920 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Fri, 8 Jul 2011 00:22:10 +0000 Subject: [PATCH] See ChangeLogs Monotone-Parent: 5c6353cb6270d51a457d46a8fe98dadae4f37193 Monotone-Revision: c0509d9d92c69255be6d27969b4f578739e78c7f Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2011-07-08T00:22:10 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 16 +++++++ SOPE/NGCards/ChangeLog | 5 ++ SOPE/NGCards/iCalRepeatableEntityObject.m | 8 +++- .../Appointments/SOGoAppointmentFolder.m | 15 +++++- .../Appointments/SOGoAppointmentObject.m | 9 +--- .../Appointments/SOGoCalendarComponent.m | 2 +- .../Appointments/SOGoComponentOccurence.m | 31 +++++++++--- UI/Scheduler/UIxAppointmentEditor.m | 47 ++++++++++++------- 8 files changed, 99 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 05319c3d7..226d52471 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2011-07-11 Francis Lachapelle + + * UI/Scheduler/UIxAppointmentEditor.m + (-takeValuesFromRequest:inContext:): when switching from an + all-day event to a non-all-day event, we must add the vTimeZone + definition. The opposite is also fixed. + + * SoObjects/Appointments/SOGoComponentOccurence.m + (-prepareDelete): when deleting an occurrence of a floating + all-day event, we must adjust the exception date to the user's timezone. + + * SoObjects/Appointments/SOGoAppointmentFolder.m + (-_flattenCycleRecord:forRange:intoArray:): when computing + occurrences of a floating all-day event, we must also ajdust the + exception dates to the user's timezone. + 2011-07-08 Francis Lachapelle * UI/MailerUI/UIxMailListActions.m (-getUIDsAndHeadersInFolder) diff --git a/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog index 045ab9989..8d3b0d28e 100644 --- a/SOPE/NGCards/ChangeLog +++ b/SOPE/NGCards/ChangeLog @@ -1,3 +1,8 @@ +2011-07-11 Francis Lachapelle + + * iCalRepeatableEntityObject.m (-addToExceptionDates:): drop the + time part when dealing with an all-day event. + 2011-03-29 Francis Lachapelle * iCalRepeatableEntityObject.m (-rules:withEventTimeZone:): new diff --git a/SOPE/NGCards/iCalRepeatableEntityObject.m b/SOPE/NGCards/iCalRepeatableEntityObject.m index e0507f3d3..a6e485a86 100644 --- a/SOPE/NGCards/iCalRepeatableEntityObject.m +++ b/SOPE/NGCards/iCalRepeatableEntityObject.m @@ -29,6 +29,7 @@ #import "NSCalendarDate+NGCards.h" #import "iCalDateTime.h" +#import "iCalEvent.h" #import "iCalTimeZone.h" #import "iCalRecurrenceRule.h" #import "iCalRecurrenceCalculator.h" @@ -174,7 +175,10 @@ dateTime = [iCalDateTime new]; [dateTime setTag: @"exdate"]; - [dateTime setDateTime: _rdate]; + if ([self isKindOfClass: [iCalEvent class]] && [(iCalEvent *)self isAllDay]) + [dateTime setDate: _rdate]; + else + [dateTime setDateTime: _rdate]; [self addChild: dateTime]; [dateTime release]; } @@ -191,7 +195,7 @@ } /** - * Return the exception dates of the event in GMT. + * Return the exception dates of the entity in GMT. * @return an array of strings. */ - (NSArray *) exceptionDates diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 16dc8da29..814d2d50f 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -850,8 +850,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir intoArray: (NSMutableArray *) theRecords { NSMutableDictionary *row, *fixedRow; - NSMutableArray *records; + NSMutableArray *records, *newExDates; NSDictionary *cycleinfo; + NSEnumerator *exDatesList; NGCalendarDateRange *firstRange, *recurrenceRange, *oneRange; NSArray *rules, *exRules, *exDates, *ranges; NSArray *elements, *components; @@ -861,6 +862,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir iCalEvent *component; iCalTimeZone *eventTimeZone; unsigned count, max, offset; + id exDate; content = [theRecord objectForKey: @"c_cycleinfo"]; if (![content isNotNull]) @@ -935,6 +937,17 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir [firstEndDate setTimeZone: timeZone]; firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate endDate: firstEndDate]; + + // Adjust the exception dates + exDatesList = [exDates objectEnumerator]; + newExDates = [NSMutableArray arrayWithCapacity: [exDates count]]; + while ((exDate = [exDatesList nextObject])) + { + exDate = [[exDate asCalendarDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 + seconds:-offset]; + [newExDates addObject: exDate]; + } + exDates = newExDates; } } diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index 932f952e0..a51b85d3a 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -91,11 +91,6 @@ iCalEvent *newOccurence, *master; NSCalendarDate *date, *firstDate; unsigned int interval, nbrDays; - SOGoUserDefaults *ud; - NSTimeZone *timeZone; - - ud = [[SOGoUser userWithLogin: owner] userDefaults]; - timeZone = [ud timeZone]; newOccurence = (iCalEvent *) [super newOccurenceWithID: theRecurrenceID]; date = [newOccurence recurrenceId]; @@ -109,7 +104,7 @@ { nbrDays = ((float) abs (interval) / 86400) + 1; [newOccurence setAllDayWithStartDate: date - duration: nbrDays]; + duration: nbrDays]; } else { @@ -121,7 +116,7 @@ minute: 0 second: interval]]; } - + return newOccurence; } diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index eeef92092..5e06a17ba 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -1218,7 +1218,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, return [self component: YES secure: NO]; } -#warning alarms: we don not handle occurrences +#warning alarms: we do not handle occurrences - (NSException *) prepareDelete { if ([[SOGoSystemDefaults sharedSystemDefaults] enableEMailAlarms]) diff --git a/SoObjects/Appointments/SOGoComponentOccurence.m b/SoObjects/Appointments/SOGoComponentOccurence.m index 831181307..938f76541 100644 --- a/SoObjects/Appointments/SOGoComponentOccurence.m +++ b/SoObjects/Appointments/SOGoComponentOccurence.m @@ -1,8 +1,9 @@ /* SOGoComponentOccurence.m - this file is part of SOGo * - * Copyright (C) 2008-2010 Inverse inc. + * Copyright (C) 2008-2011 Inverse inc. * * Author: Wolfgang Sourdeau + * Francis Lachapelle * * 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 @@ -25,8 +26,15 @@ #import #import +#import +#import #import +#import + +#import +#import + #import "SOGoAppointmentObject.h" #import "SOGoCalendarComponent.h" @@ -144,8 +152,10 @@ NSCalendarDate *recurrenceId, *currentId; NSException *error; NSString *newContent; + NSTimeZone *timeZone; iCalCalendar *calendar; iCalEntityObject *currentOccurence; + SOGoUserDefaults *ud; int max, count; if (component == master) @@ -155,10 +165,7 @@ if ([container respondsToSelector: @selector (prepareDeleteOccurence:)]) [container prepareDeleteOccurence: component]; - // Add an date exception recurrenceId = [component recurrenceId]; - [master addToExceptionDates: recurrenceId]; - [master increaseSequence]; // Remove the specified occurence within the repeating vEvent. calendar = [master parent]; @@ -177,6 +184,18 @@ count++; } + // Add an date exception + if ([master respondsToSelector: @selector (isAllDay)] && [(iCalEvent *)master isAllDay]) + { + // We're deleting an occurrence of an all-day event; adjust the recurrence id + // to the user's timezone. + ud = [[context activeUser] userDefaults]; + timeZone = [ud timeZone]; + [recurrenceId setTimeZone: timeZone]; + } + [master addToExceptionDates: recurrenceId]; + [master increaseSequence]; + // We generate the updated iCalendar file and we save it // in the database. newContent = [calendar versitString]; @@ -186,9 +205,9 @@ return error; } -- (void) saveComponent: (iCalRepeatableEntityObject *) newEvent +- (NSException *) saveComponent: (iCalRepeatableEntityObject *) newObject { - [container saveComponent: newEvent]; + return [container saveComponent: newObject]; } #warning most of SOGoCalendarComponent and SOGoComponentOccurence share the same external interface... \ diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index 7945a906b..d7c9a8b3c 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -525,19 +525,19 @@ inContext: (WOContext *) _ctx { int nbrDays; + iCalDateTime *startDate; + iCalTimeZone *tz; SOGoUserDefaults *ud; - [self event]; - + [self event]; [super takeValuesFromRequest: _rq inContext: _ctx]; - if (isAllDay) { nbrDays = ((float) abs ([aptEndDate timeIntervalSinceDate: aptStartDate]) / 86400) + 1; [event setAllDayWithStartDate: aptStartDate - duration: nbrDays]; + duration: nbrDays]; } else { @@ -545,20 +545,33 @@ [event setEndDate: aptEndDate]; } - if ([[self clientObject] isNew]) + if (!isAllDay) { - iCalTimeZone *tz; - - // Don't add a vTimeZone to all-day events - if (!isAllDay) - { - ud = [[context activeUser] userDefaults]; - - tz = [iCalTimeZone timeZoneForName: [ud timeZoneName]]; - [[event parent] addTimeZone: tz]; - [(iCalDateTime *)[event uniqueChildWithTag: @"dtstart"] setTimeZone: tz]; - [(iCalDateTime *)[event uniqueChildWithTag: @"dtend"] setTimeZone: tz]; - } + // Make sure there's a vTimeZone associated to the event unless it + // is an all-day event. + startDate = (iCalDateTime *)[event uniqueChildWithTag: @"dtstart"]; + if (![startDate timeZone]) + { + ud = [[context activeUser] userDefaults]; + tz = [iCalTimeZone timeZoneForName: [ud timeZoneName]]; + if ([[event parent] addTimeZone: tz]) + { + [startDate setTimeZone: tz]; + [(iCalDateTime *)[event uniqueChildWithTag: @"dtend"] setTimeZone: tz]; + } + } + } + else if (![[self clientObject] isNew]) + { + // Remove the vTimeZone when dealing with an all-day event. + startDate = (iCalDateTime *)[event uniqueChildWithTag: @"dtstart"]; + tz = [startDate timeZone]; + if (tz) + { + [startDate setTimeZone: nil]; + [(iCalDateTime *)[event uniqueChildWithTag: @"dtend"] setTimeZone: nil]; + [[event parent] removeChild: tz]; + } } [event setTransparency: (isTransparent? @"TRANSPARENT" : @"OPAQUE")];