see changelog

Monotone-Parent: 0f4484bf642d11bc96f9672226ec495c99e2301f
Monotone-Revision: b7b4b1f3f729de477db90d41fee55b91ea781b02

Monotone-Author: ludovic@Sophos.ca
Monotone-Date: 2008-01-14T13:57:28
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Ludovic Marcotte 2008-01-14 13:57:28 +00:00
parent 79267d40ce
commit 2d2fcffec5
20 changed files with 1282 additions and 254 deletions

View File

@ -1,3 +1,17 @@
2008-01-14 Ludovic Marcotte <ludovic@inverse.ca>
* 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 <flachapelle@inverse.ca>
* UI/MailerUI/UIxMailAccountActions.m ([UIxMailAccountActions

View File

@ -33,6 +33,8 @@
#import "iCalRecurrenceRule.h"
#import "NSCalendarDate+ICal.h"
#include <math.h>
@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])

View File

@ -41,7 +41,8 @@ SchedulerUI_OBJC_FILES = \
UIxTimeDateControl.m \
UIxCalParticipationStatusView.m \
UIxCalMonthOverview.m \
UIxCalMonthViewOld.m
UIxCalMonthViewOld.m \
UIxRecurrenceEditor.m
SchedulerUI_RESOURCE_FILES += \
Version \

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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,160 @@
}
}
- (NSString *) _dayMaskToInteger: (unsigned int) theMask
{
NSMutableString *s;
unsigned int i, v;
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 we either have an end date or a recurrence count
// it's automatically a CUSTOM one.
//if (![rule isInfinite] || [rule repeatInterval] != 1)
// {
// // We initialize the proper ivars
// repeatType = @"1";
// repeat1 = @"1";
// repeat2 = @"1,3,5";
// return;
// }
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)
{
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 +376,7 @@
ASSIGN (organizer, [component organizer]);
[self _loadCategories];
[self _loadAttendees];
[self _loadRRules];
}
}
// /* cycles */
@ -454,6 +643,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 +904,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 +1094,10 @@
{
[self setCycleEnd: @"cycle_end_never"];
}
////////////////////////////////// JUNK ////////////////////////////////////////
////////////////////////////////// JUNK ////////////////////////////////////////
////////////////////////////////// JUNK ////////////////////////////////////////
/* helpers */
- (NSString *) completeURIForMethod: (NSString *) _method
@ -985,11 +1304,171 @@
}
}
- (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)
{
}
// No end date.
else
{
}
// 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 +1490,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...

View File

@ -0,0 +1,54 @@
/* UIxRecurrenceEditor.h - this file is part of SOGo
*
* Copyright (C) 2008 Inverse groupe conseil
*
* Author: Ludovic Marcotte <ludovic@inverse.ca>
*
* 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
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef UIXRECURRENCEEDITOR_H
#define UIXRECURRENCEEDITOR_H
#import <SOGoUI/UIxComponent.h>
@interface UIxRecurrenceEditor : UIxComponent
{
NSString *item, *repeat;
}
- (NSArray *) dailyRadioList;
- (NSArray *) weeklyCheckBoxList;
- (NSArray *) dayMonthList;
- (NSArray *) monthlyRepeatList;
- (NSArray *) monthlyDayList;
- (NSArray *) monthlyRadioList;
- (NSArray *) yearlyMonthList;
- (NSArray *) yearlyDayList;
- (NSArray *) rangeRadioList;
- (NSArray *) repeatList;
- (NSArray *) yearlyRadioList;
- (void) setItem: (NSString *) theItem;
- (NSString *) item;
@end
#endif /* UIXRECURRENCEEDITOR_H */

View File

