From: wolfgang Date: Wed, 16 Jan 2008 19:02:28 +0000 (+0000) Subject: git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1317 d1b88da0-ebda-0310... X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=00899d2578fddacecd8076c633ff7604dc7d05a3;p=scalable-opengroupware.org git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1317 d1b88da0-ebda-0310-925b-ed51d893ca5b --- diff --git a/ChangeLog b/ChangeLog index 8832f35d..09f2ec57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,48 @@ +2008-01-16 Wolfgang Sourdeau + + * SoObjects/SOGo/SOGoUser.m ([SOGoUser + +userWithLogin:newLoginroles:newRoles]): try to retrieve the + specified user from the SOGoCache. + + * SoObjects/SOGo/SOGoObject.m ([SOGoObject + -lookupName:lookupNameinContext:localContextacquire:acquire]): try + to retrieve the object specified from the cache and returns it if + it exists. + + * SoObjects/Appointments/SOGoAppointmentFolder.m + ([SOGoAppointmentFolder -lookupName:inContext:acquire:]): cache + the result in the SOGoCache. + + * Main/SOGo.m ([SOGo -dispatchRequest:_request]): initialize and + kill the shared cache before and after the connection processing. + + * SoObjects/SOGo/SOGoCache.[hm]: new cache module implementing a + per-connection cache mechanism. + +2008-01-16 Ludovic Marcotte + + * Minor adjustments / bug fixes to previous commit. + +2008-01-14 Ludovic Marcotte + + * Added files related to the custom recurrence + editor of the SOGo Web interface. The CSS + needs to be done correctly. + + * Fixed a bug in the daily recurrence generator. + We now consider the byDayMask, if any. + + * Moved the repeat/reminder code to the + UIxComponentEditor class / template. + + * Added a few JavaScript methods to HTMLElement.js + +2008-01-08 Francis Lachapelle + + * UI/MailerUI/UIxMailAccountActions.m ([UIxMailAccountActions + -composeAction]): the mailto form parameter can now be a + comma-separated list of email addresses. + 2007-12-21 Ludovic Marcotte * UI/Contacts/UIxContactView.m diff --git a/Main/SOGo.m b/Main/SOGo.m index ac530d56..afb19b09 100644 --- a/Main/SOGo.m +++ b/Main/SOGo.m @@ -42,6 +42,7 @@ #import +#import #import #import #import @@ -56,6 +57,7 @@ @interface SOGo : SoApplication { NSMutableDictionary *localeLUT; + SOGoCache *cache; } - (NSDictionary *) currentLocaleConsideringLanguages:(NSArray *)_langs; @@ -390,7 +392,9 @@ static BOOL debugObjectAllocation = NO; static NSArray *runLoopModes = nil; WOResponse *resp; + cache = [SOGoCache sharedCache]; resp = [super dispatchRequest: _request]; + [SOGoCache killCache]; if (![self isTerminating]) { diff --git a/NEWS b/NEWS index 89447f0b..da541417 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +0.9.0-2008MMDD (1.0 rc4) +------------------------ +- improved the attendees window; + 0.9.0-20071217 (1.0 rc3) ------------------------ - mail folders state is now saved; diff --git a/SOPE/GDLContentStore/ChangeLog b/SOPE/GDLContentStore/ChangeLog index af7d8047..eff43347 100644 --- a/SOPE/GDLContentStore/ChangeLog +++ b/SOPE/GDLContentStore/ChangeLog @@ -1,3 +1,8 @@ +2008-01-16 Wolfgang Sourdeau + + * GCSFolder.m: fetch the content, version and dates at the same + time per record, to avoid multiple queries. + 2007-12-12 Wolfgang Sourdeau * GCSFolder.m ([GCSFolder -creationDateOfEntryWithName:]): new diff --git a/SOPE/GDLContentStore/GCSFolder.h b/SOPE/GDLContentStore/GCSFolder.h index 73b608cc..7e5ea61b 100644 --- a/SOPE/GDLContentStore/GCSFolder.h +++ b/SOPE/GDLContentStore/GCSFolder.h @@ -104,11 +104,8 @@ - (NSArray *)subFolderNames; - (NSArray *)allSubFolderNames; -- (NSNumber *)versionOfContentWithName:(NSString *)_name; -- (NSCalendarDate *)creationDateOfEntryWithName:(NSString *)_name; -- (NSCalendarDate *)lastModificationOfEntryWithName:(NSString *)_name; +- (NSDictionary *) recordOfEntryWithName: (NSString *) name; -- (NSString *)fetchContentWithName:(NSString *)_name; - (NSException *)writeContent:(NSString *)_content toName:(NSString *)_name baseVersion:(unsigned int)_baseVersion; - (NSException *)writeContent:(NSString *)_content toName:(NSString *)_name; diff --git a/SOPE/GDLContentStore/GCSFolder.m b/SOPE/GDLContentStore/GCSFolder.m index f47591e7..552c322b 100644 --- a/SOPE/GDLContentStore/GCSFolder.m +++ b/SOPE/GDLContentStore/GCSFolder.m @@ -251,15 +251,14 @@ static GCSStringFormatter *stringFormatter = nil; recursive:YES]; } -- (id) _fetchValueOfColumn: (NSString *)_col - inContentWithName: (NSString *)_name - ignoreDeleted: (BOOL) ignoreDeleted +- (NSDictionary *) _fetchValueOfColumns: (NSArray *) _cols + inContentWithName: (NSString *) _name + ignoreDeleted: (BOOL) ignoreDeleted { EOAdaptorChannel *channel; NSException *error; NSDictionary *row; NSArray *attrs; - NSString *result; NSMutableString *sql; if ((channel = [self acquireStoreChannel]) == nil) { @@ -271,12 +270,13 @@ static GCSStringFormatter *stringFormatter = nil; sql = [NSMutableString stringWithFormat: @"SELECT %@" @" FROM %@" @" WHERE c_name = '%@'", - _col, [self storeTableName], _name]; + [_cols componentsJoinedByString: @","], + [self storeTableName], _name]; if (ignoreDeleted) [sql appendString: @" AND (c_deleted != 1 OR c_deleted IS NULL)"]; /* run SQL */ - + if ((error = [channel evaluateExpressionX:sql]) != nil) { [self errorWithFormat:@"%s: cannot execute SQL '%@': %@", __PRETTY_FUNCTION__, sql, error]; @@ -286,51 +286,64 @@ static GCSStringFormatter *stringFormatter = nil; /* fetch results */ - result = nil; attrs = [channel describeResults:NO /* do not beautify names */]; - if ((row = [channel fetchAttributes:attrs withZone:NULL]) != nil) { - result = [[[row objectForKey:_col] copy] autorelease]; - if (![result isNotNull]) result = nil; + row = [channel fetchAttributes: attrs withZone: NULL]; + if (row) [channel cancelFetch]; - } /* release and return result */ [self releaseChannel:channel]; - return result; -} -- (NSNumber *)versionOfContentWithName:(NSString *)_name { - return [self _fetchValueOfColumn:@"c_version" inContentWithName:_name - ignoreDeleted: YES]; + return row; } -- (NSCalendarDate *)creationDateOfEntryWithName:(NSString *)_name { - int seconds; - - seconds = [[self _fetchValueOfColumn:@"c_creationdate" inContentWithName:_name - ignoreDeleted: YES] intValue]; +- (NSDictionary *) recordOfEntryWithName: (NSString *) name +{ + NSDictionary *row; + NSMutableDictionary *record; + NSArray *columns; + NSString *strValue; + int intValue; + + columns = [NSArray arrayWithObjects: @"c_content", @"c_version", + @"c_creationdate", @"c_lastmodified", nil]; + row = [self _fetchValueOfColumns: columns + inContentWithName: name + ignoreDeleted: YES]; + if (row) + { + record = [NSMutableDictionary dictionaryWithCapacity: 5]; + strValue = [row objectForKey: @"c_content"]; + if (![strValue isNotNull]) + strValue = @""; + [record setObject: strValue forKey: @"c_content"]; + [record setObject: [row objectForKey: @"c_version"] + forKey: @"c_version"]; + intValue = [[row objectForKey: @"c_creationdate"] intValue]; + [record + setObject: [NSCalendarDate dateWithTimeIntervalSince1970: intValue] + forKey: @"c_creationdate"]; + intValue = [[row objectForKey: @"c_lastmodified"] intValue]; + [record + setObject: [NSCalendarDate dateWithTimeIntervalSince1970: intValue] + forKey: @"c_lastmodified"]; + } + else + record = nil; - return [NSCalendarDate dateWithTimeIntervalSince1970: seconds]; + return record; } -- (NSCalendarDate *)lastModificationOfEntryWithName:(NSString *)_name { - int seconds; - - seconds = [[self _fetchValueOfColumn:@"c_lastmodified" inContentWithName:_name - ignoreDeleted: YES] intValue]; - - return [NSCalendarDate dateWithTimeIntervalSince1970: seconds]; -} +- (NSNumber *) deletionOfEntryWithName: (NSString *) name +{ + NSDictionary *row; -- (NSNumber *)deletionOfContentWithName:(NSString *)_name { - return [self _fetchValueOfColumn:@"c_deleted" inContentWithName:_name - ignoreDeleted: NO]; -} + row = [self _fetchValueOfColumns: [NSArray arrayWithObject: @"c_deleted"] + inContentWithName: name + ignoreDeleted: NO]; -- (NSString *)fetchContentWithName:(NSString *)_name { - return [self _fetchValueOfColumn:@"c_content" inContentWithName:_name - ignoreDeleted: YES]; + return [row objectForKey: @"c_deleted"]; } - (NSDictionary *)fetchContentsOfAllFiles { @@ -571,6 +584,7 @@ static GCSStringFormatter *stringFormatter = nil; { EOAdaptorChannel *storeChannel, *quickChannel; NSMutableDictionary *quickRow, *contentRow; + NSDictionary *currentRow; GCSFieldExtractor *extractor; NSException *error; NSNumber *storedVersion; @@ -598,19 +612,24 @@ static GCSStringFormatter *stringFormatter = nil; if (doLogStore) [self logWithFormat:@"should store content: '%@'\n%@", _name, _content]; - storedVersion = [self versionOfContentWithName:_name]; + currentRow = [self _fetchValueOfColumns: [NSArray arrayWithObjects: + @"c_version", + @"c_deleted", nil] + inContentWithName: _name + ignoreDeleted: NO]; + storedVersion = [currentRow objectForKey: @"c_version"]; if (doLogStore) [self logWithFormat:@" version: %@", storedVersion]; isNewRecord = [storedVersion isNotNull] ? NO : YES; if (!isNewRecord) { - if ([[self deletionOfContentWithName:_name] intValue] > 0) + if ([[currentRow objectForKey: @"c_deleted"] intValue] > 0) { [self _purgeRecordWithName: _name]; isNewRecord = YES; } } - + /* check whether sequence matches */ if (_baseVersion != 0 /* use 0 to override check */) { if (_baseVersion != [storedVersion unsignedIntValue]) { diff --git a/SOPE/NGCards/iCalDailyRecurrenceCalculator.m b/SOPE/NGCards/iCalDailyRecurrenceCalculator.m index 17a1d483..7c7d2656 100644 --- a/SOPE/NGCards/iCalDailyRecurrenceCalculator.m +++ b/SOPE/NGCards/iCalDailyRecurrenceCalculator.m @@ -33,6 +33,8 @@ #import "iCalRecurrenceRule.h" #import "NSCalendarDate+ICal.h" +#include + @interface iCalRecurrenceCalculator(PrivateAPI) - (NSCalendarDate *)lastInstanceStartDate; @end @@ -90,13 +92,23 @@ if ((jnTest % interval) == 0) { NSCalendarDate *start, *end; NGCalendarDateRange *r; - + unsigned int mask; + start = [NSCalendarDate dateForJulianNumber:jnCurrent]; [start setTimeZone:[firStart timeZone]]; start = [start hour: [firStart hourOfDay] minute:[firStart minuteOfHour] second:[firStart secondOfMinute]]; end = [start addTimeInterval:[self->firstRange duration]]; + + // We check if our start date is within the byDayMask + // FIXME: Should we also check the end date? We might want + // to check if the end date is also within it. + if ([self->rrule byDayMask]) { + mask = [start dayOfWeek] == 0 ? iCalWeekDaySunday : (unsigned int)exp2([start dayOfWeek]-1); + if (([self->rrule byDayMask]&mask) != mask) continue; + } + r = [NGCalendarDateRange calendarDateRangeWithStartDate:start endDate:end]; if ([_r containsDateRange:r]) diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 5be6e558..da40ac84 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -48,6 +48,7 @@ #import // #import +#import #import #import #import @@ -403,6 +404,11 @@ static NSNumber *sharedYes = nil; obj = [NSException exceptionWithHTTPStatus:404 /* Not Found */]; } + if (obj) + [[SOGoCache sharedCache] registerObject: obj + withName: _key + inContainer: container]; + return obj; } diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index c8ed4eb3..33dd2b6e 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -126,7 +126,7 @@ static BOOL sendEMailNotifications = NO; sm = [SoSecurityManager sharedSecurityManager]; if (![sm validatePermission: SOGoCalendarPerm_ViewAllComponent onObject: self inContext: context]) - iCalString = content; + iCalString = [record objectForKey: @"c_content"]; else if (![sm validatePermission: SOGoCalendarPerm_ViewDAndT onObject: self inContext: context]) { @@ -165,7 +165,7 @@ static BOOL sendEMailNotifications = NO; if (secure) iCalString = [self secureContentAsString]; else - iCalString = content; + iCalString = [record objectForKey: @"c_content"]; if ([iCalString length] > 0) calendar = [iCalCalendar parseSingleFromSource: iCalString]; diff --git a/SoObjects/Contacts/SOGoContactGCSEntry.m b/SoObjects/Contacts/SOGoContactGCSEntry.m index b56e5a92..b4b8be09 100644 --- a/SoObjects/Contacts/SOGoContactGCSEntry.m +++ b/SoObjects/Contacts/SOGoContactGCSEntry.m @@ -48,8 +48,11 @@ - (NGVCard *) vCard { + NSString *content; + if (!card) { + content = [record objectForKey: @"c_content"]; if ([[content uppercaseString] hasPrefix: @"BEGIN:VCARD"]) card = [NGVCard parseSingleFromSource: content]; else diff --git a/SoObjects/Mailer/SOGoMailAccounts.m b/SoObjects/Mailer/SOGoMailAccounts.m index b09e9092..515c6652 100644 --- a/SoObjects/Mailer/SOGoMailAccounts.m +++ b/SoObjects/Mailer/SOGoMailAccounts.m @@ -104,7 +104,7 @@ static NSString *AgenorShareLoginMarker = @".-."; /* first check attributes directly bound to the application */ if ((obj = [super lookupName:_key inContext:_ctx acquire:NO])) return obj; - + if (![self isInHomeFolderBranchOfLoggedInAccount: userLogin]) { [self warnWithFormat:@ "User %@ tried to access mail hierarchy of %@", userLogin, [container nameInContainer]]; diff --git a/SoObjects/Mailer/SOGoMailObject.m b/SoObjects/Mailer/SOGoMailObject.m index 6c38725f..ec0c2803 100644 --- a/SoObjects/Mailer/SOGoMailObject.m +++ b/SoObjects/Mailer/SOGoMailObject.m @@ -850,7 +850,7 @@ static BOOL debugSoParts = NO; } else clazz = Nil; - + return [clazz objectWithName:_key inContainer: self]; } diff --git a/SoObjects/SOGo/GNUmakefile b/SoObjects/SOGo/GNUmakefile index c99c714e..526cb226 100644 --- a/SoObjects/SOGo/GNUmakefile +++ b/SoObjects/SOGo/GNUmakefile @@ -20,6 +20,7 @@ libSOGo_HEADER_FILES_INSTALL_DIR = /SOGo FHS_HEADER_DIRS = SOGo libSOGo_HEADER_FILES = \ + SOGoCache.h \ SOGoObject.h \ SOGoContentObject.h \ SOGoFolder.h \ @@ -56,6 +57,7 @@ libSOGo_HEADER_FILES = \ WORequest+SOGo.h libSOGo_OBJC_FILES = \ + SOGoCache.m \ SOGoObject.m \ SOGoContentObject.m \ SOGoFolder.m \ diff --git a/SoObjects/SOGo/SOGoContentObject.h b/SoObjects/SOGo/SOGoContentObject.h index 807b9874..3f4cb53e 100644 --- a/SoObjects/SOGo/SOGoContentObject.h +++ b/SoObjects/SOGo/SOGoContentObject.h @@ -31,7 +31,7 @@ @interface SOGoContentObject : SOGoObject { NSString *ocsPath; - NSString *content; + NSDictionary *record; BOOL isNew; } diff --git a/SoObjects/SOGo/SOGoContentObject.m b/SoObjects/SOGo/SOGoContentObject.m index 9665eda9..4aa48503 100644 --- a/SoObjects/SOGo/SOGoContentObject.m +++ b/SoObjects/SOGo/SOGoContentObject.m @@ -49,9 +49,9 @@ if ((self = [super initWithName: newName inContainer: newContainer])) { ocsPath = nil; - content = [[self ocsFolder] fetchContentWithName: newName]; - [content retain]; - isNew = (!content); + record = [[self ocsFolder] recordOfEntryWithName: newName]; + [record retain]; + isNew = (!record); } return self; @@ -59,19 +59,11 @@ - (void) dealloc { - [content release]; + [record release]; [ocsPath release]; [super dealloc]; } -/* notifications */ - -- (void) sleep -{ - [content release]; content = nil; - [super sleep]; -} - /* accessors */ - (BOOL) isFolderish @@ -136,19 +128,25 @@ - (NSString *) contentAsString { - return content; + return [record objectForKey: @"c_content"]; } - (NSException *) saveContentString: (NSString *) newContent baseVersion: (unsigned int) newBaseVersion { /* Note: "iCal multifolder saves" are implemented in the apt subclass! */ - GCSFolder *folder; + GCSFolder *folder; NSException *ex; + NSMutableDictionary *newRecord; ex = nil; - ASSIGN (content, newContent); + if (record) + newRecord = [NSMutableDictionary dictionaryWithDictionary: record]; + else + newRecord = [NSMutableDictionary dictionary]; + [newRecord setObject: newContent forKey: @"c_content"]; + ASSIGN (record, newRecord); folder = [container ocsFolder]; if (folder) @@ -307,7 +305,7 @@ folder = [self ocsFolder]; if (folder) { - versionValue = [folder versionOfContentWithName: [self nameInContainer]]; + versionValue = [record objectForKey: @"c_version"]; sprintf (buf, "\"gcs%08d\"", [versionValue unsignedIntValue]); entityTag = [NSString stringWithCString: buf]; } @@ -325,7 +323,7 @@ { NSCalendarDate *date; - date = [[self ocsFolder] creationDateOfEntryWithName: nameInContainer]; + date = [record objectForKey: @"c_creationdate"]; return [date rfc822DateString]; } @@ -334,16 +332,19 @@ { NSCalendarDate *date; - date = [[self ocsFolder] lastModificationOfEntryWithName: nameInContainer]; + date = [record objectForKey: @"c_lastmodified"]; return [date rfc822DateString]; } - (NSString *) davContentLength { + NSString *content; + + content = [record objectForKey: @"c_content"]; + return [NSString stringWithFormat: @"%u", - [content - lengthOfBytesUsingEncoding: NSISOLatin1StringEncoding]]; + [content lengthOfBytesUsingEncoding: NSISOLatin1StringEncoding]]; } - (NSException *) davMoveToTargetObject: (id) _target diff --git a/SoObjects/SOGo/SOGoObject.m b/SoObjects/SOGo/SOGoObject.m index 8bb51066..9c5fbcee 100644 --- a/SoObjects/SOGo/SOGoObject.m +++ b/SoObjects/SOGo/SOGoObject.m @@ -62,6 +62,7 @@ #import "NSDictionary+Utilities.h" #import "NSString+Utilities.h" +#import "SOGoCache.h" #import "SOGoObject.h" @interface SOGoObject(Content) @@ -560,10 +561,19 @@ static BOOL kontactGroupDAV = YES; acquire: (BOOL) acquire { id obj; + SOGoCache *cache; - obj = [[self soClass] lookupKey: lookupName inContext: localContext]; - if (obj) - [obj bindToObject: self inContext: localContext]; + cache = [SOGoCache sharedCache]; + obj = [cache objectNamed: lookupName inContainer: self]; + if (!obj) + { + obj = [[self soClass] lookupKey: lookupName inContext: localContext]; + if (obj) + { + [obj bindToObject: self inContext: localContext]; + [cache registerObject: obj withName: lookupName inContainer: self]; + } + } return obj; } diff --git a/SoObjects/SOGo/SOGoUser.m b/SoObjects/SOGo/SOGoUser.m index 9c7bd9d3..fe0aa2a6 100644 --- a/SoObjects/SOGo/SOGoUser.m +++ b/SoObjects/SOGo/SOGoUser.m @@ -32,10 +32,11 @@ #import "AgenorUserDefaults.h" #import "LDAPUserManager.h" +#import "NSArray+Utilities.h" +#import "SOGoCache.h" #import "SOGoDateFormatter.h" #import "SOGoObject.h" #import "SOGoPermissions.h" -#import "NSArray+Utilities.h" #import "SOGoUser.h" @@ -124,10 +125,18 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek"; + (SOGoUser *) userWithLogin: (NSString *) newLogin roles: (NSArray *) newRoles { + SOGoCache *cache; SOGoUser *user; - user = [[self alloc] initWithLogin: newLogin roles: newRoles]; - [user autorelease]; + cache = [SOGoCache sharedCache]; + user = [cache userNamed: newLogin]; + if (!user) + { + user = [[self alloc] initWithLogin: newLogin roles: newRoles]; + [user autorelease]; + [cache registerUser: user]; + } + [user setPrimaryRoles: newRoles]; return user; } @@ -181,6 +190,11 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek"; [super dealloc]; } +- (void) setPrimaryRoles: (NSArray *) newRoles +{ + ASSIGN (roles, newRoles); +} + - (void) setCurrentPassword: (NSString *) newPassword { ASSIGN (currentPassword, newPassword); diff --git a/UI/MailerUI/UIxMailAccountActions.m b/UI/MailerUI/UIxMailAccountActions.m index ea243bca..cb54d667 100644 --- a/UI/MailerUI/UIxMailAccountActions.m +++ b/UI/MailerUI/UIxMailAccountActions.m @@ -1,6 +1,6 @@ /* UIxMailAccountActions.m - this file is part of SOGo * - * Copyright (C) 2007 Inverse groupe conseil + * Copyright (C) 2007, 2008 Inverse groupe conseil * * Author: Wolfgang Sourdeau * @@ -157,7 +157,7 @@ value = [[self request] formValueForKey: @"mailto"]; if ([value length] > 0) { - mailTo = [NSArray arrayWithObject: value]; + mailTo = [value componentsSeparatedByString: @","]; [newDraftMessage setHeaders: [NSDictionary dictionaryWithObject: mailTo forKey: @"to"]]; diff --git a/UI/Scheduler/English.lproj/Localizable.strings b/UI/Scheduler/English.lproj/Localizable.strings index c6e1c5b0..21caedce 100644 --- a/UI/Scheduler/English.lproj/Localizable.strings +++ b/UI/Scheduler/English.lproj/Localizable.strings @@ -21,6 +21,14 @@ "Friday" = "Friday"; "Saturday" = "Saturday"; +"Sun" = "Sun"; +"Mon" = "Mon"; +"Tue" = "Tue"; +"Wed" = "Wed"; +"Thu" = "Thu"; +"Fri" = "Fri"; +"Sat" = "Sat"; + "a2_Sunday" = "Su"; "a2_Monday" = "Mo"; "a2_Tuesday" = "Tu"; @@ -87,6 +95,9 @@ "Reload Remote Calendars" = "Reload Remote Calendars"; "Properties" = "Properties"; +"Compose E-Mail to All Attendees" = "Compose E-Mail to All Attendees"; +"Compose E-Mail to Undecided Attendees" = "Compose E-Mail to Undecided Attendees"; + /* Folders */ "Personal calendar" = "Personal calendar"; @@ -288,6 +299,35 @@ "cycle_end_never" = "cycle_end_never"; "cycle_end_until" = "cycle_end_until"; +"Recurrence pattern" = "Recurrence pattern"; +"Range of recurrence" = "Range of recurrence"; + +"Repeat" = "Repeat"; +"Daily" = "Daily"; +"Weekly" = "Weekly"; +"Monthly" = "Monthly"; +"Yearly" = "Yearly"; +"Every" = "Every"; +"Days" = "Days"; +"Week(s)" = "Week(s)"; +"On" = "On"; +"Month(s)" = "Month(s)"; +"The" = "The"; +"Recur on day(s)" = "Recur on day(s)"; +"Year(s)" = "Year(s)"; +"cycle_of" = "of"; +"No end date" = "No end date"; +"Create" = "Create"; +"Appointment(s)" = "Appointment(s)"; +"Repeat until" = "Repeat until"; + +"First" = "First"; +"Second" = "Second"; +"Third" = "Third"; +"Fourth" = "Fourth"; +"Fift" = "Fift"; +"Last" = "Last"; + /* Appointment categories */ "category_NONE" = "None"; @@ -348,7 +388,7 @@ validate_notitle = "No title is set, continue?"; validate_invalid_startdate = "Incorrect startdate field!"; validate_invalid_enddate = "Incorrect enddate field!"; -validate_endbeforestart = "The end date that you enteterd occurs before the start date."; +validate_endbeforestart = "The end date that you entered occurs before the start date."; "Tasks" = "Tasks"; "Show completed tasks" = "Show completed tasks"; @@ -424,4 +464,4 @@ vtodo_class2 = "(Confidential task)"; "closeThisWindowMessage" = "Thank you! You may now close this window or view your "; "Multicolumn Day View" = "Multicolumn Day View"; -"Please select an event or a task." = "Please select an event or a task."; \ No newline at end of file +"Please select an event or a task." = "Please select an event or a task."; diff --git a/UI/Scheduler/French.lproj/Localizable.strings b/UI/Scheduler/French.lproj/Localizable.strings index 725f0358..2ade4874 100644 --- a/UI/Scheduler/French.lproj/Localizable.strings +++ b/UI/Scheduler/French.lproj/Localizable.strings @@ -21,6 +21,14 @@ "Friday" = "Vendredi"; "Saturday" = "Samedi"; +"Sun" = "Dim"; +"Mon" = "Lun"; +"Tue" = "Mar"; +"Wed" = "Mer"; +"Thu" = "Jeu"; +"Fri" = "Ven"; +"Sat" = "Sam"; + "a2_Sunday" = "Di"; "a2_Monday" = "Lu"; "a2_Tuesday" = "Ma"; @@ -88,6 +96,9 @@ "Reload Remote Calendars" = "Recharger les agendas distants"; "Properties" = "Propriétés"; +"Compose E-Mail to All Attendees" = "Rédiger un courriel pour tous les participants"; +"Compose E-Mail to Undecided Attendees" = "Rédiger un courriel pour les participants indécis"; + /* Folders */ "Personal calendar" = "Agenda personnel"; @@ -286,6 +297,35 @@ "cycle_end_never" = "Jamais"; "cycle_end_until" = "À la date :"; +"Recurrence pattern" = "Définir la fréquence"; +"Range of recurrence" = "Fenêtre de répétition"; + +"Repeat" = "Répétition"; +"Daily" = "quotidienne"; +"Weekly" = "hebdomadaire"; +"Monthly" = "mensuelle"; +"Yearly" = "annuelle"; +"Every" = "Chaque"; +"Days" = "Jours"; +"Week(s)" = "Semaine(s)"; +"On" = "Le"; +"Month(s)" = "Mois"; +"The" = "Le"; +"Recur on day(s)" = "Se répète le(s) jour(s)"; +"Year(s)" = "Année(s)"; +"cycle_of" = "de"; +"No end date" = "Pas de date de fin"; +"Create" = "Créer"; +"Appointment(s)" = "Rendez-vous"; +"Repeat until" = "Répéter jusqu'à"; + +"First" = "premier"; +"Second" = "deuxieme"; +"Third" = "troisieme"; +"Fourth" = "quatrieme"; +"Fift" = "cinquieme"; +"Last" = "dernier"; + /* Appointment categories */ "category_NONE" = "Aucune"; @@ -312,12 +352,12 @@ "category_VACATION" = "Absence"; "repeat_NEVER" = "Ne se répète pas"; -"repeat_DAILY" = "quotidiennement"; -"repeat_WEEKLY" = "hebdomadairement"; -"repeat_BI-WEEKLY" = "bi-hebdomadairement"; -"repeat_EVERY WEEKDAY" = "les jours ouvrables"; -"repeat_MONTHLY" = "mensuellement"; -"repeat_YEARLY" = "annuellement"; +"repeat_DAILY" = "Quotidiennement"; +"repeat_WEEKLY" = "Hebdomadairement"; +"repeat_BI-WEEKLY" = "Bi-hebdomadairement"; +"repeat_EVERY WEEKDAY" = "Chaque jour ouvrable"; +"repeat_MONTHLY" = "Mensuellement"; +"repeat_YEARLY" = "Annuellement"; "repeat_CUSTOM" = "Personnaliser..."; "reminder_NONE" = "Pas de rappel"; diff --git a/UI/Scheduler/GNUmakefile b/UI/Scheduler/GNUmakefile index aab7f028..92f59324 100644 --- a/UI/Scheduler/GNUmakefile +++ b/UI/Scheduler/GNUmakefile @@ -41,7 +41,8 @@ SchedulerUI_OBJC_FILES = \ UIxTimeDateControl.m \ UIxCalParticipationStatusView.m \ UIxCalMonthOverview.m \ - UIxCalMonthViewOld.m + UIxCalMonthViewOld.m \ + UIxRecurrenceEditor.m SchedulerUI_RESOURCE_FILES += \ Version \ diff --git a/UI/Scheduler/German.lproj/Localizable.strings b/UI/Scheduler/German.lproj/Localizable.strings index 15ab3145..2991e771 100644 --- a/UI/Scheduler/German.lproj/Localizable.strings +++ b/UI/Scheduler/German.lproj/Localizable.strings @@ -10,6 +10,14 @@ "Friday" = "Freitag"; "Saturday" = "Samstag"; +"Sun" = "Son"; +"Mon" = "Mon"; +"Tue" = "Die"; +"Wed" = "Mit"; +"Thu" = "Don"; +"Fri" = "Fre"; +"Sat" = "Sam"; + "a2_Sunday" = "So"; "a2_Monday" = "Mo"; "a2_Tuesday" = "Di"; @@ -76,6 +84,9 @@ "Reload Remote Calendars" = "Externe Kalender neu laden"; "Properties" = "Einstellungen"; +"Compose E-Mail to All Attendees" = "E-Mail an alle Teilnehmer erstellen"; +"Compose E-Mail to Undecided Attendees" = "E-Mail an unentschlossene Teilnehmer erstellen"; + /* Folders */ "Personal calendar" = "Personal calendar"; @@ -274,6 +285,35 @@ "cycle_end_never" = "Unendlich oft wiederholen"; "cycle_end_until" = "Wiederholen bis :"; +"Recurrence pattern" = "Wiederholungsschema"; +"Range of recurrence" = "Bereich der Wiederholung"; + +"Repeat" = "Wiederhole"; +"Daily" = "Daily"; +"Weekly" = "Weekly"; +"Monthly" = "Monthly"; +"Yearly" = "Yearly"; +"Every" = "Jeden"; +"Days" = "Tage"; +"Week(s)" = "Woche(n)"; +"On" = "On"; +"Month(s)" = "Monat(e)"; +"The" = "Der"; +"Recur on day(s)" = "Wiederholung an Tag(en) "; +"Year(s)" = "Jahr(e)"; +"cycle_of" = "of"; +"No end date" = "Kein Enddatum"; +"Create" = "Erstellen"; +"Appointment(s)" = "Verabredung(en)"; +"Repeat until" = "Wiederhole bis"; + +"First" = "Erste"; +"Second" = "Zweite"; +"Third" = "Dritte"; +"Fourth" = "Vierte"; +"Fift" = "Fünfte"; +"Last" = "Letzter"; + /* Appointment categories */ "category_NONE" = "Keine"; diff --git a/UI/Scheduler/UIxAppointmentEditor.h b/UI/Scheduler/UIxAppointmentEditor.h index c3ead685..fba6ed39 100644 --- a/UI/Scheduler/UIxAppointmentEditor.h +++ b/UI/Scheduler/UIxAppointmentEditor.h @@ -35,7 +35,6 @@ NSCalendarDate *aptStartDate; NSCalendarDate *aptEndDate; NSString *item; - NSString *repeat; } /* template values */ @@ -52,12 +51,6 @@ - (void) setAptEndDate: (NSCalendarDate *) _date; - (NSCalendarDate *) aptEndDate; -- (NSString *) repeat; -- (void) setRepeat: (NSString *) newRepeat; - -- (NSString *) reminder; -- (void) setReminder: (NSString *) newReminder; - @end #endif /* UIXAPPOINTMENTEDITOR_H */ diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index 382ff96d..a1c33099 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -51,7 +51,6 @@ aptEndDate = nil; item = nil; event = nil; - repeat = nil; isAllDay = NO; } @@ -61,7 +60,6 @@ - (void) dealloc { [item release]; - [repeat release]; [aptStartDate release]; [aptEndDate release]; [super dealloc]; @@ -121,39 +119,6 @@ return aptEndDate; } -- (NSArray *) repeatList -{ - static NSArray *repeatItems = nil; - - if (!repeatItems) - { - repeatItems = [NSArray arrayWithObjects: @"DAILY", - @"WEEKLY", - @"BI-WEEKLY", - @"EVERY WEEKDAY", - @"MONTHLY", - @"YEARLY", - @"-", - @"CUSTOM", - nil]; - [repeatItems retain]; - } - - return repeatItems; -} - -- (NSString *) itemRepeatText -{ - NSString *text; - - if ([item isEqualToString: @"-"]) - text = item; - else - text = [self labelForKey: [NSString stringWithFormat: @"repeat_%@", item]]; - - return text; -} - - (void) setItem: (NSString *) newItem { ASSIGN (item, newItem); @@ -164,76 +129,6 @@ return item; } -- (NSArray *) reminderList -{ - static NSArray *reminderItems = nil; - - if (!reminderItems) - { - reminderItems = [NSArray arrayWithObjects: @"5_MINUTES_BEFORE", - @"10_MINUTES_BEFORE", - @"15_MINUTES_BEFORE", - @"30_MINUTES_BEFORE", - @"45_MINUTES_BEFORE", - @"-", - @"1_HOUR_BEFORE", - @"2_HOURS_BEFORE", - @"5_HOURS_BEFORE", - @"15_HOURS_BEFORE", - @"-", - @"1_DAY_BEFORE", - @"2_DAYS_BEFORE", - @"1_WEEK_BEFORE", - @"-", - @"CUSTOM", - nil]; - [reminderItems retain]; - } - - return reminderItems; -} - -// - (void) setReminder: (NSString *) reminder -// { -// ASSIGN(reminder, _reminder); -// } - -// - (NSString *) reminder -// { -// return reminder; -// } - -- (NSString *) reminder -{ - return @""; -} - -- (void) setReminder: (NSString *) newReminder -{ -} - -- (NSString *) itemReminderText -{ - NSString *text; - - if ([item isEqualToString: @"-"]) - text = item; - else - text = [self labelForKey: [NSString stringWithFormat: @"reminder_%@", item]]; - - return text; -} - -- (NSString *) repeat -{ - return repeat; -} - -- (void) setRepeat: (NSString *) newRepeat -{ - ASSIGN (repeat, newRepeat); -} - /* actions */ - (NSCalendarDate *) newStartDate { @@ -269,7 +164,6 @@ NSCalendarDate *startDate, *endDate; NSString *duration; unsigned int minutes; - iCalRecurrenceRule *rule; [self event]; if ([[self clientObject] isNew]) @@ -297,41 +191,6 @@ ASSIGN (aptStartDate, startDate); ASSIGN (aptEndDate, endDate); - // We initialize our repeat ivars - if ([event hasRecurrenceRules]) - { - repeat = @"CUSTOM"; - - 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; } @@ -380,7 +239,6 @@ { SOGoAppointmentObject *clientObject; int nbrDays; - iCalRecurrenceRule *rule; clientObject = [self clientObject]; [self event]; @@ -401,42 +259,6 @@ } 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)) - { - rule = [iCalRecurrenceRule new]; - - [rule setInterval: @"1"]; - 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]; - } - else if ([repeat caseInsensitiveCompare: @"MONTHLY"] == NSOrderedSame) - { - [rule setNamedValue: @"bymonthday" - to: [NSString stringWithFormat: @"%d", [aptStartDate dayOfMonth]]]; - [rule setFrequency: iCalRecurrenceFrequenceMonthly]; - } - else - [rule setFrequency: - (iCalRecurrenceFrequency) [rule valueForFrequency: repeat]]; - [event setRecurrenceRules: [NSArray arrayWithObject: rule]]; - [rule release]; - } } // TODO: add tentatively diff --git a/UI/Scheduler/UIxCalFilterPanel.m b/UI/Scheduler/UIxCalFilterPanel.m index 43437336..f29c6594 100644 --- a/UI/Scheduler/UIxCalFilterPanel.m +++ b/UI/Scheduler/UIxCalFilterPanel.m @@ -104,11 +104,7 @@ static NSArray *filters = nil; - (NSString *) filterLabel { -#if 1 - return [[[self context] page] labelForKey: [self valueForKey:@"filter"]]; -#else - return [self valueForKey: @"filter"]; -#endif + return [self labelForKey: [self valueForKey:@"filter"]]; } - (NSString *) selectedFilter diff --git a/UI/Scheduler/UIxCalendarSelector.h b/UI/Scheduler/UIxCalendarSelector.h index 21feda2f..05ffa06f 100644 --- a/UI/Scheduler/UIxCalendarSelector.h +++ b/UI/Scheduler/UIxCalendarSelector.h @@ -1,6 +1,6 @@ /* UIxCalendarSelector.h - this file is part of SOGo * - * Copyright (C) 2007 Inverse groupe conseil + * Copyright (C) 2007, 2008 Inverse groupe conseil * * Author: Wolfgang Sourdeau * @@ -41,6 +41,8 @@ - (void) setCurrentCalendar: (NSDictionary *) newCalendar; - (NSDictionary *) currentCalendar; +- (WOResponse *) calendarsListAction; + @end #endif /* UIXCALENDARSELECTOR_H */ diff --git a/UI/Scheduler/UIxCalendarSelector.m b/UI/Scheduler/UIxCalendarSelector.m index 1e49c8e2..743375ee 100644 --- a/UI/Scheduler/UIxCalendarSelector.m +++ b/UI/Scheduler/UIxCalendarSelector.m @@ -1,6 +1,6 @@ /* UIxCalendarSelector.m - this file is part of SOGo * - * Copyright (C) 2007 Inverse groupe conseil + * Copyright (C) 2007, 2008 Inverse groupe conseil * * Author: Wolfgang Sourdeau * @@ -24,8 +24,11 @@ #import #import +#import + #import +#import #import #import @@ -171,4 +174,16 @@ colorForNumber (unsigned int number) keysWithFormat: @"color: %{color}; background-color: %{color};"]; } +- (WOResponse *) calendarsListAction +{ + WOResponse *response; + + response = [self responseWithStatus: 200]; + [response setHeader: @"text/plain; charset=utf-8" + forKey: @"content-type"]; + [response appendContentString: [[self calendars] jsonRepresentation]]; + + return response; +} + @end /* UIxCalendarSelector */ diff --git a/UI/Scheduler/UIxComponentEditor.h b/UI/Scheduler/UIxComponentEditor.h index e6172e00..55bf5739 100644 --- a/UI/Scheduler/UIxComponentEditor.h +++ b/UI/Scheduler/UIxComponentEditor.h @@ -64,6 +64,22 @@ NSString *attendeesUIDs; NSString *attendeesEmails; NSString *attendeesStates; + + NSString *repeat; + NSString *reminder; + + /* ugly */ + NSString *repeatType; + NSString *repeat1; + NSString *repeat2; + NSString *repeat3; + NSString *repeat4; + NSString *repeat5; + NSString *repeat6; + NSString *repeat7; + + NSString *range1; + NSString *range2; } - (NSString *) toolbar; @@ -120,6 +136,15 @@ - (void) setAttendeesEmails: (NSString *) newAttendeesEmails; - (NSString *) attendeesEmails; +- (NSString *) repeat; +- (void) setRepeat: (NSString *) newRepeat; + +- (NSString *) reminder; +- (void) setReminder: (NSString *) newReminder; + +////////////////////////////////// JUNK //////////////////////////////////////// +////////////////////////////////// JUNK //////////////////////////////////////// +////////////////////////////////// JUNK //////////////////////////////////////// - (NSArray *) cycles; - (void) setCycle: (NSDictionary *) _cycle; - (NSDictionary *) cycle; @@ -136,6 +161,9 @@ - (BOOL) isCycleEndUntil; - (void) setIsCycleEndUntil; - (void) setIsCycleEndNever; +////////////////////////////////// JUNK //////////////////////////////////////// +////////////////////////////////// JUNK //////////////////////////////////////// +////////////////////////////////// JUNK //////////////////////////////////////// /* access */ - (BOOL) isMyComponent; diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index cddb44ee..789f21f7 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -58,6 +58,14 @@ #import "UIxComponentEditor.h" +#define REPEAT(X) \ +- (NSString *) repeat##X { return repeat##X; } \ +- (void) setRepeat##X: (NSString *) theValue { NSLog(@"setRepeat %@", theValue); ASSIGN(repeat##X, theValue); } \ + +#define RANGE(X) \ +- (NSString *) range##X { return range##X; } \ +- (void) setRange##X: (NSString *) theValue { ASSIGN(range##X, theValue); } + @implementation UIxComponentEditor - (id) init @@ -75,6 +83,18 @@ attendeesEmails = nil; attendeesStates = nil; calendarList = nil; + repeat = nil; + reminder = nil; + repeatType = nil; + repeat1 = nil; + repeat2 = nil; + repeat3 = nil; + repeat4 = nil; + repeat5 = nil; + repeat6 = nil; + repeat7 = nil; + range1 = nil; + range2 = nil; } return self; @@ -100,6 +120,20 @@ [attendeesStates release]; [calendarList release]; + [repeat release]; + [reminder release]; + + [repeatType release]; + [repeat1 release]; + [repeat2 release]; + [repeat3 release]; + [repeat4 release]; + [repeat5 release]; + [repeat6 release]; + [repeat7 release]; + [range1 release]; + [range2 release]; + [component release]; [super dealloc]; @@ -160,6 +194,149 @@ } } +- (NSString *) _dayMaskToInteger: (unsigned int) theMask +{ + NSMutableString *s; + unsigned int i; + + unsigned char maskDays[] = { iCalWeekDayMonday, iCalWeekDayTuesday, + iCalWeekDayWednesday, iCalWeekDayThursday, + iCalWeekDayFriday, iCalWeekDaySaturday, + iCalWeekDaySunday }; + + s = [NSMutableString string]; + + for (i = 0; i < 7; i++) + { + if ((theMask&maskDays[i]) == maskDays[i]) + [s appendFormat: @"%d,", i+1]; + } + + if ([s length]) + return [s substringToIndex: [s length]-1]; + + return s; +} + +- (void) _loadRRules +{ + // We initialize our repeat ivars + if ([component hasRecurrenceRules]) + { + iCalRecurrenceRule *rule; + + [self setRepeat: @"CUSTOM"]; + + rule = [[component recurrenceRules] lastObject]; + + if ([rule frequency] == iCalRecurrenceFrequenceDaily) + { + repeatType = @"0"; + + if ([rule byDayMask] == (iCalWeekDayMonday + | iCalWeekDayTuesday + | iCalWeekDayWednesday + | iCalWeekDayThursday + | iCalWeekDayFriday)) + { + if ([rule isInfinite]) + { + repeat = @"EVERY WEEKDAY"; + } + repeat1 = @"1"; + } + else + { + repeat1 = @"0"; + + if ([rule repeatInterval] == 1 && [rule isInfinite]) + { + repeat = @"DAILY"; + } + + [self setRepeat2: [NSString stringWithFormat: @"%d", [rule repeatInterval]]]; + } + } + else if ([rule frequency] == iCalRecurrenceFrequenceWeekly) + { + repeatType = @"1"; + + if (![rule byDayMask]) + { + if ([rule repeatInterval] == 1) + repeat = @"WEEKLY"; + else if ([rule repeatInterval] == 2) + repeat = @"BI-WEEKLY"; + } + else + { + [self setRepeat1: [NSString stringWithFormat: @"%d", [rule repeatInterval]]]; + [self setRepeat2: [self _dayMaskToInteger: [rule byDayMask]]]; + } + } + else if ([rule frequency] == iCalRecurrenceFrequenceMonthly) + { + repeatType = @"2"; + + if ([rule byDayMask]) + { + // TODO + [self setRepeat2: @"0"]; + } + else if ([[rule byMonthDay] count]) + { + [self setRepeat2: @"1"]; + [self setRepeat5: [[rule byMonthDay] componentsJoinedByString: @","]]; + } + else if ([rule repeatInterval] == 1) + repeat = @"MONTHLY"; + + [self setRepeat1: [NSString stringWithFormat: @"%d", [rule repeatInterval]]]; + } + else + { + repeatType = @"3"; + + if ([rule namedValue: @"bymonth"]) + { + if (![rule byDayMask]) + { + [self setRepeat2: @"0"]; + [self setRepeat3: [rule namedValue: @"bymonthday"]]; + [self setRepeat4: [NSString stringWithFormat: @"%d", [[rule namedValue: @"bymonth"] intValue]-1]]; + } + else + { + // TODO + [self setRepeat2: @"1"]; + } + } + else if ([rule repeatInterval] == 1) + repeat = @"YEARLY"; + + [self setRepeat1: [NSString stringWithFormat: @"%d", [rule repeatInterval]]]; + } + + // We decode the proper end date, recurrences count, etc. + if ([rule repeatCount]) + { + [self setRange1: @"1"]; + [self setRange2: [rule namedValue: @"count"]]; + } + else if ([rule untilDate]) + { + [self setRange1: @"2"]; + [self setRange2: [[rule untilDate] descriptionWithCalendarFormat: @"%Y-%m-%d"]]; + } + else + { + [self setRange1: @"0"]; + } + } + else + DESTROY(repeat); +} + /* warning: we use this method which will be triggered by the template system when the page is instantiated, but we should find another and cleaner way of doing this... for example, when the clientObject is set */ @@ -188,6 +365,7 @@ ASSIGN (organizer, [component organizer]); [self _loadCategories]; [self _loadAttendees]; + [self _loadRRules]; } } // /* cycles */ @@ -454,6 +632,109 @@ [NSString stringWithFormat: @"category_%@", item]]; } +- (NSArray *) repeatList +{ + static NSArray *repeatItems = nil; + + if (!repeatItems) + { + repeatItems = [NSArray arrayWithObjects: @"DAILY", + @"WEEKLY", + @"BI-WEEKLY", + @"EVERY WEEKDAY", + @"MONTHLY", + @"YEARLY", + @"-", + @"CUSTOM", + nil]; + [repeatItems retain]; + } + + return repeatItems; +} + +- (NSString *) itemRepeatText +{ + NSString *text; + + if ([item isEqualToString: @"-"]) + text = item; + else + text = [self labelForKey: [NSString stringWithFormat: @"repeat_%@", item]]; + + return text; +} + +- (NSArray *) reminderList +{ + static NSArray *reminderItems = nil; + + if (!reminderItems) + { + reminderItems = [NSArray arrayWithObjects: @"5_MINUTES_BEFORE", + @"10_MINUTES_BEFORE", + @"15_MINUTES_BEFORE", + @"30_MINUTES_BEFORE", + @"45_MINUTES_BEFORE", + @"-", + @"1_HOUR_BEFORE", + @"2_HOURS_BEFORE", + @"5_HOURS_BEFORE", + @"15_HOURS_BEFORE", + @"-", + @"1_DAY_BEFORE", + @"2_DAYS_BEFORE", + @"1_WEEK_BEFORE", + @"-", + @"CUSTOM", + nil]; + [reminderItems retain]; + } + + return reminderItems; +} + +// - (void) setReminder: (NSString *) reminder +// { +// ASSIGN(reminder, _reminder); +// } + +// - (NSString *) reminder +// { +// return reminder; +// } + +- (NSString *) reminder +{ + return @""; +} + +- (void) setReminder: (NSString *) newReminder +{ +} + +- (NSString *) itemReminderText +{ + NSString *text; + + if ([item isEqualToString: @"-"]) + text = item; + else + text = [self labelForKey: [NSString stringWithFormat: @"reminder_%@", item]]; + + return text; +} + +- (NSString *) repeat +{ + return repeat; +} + +- (void) setRepeat: (NSString *) newRepeat +{ + ASSIGN(repeat, newRepeat); +} + - (NSString *) _permissionForEditing { NSString *perm; @@ -612,6 +893,29 @@ return status; } +- (void) setRepeatType: (NSString *) theValue +{ + ASSIGN (repeatType, theValue); +} + +- (NSString *) repeatType +{ + return repeatType; +} + +REPEAT(1); +REPEAT(2); +REPEAT(3); +REPEAT(4); +REPEAT(5); +REPEAT(6); +REPEAT(7); +RANGE(1); +RANGE(2); + +////////////////////////////////// JUNK //////////////////////////////////////// +////////////////////////////////// JUNK //////////////////////////////////////// +////////////////////////////////// JUNK //////////////////////////////////////// - (NSArray *) cycles { NSBundle *bundle; @@ -779,6 +1083,10 @@ { [self setCycleEnd: @"cycle_end_never"]; } +////////////////////////////////// JUNK //////////////////////////////////////// +////////////////////////////////// JUNK //////////////////////////////////////// +////////////////////////////////// JUNK //////////////////////////////////////// + /* helpers */ - (NSString *) completeURIForMethod: (NSString *) _method @@ -985,11 +1293,174 @@ } } +- (void) _handleCustomRRule: (iCalRecurrenceRule *) theRule + +{ + int type, range; + + // We decode the range + range = [[self range1] intValue]; + + // Create X appointments + if (range == 1) + { + [theRule setRepeatCount: [[self range2] intValue]]; + } + // Repeat until date + else if (range == 2) + { + [theRule setUntilDate: [NSCalendarDate dateWithString: [self range2] + calendarFormat: @"%Y-%m-%d"]]; + } + // No end date. + else + { + // Do nothing? + } + + + // We decode the type and the rest accordingly. + type = [[self repeatType] intValue]; + + switch (type) + { + // DAILY: + // + // repeat1 holds the value of the radio button: + // 0 -> Every X days + // 1 -> Every weekday + // + // repeat2 holds the value of X when repeat1 equals 0 + // + case 0: + { + [theRule setFrequency: iCalRecurrenceFrequenceDaily]; + + if ([[self repeat1] intValue] == 0) + { + [theRule setInterval: [self repeat2]]; + } + else + { + [theRule setByDayMask: (iCalWeekDayMonday + |iCalWeekDayTuesday + |iCalWeekDayWednesday + |iCalWeekDayThursday + |iCalWeekDayFriday)]; + } + } + break; + + // WEEKLY + // + // repeat1 holds the value of "Every X week(s)" + // + // repeat2 holds which days are part of the recurrence rule + // 1 -> Monday + // 2 -> Tuesday .. and so on. + // The list is separated by commas, like: 1,3,4 + case 1: + { + NSArray *v; + int c, mask; + + [theRule setFrequency: iCalRecurrenceFrequenceWeekly]; + [theRule setInterval: [self repeat1]]; + + v = [[self repeat2] componentsSeparatedByString: @","]; + c = [v count]; + mask = 0; + + while (c--) + { + mask |= (unsigned int)exp2([[v objectAtIndex: c] intValue]-1); + } + + [theRule setByDayMask: mask]; + } + break; + + // MONTHLY + // + // repeat1 holds the value of "Every X month(s)" + // + // repeat2 holds the value of the radio-button "The" / "Recur on day(s)" + // 0 -> The + // 1 -> Recur on day(s) + // + // repeat3 holds the value of the first popup + // 0 -> First + // 1 -> Second ... and so on. + // + // repeat4 holds the value of the second popop + // 0 -> Sunday + // 1 -> Monday ... and so on. + // 7 -> Day of the month + // + // repeat5 holds the selected days when "Recur on day(s)" + // is chosen. The value starts at 1. + // + case 2: + { + [theRule setFrequency: iCalRecurrenceFrequenceMonthly]; + [theRule setInterval: [self repeat1]]; + + // We recur on specific days... + if ([[self repeat2] intValue] == 1) + { + [theRule setNamedValue: @"bymonthday" to: [self repeat5]]; + } + else + { + // TODO + } + } + break; + + // YEARLY + // + // repeat1 holds the value of "Every X year(s)" + // + // repeat2 holds the value of the radio-button "Every" / "Every .. of .." + // 0 -> Every + // 1 -> Every .. of .. + // + // repeat3 holds the value of the DAY parameter + // repeat4 holds the value of the MONTH parameter (0 -> January, 1 -> February ... ) + // ex: 3 February + // + // repeat5 holds the value of the OCCURENCE parameter (0 -> First, 1 -> Second ..) + // repeat6 holds the value of the DAY parameter (0 -> Sunday, 1 -> Monday, etc..) + // repeat7 holds the value of the MONTH parameter (0 -> January, 1 -> February ... ) + // + case 3: + default: + { + [theRule setFrequency: iCalRecurrenceFrequenceYearly]; + [theRule setInterval: [self repeat1]]; + + // We recur Every .. of .. + if ([[self repeat2] intValue] == 1) + { + // TODO + } + else + { + [theRule setNamedValue: @"bymonthday" to: [self repeat3]]; + [theRule setNamedValue: @"bymonth" + to: [NSString stringWithFormat: @"%d", ([[self repeat4] intValue]+1)]]; + } + } + break; + } +} + - (void) takeValuesFromRequest: (WORequest *) _rq inContext: (WOContext *) _ctx { - NSCalendarDate *now; SOGoCalendarComponent *clientObject; + iCalRecurrenceRule *rule; + NSCalendarDate *now; [super takeValuesFromRequest: _rq inContext: _ctx]; @@ -1011,6 +1482,53 @@ } [component setPriority: priority]; [component setLastModified: now]; + + // We remove any repeat rules + if (!repeat && [component hasRecurrenceRules]) + [component removeAllRecurrenceRules]; + else if ([repeat caseInsensitiveCompare: @"-"] != NSOrderedSame) + { + rule = [iCalRecurrenceRule new]; + + [rule setInterval: @"1"]; + + 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]; + } + else if ([repeat caseInsensitiveCompare: @"MONTHLY"] == NSOrderedSame) + { + [rule setNamedValue: @"bymonthday" + to: [NSString stringWithFormat: @"%d", [[component startDate] dayOfMonth]]]; + [rule setFrequency: iCalRecurrenceFrequenceMonthly]; + } + else if ([repeat caseInsensitiveCompare: @"DAILY"] == NSOrderedSame || + [repeat caseInsensitiveCompare: @"WEEKLY"] == NSOrderedSame || + [repeat caseInsensitiveCompare: @"YEARLY"] == NSOrderedSame) + { + [rule setFrequency: + (iCalRecurrenceFrequency) [rule valueForFrequency: repeat]]; + } + else + { + // We have a CUSTOM recurrence. Let's decode what kind of custome recurrence + // we have and set that. + [self _handleCustomRRule: rule]; + } + + [component setRecurrenceRules: [NSArray arrayWithObject: rule]]; + [rule release]; + } } #warning the following methods probably share some code... diff --git a/UI/Scheduler/UIxTaskEditor.h b/UI/Scheduler/UIxTaskEditor.h index 871593c4..1b503d34 100644 --- a/UI/Scheduler/UIxTaskEditor.h +++ b/UI/Scheduler/UIxTaskEditor.h @@ -52,9 +52,6 @@ - (void) setTaskDueDate: (NSCalendarDate *) _date; - (NSCalendarDate *) taskDueDate; -- (NSString *) repeat; -- (void) setRepeat: (NSString *) newRepeat; - @end #endif /* UIXAPPOINTMENTEDITOR_H */ diff --git a/UI/Scheduler/UIxTaskEditor.m b/UI/Scheduler/UIxTaskEditor.m index 295bbcc7..6b129716 100644 --- a/UI/Scheduler/UIxTaskEditor.m +++ b/UI/Scheduler/UIxTaskEditor.m @@ -138,39 +138,6 @@ return !hasDueDate; } -- (NSArray *) repeatList -{ - static NSArray *repeatItems = nil; - - if (!repeatItems) - { - repeatItems = [NSArray arrayWithObjects: @"DAILY", - @"WEEKLY", - @"BI-WEEKLY", - @"EVERY WEEKDAY", - @"MONTHLY", - @"YEARLY", - @"-", - @"CUSTOM", - nil]; - [repeatItems retain]; - } - - return repeatItems; -} - -- (NSString *) itemRepeatText -{ - NSString *text; - - if ([item isEqualToString: @"-"]) - text = item; - else - text = [self labelForKey: [NSString stringWithFormat: @"repeat_%@", item]]; - - return text; -} - - (NSArray *) statusList { static NSArray *statusItems = nil; @@ -203,15 +170,6 @@ return item; } -- (NSString *) repeat -{ - return @""; -} - -- (void) setRepeat: (NSString *) newRepeat -{ -} - - (NSString *) status { return status; diff --git a/UI/Scheduler/product.plist b/UI/Scheduler/product.plist index 734735ff..5b1c5248 100644 --- a/UI/Scheduler/product.plist +++ b/UI/Scheduler/product.plist @@ -44,6 +44,11 @@ protectedBy = "View"; pageName = "UIxCalDateSelector"; }; + calendarslist = { + protectedBy = "View"; + pageName = "UIxCalendarSelector"; + actionName = "calendarsList"; + }; eventslist = { protectedBy = "View"; actionClass = "UIxCalListingActions"; @@ -97,6 +102,10 @@ protectedBy = "View"; pageName = "UIxAttendeesEditor"; }; + editRecurrence = { + protectedBy = "View"; + pageName = "UIxRecurrenceEditor"; + }; }; }; diff --git a/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox b/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox index 14c3cf60..701eef9d 100644 --- a/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox +++ b/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox @@ -10,7 +10,7 @@ + var:value="pathToAttachment"/>
diff --git a/UI/Templates/SchedulerUI/UIxAppointmentEditor.wox b/UI/Templates/SchedulerUI/UIxAppointmentEditor.wox index 909b253a..34263467 100644 --- a/UI/Templates/SchedulerUI/UIxAppointmentEditor.wox +++ b/UI/Templates/SchedulerUI/UIxAppointmentEditor.wox @@ -11,6 +11,16 @@ var:component="event" var:saveURL="saveURL"> + +