mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-04-16 18:58:50 +00:00
Monotone-Parent: 71bb185f5f96c21cf62ca4dd2cadf54d83dc4f7c
Monotone-Revision: 11fad7a10b612bfb5d7852bc31ad9fa992c6a07b Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2006-10-18T14:42:44 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
10
ChangeLog
10
ChangeLog
@@ -1,3 +1,13 @@
|
||||
2006-10-18 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* UI/Scheduler/UIxAppointmentEditor.m,
|
||||
UI/Scheduler/UIxTaskEditor.m:
|
||||
refactored to user UIxComponentEditor as parent class.
|
||||
|
||||
* UI/Scheduler/UIxComponentEditor.[hm]: new class module
|
||||
containing the methods common to the UIxTaskEditor and the
|
||||
UIxAppointmentEditor.
|
||||
|
||||
2006-10-17 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/Appointments/SOGoAppointmentFolder.m
|
||||
|
||||
@@ -23,68 +23,50 @@
|
||||
#ifndef UIXAPPOINTMENTEDITOR_H
|
||||
#define UIXAPPOINTMENTEDITOR_H
|
||||
|
||||
#import <SOGoUI/UIxComponent.h>
|
||||
#import <UIxComponentEditor.h>
|
||||
|
||||
@class NSString;
|
||||
@class iCalPerson;
|
||||
@class iCalRecurrenceRule;
|
||||
|
||||
@interface UIxAppointmentEditor : UIxComponent
|
||||
@interface UIxAppointmentEditor : UIxComponentEditor
|
||||
{
|
||||
NSString *iCalString;
|
||||
NSString *errorText;
|
||||
id item;
|
||||
|
||||
/* individual values */
|
||||
NSCalendarDate *startDate;
|
||||
NSCalendarDate *endDate;
|
||||
NSCalendarDate *cycleUntilDate;
|
||||
NSString *title;
|
||||
NSString *location;
|
||||
NSString *comment;
|
||||
iCalPerson *organizer;
|
||||
NSArray *participants; /* array of iCalPerson's */
|
||||
NSArray *resources; /* array of iCalPerson's */
|
||||
NSString *priority;
|
||||
NSArray *categories;
|
||||
NSString *accessClass;
|
||||
BOOL isPrivate; /* default: NO */
|
||||
BOOL checkForConflicts; /* default: NO */
|
||||
NSDictionary *cycle;
|
||||
NSString *cycleEnd;
|
||||
}
|
||||
|
||||
- (NSString *)iCalStringTemplate;
|
||||
- (NSString *)iCalString;
|
||||
- (void) setAptStartDate: (NSCalendarDate *) _date;
|
||||
- (NSCalendarDate *) aptStartDate;
|
||||
|
||||
- (void)setIsPrivate:(BOOL)_yn;
|
||||
- (void)setAccessClass:(NSString *)_class;
|
||||
- (void) setAptEndDate: (NSCalendarDate *) _date;
|
||||
- (NSCalendarDate *) aptEndDate;
|
||||
|
||||
- (void)setCheckForConflicts:(BOOL)_checkForConflicts;
|
||||
- (BOOL)checkForConflicts;
|
||||
/* iCal */
|
||||
|
||||
- (BOOL)hasCycle;
|
||||
- (iCalRecurrenceRule *)rrule;
|
||||
- (void)adjustCycleControlsForRRule:(iCalRecurrenceRule *)_rrule;
|
||||
- (NSDictionary *)cycleMatchingRRule:(iCalRecurrenceRule *)_rrule;
|
||||
- (NSString *) iCalStringTemplate;
|
||||
|
||||
- (BOOL)isCycleEndUntil;
|
||||
- (void)setIsCycleEndUntil;
|
||||
- (void)setIsCycleEndNever;
|
||||
/* new */
|
||||
|
||||
- (NSString *)_completeURIForMethod:(NSString *)_method;
|
||||
- (id) newAction;
|
||||
|
||||
- (NSArray *)getICalPersonsFromFormValues:(NSArray *)_values
|
||||
treatAsResource:(BOOL)_isResource;
|
||||
/* save */
|
||||
|
||||
- (NSString *)iCalParticipantsAndResourcesStringFromQueryParameters;
|
||||
- (NSString *)iCalParticipantsStringFromQueryParameters;
|
||||
- (NSString *)iCalResourcesStringFromQueryParameters;
|
||||
- (NSString *)iCalStringFromQueryParameter:(NSString *)_qp
|
||||
format:(NSString *)_format;
|
||||
- (NSString *)iCalOrganizerString;
|
||||
- (void) loadValuesFromAppointment: (iCalEvent *) _apt;
|
||||
- (void) saveValuesIntoAppointment: (iCalEvent *) _apt;
|
||||
- (iCalEvent *) appointmentFromString: (NSString *) _iCalString;
|
||||
|
||||
- (id)acceptOrDeclineAction:(BOOL)_accept;
|
||||
/* conflict management */
|
||||
|
||||
- (BOOL) containsConflict: (id) _apt;
|
||||
- (id <WOActionResults>) defaultAction;
|
||||
- (id <WOActionResults>) saveAction;
|
||||
- (id) acceptAction;
|
||||
- (id) declineAction;
|
||||
|
||||
- (NSString *) saveUrl;
|
||||
|
||||
// TODO: add tentatively
|
||||
|
||||
- (id) acceptOrDeclineAction: (BOOL) _accept;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
#import <NGCards/NSCalendarDate+NGCards.h>
|
||||
|
||||
#import <SOGo/AgenorUserManager.h>
|
||||
#import <SOGo/NSCalendarDate+SOGo.h>
|
||||
|
||||
#import "common.h"
|
||||
#import <NGCards/NGCards.h>
|
||||
#import <NGExtensions/NGCalendarDateRange.h>
|
||||
#import <SOGoUI/SOGoDateFormatter.h>
|
||||
#import <SOGo/AgenorUserManager.h>
|
||||
#import <Appointments/SOGoAppointmentFolder.h>
|
||||
#import <Appointments/SOGoAppointmentObject.h>
|
||||
#import "UIxComponent+Agenor.h"
|
||||
@@ -49,375 +49,42 @@
|
||||
NSStringFromClass([self superclass]), [super version]);
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
[self setIsPrivate:NO];
|
||||
[self setCheckForConflicts:NO];
|
||||
[self setIsCycleEndNever];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[iCalString release];
|
||||
[errorText release];
|
||||
[item release];
|
||||
|
||||
[startDate release];
|
||||
- (void) dealloc
|
||||
{
|
||||
[endDate release];
|
||||
[cycleUntilDate release];
|
||||
[title release];
|
||||
[location release];
|
||||
[organizer release];
|
||||
[comment release];
|
||||
[participants release];
|
||||
[resources release];
|
||||
[priority release];
|
||||
[categories release];
|
||||
[accessClass release];
|
||||
[cycle release];
|
||||
[cycleEnd release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (void)setItem:(id)_item {
|
||||
ASSIGN(item, _item);
|
||||
}
|
||||
- (id)item {
|
||||
return item;
|
||||
- (void) setAptStartDate: (NSCalendarDate *)_date
|
||||
{
|
||||
[self setStartDate: _date];
|
||||
}
|
||||
|
||||
- (void)setErrorText:(NSString *)_txt {
|
||||
ASSIGNCOPY(errorText, _txt);
|
||||
}
|
||||
- (NSString *)errorText {
|
||||
return errorText;
|
||||
}
|
||||
- (BOOL)hasErrorText {
|
||||
return [errorText length] > 0 ? YES : NO;
|
||||
- (NSCalendarDate *) aptStartDate
|
||||
{
|
||||
return [self startDate];
|
||||
}
|
||||
|
||||
- (NSFormatter *)titleDateFormatter {
|
||||
SOGoDateFormatter *fmt;
|
||||
|
||||
fmt = [[[SOGoDateFormatter alloc] initWithLocale:[self locale]] autorelease];
|
||||
[fmt setFullWeekdayNameAndDetails];
|
||||
return fmt;
|
||||
}
|
||||
|
||||
- (void)setAptStartDate:(NSCalendarDate *)_date {
|
||||
ASSIGN(startDate, _date);
|
||||
}
|
||||
- (NSCalendarDate *)aptStartDate {
|
||||
return startDate;
|
||||
}
|
||||
- (void)setAptEndDate:(NSCalendarDate *)_date {
|
||||
- (void) setAptEndDate: (NSCalendarDate *) _date
|
||||
{
|
||||
ASSIGN(endDate, _date);
|
||||
}
|
||||
- (NSCalendarDate *)aptEndDate {
|
||||
|
||||
- (NSCalendarDate *) aptEndDate
|
||||
{
|
||||
return endDate;
|
||||
}
|
||||
|
||||
- (void)setTitle:(NSString *)_value {
|
||||
ASSIGNCOPY(title, _value);
|
||||
}
|
||||
- (NSString *)title {
|
||||
return title;
|
||||
}
|
||||
- (void)setLocation:(NSString *)_value {
|
||||
ASSIGNCOPY(location, _value);
|
||||
}
|
||||
- (NSString *)location {
|
||||
return location;
|
||||
}
|
||||
- (void)setComment:(NSString *)_value {
|
||||
ASSIGNCOPY(comment, _value);
|
||||
}
|
||||
- (NSString *)comment {
|
||||
return comment;
|
||||
}
|
||||
|
||||
- (void)setParticipants:(NSArray *)_parts {
|
||||
ASSIGN(participants, _parts);
|
||||
}
|
||||
- (NSArray *)participants {
|
||||
return participants;
|
||||
}
|
||||
- (void)setResources:(NSArray *)_res {
|
||||
ASSIGN(resources, _res);
|
||||
}
|
||||
- (NSArray *)resources {
|
||||
return resources;
|
||||
}
|
||||
|
||||
/* priorities */
|
||||
|
||||
- (NSArray *)priorities {
|
||||
/* 0 == undefined
|
||||
5 == normal
|
||||
1 == high
|
||||
*/
|
||||
static NSArray *priorities = nil;
|
||||
|
||||
if (!priorities)
|
||||
priorities = [[NSArray arrayWithObjects:@"0", @"5", @"1", nil] retain];
|
||||
return priorities;
|
||||
}
|
||||
|
||||
- (NSString *)itemPriorityText {
|
||||
NSString *key;
|
||||
|
||||
key = [NSString stringWithFormat:@"prio_%@", item];
|
||||
return [self labelForKey:key];
|
||||
}
|
||||
|
||||
- (void)setPriority:(NSString *)_priority {
|
||||
ASSIGN(priority, _priority);
|
||||
}
|
||||
- (NSString *)priority {
|
||||
return priority;
|
||||
}
|
||||
|
||||
|
||||
/* categories */
|
||||
|
||||
- (NSArray *)categoryItems {
|
||||
// TODO: make this configurable?
|
||||
/*
|
||||
Tasks categories will be modified as follow :
|
||||
– by default (a simple logo or no logo at all),
|
||||
– appointment,
|
||||
– outside,
|
||||
– meeting,
|
||||
– holidays,
|
||||
– phone.
|
||||
*/
|
||||
static NSArray *categoryItems = nil;
|
||||
|
||||
if (!categoryItems) {
|
||||
categoryItems = [[NSArray arrayWithObjects:@"APPOINTMENT",
|
||||
@"NOT IN OFFICE",
|
||||
@"MEETING",
|
||||
@"HOLIDAY",
|
||||
@"PHONE CALL",
|
||||
nil] retain];
|
||||
}
|
||||
return categoryItems;
|
||||
}
|
||||
|
||||
- (NSString *) itemCategoryText {
|
||||
return [[self labelForKey: item] stringByEscapingHTMLString];
|
||||
}
|
||||
|
||||
- (void)setCategories:(NSArray *)_categories {
|
||||
ASSIGN(categories, _categories);
|
||||
}
|
||||
|
||||
- (NSArray *)categories {
|
||||
return categories;
|
||||
}
|
||||
|
||||
/* class */
|
||||
|
||||
#if 0
|
||||
- (NSArray *)accessClassItems {
|
||||
static NSArray classItems = nil;
|
||||
|
||||
if (!classItems) {
|
||||
return [[NSArray arrayWithObjects:@"PUBLIC", @"PRIVATE", nil] retain];
|
||||
}
|
||||
return classItems;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)setAccessClass:(NSString *)_class {
|
||||
ASSIGN(accessClass, _class);
|
||||
}
|
||||
- (NSString *)accessClass {
|
||||
return accessClass;
|
||||
}
|
||||
|
||||
- (void)setIsPrivate:(BOOL)_yn {
|
||||
if (_yn)
|
||||
[self setAccessClass:@"PRIVATE"];
|
||||
else
|
||||
[self setAccessClass:@"PUBLIC"];
|
||||
isPrivate = _yn;
|
||||
}
|
||||
- (BOOL)isPrivate {
|
||||
return isPrivate;
|
||||
}
|
||||
|
||||
- (void)setCheckForConflicts:(BOOL)_checkForConflicts {
|
||||
checkForConflicts = _checkForConflicts;
|
||||
}
|
||||
- (BOOL)checkForConflicts {
|
||||
return checkForConflicts;
|
||||
}
|
||||
|
||||
- (NSArray *)cycles {
|
||||
static NSArray *cycles = nil;
|
||||
|
||||
if (!cycles) {
|
||||
NSBundle *bundle;
|
||||
NSString *path;
|
||||
|
||||
bundle = [NSBundle bundleForClass:[self class]];
|
||||
path = [bundle pathForResource:@"cycles" ofType:@"plist"];
|
||||
NSAssert(path != nil, @"Cannot find cycles.plist!");
|
||||
cycles = [[NSArray arrayWithContentsOfFile:path] retain];
|
||||
NSAssert(cycles != nil, @"Cannot instantiate cycles from cycles.plist!");
|
||||
}
|
||||
return cycles;
|
||||
}
|
||||
|
||||
- (void)setCycle:(NSDictionary *)_cycle {
|
||||
ASSIGN(cycle, _cycle);
|
||||
}
|
||||
- (NSDictionary *)cycle {
|
||||
return cycle;
|
||||
}
|
||||
- (BOOL)hasCycle {
|
||||
[self debugWithFormat:@"cycle: %@", cycle];
|
||||
if (![cycle objectForKey:@"rule"])
|
||||
return NO;
|
||||
return YES;
|
||||
}
|
||||
- (NSString *)cycleLabel {
|
||||
NSString *key;
|
||||
|
||||
key = [(NSDictionary *)item objectForKey:@"label"];
|
||||
return [self labelForKey:key];
|
||||
}
|
||||
|
||||
|
||||
- (void)setCycleUntilDate:(NSCalendarDate *)_cycleUntilDate {
|
||||
NSCalendarDate *until;
|
||||
|
||||
/* copy hour/minute/second from startDate */
|
||||
until = [_cycleUntilDate hour:[startDate hourOfDay]
|
||||
minute:[startDate minuteOfHour]
|
||||
second:[startDate secondOfMinute]];
|
||||
[until setTimeZone:[startDate timeZone]];
|
||||
ASSIGN(cycleUntilDate, until);
|
||||
}
|
||||
- (NSCalendarDate *)cycleUntilDate {
|
||||
return cycleUntilDate;
|
||||
}
|
||||
|
||||
- (iCalRecurrenceRule *)rrule {
|
||||
NSString *ruleRep;
|
||||
iCalRecurrenceRule *rule;
|
||||
|
||||
if (![self hasCycle])
|
||||
return nil;
|
||||
ruleRep = [cycle objectForKey:@"rule"];
|
||||
rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:ruleRep];
|
||||
|
||||
if (cycleUntilDate && [self isCycleEndUntil])
|
||||
[rule setUntilDate:cycleUntilDate];
|
||||
return rule;
|
||||
}
|
||||
|
||||
- (void)adjustCycleControlsForRRule:(iCalRecurrenceRule *)_rrule {
|
||||
NSDictionary *c;
|
||||
NSCalendarDate *until;
|
||||
|
||||
c = [self cycleMatchingRRule:_rrule];
|
||||
[self setCycle:c];
|
||||
|
||||
until = [[[_rrule untilDate] copy] autorelease];
|
||||
if (!until)
|
||||
until = startDate;
|
||||
else
|
||||
[self setIsCycleEndUntil];
|
||||
|
||||
[until setTimeZone:[[self clientObject] userTimeZone]];
|
||||
[self setCycleUntilDate:until];
|
||||
}
|
||||
|
||||
/*
|
||||
This method is necessary, because we have a fixed sets of cycles in the UI.
|
||||
The model is able to represent arbitrary rules, however.
|
||||
There SHOULD be a different UI, similar to iCal.app, to allow modelling
|
||||
of more complex rules.
|
||||
|
||||
This method obviously cannot map all existing rules back to the fixed list
|
||||
in cycles.plist. This should be fixed in a future version when interop
|
||||
becomes more important.
|
||||
*/
|
||||
- (NSDictionary *)cycleMatchingRRule:(iCalRecurrenceRule *)_rrule {
|
||||
NSString *cycleRep;
|
||||
NSArray *cycles;
|
||||
unsigned i, count;
|
||||
|
||||
if (!_rrule)
|
||||
return [[self cycles] objectAtIndex:0];
|
||||
|
||||
cycleRep = [_rrule versitString];
|
||||
cycles = [self cycles];
|
||||
count = [cycles count];
|
||||
for (i = 1; i < count; i++) {
|
||||
NSDictionary *c;
|
||||
NSString *cr;
|
||||
|
||||
c = [cycles objectAtIndex:i];
|
||||
cr = [c objectForKey:@"rule"];
|
||||
if ([cr isEqualToString:cycleRep])
|
||||
return c;
|
||||
}
|
||||
[self warnWithFormat:@"No default cycle for rrule found! -> %@", _rrule];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* cycle "ends" - supposed to be 'never', 'COUNT' or 'UNTIL' */
|
||||
- (NSArray *)cycleEnds {
|
||||
static NSArray *ends = nil;
|
||||
|
||||
if (!ends) {
|
||||
ends = [[NSArray alloc] initWithObjects:@"cycle_end_never",
|
||||
@"cycle_end_until",
|
||||
nil];
|
||||
}
|
||||
return ends;
|
||||
}
|
||||
|
||||
- (void)setCycleEnd:(NSString *)_cycleEnd {
|
||||
ASSIGNCOPY(cycleEnd, _cycleEnd);
|
||||
}
|
||||
- (NSString *)cycleEnd {
|
||||
return cycleEnd;
|
||||
}
|
||||
- (BOOL)isCycleEndUntil {
|
||||
return (cycleEnd &&
|
||||
[cycleEnd isEqualToString:@"cycle_end_until"]);
|
||||
}
|
||||
- (void)setIsCycleEndUntil {
|
||||
[self setCycleEnd:@"cycle_end_until"];
|
||||
}
|
||||
- (void)setIsCycleEndNever {
|
||||
[self setCycleEnd:@"cycle_end_never"];
|
||||
}
|
||||
|
||||
/* transparency */
|
||||
|
||||
- (NSString *)transparency {
|
||||
return @"TRANSPARENT";
|
||||
}
|
||||
|
||||
|
||||
/* iCal */
|
||||
|
||||
- (void)setICalString:(NSString *)_s {
|
||||
ASSIGNCOPY(iCalString, _s);
|
||||
}
|
||||
- (NSString *)iCalString {
|
||||
return iCalString;
|
||||
}
|
||||
|
||||
- (NSString *)iCalStringTemplate {
|
||||
static NSString *iCalStringTemplate = \
|
||||
@"BEGIN:VCALENDAR\r\n"
|
||||
@@ -473,105 +140,10 @@
|
||||
return template;
|
||||
}
|
||||
|
||||
- (NSString *)iCalParticipantsAndResourcesStringFromQueryParameters {
|
||||
NSString *s;
|
||||
|
||||
s = [self iCalParticipantsStringFromQueryParameters];
|
||||
return [s stringByAppendingString:
|
||||
[self iCalResourcesStringFromQueryParameters]];
|
||||
}
|
||||
|
||||
- (NSString *)iCalParticipantsStringFromQueryParameters {
|
||||
static NSString *iCalParticipantString = \
|
||||
@"ATTENDEE;ROLE=REQ-PARTICIPANT;CN=\"%@\":mailto:%@\r\n";
|
||||
|
||||
return [self iCalStringFromQueryParameter:@"ps"
|
||||
format:iCalParticipantString];
|
||||
}
|
||||
|
||||
- (NSString *)iCalResourcesStringFromQueryParameters {
|
||||
static NSString *iCalResourceString = \
|
||||
@"ATTENDEE;ROLE=NON-PARTICIPANT;CN=\"%@\":mailto:%@\r\n";
|
||||
|
||||
return [self iCalStringFromQueryParameter:@"rs"
|
||||
format:iCalResourceString];
|
||||
}
|
||||
|
||||
- (NSString *)iCalStringFromQueryParameter:(NSString *)_qp
|
||||
format:(NSString *)_format
|
||||
{
|
||||
AgenorUserManager *um;
|
||||
NSMutableString *iCalRep;
|
||||
NSString *s;
|
||||
|
||||
um = [AgenorUserManager sharedUserManager];
|
||||
iCalRep = (NSMutableString *)[NSMutableString string];
|
||||
s = [self queryParameterForKey:_qp];
|
||||
if(s && [s length] > 0) {
|
||||
NSArray *es;
|
||||
unsigned i, count;
|
||||
|
||||
es = [s componentsSeparatedByString:@","];
|
||||
count = [es count];
|
||||
for(i = 0; i < count; i++) {
|
||||
NSString *email, *cn;
|
||||
|
||||
email = [es objectAtIndex:i];
|
||||
cn = [um getCNForUID:[um getUIDForEmail:email]];
|
||||
[iCalRep appendFormat:_format, cn, email];
|
||||
}
|
||||
}
|
||||
return iCalRep;
|
||||
}
|
||||
|
||||
- (NSString *)iCalOrganizerString {
|
||||
static NSString *fmt = @"ORGANIZER;CN=\"%@\":mailto:%@\r\n";
|
||||
return [NSString stringWithFormat:fmt,
|
||||
[self cnForUser],
|
||||
[self emailForUser]];
|
||||
}
|
||||
|
||||
#if 0
|
||||
- (iCalPerson *)getOrganizer {
|
||||
iCalPerson *p;
|
||||
NSString *emailProp;
|
||||
|
||||
emailProp = [@"mailto:" stringByAppendingString:[self emailForUser]];
|
||||
p = [[[iCalPerson alloc] init] autorelease];
|
||||
[p setEmail:emailProp];
|
||||
[p setCn:[self cnForUser]];
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* helper */
|
||||
|
||||
- (NSString *)_completeURIForMethod:(NSString *)_method {
|
||||
NSString *uri;
|
||||
NSRange r;
|
||||
|
||||
uri = [[[self context] request] uri];
|
||||
|
||||
/* first: identify query parameters */
|
||||
r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
|
||||
if (r.length > 0)
|
||||
uri = [uri substringToIndex:r.location];
|
||||
|
||||
/* next: append trailing slash */
|
||||
if (![uri hasSuffix:@"/"])
|
||||
uri = [uri stringByAppendingString:@"/"];
|
||||
|
||||
/* next: append method */
|
||||
uri = [uri stringByAppendingString:_method];
|
||||
|
||||
/* next: append query parameters */
|
||||
return [self completeHrefForMethod:uri];
|
||||
}
|
||||
|
||||
/* new */
|
||||
|
||||
- (id)newAction {
|
||||
- (id) newAction
|
||||
{
|
||||
/*
|
||||
This method creates a unique ID and redirects to the "edit" method on the
|
||||
new ID.
|
||||
@@ -627,117 +199,20 @@
|
||||
|
||||
/* save */
|
||||
|
||||
/* returned dates are in GMT */
|
||||
- (NSArray *)getICalPersonsFromFormValues:(NSArray *)_values
|
||||
treatAsResource:(BOOL)_isResource
|
||||
- (void) loadValuesFromAppointment: (iCalEvent *) appointment
|
||||
{
|
||||
unsigned i, count;
|
||||
NSMutableArray *result;
|
||||
|
||||
count = [_values count];
|
||||
result = [[NSMutableArray alloc] initWithCapacity:count];
|
||||
for (i = 0; i < count; i++) {
|
||||
NSString *pString, *email, *cn;
|
||||
NSRange r;
|
||||
iCalPerson *p;
|
||||
|
||||
pString = [_values objectAtIndex:i];
|
||||
if ([pString length] == 0)
|
||||
continue;
|
||||
|
||||
/* delimiter between email and cn */
|
||||
r = [pString rangeOfString:@";"];
|
||||
if (r.length > 0) {
|
||||
email = [pString substringToIndex:r.location];
|
||||
cn = (r.location + 1 < [pString length])
|
||||
? [pString substringFromIndex:r.location + 1]
|
||||
: nil;
|
||||
}
|
||||
else {
|
||||
email = pString;
|
||||
cn = nil;
|
||||
}
|
||||
if (cn == nil) {
|
||||
/* fallback */
|
||||
AgenorUserManager *um = [AgenorUserManager sharedUserManager];
|
||||
cn = [um getCNForUID:[um getUIDForEmail:email]];
|
||||
}
|
||||
|
||||
p = [[iCalPerson alloc] init];
|
||||
[p setEmail:[@"mailto:" stringByAppendingString:email]];
|
||||
if ([cn isNotNull]) [p setCn:cn];
|
||||
|
||||
/* see RFC2445, sect. 4.2.16 for details */
|
||||
[p setRole:_isResource ? @"NON-PARTICIPANT" : @"REQ-PARTICIPANT"];
|
||||
[result addObject:p];
|
||||
[p release];
|
||||
}
|
||||
return [result autorelease];
|
||||
}
|
||||
|
||||
- (BOOL)isWriteableClientObject {
|
||||
return [[self clientObject]
|
||||
respondsToSelector:@selector(saveContentString:)];
|
||||
}
|
||||
|
||||
- (NSException *)validateObjectForStatusChange {
|
||||
BOOL ok;
|
||||
id co;
|
||||
|
||||
co = [self clientObject];
|
||||
ok = [co respondsToSelector:@selector(changeParticipationStatus:inContext:)];
|
||||
if (!ok) {
|
||||
return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
|
||||
reason:
|
||||
@"method cannot be invoked on the specified object"];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)loadValuesFromAppointment: (iCalEvent *)_appointment
|
||||
{
|
||||
NSString *s;
|
||||
iCalRecurrenceRule *rrule;
|
||||
NSTimeZone *uTZ;
|
||||
|
||||
if ((startDate = [_appointment startDate]) == nil)
|
||||
startDate = [[NSCalendarDate date] hour:11 minute:0];
|
||||
if ((endDate = [_appointment endDate]) == nil) {
|
||||
endDate =
|
||||
[startDate hour:[startDate hourOfDay] + 1 minute:0];
|
||||
}
|
||||
[self loadValuesFromComponent: appointment];
|
||||
|
||||
uTZ = [[self clientObject] userTimeZone];
|
||||
[startDate setTimeZone: uTZ];
|
||||
endDate = [appointment endDate];
|
||||
if (!endDate)
|
||||
endDate = [[self startDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 1 minutes: 0 seconds: 0];
|
||||
|
||||
[endDate setTimeZone: uTZ];
|
||||
// startDate = [startDate adjustedDate];
|
||||
// endDate = [endDate adjustedDate];
|
||||
[startDate retain];
|
||||
[endDate retain];
|
||||
|
||||
title = [[_appointment summary] copy];
|
||||
location = [[_appointment location] copy];
|
||||
comment = [[_appointment comment] copy];
|
||||
priority = [[_appointment priority] copy];
|
||||
categories = [[[_appointment categories] commaSeparatedValues] retain];
|
||||
organizer = [[_appointment organizer] retain];
|
||||
participants = [[_appointment participants] retain];
|
||||
resources = [[_appointment resources] retain];
|
||||
|
||||
// NSLog (@"summary éàè: '%@'", title);
|
||||
|
||||
s = [_appointment accessClass];
|
||||
if(!s || [s isEqualToString:@"PUBLIC"])
|
||||
[self setIsPrivate:NO];
|
||||
else
|
||||
[self setIsPrivate:YES]; /* we're possibly loosing information here */
|
||||
|
||||
/* cycles */
|
||||
if ([_appointment isRecurrent])
|
||||
{
|
||||
rrule = [[_appointment recurrenceRules] objectAtIndex: 0];
|
||||
[self adjustCycleControlsForRRule:rrule];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)saveValuesIntoAppointment:(iCalEvent *)_appointment {
|
||||
@@ -795,36 +270,10 @@
|
||||
return appointment;
|
||||
}
|
||||
|
||||
/* contact editor compatibility */
|
||||
|
||||
- (void)setContentString:(NSString *)_s {
|
||||
[self setICalString:_s];
|
||||
}
|
||||
- (NSString *)contentStringTemplate {
|
||||
return [self iCalStringTemplate];
|
||||
}
|
||||
|
||||
/* access */
|
||||
|
||||
- (BOOL) isMyApt
|
||||
{
|
||||
// TODO: this should check a set of emails against the SoUser
|
||||
return (![[organizer email] length]
|
||||
|| [[organizer rfc822Email] isEqualToString: [self emailForUser]]);
|
||||
}
|
||||
|
||||
- (BOOL)canAccessApt {
|
||||
return [self isMyApt];
|
||||
}
|
||||
|
||||
- (BOOL)canEditApt {
|
||||
return [self isMyApt];
|
||||
}
|
||||
|
||||
|
||||
/* conflict management */
|
||||
|
||||
- (BOOL)containsConflict:(iCalEvent *)_apt {
|
||||
- (BOOL) containsConflict: (id) _apt
|
||||
{
|
||||
NSArray *attendees, *uids;
|
||||
SOGoAppointmentFolder *groupCalendar;
|
||||
NSArray *infos;
|
||||
@@ -863,28 +312,10 @@
|
||||
return [ranges count] != 0 ? YES : NO;
|
||||
}
|
||||
|
||||
/* response generation */
|
||||
|
||||
- (NSString *)initialCycleVisibility {
|
||||
if (![self hasCycle])
|
||||
return @"visibility: hidden;";
|
||||
return @"visibility: visible;";
|
||||
}
|
||||
|
||||
- (NSString *)initialCycleEndUntilVisibility {
|
||||
if ([self isCycleEndUntil])
|
||||
return @"visibility: visible;";
|
||||
return @"visibility: hidden;";
|
||||
}
|
||||
|
||||
|
||||
/* actions */
|
||||
|
||||
- (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)testAction {
|
||||
- (id) testAction
|
||||
{
|
||||
/* for testing only */
|
||||
WORequest *req;
|
||||
iCalEvent *apt;
|
||||
@@ -901,7 +332,8 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id<WOActionResults>)defaultAction {
|
||||
- (id<WOActionResults>) defaultAction
|
||||
{
|
||||
NSString *ical;
|
||||
|
||||
/* load iCalendar file */
|
||||
@@ -910,14 +342,14 @@
|
||||
// ical = [[self clientObject] valueForKey:@"iCalString"];
|
||||
ical = [[self clientObject] contentAsString];
|
||||
if ([ical length] == 0) /* a new appointment */
|
||||
ical = [self contentStringTemplate];
|
||||
ical = [self iCalStringTemplate];
|
||||
|
||||
[self setContentString:ical];
|
||||
[self setICalString:ical];
|
||||
[self loadValuesFromAppointment: [self appointmentFromString: ical]];
|
||||
|
||||
if (![self canEditApt]) {
|
||||
if (![self canEditComponent]) {
|
||||
/* TODO: we need proper ACLs */
|
||||
return [self redirectToLocation:[self _completeURIForMethod:@"../view"]];
|
||||
return [self redirectToLocation: [self completeURIForMethod: @"../view"]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -993,17 +425,20 @@
|
||||
[[self clientObject] baseURL]];
|
||||
}
|
||||
|
||||
- (id)acceptAction {
|
||||
- (id) acceptAction
|
||||
{
|
||||
return [self acceptOrDeclineAction:YES];
|
||||
}
|
||||
|
||||
- (id)declineAction {
|
||||
- (id) declineAction
|
||||
{
|
||||
return [self acceptOrDeclineAction:NO];
|
||||
}
|
||||
|
||||
// TODO: add tentatively
|
||||
|
||||
- (id)acceptOrDeclineAction:(BOOL)_accept {
|
||||
- (id) acceptOrDeclineAction: (BOOL) _accept
|
||||
{
|
||||
// TODO: this should live in the SoObjects
|
||||
NSException *ex;
|
||||
|
||||
@@ -1015,7 +450,7 @@
|
||||
inContext:[self context]];
|
||||
if (ex != nil) return ex;
|
||||
|
||||
return [self redirectToLocation:[self _completeURIForMethod:@"../view"]];
|
||||
return [self redirectToLocation: [self completeURIForMethod: @"../view"]];
|
||||
}
|
||||
|
||||
@end /* UIxAppointmentEditor */
|
||||
|
||||
151
UI/Scheduler/UIxComponentEditor.h
Normal file
151
UI/Scheduler/UIxComponentEditor.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/* UIxComponentEditor.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2006 Inverse groupe conseil
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@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 UIXCOMPONENTEDITOR_H
|
||||
#define UIXCOMPONENTEDITOR_H
|
||||
|
||||
#import <SOGoUI/UIxComponent.h>
|
||||
|
||||
@class NSArray;
|
||||
@class NSCalendarDate;
|
||||
@class NSDictionary;
|
||||
@class NSFormatter;
|
||||
@class NSString;
|
||||
|
||||
@class iCalPerson;
|
||||
@class iCalRecurrenceRule;
|
||||
@class iCalRepeatableEntityObject;
|
||||
|
||||
@interface UIxComponentEditor : UIxComponent
|
||||
{
|
||||
@private
|
||||
NSString *iCalString;
|
||||
NSString *errorText;
|
||||
id item;
|
||||
|
||||
/* individual values */
|
||||
NSCalendarDate *startDate;
|
||||
NSCalendarDate *cycleUntilDate;
|
||||
NSString *title;
|
||||
NSString *location;
|
||||
NSString *comment;
|
||||
iCalPerson *organizer;
|
||||
NSArray *participants; /* array of iCalPerson's */
|
||||
NSArray *resources; /* array of iCalPerson's */
|
||||
NSString *priority;
|
||||
NSArray *categories;
|
||||
NSString *accessClass;
|
||||
BOOL isPrivate; /* default: NO */
|
||||
BOOL checkForConflicts; /* default: NO */
|
||||
NSDictionary *cycle;
|
||||
NSString *cycleEnd;
|
||||
}
|
||||
|
||||
- (void) setAccessClass: (NSString *) _class;
|
||||
- (NSString *) accessClass;
|
||||
|
||||
- (void) setIsPrivate: (BOOL) _yn;
|
||||
- (BOOL) isPrivate;
|
||||
|
||||
- (NSArray *) categoryItems;
|
||||
- (void) setCategories: (NSArray *) _categories;
|
||||
- (NSArray *) categories;
|
||||
- (NSString *) itemCategoryText;
|
||||
|
||||
- (NSArray *) priorities;
|
||||
- (void) setPriority: (NSString *) _priority;
|
||||
- (NSString *) priority;
|
||||
|
||||
- (void) setItem: (id) _item;
|
||||
- (id) item;
|
||||
- (NSString *) itemPriorityText;
|
||||
|
||||
- (void) setErrorText: (NSString *) _txt;
|
||||
- (NSString *) errorText;
|
||||
- (BOOL) hasErrorText;
|
||||
|
||||
- (void) setICalString: (NSString *) _s;
|
||||
- (NSString *) iCalString;
|
||||
|
||||
- (void) setStartDate: (NSCalendarDate *) _date;
|
||||
- (NSCalendarDate *) startDate;
|
||||
|
||||
- (void) setTitle: (NSString *) _value;
|
||||
- (NSString *) title;
|
||||
|
||||
- (void) setLocation: (NSString *) _value;
|
||||
- (NSString *) location;
|
||||
|
||||
- (void) setComment: (NSString *) _value;
|
||||
- (NSString *) comment;
|
||||
|
||||
- (void) setParticipants: (NSArray *) _parts;
|
||||
- (NSArray *) participants;
|
||||
|
||||
- (void) setResources: (NSArray *) _res;
|
||||
- (NSArray *) resources;
|
||||
|
||||
- (void) setCheckForConflicts: (BOOL) _checkForConflicts;
|
||||
- (BOOL) checkForConflicts;
|
||||
|
||||
- (NSArray *) cycles;
|
||||
- (void) setCycle: (NSDictionary *) _cycle;
|
||||
- (NSDictionary *) cycle;
|
||||
- (BOOL) hasCycle;
|
||||
- (NSString *) cycleLabel;
|
||||
- (void) setCycleUntilDate: (NSCalendarDate *) _cycleUntilDate;
|
||||
- (NSCalendarDate *) cycleUntilDate;
|
||||
- (iCalRecurrenceRule *) rrule;
|
||||
- (void) adjustCycleControlsForRRule: (iCalRecurrenceRule *) _rrule;
|
||||
- (NSDictionary *) cycleMatchingRRule: (iCalRecurrenceRule *) _rrule;
|
||||
- (NSArray *) cycleEnds;
|
||||
- (void) setCycleEnd: (NSString *) _cycleEnd;
|
||||
- (NSString *) cycleEnd;
|
||||
- (BOOL) isCycleEndUntil;
|
||||
- (void) setIsCycleEndUntil;
|
||||
- (void) setIsCycleEndNever;
|
||||
|
||||
/* access */
|
||||
- (BOOL) isMyComponent;
|
||||
- (BOOL) canAccessComponent;
|
||||
- (BOOL) canEditComponent;
|
||||
|
||||
/* helpers */
|
||||
- (NSFormatter *) titleDateFormatter;
|
||||
- (NSString *) completeURIForMethod: (NSString *) _method;
|
||||
- (BOOL) isWriteableClientObject;
|
||||
- (NSException *) validateObjectForStatusChange;
|
||||
|
||||
/* subclasses */
|
||||
- (void) loadValuesFromComponent: (iCalRepeatableEntityObject *) component;
|
||||
|
||||
- (NSString *) iCalStringTemplate;
|
||||
- (NSString *) iCalParticipantsAndResourcesStringFromQueryParameters;
|
||||
- (NSString *) iCalParticipantsStringFromQueryParameters;
|
||||
- (NSString *) iCalResourcesStringFromQueryParameters;
|
||||
- (NSString *) iCalStringFromQueryParameter: (NSString *) _qp
|
||||
format: (NSString *) _format;
|
||||
- (NSString *) iCalOrganizerString;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* UIXCOMPONENTEDITOR_H */
|
||||
692
UI/Scheduler/UIxComponentEditor.m
Normal file
692
UI/Scheduler/UIxComponentEditor.m
Normal file
@@ -0,0 +1,692 @@
|
||||
/* UIxComponentEditor.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2006 Inverse groupe conseil
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@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/NSBundle.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalRepeatableEntityObject.h>
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
#import <NGCards/NSCalendarDate+NGCards.h>
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
|
||||
#import <SOGo/AgenorUserManager.h>
|
||||
#import <SOGoUI/SOGoDateFormatter.h>
|
||||
|
||||
#import "UIxComponent+Agenor.h"
|
||||
|
||||
#import "UIxComponentEditor.h"
|
||||
|
||||
@implementation UIxComponentEditor
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
[self setIsPrivate: NO];
|
||||
[self setCheckForConflicts: NO];
|
||||
[self setIsCycleEndNever];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[iCalString release];
|
||||
[errorText release];
|
||||
[item release];
|
||||
[startDate release];
|
||||
[cycleUntilDate release];
|
||||
[title release];
|
||||
[location release];
|
||||
[organizer release];
|
||||
[comment release];
|
||||
[participants release];
|
||||
[resources release];
|
||||
[priority release];
|
||||
[categories release];
|
||||
[accessClass release];
|
||||
[cycle release];
|
||||
[cycleEnd release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (void) setAccessClass: (NSString *) _class
|
||||
{
|
||||
ASSIGN(accessClass, _class);
|
||||
}
|
||||
|
||||
- (NSString *) accessClass
|
||||
{
|
||||
return accessClass;
|
||||
}
|
||||
|
||||
- (void) setIsPrivate: (BOOL) _yn
|
||||
{
|
||||
if (_yn)
|
||||
[self setAccessClass:@"PRIVATE"];
|
||||
else
|
||||
[self setAccessClass:@"PUBLIC"];
|
||||
|
||||
isPrivate = _yn;
|
||||
}
|
||||
|
||||
- (BOOL) isPrivate
|
||||
{
|
||||
return isPrivate;
|
||||
}
|
||||
|
||||
- (void) setItem: (id) _item
|
||||
{
|
||||
ASSIGN(item, _item);
|
||||
}
|
||||
|
||||
- (id) item
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
- (NSString *) itemPriorityText
|
||||
{
|
||||
return [self labelForKey: [NSString stringWithFormat: @"prio_%@", item]];
|
||||
}
|
||||
|
||||
- (void) setErrorText: (NSString *) _txt
|
||||
{
|
||||
ASSIGNCOPY(errorText, _txt);
|
||||
}
|
||||
|
||||
- (NSString *) errorText
|
||||
{
|
||||
return errorText;
|
||||
}
|
||||
|
||||
- (BOOL) hasErrorText
|
||||
{
|
||||
return [errorText length] > 0 ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setStartDate: (NSCalendarDate *) _date
|
||||
{
|
||||
ASSIGN(startDate, _date);
|
||||
}
|
||||
|
||||
- (NSCalendarDate *) startDate
|
||||
{
|
||||
return startDate;
|
||||
}
|
||||
|
||||
- (void) setTitle: (NSString *) _value
|
||||
{
|
||||
ASSIGNCOPY(title, _value);
|
||||
}
|
||||
|
||||
- (NSString *) title
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
- (void) setLocation: (NSString *) _value
|
||||
{
|
||||
ASSIGNCOPY(location, _value);
|
||||
}
|
||||
|
||||
- (NSString *) location
|
||||
{
|
||||
return location;
|
||||
}
|
||||
|
||||
- (void) setComment: (NSString *) _value
|
||||
{
|
||||
ASSIGNCOPY(comment, _value);
|
||||
}
|
||||
|
||||
- (NSString *) comment
|
||||
{
|
||||
return comment;
|
||||
}
|
||||
|
||||
- (NSArray *) categoryItems
|
||||
{
|
||||
// TODO: make this configurable?
|
||||
/*
|
||||
Tasks categories will be modified as follow :
|
||||
– by default (a simple logo or no logo at all),
|
||||
– task,
|
||||
– outside,
|
||||
– meeting,
|
||||
– holidays,
|
||||
– phone.
|
||||
*/
|
||||
static NSArray *categoryItems = nil;
|
||||
|
||||
if (!categoryItems)
|
||||
{
|
||||
categoryItems = [NSArray arrayWithObjects: @"APPOINTMENT",
|
||||
@"NOT IN OFFICE",
|
||||
@"MEETING",
|
||||
@"HOLIDAY",
|
||||
@"PHONE CALL",
|
||||
nil];
|
||||
[categoryItems retain];
|
||||
}
|
||||
|
||||
return categoryItems;
|
||||
}
|
||||
|
||||
- (void) setCategories: (NSArray *) _categories
|
||||
{
|
||||
ASSIGN(categories, _categories);
|
||||
}
|
||||
|
||||
- (NSArray *) categories
|
||||
{
|
||||
return categories;
|
||||
}
|
||||
|
||||
- (NSString *) itemCategoryText
|
||||
{
|
||||
return [[self labelForKey: item] stringByEscapingHTMLString];
|
||||
}
|
||||
|
||||
/* priorities */
|
||||
|
||||
- (NSArray *) priorities
|
||||
{
|
||||
/* 0 == undefined
|
||||
5 == normal
|
||||
1 == high
|
||||
*/
|
||||
static NSArray *priorities = nil;
|
||||
|
||||
if (!priorities)
|
||||
{
|
||||
priorities = [NSArray arrayWithObjects:@"0", @"5", @"1", nil];
|
||||
[priorities retain];
|
||||
}
|
||||
|
||||
return priorities;
|
||||
}
|
||||
|
||||
- (void) setPriority: (NSString *) _priority
|
||||
{
|
||||
ASSIGN(priority, _priority);
|
||||
}
|
||||
|
||||
- (NSString *) priority
|
||||
{
|
||||
return priority;
|
||||
}
|
||||
|
||||
- (void) setParticipants: (NSArray *) _parts
|
||||
{
|
||||
ASSIGN(participants, _parts);
|
||||
}
|
||||
|
||||
- (NSArray *) participants
|
||||
{
|
||||
return participants;
|
||||
}
|
||||
|
||||
- (void) setResources: (NSArray *) _res
|
||||
{
|
||||
ASSIGN(resources, _res);
|
||||
}
|
||||
|
||||
- (NSArray *) resources
|
||||
{
|
||||
return resources;
|
||||
}
|
||||
|
||||
- (void) setCheckForConflicts: (BOOL) _checkForConflicts
|
||||
{
|
||||
checkForConflicts = _checkForConflicts;
|
||||
}
|
||||
|
||||
- (BOOL) checkForConflicts
|
||||
{
|
||||
return checkForConflicts;
|
||||
}
|
||||
|
||||
- (NSArray *) cycles
|
||||
{
|
||||
NSBundle *bundle;
|
||||
NSString *path;
|
||||
static NSArray *cycles = nil;
|
||||
|
||||
if (!cycles)
|
||||
{
|
||||
bundle = [NSBundle bundleForClass:[self class]];
|
||||
path = [bundle pathForResource:@"cycles" ofType:@"plist"];
|
||||
NSAssert(path != nil, @"Cannot find cycles.plist!");
|
||||
cycles = [[NSArray arrayWithContentsOfFile:path] retain];
|
||||
NSAssert(cycles != nil, @"Cannot instantiate cycles from cycles.plist!");
|
||||
}
|
||||
|
||||
return cycles;
|
||||
}
|
||||
|
||||
- (void) setCycle: (NSDictionary *) _cycle
|
||||
{
|
||||
ASSIGN(cycle, _cycle);
|
||||
}
|
||||
|
||||
- (NSDictionary *) cycle
|
||||
{
|
||||
return cycle;
|
||||
}
|
||||
|
||||
- (BOOL) hasCycle
|
||||
{
|
||||
return ([cycle objectForKey: @"rule"] != nil);
|
||||
}
|
||||
|
||||
- (NSString *) cycleLabel
|
||||
{
|
||||
NSString *key;
|
||||
|
||||
key = [(NSDictionary *)item objectForKey:@"label"];
|
||||
|
||||
return [self labelForKey:key];
|
||||
}
|
||||
|
||||
- (void) setCycleUntilDate: (NSCalendarDate *) _cycleUntilDate
|
||||
{
|
||||
NSCalendarDate *until;
|
||||
|
||||
/* copy hour/minute/second from startDate */
|
||||
until = [_cycleUntilDate hour: [startDate hourOfDay]
|
||||
minute: [startDate minuteOfHour]
|
||||
second: [startDate secondOfMinute]];
|
||||
[until setTimeZone: [startDate timeZone]];
|
||||
ASSIGN(cycleUntilDate, until);
|
||||
}
|
||||
|
||||
- (NSCalendarDate *) cycleUntilDate
|
||||
{
|
||||
return cycleUntilDate;
|
||||
}
|
||||
|
||||
- (iCalRecurrenceRule *) rrule
|
||||
{
|
||||
NSString *ruleRep;
|
||||
iCalRecurrenceRule *rule;
|
||||
|
||||
if (![self hasCycle])
|
||||
return nil;
|
||||
ruleRep = [cycle objectForKey:@"rule"];
|
||||
rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:ruleRep];
|
||||
|
||||
if (cycleUntilDate && [self isCycleEndUntil])
|
||||
[rule setUntilDate:cycleUntilDate];
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
- (void) adjustCycleControlsForRRule: (iCalRecurrenceRule *) _rrule
|
||||
{
|
||||
NSDictionary *c;
|
||||
NSCalendarDate *until;
|
||||
|
||||
c = [self cycleMatchingRRule:_rrule];
|
||||
[self setCycle:c];
|
||||
|
||||
until = [[[_rrule untilDate] copy] autorelease];
|
||||
if (!until)
|
||||
until = startDate;
|
||||
else
|
||||
[self setIsCycleEndUntil];
|
||||
|
||||
[until setTimeZone:[[self clientObject] userTimeZone]];
|
||||
[self setCycleUntilDate:until];
|
||||
}
|
||||
|
||||
/*
|
||||
This method is necessary, because we have a fixed sets of cycles in the UI.
|
||||
The model is able to represent arbitrary rules, however.
|
||||
There SHOULD be a different UI, similar to iCal.app, to allow modelling
|
||||
of more complex rules.
|
||||
|
||||
This method obviously cannot map all existing rules back to the fixed list
|
||||
in cycles.plist. This should be fixed in a future version when interop
|
||||
becomes more important.
|
||||
*/
|
||||
- (NSDictionary *) cycleMatchingRRule: (iCalRecurrenceRule *) _rrule
|
||||
{
|
||||
NSString *cycleRep;
|
||||
NSArray *cycles;
|
||||
unsigned i, count;
|
||||
|
||||
if (!_rrule)
|
||||
return [[self cycles] objectAtIndex:0];
|
||||
|
||||
cycleRep = [_rrule versitString];
|
||||
cycles = [self cycles];
|
||||
count = [cycles count];
|
||||
for (i = 1; i < count; i++) {
|
||||
NSDictionary *c;
|
||||
NSString *cr;
|
||||
|
||||
c = [cycles objectAtIndex:i];
|
||||
cr = [c objectForKey:@"rule"];
|
||||
if ([cr isEqualToString:cycleRep])
|
||||
return c;
|
||||
}
|
||||
[self warnWithFormat:@"No default cycle for rrule found! -> %@", _rrule];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* cycle "ends" - supposed to be 'never', 'COUNT' or 'UNTIL' */
|
||||
- (NSArray *) cycleEnds
|
||||
{
|
||||
static NSArray *ends = nil;
|
||||
|
||||
if (!ends)
|
||||
{
|
||||
ends = [NSArray arrayWithObjects: @"cycle_end_never",
|
||||
@"cycle_end_until", nil];
|
||||
[ends retain];
|
||||
}
|
||||
|
||||
return ends;
|
||||
}
|
||||
|
||||
- (void) setCycleEnd: (NSString *) _cycleEnd
|
||||
{
|
||||
ASSIGNCOPY(cycleEnd, _cycleEnd);
|
||||
}
|
||||
|
||||
- (NSString *) cycleEnd
|
||||
{
|
||||
return cycleEnd;
|
||||
}
|
||||
|
||||
- (BOOL) isCycleEndUntil
|
||||
{
|
||||
return (cycleEnd &&
|
||||
[cycleEnd isEqualToString:@"cycle_end_until"]);
|
||||
}
|
||||
|
||||
- (void) setIsCycleEndUntil
|
||||
{
|
||||
[self setCycleEnd:@"cycle_end_until"];
|
||||
}
|
||||
|
||||
- (void) setIsCycleEndNever
|
||||
{
|
||||
[self setCycleEnd:@"cycle_end_never"];
|
||||
}
|
||||
|
||||
/* helpers */
|
||||
- (NSFormatter *) titleDateFormatter
|
||||
{
|
||||
SOGoDateFormatter *fmt;
|
||||
|
||||
fmt = [[SOGoDateFormatter alloc] initWithLocale: [self locale]];
|
||||
[fmt autorelease];
|
||||
[fmt setFullWeekdayNameAndDetails];
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
- (NSString *) completeURIForMethod: (NSString *) _method
|
||||
{
|
||||
NSString *uri;
|
||||
NSRange r;
|
||||
|
||||
uri = [[[self context] request] uri];
|
||||
|
||||
/* first: identify query parameters */
|
||||
r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
|
||||
if (r.length > 0)
|
||||
uri = [uri substringToIndex:r.location];
|
||||
|
||||
/* next: append trailing slash */
|
||||
if (![uri hasSuffix:@"/"])
|
||||
uri = [uri stringByAppendingString:@"/"];
|
||||
|
||||
/* next: append method */
|
||||
uri = [uri stringByAppendingString:_method];
|
||||
|
||||
/* next: append query parameters */
|
||||
return [self completeHrefForMethod:uri];
|
||||
}
|
||||
|
||||
- (BOOL) isWriteableClientObject
|
||||
{
|
||||
return [[self clientObject]
|
||||
respondsToSelector:@selector(saveContentString:)];
|
||||
}
|
||||
|
||||
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) _rq
|
||||
inContext: (WOContext*) _c
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL) containsConflict: (id) _component
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
/* access */
|
||||
|
||||
#if 0
|
||||
- (iCalPerson *) getOrganizer
|
||||
{
|
||||
iCalPerson *p;
|
||||
NSString *emailProp;
|
||||
|
||||
emailProp = [@"mailto:" stringByAppendingString:[self emailForUser]];
|
||||
p = [[[iCalPerson alloc] init] autorelease];
|
||||
[p setEmail:emailProp];
|
||||
[p setCn:[self cnForUser]];
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (BOOL) isMyComponent
|
||||
{
|
||||
// TODO: this should check a set of emails against the SoUser
|
||||
return (![[organizer email] length]
|
||||
|| [[organizer rfc822Email] isEqualToString: [self emailForUser]]);
|
||||
}
|
||||
|
||||
- (BOOL) canAccessComponent
|
||||
{
|
||||
return [self isMyComponent];
|
||||
}
|
||||
|
||||
- (BOOL) canEditComponent
|
||||
{
|
||||
return [self isMyComponent];
|
||||
}
|
||||
|
||||
/* response generation */
|
||||
|
||||
- (NSString *) initialCycleVisibility
|
||||
{
|
||||
return ([self hasCycle]
|
||||
? @"visibility: visible;"
|
||||
: @"visibility: hidden;");
|
||||
}
|
||||
|
||||
- (NSString *) initialCycleEndUntilVisibility {
|
||||
return ([self isCycleEndUntil]
|
||||
? @"visibility: visible;"
|
||||
: @"visibility: hidden;");
|
||||
}
|
||||
|
||||
/* subclasses */
|
||||
- (void) loadValuesFromComponent: (iCalRepeatableEntityObject *) component
|
||||
{
|
||||
NSString *s;
|
||||
iCalRecurrenceRule *rrule;
|
||||
NSTimeZone *uTZ;
|
||||
|
||||
if ((startDate = [component startDate]) == nil)
|
||||
startDate = [[NSCalendarDate date] hour:11 minute:0];
|
||||
|
||||
uTZ = [[self clientObject] userTimeZone];
|
||||
[startDate setTimeZone: uTZ];
|
||||
[startDate retain];
|
||||
|
||||
title = [[component summary] copy];
|
||||
location = [[component location] copy];
|
||||
comment = [[component comment] copy];
|
||||
priority = [[component priority] copy];
|
||||
categories = [[[component categories] commaSeparatedValues] retain];
|
||||
organizer = [[component organizer] retain];
|
||||
participants = [[component participants] retain];
|
||||
resources = [[component resources] retain];
|
||||
|
||||
// NSLog (@"summary éàè: '%@'", title);
|
||||
|
||||
s = [component accessClass];
|
||||
if (!s || [s isEqualToString:@"PUBLIC"])
|
||||
[self setIsPrivate:NO];
|
||||
else
|
||||
[self setIsPrivate:YES]; /* we're possibly loosing information here */
|
||||
|
||||
/* cycles */
|
||||
if ([component isRecurrent])
|
||||
{
|
||||
rrule = [[component recurrenceRules] objectAtIndex: 0];
|
||||
[self adjustCycleControlsForRRule: rrule];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *) iCalStringTemplate
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString *) iCalParticipantsAndResourcesStringFromQueryParameters
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self iCalParticipantsStringFromQueryParameters];
|
||||
return [s stringByAppendingString:
|
||||
[self iCalResourcesStringFromQueryParameters]];
|
||||
}
|
||||
|
||||
- (NSString *) iCalParticipantsStringFromQueryParameters
|
||||
{
|
||||
static NSString *iCalParticipantString = \
|
||||
@"ATTENDEE;ROLE=REQ-PARTICIPANT;CN=\"%@\":mailto:%@\r\n";
|
||||
|
||||
return [self iCalStringFromQueryParameter: @"ps"
|
||||
format: iCalParticipantString];
|
||||
}
|
||||
|
||||
- (NSString *) iCalResourcesStringFromQueryParameters
|
||||
{
|
||||
static NSString *iCalResourceString = \
|
||||
@"ATTENDEE;ROLE=NON-PARTICIPANT;CN=\"%@\":mailto:%@\r\n";
|
||||
|
||||
return [self iCalStringFromQueryParameter: @"rs"
|
||||
format: iCalResourceString];
|
||||
}
|
||||
|
||||
- (NSString *) iCalStringFromQueryParameter: (NSString *) _qp
|
||||
format: (NSString *) _format
|
||||
{
|
||||
AgenorUserManager *um;
|
||||
NSMutableString *iCalRep;
|
||||
NSString *s;
|
||||
|
||||
um = [AgenorUserManager sharedUserManager];
|
||||
iCalRep = (NSMutableString *)[NSMutableString string];
|
||||
s = [self queryParameterForKey:_qp];
|
||||
if(s && [s length] > 0) {
|
||||
NSArray *es;
|
||||
unsigned i, count;
|
||||
|
||||
es = [s componentsSeparatedByString:@","];
|
||||
count = [es count];
|
||||
for(i = 0; i < count; i++) {
|
||||
NSString *email, *cn;
|
||||
|
||||
email = [es objectAtIndex:i];
|
||||
cn = [um getCNForUID:[um getUIDForEmail:email]];
|
||||
[iCalRep appendFormat:_format, cn, email];
|
||||
}
|
||||
}
|
||||
return iCalRep;
|
||||
}
|
||||
|
||||
- (NSString *) iCalOrganizerString
|
||||
{
|
||||
return [NSString stringWithFormat: @"ORGANIZER;CN=\"%@\":mailto:%@\r\n",
|
||||
[self cnForUser], [self emailForUser]];
|
||||
}
|
||||
|
||||
- (NSString *) saveUrl
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSException *) validateObjectForStatusChange
|
||||
{
|
||||
id co;
|
||||
|
||||
co = [self clientObject];
|
||||
if (![co
|
||||
respondsToSelector: @selector(changeParticipationStatus:inContext:)])
|
||||
return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
|
||||
reason:
|
||||
@"method cannot be invoked on the specified object"];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* contact editor compatibility */
|
||||
|
||||
- (void) setICalString: (NSString *) _s
|
||||
{
|
||||
ASSIGNCOPY(iCalString, _s);
|
||||
}
|
||||
|
||||
- (NSString *) iCalString
|
||||
{
|
||||
return iCalString;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -23,68 +23,52 @@
|
||||
#ifndef UIXTASKEDITOR_H
|
||||
#define UIXTASKEDITOR_H
|
||||
|
||||
#import <SOGoUI/UIxComponent.h>
|
||||
#import "UIxComponentEditor.h"
|
||||
|
||||
@class NSString;
|
||||
@class iCalPerson;
|
||||
@class iCalRecurrenceRule;
|
||||
@class iCalToDo;
|
||||
|
||||
@interface UIxTaskEditor : UIxComponent
|
||||
@interface UIxTaskEditor : UIxComponentEditor
|
||||
{
|
||||
NSString *iCalString;
|
||||
NSString *errorText;
|
||||
id item;
|
||||
|
||||
/* individual values */
|
||||
NSCalendarDate *startDate;
|
||||
NSCalendarDate *dueDate;
|
||||
NSCalendarDate *cycleUntilDate;
|
||||
NSString *title;
|
||||
NSString *location;
|
||||
NSString *comment;
|
||||
iCalPerson *organizer;
|
||||
NSArray *participants; /* array of iCalPerson's */
|
||||
NSArray *resources; /* array of iCalPerson's */
|
||||
NSString *priority;
|
||||
NSArray *categories;
|
||||
NSString *accessClass;
|
||||
BOOL isPrivate; /* default: NO */
|
||||
BOOL checkForConflicts; /* default: NO */
|
||||
NSDictionary *cycle;
|
||||
NSString *cycleEnd;
|
||||
}
|
||||
|
||||
- (NSString *)iCalStringTemplate;
|
||||
- (NSString *)iCalString;
|
||||
- (void) setTaskStartDate: (NSCalendarDate *) _date;
|
||||
- (NSCalendarDate *) taskStartDate;
|
||||
|
||||
- (void)setIsPrivate:(BOOL)_yn;
|
||||
- (void)setAccessClass:(NSString *)_class;
|
||||
- (void) setTaskDueDate: (NSCalendarDate *) _date;
|
||||
- (NSCalendarDate *) taskDueDate;
|
||||
|
||||
- (void)setCheckForConflicts:(BOOL)_checkForConflicts;
|
||||
- (BOOL)checkForConflicts;
|
||||
/* iCal */
|
||||
|
||||
- (BOOL)hasCycle;
|
||||
- (iCalRecurrenceRule *)rrule;
|
||||
- (void)adjustCycleControlsForRRule:(iCalRecurrenceRule *)_rrule;
|
||||
- (NSDictionary *)cycleMatchingRRule:(iCalRecurrenceRule *)_rrule;
|
||||
- (NSString *) iCalStringTemplate;
|
||||
|
||||
- (BOOL)isCycleEndUntil;
|
||||
- (void)setIsCycleEndUntil;
|
||||
- (void)setIsCycleEndNever;
|
||||
/* new */
|
||||
|
||||
- (NSString *)_completeURIForMethod:(NSString *)_method;
|
||||
- (id) newAction;
|
||||
|
||||
- (NSArray *)getICalPersonsFromFormValues:(NSArray *)_values
|
||||
treatAsResource:(BOOL)_isResource;
|
||||
/* save */
|
||||
|
||||
- (NSString *)iCalParticipantsAndResourcesStringFromQueryParameters;
|
||||
- (NSString *)iCalParticipantsStringFromQueryParameters;
|
||||
- (NSString *)iCalResourcesStringFromQueryParameters;
|
||||
- (NSString *)iCalStringFromQueryParameter:(NSString *)_qp
|
||||
format:(NSString *)_format;
|
||||
- (NSString *)iCalOrganizerString;
|
||||
- (void) loadValuesFromTask: (iCalToDo *) _task;
|
||||
- (void) saveValuesIntoTask: (iCalToDo *) _task;
|
||||
- (iCalToDo *) taskFromString: (NSString *) _iCalString;
|
||||
|
||||
- (id)acceptOrDeclineAction:(BOOL)_accept;
|
||||
/* conflict management */
|
||||
|
||||
- (BOOL) containsConflict: (id) _task;
|
||||
- (id <WOActionResults>) defaultAction;
|
||||
- (id <WOActionResults>) saveAction;
|
||||
- (id) changeStatusAction;
|
||||
- (id) acceptAction;
|
||||
- (id) declineAction;
|
||||
|
||||
- (NSString *) saveUrl;
|
||||
|
||||
// TODO: add tentatively
|
||||
|
||||
- (id) acceptOrDeclineAction: (BOOL) _accept;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
#import <NGCards/NSCalendarDate+NGCards.h>
|
||||
|
||||
#import <SOGo/NSCalendarDate+SOGo.h>
|
||||
|
||||
#import "UIxTaskEditor.h"
|
||||
@@ -39,382 +36,36 @@
|
||||
|
||||
@implementation UIxTaskEditor
|
||||
|
||||
+ (int)version {
|
||||
return [super version] + 0 /* v2 */;
|
||||
}
|
||||
|
||||
+ (void)initialize {
|
||||
NSAssert2([super version] == 2,
|
||||
@"invalid superclass (%@) version %i !",
|
||||
NSStringFromClass([self superclass]), [super version]);
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
[self setIsPrivate:NO];
|
||||
[self setCheckForConflicts:NO];
|
||||
[self setIsCycleEndNever];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[iCalString release];
|
||||
[errorText release];
|
||||
[item release];
|
||||
|
||||
[startDate release];
|
||||
- (void) dealloc
|
||||
{
|
||||
[dueDate release];
|
||||
[cycleUntilDate release];
|
||||
[title release];
|
||||
[location release];
|
||||
[organizer release];
|
||||
[comment release];
|
||||
[participants release];
|
||||
[resources release];
|
||||
[priority release];
|
||||
[categories release];
|
||||
[accessClass release];
|
||||
[cycle release];
|
||||
[cycleEnd release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (void) setItem: (id) _item
|
||||
- (void) setTaskStartDate: (NSCalendarDate *) _date
|
||||
{
|
||||
ASSIGN(item, _item);
|
||||
[self setStartDate: _date];
|
||||
}
|
||||
|
||||
- (id) item
|
||||
- (NSCalendarDate *) taskStartDate
|
||||
{
|
||||
return item;
|
||||
return [self startDate];
|
||||
}
|
||||
|
||||
- (void)setErrorText:(NSString *)_txt {
|
||||
ASSIGNCOPY(errorText, _txt);
|
||||
}
|
||||
- (NSString *)errorText {
|
||||
return errorText;
|
||||
}
|
||||
- (BOOL)hasErrorText {
|
||||
return [errorText length] > 0 ? YES : NO;
|
||||
}
|
||||
|
||||
- (NSFormatter *)titleDateFormatter {
|
||||
SOGoDateFormatter *fmt;
|
||||
|
||||
fmt = [[[SOGoDateFormatter alloc] initWithLocale:[self locale]] autorelease];
|
||||
[fmt setFullWeekdayNameAndDetails];
|
||||
return fmt;
|
||||
}
|
||||
|
||||
- (void)setTaskStartDate:(NSCalendarDate *)_date {
|
||||
ASSIGN(startDate, _date);
|
||||
}
|
||||
- (NSCalendarDate *)taskStartDate {
|
||||
return startDate;
|
||||
}
|
||||
- (void)setTaskDueDate:(NSCalendarDate *)_date {
|
||||
- (void) setTaskDueDate: (NSCalendarDate *) _date
|
||||
{
|
||||
ASSIGN(dueDate, _date);
|
||||
}
|
||||
- (NSCalendarDate *)taskDueDate {
|
||||
|
||||
- (NSCalendarDate *) taskDueDate
|
||||
{
|
||||
return dueDate;
|
||||
}
|
||||
|
||||
- (void)setTitle:(NSString *)_value {
|
||||
ASSIGNCOPY(title, _value);
|
||||
}
|
||||
- (NSString *)title {
|
||||
return title;
|
||||
}
|
||||
- (void)setLocation:(NSString *)_value {
|
||||
ASSIGNCOPY(location, _value);
|
||||
}
|
||||
- (NSString *)location {
|
||||
return location;
|
||||
}
|
||||
- (void)setComment:(NSString *)_value {
|
||||
ASSIGNCOPY(comment, _value);
|
||||
}
|
||||
- (NSString *)comment {
|
||||
return comment;
|
||||
}
|
||||
|
||||
- (void)setParticipants:(NSArray *)_parts {
|
||||
ASSIGN(participants, _parts);
|
||||
}
|
||||
- (NSArray *)participants {
|
||||
return participants;
|
||||
}
|
||||
- (void)setResources:(NSArray *)_res {
|
||||
ASSIGN(resources, _res);
|
||||
}
|
||||
- (NSArray *)resources {
|
||||
return resources;
|
||||
}
|
||||
|
||||
/* priorities */
|
||||
|
||||
- (NSArray *)priorities {
|
||||
/* 0 == undefined
|
||||
5 == normal
|
||||
1 == high
|
||||
*/
|
||||
static NSArray *priorities = nil;
|
||||
|
||||
if (!priorities)
|
||||
priorities = [[NSArray arrayWithObjects:@"0", @"5", @"1", nil] retain];
|
||||
return priorities;
|
||||
}
|
||||
|
||||
- (NSString *)itemPriorityText {
|
||||
NSString *key;
|
||||
|
||||
key = [NSString stringWithFormat:@"prio_%@", item];
|
||||
return [self labelForKey:key];
|
||||
}
|
||||
|
||||
- (void)setPriority:(NSString *)_priority {
|
||||
ASSIGN(priority, _priority);
|
||||
}
|
||||
- (NSString *)priority {
|
||||
return priority;
|
||||
}
|
||||
|
||||
|
||||
/* categories */
|
||||
|
||||
- (NSArray *)categoryItems {
|
||||
// TODO: make this configurable?
|
||||
/*
|
||||
Tasks categories will be modified as follow :
|
||||
– by default (a simple logo or no logo at all),
|
||||
– task,
|
||||
– outside,
|
||||
– meeting,
|
||||
– holidays,
|
||||
– phone.
|
||||
*/
|
||||
static NSArray *categoryItems = nil;
|
||||
|
||||
if (!categoryItems) {
|
||||
categoryItems = [[NSArray arrayWithObjects:@"TASK",
|
||||
@"NOT IN OFFICE",
|
||||
@"MEETING",
|
||||
@"HOLIDAY",
|
||||
@"PHONE CALL",
|
||||
nil] retain];
|
||||
}
|
||||
return categoryItems;
|
||||
}
|
||||
|
||||
- (NSString *) itemCategoryText {
|
||||
return [[self labelForKey: item] stringByEscapingHTMLString];
|
||||
}
|
||||
|
||||
- (void)setCategories:(NSArray *)_categories {
|
||||
ASSIGN(categories, _categories);
|
||||
}
|
||||
|
||||
- (NSArray *)categories {
|
||||
return categories;
|
||||
}
|
||||
|
||||
/* class */
|
||||
|
||||
#if 0
|
||||
- (NSArray *)accessClassItems {
|
||||
static NSArray classItems = nil;
|
||||
|
||||
if (!classItems) {
|
||||
return [[NSArray arrayWithObjects:@"PUBLIC", @"PRIVATE", nil] retain];
|
||||
}
|
||||
return classItems;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)setAccessClass:(NSString *)_class {
|
||||
ASSIGN(accessClass, _class);
|
||||
}
|
||||
- (NSString *)accessClass {
|
||||
return accessClass;
|
||||
}
|
||||
|
||||
- (void)setIsPrivate:(BOOL)_yn {
|
||||
if (_yn)
|
||||
[self setAccessClass:@"PRIVATE"];
|
||||
else
|
||||
[self setAccessClass:@"PUBLIC"];
|
||||
isPrivate = _yn;
|
||||
}
|
||||
- (BOOL)isPrivate {
|
||||
return isPrivate;
|
||||
}
|
||||
|
||||
- (void)setCheckForConflicts:(BOOL)_checkForConflicts {
|
||||
checkForConflicts = _checkForConflicts;
|
||||
}
|
||||
- (BOOL)checkForConflicts {
|
||||
return checkForConflicts;
|
||||
}
|
||||
|
||||
- (NSArray *)cycles {
|
||||
static NSArray *cycles = nil;
|
||||
|
||||
if (!cycles) {
|
||||
NSBundle *bundle;
|
||||
NSString *path;
|
||||
|
||||
bundle = [NSBundle bundleForClass:[self class]];
|
||||
path = [bundle pathForResource:@"cycles" ofType:@"plist"];
|
||||
NSAssert(path != nil, @"Cannot find cycles.plist!");
|
||||
cycles = [[NSArray arrayWithContentsOfFile:path] retain];
|
||||
NSAssert(cycles != nil, @"Cannot instantiate cycles from cycles.plist!");
|
||||
}
|
||||
return cycles;
|
||||
}
|
||||
|
||||
- (void)setCycle:(NSDictionary *)_cycle {
|
||||
ASSIGN(cycle, _cycle);
|
||||
}
|
||||
- (NSDictionary *)cycle {
|
||||
return cycle;
|
||||
}
|
||||
- (BOOL)hasCycle {
|
||||
[self debugWithFormat:@"cycle: %@", cycle];
|
||||
if (![cycle objectForKey:@"rule"])
|
||||
return NO;
|
||||
return YES;
|
||||
}
|
||||
- (NSString *)cycleLabel {
|
||||
NSString *key;
|
||||
|
||||
key = [(NSDictionary *)item objectForKey:@"label"];
|
||||
return [self labelForKey:key];
|
||||
}
|
||||
|
||||
|
||||
- (void)setCycleUntilDate:(NSCalendarDate *)_cycleUntilDate {
|
||||
NSCalendarDate *until;
|
||||
|
||||
/* copy hour/minute/second from startDate */
|
||||
until = [_cycleUntilDate hour:[startDate hourOfDay]
|
||||
minute:[startDate minuteOfHour]
|
||||
second:[startDate secondOfMinute]];
|
||||
[until setTimeZone:[startDate timeZone]];
|
||||
ASSIGN(cycleUntilDate, until);
|
||||
}
|
||||
- (NSCalendarDate *)cycleUntilDate {
|
||||
return cycleUntilDate;
|
||||
}
|
||||
|
||||
- (iCalRecurrenceRule *)rrule {
|
||||
NSString *ruleRep;
|
||||
iCalRecurrenceRule *rule;
|
||||
|
||||
if (![self hasCycle])
|
||||
return nil;
|
||||
ruleRep = [cycle objectForKey:@"rule"];
|
||||
rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:ruleRep];
|
||||
|
||||
if (cycleUntilDate && [self isCycleEndUntil])
|
||||
[rule setUntilDate:cycleUntilDate];
|
||||
return rule;
|
||||
}
|
||||
|
||||
- (void)adjustCycleControlsForRRule:(iCalRecurrenceRule *)_rrule {
|
||||
NSDictionary *c;
|
||||
NSCalendarDate *until;
|
||||
|
||||
c = [self cycleMatchingRRule:_rrule];
|
||||
[self setCycle:c];
|
||||
|
||||
until = [[[_rrule untilDate] copy] autorelease];
|
||||
if (!until)
|
||||
until = startDate;
|
||||
else
|
||||
[self setIsCycleEndUntil];
|
||||
|
||||
[until setTimeZone:[[self clientObject] userTimeZone]];
|
||||
[self setCycleUntilDate:until];
|
||||
}
|
||||
|
||||
/*
|
||||
This method is necessary, because we have a fixed sets of cycles in the UI.
|
||||
The model is able to represent arbitrary rules, however.
|
||||
There SHOULD be a different UI, similar to iCal.app, to allow modelling
|
||||
of more complex rules.
|
||||
|
||||
This method obviously cannot map all existing rules back to the fixed list
|
||||
in cycles.plist. This should be fixed in a future version when interop
|
||||
becomes more important.
|
||||
*/
|
||||
- (NSDictionary *)cycleMatchingRRule:(iCalRecurrenceRule *)_rrule {
|
||||
NSString *cycleRep;
|
||||
NSArray *cycles;
|
||||
unsigned i, count;
|
||||
|
||||
if (!_rrule)
|
||||
return [[self cycles] objectAtIndex:0];
|
||||
|
||||
cycleRep = [_rrule versitString];
|
||||
cycles = [self cycles];
|
||||
count = [cycles count];
|
||||
for (i = 1; i < count; i++) {
|
||||
NSDictionary *c;
|
||||
NSString *cr;
|
||||
|
||||
c = [cycles objectAtIndex:i];
|
||||
cr = [c objectForKey:@"rule"];
|
||||
if ([cr isEqualToString:cycleRep])
|
||||
return c;
|
||||
}
|
||||
[self warnWithFormat:@"No default cycle for rrule found! -> %@", _rrule];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* cycle "ends" - supposed to be 'never', 'COUNT' or 'UNTIL' */
|
||||
- (NSArray *)cycleEnds {
|
||||
static NSArray *ends = nil;
|
||||
|
||||
if (!ends) {
|
||||
ends = [[NSArray alloc] initWithObjects:@"cycle_end_never",
|
||||
@"cycle_end_until",
|
||||
nil];
|
||||
}
|
||||
return ends;
|
||||
}
|
||||
|
||||
- (void)setCycleEnd:(NSString *)_cycleEnd {
|
||||
ASSIGNCOPY(cycleEnd, _cycleEnd);
|
||||
}
|
||||
- (NSString *)cycleEnd {
|
||||
return cycleEnd;
|
||||
}
|
||||
- (BOOL)isCycleEndUntil {
|
||||
return (cycleEnd &&
|
||||
[cycleEnd isEqualToString:@"cycle_end_until"]);
|
||||
}
|
||||
- (void)setIsCycleEndUntil {
|
||||
[self setCycleEnd:@"cycle_end_until"];
|
||||
}
|
||||
- (void)setIsCycleEndNever {
|
||||
[self setCycleEnd:@"cycle_end_never"];
|
||||
}
|
||||
|
||||
/* iCal */
|
||||
|
||||
- (void)setICalString:(NSString *)_s {
|
||||
ASSIGNCOPY(iCalString, _s);
|
||||
}
|
||||
- (NSString *)iCalString {
|
||||
return iCalString;
|
||||
}
|
||||
|
||||
- (NSString *)iCalStringTemplate {
|
||||
- (NSString *) iCalStringTemplate
|
||||
{
|
||||
static NSString *iCalStringTemplate = \
|
||||
@"BEGIN:VCALENDAR\r\n"
|
||||
@"METHOD:REQUEST\r\n"
|
||||
@@ -464,105 +115,10 @@
|
||||
return template;
|
||||
}
|
||||
|
||||
- (NSString *)iCalParticipantsAndResourcesStringFromQueryParameters {
|
||||
NSString *s;
|
||||
|
||||
s = [self iCalParticipantsStringFromQueryParameters];
|
||||
return [s stringByAppendingString:
|
||||
[self iCalResourcesStringFromQueryParameters]];
|
||||
}
|
||||
|
||||
- (NSString *)iCalParticipantsStringFromQueryParameters {
|
||||
static NSString *iCalParticipantString = \
|
||||
@"ATTENDEE;ROLE=REQ-PARTICIPANT;CN=\"%@\":mailto:%@\r\n";
|
||||
|
||||
return [self iCalStringFromQueryParameter:@"ps"
|
||||
format:iCalParticipantString];
|
||||
}
|
||||
|
||||
- (NSString *)iCalResourcesStringFromQueryParameters {
|
||||
static NSString *iCalResourceString = \
|
||||
@"ATTENDEE;ROLE=NON-PARTICIPANT;CN=\"%@\":mailto:%@\r\n";
|
||||
|
||||
return [self iCalStringFromQueryParameter:@"rs"
|
||||
format:iCalResourceString];
|
||||
}
|
||||
|
||||
- (NSString *)iCalStringFromQueryParameter:(NSString *)_qp
|
||||
format:(NSString *)_format
|
||||
{
|
||||
AgenorUserManager *um;
|
||||
NSMutableString *iCalRep;
|
||||
NSString *s;
|
||||
|
||||
um = [AgenorUserManager sharedUserManager];
|
||||
iCalRep = (NSMutableString *)[NSMutableString string];
|
||||
s = [self queryParameterForKey:_qp];
|
||||
if(s && [s length] > 0) {
|
||||
NSArray *es;
|
||||
unsigned i, count;
|
||||
|
||||
es = [s componentsSeparatedByString:@","];
|
||||
count = [es count];
|
||||
for(i = 0; i < count; i++) {
|
||||
NSString *email, *cn;
|
||||
|
||||
email = [es objectAtIndex:i];
|
||||
cn = [um getCNForUID:[um getUIDForEmail:email]];
|
||||
[iCalRep appendFormat:_format, cn, email];
|
||||
}
|
||||
}
|
||||
return iCalRep;
|
||||
}
|
||||
|
||||
- (NSString *)iCalOrganizerString {
|
||||
static NSString *fmt = @"ORGANIZER;CN=\"%@\":mailto:%@\r\n";
|
||||
return [NSString stringWithFormat:fmt,
|
||||
[self cnForUser],
|
||||
[self emailForUser]];
|
||||
}
|
||||
|
||||
#if 0
|
||||
- (iCalPerson *)getOrganizer {
|
||||
iCalPerson *p;
|
||||
NSString *emailProp;
|
||||
|
||||
emailProp = [@"mailto:" stringByAppendingString:[self emailForUser]];
|
||||
p = [[[iCalPerson alloc] init] autorelease];
|
||||
[p setEmail:emailProp];
|
||||
[p setCn:[self cnForUser]];
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* helper */
|
||||
|
||||
- (NSString *)_completeURIForMethod:(NSString *)_method {
|
||||
NSString *uri;
|
||||
NSRange r;
|
||||
|
||||
uri = [[[self context] request] uri];
|
||||
|
||||
/* first: identify query parameters */
|
||||
r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
|
||||
if (r.length > 0)
|
||||
uri = [uri substringToIndex:r.location];
|
||||
|
||||
/* next: append trailing slash */
|
||||
if (![uri hasSuffix:@"/"])
|
||||
uri = [uri stringByAppendingString:@"/"];
|
||||
|
||||
/* next: append method */
|
||||
uri = [uri stringByAppendingString:_method];
|
||||
|
||||
/* next: append query parameters */
|
||||
return [self completeHrefForMethod:uri];
|
||||
}
|
||||
|
||||
/* new */
|
||||
|
||||
- (id)newAction {
|
||||
- (id) newAction
|
||||
{
|
||||
/*
|
||||
This method creates a unique ID and redirects to the "edit" method on the
|
||||
new ID.
|
||||
@@ -618,120 +174,24 @@
|
||||
|
||||
/* save */
|
||||
|
||||
/* returned dates are in GMT */
|
||||
- (NSArray *) getICalPersonsFromFormValues: (NSArray *) _values
|
||||
treatAsResource: (BOOL) _isResource
|
||||
- (void) loadValuesFromTask: (iCalToDo *) _task
|
||||
{
|
||||
unsigned i, count;
|
||||
NSMutableArray *result;
|
||||
|
||||
count = [_values count];
|
||||
result = [[NSMutableArray alloc] initWithCapacity:count];
|
||||
for (i = 0; i < count; i++) {
|
||||
NSString *pString, *email, *cn;
|
||||
NSRange r;
|
||||
iCalPerson *p;
|
||||
|
||||
pString = [_values objectAtIndex:i];
|
||||
if ([pString length] == 0)
|
||||
continue;
|
||||
|
||||
/* delimiter between email and cn */
|
||||
r = [pString rangeOfString:@";"];
|
||||
if (r.length > 0) {
|
||||
email = [pString substringToIndex:r.location];
|
||||
cn = (r.location + 1 < [pString length])
|
||||
? [pString substringFromIndex:r.location + 1]
|
||||
: nil;
|
||||
}
|
||||
else {
|
||||
email = pString;
|
||||
cn = nil;
|
||||
}
|
||||
if (cn == nil) {
|
||||
/* fallback */
|
||||
AgenorUserManager *um = [AgenorUserManager sharedUserManager];
|
||||
cn = [um getCNForUID:[um getUIDForEmail:email]];
|
||||
}
|
||||
|
||||
p = [[iCalPerson alloc] init];
|
||||
[p setEmail:[@"mailto:" stringByAppendingString:email]];
|
||||
if ([cn isNotNull]) [p setCn:cn];
|
||||
|
||||
/* see RFC2445, sect. 4.2.16 for details */
|
||||
[p setRole:_isResource ? @"NON-PARTICIPANT" : @"REQ-PARTICIPANT"];
|
||||
[result addObject:p];
|
||||
[p release];
|
||||
}
|
||||
return [result autorelease];
|
||||
}
|
||||
|
||||
- (BOOL)isWriteableClientObject {
|
||||
return [[self clientObject]
|
||||
respondsToSelector:@selector(saveContentString:)];
|
||||
}
|
||||
|
||||
- (NSException *)validateObjectForStatusChange {
|
||||
BOOL ok;
|
||||
id co;
|
||||
|
||||
co = [self clientObject];
|
||||
ok = [co respondsToSelector:@selector(changeParticipationStatus:inContext:)];
|
||||
if (!ok) {
|
||||
return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
|
||||
reason:
|
||||
@"method cannot be invoked on the specified object"];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)loadValuesFromTask: (iCalToDo *)_task
|
||||
{
|
||||
NSString *s;
|
||||
iCalRecurrenceRule *rrule;
|
||||
NSTimeZone *uTZ;
|
||||
|
||||
if ((startDate = [_task startDate]) == nil)
|
||||
startDate = [[NSCalendarDate date] hour:11 minute:0];
|
||||
if ((dueDate = [_task due]) == nil) {
|
||||
dueDate =
|
||||
[startDate hour:[startDate hourOfDay] + 1 minute:0];
|
||||
}
|
||||
[self loadValuesFromComponent: _task];
|
||||
|
||||
uTZ = [[self clientObject] userTimeZone];
|
||||
[startDate setTimeZone: uTZ];
|
||||
dueDate = [_task due];
|
||||
if (!dueDate)
|
||||
dueDate = [[self startDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 1 minutes: 0 seconds: 0];
|
||||
|
||||
[dueDate setTimeZone: uTZ];
|
||||
// startDate = [startDate adjustedDate];
|
||||
// dueDate = [dueDate adjustedDate];
|
||||
[startDate retain];
|
||||
[dueDate retain];
|
||||
|
||||
title = [[_task summary] copy];
|
||||
location = [[_task location] copy];
|
||||
comment = [[_task comment] copy];
|
||||
priority = [[_task priority] copy];
|
||||
categories = [[[_task categories] commaSeparatedValues] retain];
|
||||
organizer = [[_task organizer] retain];
|
||||
participants = [[_task participants] retain];
|
||||
resources = [[_task resources] retain];
|
||||
|
||||
// NSLog (@"summary éàè: '%@'", title);
|
||||
|
||||
s = [_task accessClass];
|
||||
if(!s || [s isEqualToString:@"PUBLIC"])
|
||||
[self setIsPrivate:NO];
|
||||
else
|
||||
[self setIsPrivate:YES]; /* we're possibly loosing information here */
|
||||
|
||||
/* cycles */
|
||||
if ([_task isRecurrent])
|
||||
{
|
||||
rrule = [[_task recurrenceRules] objectAtIndex: 0];
|
||||
[self adjustCycleControlsForRRule:rrule];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)saveValuesIntoTask:(iCalToDo *)_task {
|
||||
- (void) saveValuesIntoTask: (iCalToDo *) _task
|
||||
{
|
||||
/* merge in form values */
|
||||
NSArray *attendees, *lResources;
|
||||
iCalRecurrenceRule *rrule;
|
||||
@@ -785,36 +245,10 @@
|
||||
return task;
|
||||
}
|
||||
|
||||
/* contact editor compatibility */
|
||||
|
||||
- (void)setContentString:(NSString *)_s {
|
||||
[self setICalString:_s];
|
||||
}
|
||||
- (NSString *)contentStringTemplate {
|
||||
return [self iCalStringTemplate];
|
||||
}
|
||||
|
||||
/* access */
|
||||
|
||||
- (BOOL) isMyTask
|
||||
{
|
||||
// TODO: this should check a set of emails against the SoUser
|
||||
return (![[organizer email] length]
|
||||
|| [[organizer rfc822Email] isEqualToString: [self emailForUser]]);
|
||||
}
|
||||
|
||||
- (BOOL)canAccessTask {
|
||||
return [self isMyTask];
|
||||
}
|
||||
|
||||
- (BOOL)canEditTask {
|
||||
return [self isMyTask];
|
||||
}
|
||||
|
||||
|
||||
/* conflict management */
|
||||
|
||||
- (BOOL)containsConflict:(iCalToDo *)_task {
|
||||
- (BOOL) containsConflict: (id) _task
|
||||
{
|
||||
NSArray *attendees, *uids;
|
||||
SOGoAppointmentFolder *groupCalendar;
|
||||
NSArray *infos;
|
||||
@@ -853,47 +287,6 @@
|
||||
return [ranges count] != 0 ? YES : NO;
|
||||
}
|
||||
|
||||
/* response generation */
|
||||
|
||||
- (NSString *)initialCycleVisibility {
|
||||
if (![self hasCycle])
|
||||
return @"visibility: hidden;";
|
||||
return @"visibility: visible;";
|
||||
}
|
||||
|
||||
- (NSString *)initialCycleEndUntilVisibility {
|
||||
if ([self isCycleEndUntil])
|
||||
return @"visibility: visible;";
|
||||
return @"visibility: hidden;";
|
||||
}
|
||||
|
||||
|
||||
/* actions */
|
||||
|
||||
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) _rq
|
||||
inContext: (WOContext*) _c
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id) testAction
|
||||
{
|
||||
/* for testing only */
|
||||
WORequest *req;
|
||||
iCalToDo *task;
|
||||
NSString *content;
|
||||
|
||||
req = [[self context] request];
|
||||
task = [self taskFromString: [self iCalString]];
|
||||
[self saveValuesIntoTask:task];
|
||||
content = [[task parent] versitString];
|
||||
[self logWithFormat:@"%s -- iCal:\n%@",
|
||||
__PRETTY_FUNCTION__,
|
||||
content];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id <WOActionResults>) defaultAction
|
||||
{
|
||||
NSString *ical;
|
||||
@@ -904,14 +297,14 @@
|
||||
// ical = [[self clientObject] valueForKey:@"iCalString"];
|
||||
ical = [[self clientObject] contentAsString];
|
||||
if ([ical length] == 0) /* a new task */
|
||||
ical = [self contentStringTemplate];
|
||||
ical = [self iCalStringTemplate];
|
||||
|
||||
[self setContentString:ical];
|
||||
[self setICalString:ical];
|
||||
[self loadValuesFromTask: [self taskFromString: ical]];
|
||||
|
||||
if (![self canEditTask]) {
|
||||
if (![self canEditComponent]) {
|
||||
/* TODO: we need proper ACLs */
|
||||
return [self redirectToLocation:[self _completeURIForMethod:@"../view"]];
|
||||
return [self redirectToLocation: [self completeURIForMethod: @"../view"]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -1017,7 +410,7 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
return [self redirectToLocation: [self _completeURIForMethod: @".."]];
|
||||
return [self redirectToLocation: [self completeURIForMethod: @".."]];
|
||||
}
|
||||
|
||||
- (id)acceptAction {
|
||||
@@ -1048,7 +441,7 @@
|
||||
inContext:[self context]];
|
||||
if (ex != nil) return ex;
|
||||
|
||||
return [self redirectToLocation:[self _completeURIForMethod:@"../view"]];
|
||||
return [self redirectToLocation: [self completeURIForMethod:@"../view"]];
|
||||
}
|
||||
|
||||
@end /* UIxTaskEditor */
|
||||
|
||||
Reference in New Issue
Block a user