@ -0,0 +1,244 @@
/* UIxRecurrenceEditor.m - this file is part of SOGo
*
* Copyright (C) 2008 Inverse groupe conseil
*
* Author: Ludovic Marcotte <ludovic@inverse.ca>
*
* 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
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <Common/UIxPageFrame.h>
#import "UIxRecurrenceEditor.h"
@implementation UIxRecurrenceEditor
- (id) defaultAction
{
[[self parent] setToolbar: @""];
return self;
}
//
// Items used for the "Daily" recurrences.
//
- (NSArray *) dailyRadioList
{
static NSArray *dailyItems = nil;
if (!dailyItems)
{
dailyItems = [NSArray arrayWithObjects: @"Every", @"Every weekday", nil];
[dailyItems retain];
}
return dailyItems;
}
//
// Items used for the "Weekly" recurrences.
//
- (NSArray *) weeklyCheckBoxList
{
static NSArray *dayItems = nil;
if (!dayItems)
{
dayItems = [NSArray arrayWithObjects: @"Mon", @"Tue", @"Wed",
@"Thu", @"Fri", @"Sat", @"Sun", nil];
[dayItems retain];
}
return dayItems;
}
//
// Items used for the "Montly" recurrences".
//
- (NSArray *) dayMonthList
{
static NSArray *dayMonthList = nil;
if (!dayMonthList)
{
int i;
dayMonthList = [[NSMutableArray alloc] init];
for (i = 1; i <= 31; i++)
{
[(NSMutableArray *)dayMonthList addObject: [NSString stringWithFormat: @"%d", i]];
}
}
return dayMonthList;
}
- (NSArray *) monthlyRepeatList
{
static NSArray *monthlyRepeatList = nil;
if (!monthlyRepeatList)
{
monthlyRepeatList = [NSArray arrayWithObjects: @"FIRST", @"SECOND", @"THIRD",
@"FOURTH", @"FIFT", @"LAST", nil];
[monthlyRepeatList retain];
}
return monthlyRepeatList;
}
- (NSArray *) monthlyDayList
{
static NSArray *monthlyDayList = nil;
if (!monthlyDayList)
{
monthlyDayList = [NSArray arrayWithObjects: @"SUNDAY", @"MONDAY", @"TUESDAY",
@"WEDNESDAY", @"THURSDAY", @"FRIDAY",
@"SATURDAY", @"DAYOFTHEMONTH", nil];
[monthlyDayList retain];
}
return monthlyDayList;
}
- (NSArray *) monthlyRadioList
{
static NSArray *monthlyRadioList = nil;
if (!monthlyRadioList)
{
monthlyRadioList = [NSArray arrayWithObjects: @"The", @"Recur on day(s)", nil];
[monthlyRadioList retain];
}
return monthlyRadioList;
}
//
// Items used for the "Yearly" recurrences".
//
- (NSArray *) yearlyRadioList
{
static NSArray *yearlyRadioList = nil;
if (!yearlyRadioList)
{
yearlyRadioList = [NSArray arrayWithObjects: @"Every", @"Every", nil];
[yearlyRadioList retain];
}
return yearlyRadioList;
}
- (NSArray *) yearlyMonthList
{
static NSArray *yearlyMonthList = nil;
if (!yearlyMonthList)
{
yearlyMonthList = [NSArray arrayWithObjects: @"JANUARY", @"FEBRUARY", @"MARCH",
@"APRIL", @"MAY", @"JUNE", @"JULY", @"AUGUST",
@"SEPTEMBER", @"OCTOBER", @"NOVEMBER", @"DECEMBER", nil];
[yearlyMonthList retain];
}
return yearlyMonthList;
}
- (NSArray *) yearlyDayList
{
static NSArray *yearlyDayList = nil;
if (!yearlyDayList)
{
yearlyDayList = [NSArray arrayWithObjects: @"SUNDAY", @"MONDAY", @"TUESDAY",
@"WEDNESDAY", @"THURSDAY", @"FRIDAY",
@"SATURDAY", nil];
[yearlyDayList retain];
}
return yearlyDayList;
}
//
// Items used to specify the range.
//
- (NSArray *) rangeRadioList
{
static NSArray *rangeRadioList = nil;
if (!rangeRadioList)
{
rangeRadioList = [NSArray arrayWithObjects: @"No end date", @"Create",
@"Repeat until", nil];
[rangeRadioList retain];
}
return rangeRadioList;
}
//
// Items used to specify what kind of recurrence we want
//
- (NSArray *) repeatList
{
static NSArray *repeatList = nil;
if (!repeatList)
{
repeatList = [NSArray arrayWithObjects: @"DAILY", @"WEEKLY",
@"MONTHLY", @"YEARLY", nil];
[repeatList retain];
}
return repeatList;
}
//
// Accessors
//
- (void) setItem: (NSString *) theItem
{
item = theItem;
}
- (NSString *) item
{
return item;
}
- (NSString *) itemText
{
NSString *text;
text = [self labelForKey: [NSString stringWithFormat: @"repeat_%@", item]];
return text;
}
@end

View File

@ -52,9 +52,6 @@
- (void) setTaskDueDate: (NSCalendarDate *) _date;
- (NSCalendarDate *) taskDueDate;
- (NSString *) repeat;
- (void) setRepeat: (NSString *) newRepeat;
@end
#endif /* UIXAPPOINTMENTEDITOR_H */

View File

@ -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;

View File

@ -97,6 +97,10 @@
protectedBy = "View";
pageName = "UIxAttendeesEditor";
};
editRecurrence = {
protectedBy = "View";
pageName = "UIxRecurrenceEditor";
};
};
};

View File

@ -40,18 +40,4 @@
const:dayStartHour="0"
const:dayEndHour="23"
/></span></span>
<hr />
<label><var:string label:value="Repeat:" />
<span class="content"><var:popup list="repeatList" item="item"
label:noSelectionString="repeat_NEVER"
const:disabledValue="-"
string="itemRepeatText" selection="repeat"
/></span></label>
<hr />
<label><var:string label:value="Reminder:" />
<span class="content"><var:popup list="reminderList" item="item"
const:disabledValue="-"
label:noSelectionString="reminder_NONE"
string="itemReminderText" selection="reminder"
/></span></label>
</var:component>

View File

@ -72,6 +72,21 @@
<hr />
<var:component-content />
<hr />
<label><var:string label:value="Repeat:" />
<span class="content"><var:popup list="repeatList" item="item"
label:noSelectionString="repeat_NEVER"
const:disabledValue="-"
const:id="repeatList"
string="itemRepeatText" selection="repeat"
/></span></label>
<hr />
<label><var:string label:value="Reminder:" />
<span class="content"><var:popup list="reminderList" item="item"
const:disabledValue="-"
label:noSelectionString="reminder_NONE"
string="itemReminderText" selection="reminder"
/></span></label>
<hr />
<label id="commentArea"><var:string label:value="Description:"
/><textarea rows="20" name="comment" var:value="comment" /></label>
<label id="documentLabel" style="display: none;"><var:string label:value="Document:"
@ -96,6 +111,40 @@
<input type="hidden" name="calendarFoldersList"
id="calendarFoldersList"
var:value="calendarsFoldersList"/>
<input type="hidden" name="repeatType"
id="repeatType"
var:value="repeatType"/>
<input type="hidden" name="repeat1"
id="repeat1"
var:value="repeat1"/>
<input type="hidden" name="repeat2"
id="repeat2"
var:value="repeat2"/>
<input type="hidden" name="repeat3"
id="repeat3"
var:value="repeat3"/>
<input type="hidden" name="repeat4"
id="repeat4"
var:value="repeat4"/>
<input type="hidden" name="repeat5"
id="repeat5"
var:value="repeat5"/>
<input type="hidden" name="repeat6"
id="repeat6"
var:value="repeat6"/>
<input type="hidden" name="repeat7"
id="repeat7"
var:value="repeat7"/>
<input type="hidden" name="range1"
id="range1"
var:value="range1"/>
<input type="hidden" name="range2"
id="range2"
var:value="range2"/>
</div>
</form>
</var:component>

View File

@ -0,0 +1,154 @@
<?xml version='1.0' standalone='yes'?>
<!DOCTYPE var:component>
<var:component
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:uix="OGo:uix"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label"
className="UIxPageFrame"
const:toolbar="none"
const:popup="YES"
const:jsFiles="skycalendar.js">
<form id="recurrence_form">
<div id="recurrence_pattern">
<var:string label:value="Recurrence pattern"/>
<br />
<br />
<var:string label:value="Repeat"/>
<var:popup list="repeatList" const:id="repeatType" item="item"
string="itemText" selection="repeatType"
/>
<hr />
<div id="recurrenceDaily">
<var:radio-button-list list="dailyRadioList" const:id="dailyRadioButton" item="item"
const:name="dailyRadioButtonName" value="item" />
<input type="text" name="dailyDaysFieldName" const:id="dailyDaysField"
class="textField"
var:value="title"
/>
<var:string label:value="Days"/>
</div>
<hr />
<div id="recurrenceWeekly">
<var:string label:value="Every"/>
<input type="text" name="weeklyWeeksFieldName" const:id="weeklyWeeksField"
class="textField"
var:value="title"
/>
<var:string label:value="Week(s)"/>
<br />
<var:string label:value="On"/>
<var:checkbox-list list="weeklyCheckBoxList" const:id="weeklyCheckBox" item="item"
const:name="weeklyCheckBoxName" value="item" />
</div>
<hr />
<div id="recurrenceMonthly">
<var:string label:value="Every"/>
<input type="text" name="monthlyMonthsFieldName" const:id="monthlyMonthsField"
class="textField"
var:value="title"
/>
<var:string label:value="Month(s)"/>
<br />
<var:radio-button-list list="monthlyRadioList" const:id="monthlyRadioButton" item="item"
const:name="monthlyRadioButtonName" value="item" />
<br />
<var:popup list="monthlyRepeatList" const:id="monthlyRepeat" item="item"
label:noSelectionString="FIRST"
string="itemText" selection="FIRST"
/>
<var:popup list="monthlyDayList" const:id="monthlyDay" item="item"
label:noSelectionString="MONDAY"
string="itemText" selection="MONDAY"
/>
<br />
<var:checkbox-list list="dayMonthList" const:id="monthlyCheckBox" item="item"
const:name="monthlyCheckBoxName" value="item" />
</div>
<hr />
<div id="recurrenceYearly">
<var:string label:value="Every"/>
<input type="text" name="yearlyYearsFieldName" const:id="yearlyYearsField"
class="textField"
var:value="title"
/>
<var:string label:value="Year(s)"/>
<br />
<var:radio-button-list list="yearlyRadioList" const:id="yearlyRadioButton" item="item"
const:name="yearlyRadioButtonName" value="item" />
<br />
<input type="text" name="yearlyDayFieldName" const:id="yearlyDayField"
class="textField"
var:value="title"
/>
<var:popup list="yearlyMonthList" const:id="yearlyMonth1" item="item"
label:noSelectionString="JANUARY"
string="itemText" selection="JANUARY"
/>
<br />
<var:popup list="monthlyRepeatList" const:id="yearlyRepeat" item="item"
label:noSelectionString="FIRST"
string="itemText" selection="FIRST"
/>
<var:popup list="yearlyDayList" const:id="yearlyDay" item="item"
label:noSelectionString="MONDAY"
string="itemText" selection="MONDAY"
/>
<var:string label:value="of"/>
<var:popup list="yearlyMonthList" const:id="yearlyMonth2" item="item"
label:noSelectionString="JANUARY"
string="itemText" selection="JANUARY"
/>
</div>
</div>
<br />
<br />
<hr />
<br />
<br />
<div id="range_of_recurrence">
<var:string label:value="Range of recurrence"/>
<br />
<br />
<var:radio-button-list list="rangeRadioList" const:id="rangeRadioButton" item="item"
const:name="rangeRadioButtonName" value="item" />
<br />
<input type="text" name="rangeAppointmentsFieldName" const:id="rangeAppointmentsField"
class="textField"
var:value="title"
/>
<var:string label:value="Appointments(s)"/>
<br />
<var:component className="UIxDatePicker"
const:dateID="endDate"
day="endDateDay"
month="endDateMonth"
year="endDateYear"
label:label="browse end date"
/>
</div>
<div id="windowButtons">
<hr />
<a id="cancelButton" href="#" class="button"
><var:string label:value="Cancel"/></a>
<a id="okButton" href="#" class="button"
><var:string label:value="OK"/></a>
</div>
</form>
</var:component>

View File

@ -51,11 +51,4 @@
var:disabled="statusPercentDisabled"
/><var:string label:value="% complete"
/></span></span>
<hr />
<label><var:string label:value="Repeat:" />
<span class="content"><var:popup list="repeatList" item="item"
label:noSelectionString="repeat_NEVER"
const:disabledValue="-"
string="itemRepeatText" selection="repeat"
/></span></label>
</var:component>

View File

@ -236,6 +236,44 @@ Element.addMethods({
radioValue = input.value;
});
return radioValue;
},
setRadioValue: function(element, radioName, value) {
element = $(element);
var i = 0;
Form.getInputs(element, 'radio', radioName).each(function(input) {
if (i == value)
input.checked = 1;
i++;
});
},
getCheckBoxListValues: function(element, checkboxName) {
element = $(element);
var values = new Array();
var i = 0;
Form.getInputs(element, 'checkbox', checkboxName).each(function(input) {
if (input.checked)
values.push(i+1);
i++;
});
return values.join(",");
},
setCheckBoxListValues: function(element, checkboxName, values) {
element = $(element);
var v = values.split(',');
var i = 1;
Form.getInputs(element, 'checkbox', checkboxName).each(function(input) {
if ($(v).indexOf(i+"") != -1)
input.checked = 1;
i++;
});
}
});

View File

@ -124,6 +124,19 @@ function onComponentEditorLoad(event) {
Event.observe(menuItems[i], "mousedown",
onMenuSetClassification.bindAsEventListener(menuItems[i]),
false);
$("repeatList").observe("change", onPopupRecurrenceWindow);
}
function onPopupRecurrenceWindow(event) {
if (event)
preventDefault(event);
if ($("repeatList").value == 7)
window.open(ApplicationBaseURL + "/editRecurrence", null,
"width=803,height=573");
return false;
}
FastInit.addOnLoad(onComponentEditorLoad);

View File

@ -0,0 +1,7 @@
DIV#windowButtons
{ position: absolute;
bottom: 0px;
left: 0px;
right: 0px;
height: 4em;
text-align: right; }

View File

@ -0,0 +1,135 @@
function initializeWindowButtons() {
var okButton = $("okButton");
var cancelButton = $("cancelButton");
Event.observe(okButton, "click", onEditorOkClick, false);
Event.observe(cancelButton, "click", onEditorCancelClick, false);
}
function initializeFormValues() {
$("repeatType").value = parent$("repeatType").value;
if ($("repeatType").value == 0) {
$('recurrence_form').setRadioValue('dailyRadioButtonName', parent$("repeat1").value);
$('dailyDaysField').value = parent$("repeat2").value;
}
else if ($("repeatType").value == 1) {
$('weeklyWeeksField').value = parent$("repeat1").value;
$('recurrence_form').setCheckBoxListValues('weeklyCheckBoxName', parent$("repeat2").value);
}
else if ($("repeatType").value == 2) {
$('monthlyMonthsField').value = parent$("repeat1").value;
$('recurrence_form').setRadioValue('monthlyRadioButtonName', parent$("repeat2").value);
$('monthlyRepeat').value = parent$("repeat3").value;
$('monthlyDay').value = parent$("repeat4").value;
$('recurrence_form').setCheckBoxListValues('monthlyCheckBoxName', parent$("repeat5").value);
}
else {
$('yearlyYearsField').value = parent$("repeat1").value;
$('recurrence_form').setRadioValue('yearlyRadioButtonName', parent$("repeat2").value);
$('yearlyDayField').value = parent$("repeat3").value;
$('yearlyMonth1').value = parent$("repeat4").value;
$('yearlyRepeat').value = parent$("repeat5").value;
$('yearlyDay').value = parent$("repeat6").value;
$('yearlyMonth2').value = parent$("repeat7").value;
}
$('recurrence_form').setRadioValue('rangeRadioButtonName', parent$("range1").value);
if (parent$("range1").value == 1) {
$('rangeAppointmentsField').value = parent$("range2").value;
}
else if (parent$("range1").value == 2) {
$('endDate').value = parent$("range2").value;
}
}
function onEditorOkClick(event) {
preventDefault(event);
var v;
parent$("repeatType").value = $("repeatType").value;
if ($("repeatType").value == 0) {
parent$("repeat1").value = $('recurrence_form').getRadioValue('dailyRadioButtonName');
parent$("repeat2").value = $('dailyDaysField').value;
// We check if the dailyDaysField really contains an integer
v = parseInt(parent$("repeat2").value);
if (parent$("repeat1").value == 0 && (isNaN(v) || v <= 0)) {
window.alert("Please specify a numerical value in the Days field greater or equal to 1.");
return false;
}
}
else if ($("repeatType").value == 1) {
parent$("repeat1").value = $('weeklyWeeksField').value;
parent$("repeat2").value = $('recurrence_form').getCheckBoxListValues('weeklyCheckBoxName');
// We check if the weeklyWeeksField really contains an integer
v = parseInt(parent$("repeat1").value);
if (isNaN(v) || v <= 0) {
window.alert("Please specify a numerical value in the Week(s) field greater or equal to 1.");
return false;
}
}
else if ($("repeatType").value == 2) {
parent$("repeat1").value = $('monthlyMonthsField').value;
parent$("repeat2").value = $('recurrence_form').getRadioValue('monthlyRadioButtonName');
parent$("repeat3").value = $('monthlyRepeat').value;
parent$("repeat4").value = $('monthlyDay').value;
parent$("repeat5").value = $('recurrence_form').getCheckBoxListValues('monthlyCheckBoxName');
// We check if the monthlyMonthsField really contains an integer
v = parseInt(parent$("repeat1").value);
if (isNaN(v) || v <= 0) {
window.alert("Please specify a numerical value in the Month(s) field greater or equal to 1.");
return false;
}
}
else {
parent$("repeat1").value = $('yearlyYearsField').value;
parent$("repeat2").value = $('recurrence_form').getRadioValue('yearlyRadioButtonName');
parent$("repeat3").value = $('yearlyDayField').value;
parent$("repeat4").value = $('yearlyMonth1').value;
parent$("repeat5").value = $('yearlyRepeat').value;
parent$("repeat6").value = $('yearlyDay').value;
parent$("repeat7").value = $('yearlyMonth2').value;
// We check if the yearlyYearsField really contains an integer
v = parseInt(parent$("repeat1").value);
if (isNaN(v) || v <= 0) {
window.alert("Please specify a numerical value in the Year(s) field greater or equal to 1.");
return false;
}
}
parent$("range1").value = $('recurrence_form').getRadioValue('rangeRadioButtonName');
if (parent$("range1").value == 1) {
parent$("range2").value = $('rangeAppointmentsField').value;
// We check if the rangeAppointmentsField really contains an integer
v = parseInt(parent$("range2").value);
if (isNaN(v) || v <= 0) {
window.alert("Please specify a numerical value in the Appointment(s) field greater or equal to 1.");
return false;
}
}
else if (parent$("range1").value == 2) {
parent$("range2").value = $('endDate').value;
}
window.close();
}
function onEditorCancelClick(event) {
preventDefault(event);
window.close();
}
function onRecurrenceLoadHandler() {
initializeWindowButtons();
initializeFormValues();
}
FastInit.addOnLoad(onRecurrenceLoadHandler);