refType = 4;
sourceTree = "<group>";
};
+ AD071F6606CE66DF00A9EEF4 = {
+ fileEncoding = 4;
+ indentWidth = 8;
+ isa = PBXFileReference;
+ lastKnownFileType = text;
+ path = README;
+ refType = 4;
+ sourceTree = "<group>";
+ tabWidth = 8;
+ };
AD152B6F06AC159A002375D2 = {
fileEncoding = 4;
isa = PBXFileReference;
AD6BCF12069D77E9003664CD,
AD6BCF0E069D77E9003664CD,
AD6BCF0F069D77E9003664CD,
+ AD071F6606CE66DF00A9EEF4,
AD6BCF10069D77E9003664CD,
AD6BCF11069D77E9003664CD,
AD0712CA06C917A600A9EEF4,
+2004-08-14 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * UIxComponent.m: new method -isUIxDebugEnabled, triggered by new
+ default "SOGoUIxDebugEnabled" (v0.9.9)
+
2004-08-13 Marcus Mueller <znek@mulle-kybernetik.com>
* v0.9.8
--- /dev/null
+Defaults
+========
+
+
+Name Value Synopsis
+------------------------------------------------------------------------------
+SOGoUIxDebugEnabled BOOL Trigger display of debug UI. Default is NO.
/* locale */
- (NSDictionary *)locale;
+/* Debugging */
+- (BOOL)isUIxDebugEnabled;
+
@end
#endif /* __UIxComponent_H_ */
static NSMutableArray *monthLabelKeys = nil;
static NSMutableArray *abbrMonthLabelKeys = nil;
+static BOOL uixDebugEnabled = NO;
+
+ (void)initialize {
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+
+ uixDebugEnabled = [ud boolForKey:@"SOGoUIxDebugEnabled"];
+
if (MET == nil) {
MET = [[NSTimeZone timeZoneWithAbbreviation:@"MET"] retain];
GMT = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
return [[self context] valueForKey:@"locale"];
}
+/* Debugging */
+
+- (BOOL)isUIxDebugEnabled {
+ return uixDebugEnabled;
+}
+
@end /* UIxComponent */
# $Id$
-SUBMINOR_VERSION:=8
+SUBMINOR_VERSION:=9
+2004-08-14 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * UIxAppointmentView.[h,m,wox], UIxAppointmentEditor.[h,m,wox]:
+ general enhancements, use new API. (v0.9.35)
+
2004-08-13 Marcus Mueller <znek@mulle-kybernetik.com>
* v0.9.34
/* TODO: CLEAN UP */
-@class NSString;
-@class SOGoAppointment;
+@class NSString, SOGoAppointment, iCalPerson;
@interface UIxAppointmentEditor : UIxComponent
{
- (NSString *)iCalStringTemplate;
- (NSString *)iCalString;
+- (NSString *)emailForUser;
+- (NSString *)cnForUser;
+
- (NSString *)_completeURIForMethod:(NSString *)_method;
+- (iCalPerson *)getOrganizer;
+- (NSArray *)getICalPersonsFromFormValues:(NSArray *)_values
+ treatAsResource:(BOOL)_isResource;
@end
+#include "common.h"
#include <SOGoUI/SOGoDateFormatter.h>
#include <SOGoLogic/SOGoAppointment.h>
#include <Appointments/SOGoAppointmentFolder.h>
#include <Appointments/SOGoAppointmentObject.h>
-#include "iCalPerson+UIx.h"
-#include "common.h"
#include <NGiCal/NGiCal.h>
+#include <SOGoLogic/AgenorUserManager.h>
+#include "iCalPerson+UIx.h"
@interface NSDate(UsedPrivates)
- (NSString *)icalString; // TODO: this is in NGiCal
/* backend */
-
- (SOGoAppointment *)appointment {
if (self->appointment == nil) {
self->appointment = [[SOGoAppointment alloc]
return self->appointment;
}
-- (BOOL)hasParticipants {
- return [[self participants] count] != 0;
-}
-
-- (NSArray *)participants {
-#warning TODO: FILTER ROLE!
- return [self->appointment attendees];
-}
-
-- (NSArray *)resources {
-#warning TODO: FILTER ROLE!
- return [self->appointment attendees];
-}
-
-
/* JavaScript */
- (NSString *)jsCode {
return [self completeHrefForMethod:uri];
}
-/* HACK: this is for agenor only */
+
+/* email, cn */
+
- (NSString *)emailForUser {
NSString *uid;
- NSRange r;
-#warning !! USE USER MANAGER INSTEAD!
uid = [[self user] login];
- r = [uid rangeOfString:@"@"];
- if(r.length > 0)
- return uid;
- return [NSString stringWithFormat:@"%@@equipement.gouv.fr", uid];
+ return [[AgenorUserManager sharedUserManager] getEmailForUID:uid];
+}
+
+- (NSString *)cnForUser {
+ NSString *uid;
+
+ uid = [[self user] login];
+ return [[AgenorUserManager sharedUserManager] getCNForUID:uid];
}
- (NSString *)combinedCNAndEmailForUser {
return [NSString stringWithFormat:@"%@;%@",
[self emailForUser],
- [self shortUserNameForDisplay]];
+ [self cnForUser]];
}
- (NSString *)combinedCNAndEmail {
return date;
}
+- (iCalPerson *)getOrganizer {
+ iCalPerson *p;
+ NSString *emailProp;
+
+ emailProp = [NSString stringWithFormat:@"mailto:%@",
+ [self emailForUser]];
+ p = [[iCalPerson alloc] init];
+ [p setEmail:emailProp];
+ [p setCn:[self cnForUser]];
+ return [p autorelease];
+}
+
+- (NSArray *)getICalPersonsFromFormValues:(NSArray *)_values
+ treatAsResource:(BOOL)_isResource
+{
+ 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];
+ if(r.location + 1 < [pString length]) {
+ cn = [pString substringFromIndex:r.location + 1];
+ }
+ else {
+ cn = 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)
+ [p setCn:cn];
+
+ /* see RFC2445, sect. 4.2.16 for details */
+ if(_isResource) {
+ [p setRole:@"X-OGo-RESOURCE"];
+ }
+ else {
+ [p setRole:@"REQ-PARTICIPANT"];
+ }
+ [result addObject:p];
+ [p release];
+ }
+ return [result autorelease];
+}
+
/* for testing only */
- (id)testAction {
WORequest *req;
NSString *iCalString;
NSString *summary, *location, *uri;
NSCalendarDate *sd, *ed;
- NSArray *ps;
- unsigned i, count;
+ NSArray *attendees;
WORequest *req;
[apt setLocation:location];
[apt removeAllAttendees]; /* clean up */
- ps = [req formValuesForKey:@"participants"];
- count = [ps count];
- for (i = 0; i < count; i++) {
- NSString *pString, *email, *cn;
- NSRange r;
- iCalPerson *p;
-
- pString = [ps objectAtIndex:i];
- if([pString length] == 0)
- continue;
-
- /* delimiter between email and cn */
- r = [pString rangeOfString:@";"];
- if(r.length > 0) {
- email = [pString substringToIndex:r.location];
- if(r.location + 1 < [pString length]) {
- cn = [pString substringFromIndex:r.location + 1];
- }
- else {
- cn = nil;
- }
- }
- else {
- email = pString;
- cn = nil;
- }
- if(cn == nil) {
- /* construct a fake CN if possible */
- r = [email rangeOfString:@"@"];
- if (r.length > 0)
- cn = [email substringToIndex:r.location];
- }
- p = [[iCalPerson alloc] init];
- [p setEmail:[@"mailto:" stringByAppendingString:email]];
- if(cn)
- [p setCn:cn];
- [apt addToAttendees:p];
- [p release];
- }
-
+ attendees = \
+ [self getICalPersonsFromFormValues:[req formValuesForKey:@"participants"]
+ treatAsResource:NO];
+ [apt appendAttendees:attendees];
+ attendees = \
+ [self getICalPersonsFromFormValues:[req formValuesForKey:@"resources"]
+ treatAsResource:YES];
+ [apt appendAttendees:attendees];
+ [apt setOrganizer:[self getOrganizer]];
+
/* receive current representation for save operation */
iCalString = [apt iCalString];
[apt release]; apt = nil;
/>
<hr />
<table id="participants">
- <var:if condition="hasParticipants" const:negate="YES">
+ <var:if condition="appointment.hasParticipants"
+ const:negate="YES"
+ >
<tr>
<td><input type="checkbox"
checked="YES"
var:id="emailForUser"
name="participants"
/></td>
- <td><var:string value="shortUserNameForDisplay" /></td>
+ <td><var:string value="cnForUser" /></td>
</tr>
</var:if>
- <var:if condition="hasParticipants">
- <var:foreach list="participants" item="item">
+ <var:if condition="appointment.hasParticipants">
+ <var:foreach list="appointment.participants"
+ item="item"
+ >
<tr>
<td><input type="checkbox"
checked="YES"
/>
<hr />
<table id="resources">
- <var:foreach list="resources" item="item">
+ <var:foreach list="appointment.resources"
+ item="item"
+ >
<tr>
<td><input type="checkbox"
checked="YES"
</tr>
</table>
</form>
- <!-- -->
- <hr />
- clientObject: <var:string value="clientObject" />
+ <var:if condition="isUIxDebugEnabled">
+ <hr />
+ clientObject: <var:string value="clientObject" />
+ </var:if>
</var:component>
#include <SOGoUI/UIxComponent.h>
+@class SOGoDateFormatter;
+
@interface UIxAppointmentView : UIxComponent
{
NSString *tabSelection;
id appointment;
id attendee;
+ SOGoDateFormatter *dateFormatter;
}
- (id)appointment;
// $Id$
#include "UIxAppointmentView.h"
-#include "common.h"
#include <NGiCal/NGiCal.h>
#include <SOGoLogic/SOGoAppointment.h>
+#include <SOGoUI/SOGoDateFormatter.h>
+#include "common.h"
@implementation UIxAppointmentView
- (void)dealloc {
[self->appointment release];
[self->attendee release];
+ [self->dateFormatter release];
[super dealloc];
}
return self->attendee;
}
-/* backend */
-
-- (SOGoAppointment *)appointment {
- NSString *iCalString;
-
- if (self->appointment)
- return self->appointment;
-
- iCalString = [[self clientObject] valueForKey:@"iCalString"];
- if (![iCalString isNotNull] || [iCalString length] == 0) {
- [self debugWithFormat:@"ERROR(%s): missing iCal string!",
- __PRETTY_FUNCTION__];
- return nil;
- }
-
- self->appointment = [[SOGoAppointment alloc] initWithICalString:iCalString];
- return self->appointment;
+- (SOGoDateFormatter *)dateFormatter {
+ if(self->dateFormatter == nil) {
+ self->dateFormatter = \
+ [[SOGoDateFormatter alloc] initWithLocale:[self locale]];
+ [self->dateFormatter setFullWeekdayNameAndDetails];
+ }
+ return self->dateFormatter;
}
-- (NSString *)formattedAptStartTime {
+- (NSCalendarDate *)startTime {
NSCalendarDate *date;
date = [[self appointment] startDate];
[date setTimeZone:[self viewTimeZone]];
- return [date descriptionWithCalendarFormat:@"%A, %Y-%m-%d %H:%M %Z"];
+ return date;
}
-- (NSString *)formattedAptEndTime {
+- (NSCalendarDate *)endTime {
NSCalendarDate *date;
date = [[self appointment] endDate];
[date setTimeZone:[self viewTimeZone]];
- return [date descriptionWithCalendarFormat:@"%A, %Y-%m-%d %H:%M %Z"];
+ return date;
+}
+
+- (NSString *)resourcesAsString {
+ NSArray *resources, *cns;
+
+ resources = [[self appointment] resources];
+ cns = [resources valueForKey:@"cnForDisplay"];
+ return [cns componentsJoinedByString:@"<br />"];
+}
+
+
+/* backend */
+
+- (SOGoAppointment *)appointment {
+ NSString *iCalString;
+
+ if (self->appointment)
+ return self->appointment;
+
+ iCalString = [[self clientObject] valueForKey:@"iCalString"];
+ if (![iCalString isNotNull] || [iCalString length] == 0) {
+ [self debugWithFormat:@"ERROR(%s): missing iCal string!",
+ __PRETTY_FUNCTION__];
+ return nil;
+ }
+
+ self->appointment = [[SOGoAppointment alloc] initWithICalString:iCalString];
+ return self->appointment;
}
<table border="0" cellpadding="2" width="100%" cellspacing="0">
<tr bgcolor="#e8e8e0">
<td align="left">
- <span class="aptview_title"><var:string value="formattedAptStartTime" /></span>
+ <span class="aptview_title"
+ ><var:string value="startTime"
+ formatter="dateFormatter"
+ /></span>
</td>
<td align="right" >
<table border='0' cellpadding='0' cellspacing='1'>
<tr>
- <td class="button_auto_env" nowrap="true" valign='middle' align='center'>
+ <td class="button_auto_env"
+ nowrap="true"
+ valign='middle'
+ align='center'
+ >
<a class="button_auto"
href="printview"
var:queryDictionary="queryParameters"
target="SOGoPrintView"
>printview</a>
</td>
- <td class="button_auto_env" nowrap="true" valign='middle' align='center'>
+ <td class="button_auto_env"
+ nowrap="true"
+ valign='middle'
+ align='center'
+ >
<a class="button_auto"
href="edit"
var:queryDictionary="queryParameters"
>edit</a>
</td>
- <td class="button_auto_env" nowrap="true" valign='middle' align='center'>
+ <td class="button_auto_env"
+ nowrap="true"
+ valign='middle'
+ align='center'
+ >
<a class="button_auto"
href="delete"
var:queryDictionary="queryParameters"
>
<uix:tab const:key="attributes"
const:label="attributes"
- var:href="attributesTabLink">
- <table width="100%" border="0" cellpadding="4" cellspacing="0">
+ var:href="attributesTabLink"
+ >
+ <table width="100%" border="0" cellpadding="4" cellspacing="0">
<tr valign="top">
<td align="right" width="15%" bgcolor="#E8E8E0">
<span class="aptview_text">Start time:</span>
</td>
<td align="left" bgcolor="#FFFFF0">
<span class="aptview_text">
- <var:string value="formattedAptStartTime" />
+ <var:string value="startTime"
+ formatter="dateFormatter"
+ />
</span>
</td>
</tr>
</td>
<td align="left" bgcolor="#FFFFF0">
<span class="aptview_text">
- <var:string value="formattedAptEndTime" />
+ <var:string value="endTime"
+ formatter="dateFormatter"
+ />
</span>
</td>
</tr>
- </table>
+ <tr valign="top">
+ <td align="right" width="15%" bgcolor="#E8E8E0">
+ <span class="aptview_text">Resources:</span>
+ </td>
+ <td align="left" bgcolor="#FFFFF0">
+ <span class="aptview_text">
+ <var:string value="resourcesAsString"
+ const:escapeHTML="NO"
+ />
+ </span>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="right" width="15%" bgcolor="#E8E8E0">
+ <span class="aptview_text">Organizer:</span>
+ </td>
+ <td align="left" bgcolor="#FFFFF0">
+ <span class="aptview_text">
+ <var:string value="appointment.organizer.cnForDisplay" />
+ </span>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="right" width="15%" bgcolor="#E8E8E0">
+ <span class="aptview_text">Comment:</span>
+ </td>
+ <td align="left" bgcolor="#FFFFF0">
+ <span class="aptview_text">
+ <var:string value="appointment.comment" />
+ </span>
+ </td>
+ </tr>
+ </table>
</uix:tab>
<uix:tab const:key="participants"
const:label="participants"
<span class="aptview_title">Email</span>
</td>
</tr>
- <var:foreach list="appointment.attendees" item="attendee">
+ <var:foreach list="appointment.participants"
+ item="attendee"
+ >
<tr valign="top">
<td align="left" bgcolor="#FFFFF0">
<span class="aptview_text">
<td align="left" bgcolor="#FFFFF0">
<span class="aptview_text">
<a var:href="attendee.email"
- ><var:string value="attendee.rfc822Email" /></a>
+ ><var:string value="attendee.rfc822Email" /></a>
</span>
</td>
</tr>
</var:foreach>
</table>
</uix:tab>
- <uix:tab const:key="debug"
- const:label="DEBUG"
- var:href="debugTabLink">
- SOGo Server - <var:string value="name"/>
- <br />
- Client: <var:string value="clientObject"/>
- <br />
- Group: <var:string value="clientObject.group"/><br />
- Deletable: <var:string value="clientObject.isDeletionAllowed"/><br />
- Generation: <var:string value="clientObject.zlGenerationCount"/><br />
- MsgClass: <var:string value="clientObject.outlookMessageClass"/><br />
-
- <hr />
- As iCal:<br />
- <pre><var:string value="clientObject.iCalString"/></pre>
-
- <hr />
- As Mail:<br />
- <pre><var:string value="clientObject.iCalMailString"/></pre>
-
- </uix:tab>
+ <var:if condition="isUIxDebugEnabled">
+ <uix:tab const:key="debug"
+ const:label="DEBUG"
+ var:href="debugTabLink">
+ SOGo Server - <var:string value="name"/>
+ <br />
+ Client: <var:string value="clientObject"/>
+ <br />
+ Group: <var:string value="clientObject.group"
+ /><br />
+ Deletable: <var:string value="clientObject.isDeletionAllowed"
+ /><br />
+ Generation: <var:string value="clientObject.zlGenerationCount"
+ /><br />
+ MsgClass: <var:string value="clientObject.outlookMessageClass"
+ /><br />
+
+ <hr />
+ As iCal:<br />
+ <pre><var:string value="clientObject.iCalString"/></pre>
+
+ <hr />
+ As Mail:<br />
+ <pre><var:string value="clientObject.iCalMailString"/></pre>
+
+ </uix:tab>
+ </var:if>
</uix:tabview>
</td>
</tr>
# $Id$
-SUBMINOR_VERSION:=33
+SUBMINOR_VERSION:=35
# v0.9.31 requires libWEExtensions v4.2.52
# v0.9.29 requires libWEExtensions v4.2.51
+ (id)sharedUserManager;
-- (NSString *)getUIDForEMail:(NSString *)_email;
+- (NSString *)getUIDForEmail:(NSString *)_email;
- (NSString *)getEmailForUID:(NSString *)_uid;
+- (NSString *)getCNForUID:(NSString *)_uid;
+
@end
#endif /* __AgenorUserManager_H_ */
}
-- (NSString *)getUIDForEMail:(NSString *)_email {
+- (NSString *)getUIDForEmail:(NSString *)_email {
NSRange r;
NSString *domain;
+2004-08-14 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v0.9.4
+
+ * AgenorUserManager.[hm]: fixed typo, exposed new method
+ -getCNForUID:. This is very naive and should be fixed to use
+ LDAP instead.
+
+ * SOGoAppointment.[hm]: ROLE is set properly now. Added
+ -participants and -resources to differentiate between specific
+ roles in a UI convenient way. Resources are indentified via a
+ custom ROLE dubbed "X-OGo-RESOURCE".
+
2004-08-13 Marcus Mueller <znek@mulle-kybernetik.com>
* AgenorUserManager.[hm]: new singleton object to manage Agenor
2004-06-25 Marcus Mueller <znek@mulle-kybernetik.com>
- * created.
\ No newline at end of file
+ * created.
{
id calendar;
id event;
+ id participants;
}
- (id)initWithICalString:(NSString *)_iCal;
- (void)removeAllAttendees;
- (void)addToAttendees:(iCalPerson *)_person;
+- (void)appendAttendees:(NSArray *)_persons;
- (NSArray *)attendees;
-/* generating iCal */
+/* attendees -> role != X-OGo-RESOURCE */
+- (NSArray *)participants;
+/* attendees -> role == X-OGo-RESOURCE */
+- (NSArray *)resources;
+/* TODO: should have coder instead */
- (NSString *)iCalString;
/* do we really need these? */
-
- (id)calendar;
- (id)event;
#include "SOGoAppointment.h"
#include <SaxObjC/SaxObjC.h>
#include <NGiCal/NGiCal.h>
+#include <EOControl/EOControl.h>
#include "common.h"
@interface NSDate(UsedPrivates)
- (NSString *)icalString; // declared in NGiCal
@end
+@interface SOGoAppointment (PrivateAPI)
+- (NSArray *)_filteredAttendeesThinkingOfPersons:(BOOL)_persons;
+@end
+
@implementation SOGoAppointment
static id<NSObject,SaxXMLReader> parser = nil;
NSString *x;
p = [persons objectAtIndex:i];
- [s appendString:@"\nATTENDEE;CN=\""];
+ [s appendString:@"\nATTENDEE;"];
+ if((x = [p role])) {
+ [s appendString:@"ROLE="];
+ [s appendString:x];
+ [s appendString:@";"];
+ }
+ [s appendString:@"CN=\""];
if((x = [p cn])) {
[s appendString:x];
}
- (void)addToAttendees:(iCalPerson *)_person {
[self->event addToAttendees:_person];
}
+- (void)appendAttendees:(NSArray *)_persons {
+ unsigned i, count;
+
+ count = [_persons count];
+ for(i = 0; i < count; i++) {
+ [self addToAttendees:[_persons objectAtIndex:i]];
+ }
+}
- (NSArray *)attendees {
return [self->event attendees];
}
+- (BOOL)hasParticipants {
+ return [[self participants] count] != 0;
+}
+
+- (NSArray *)participants {
+ if(self->participants == nil) {
+ ASSIGN(self->participants,
+ [self _filteredAttendeesThinkingOfPersons:YES]);
+ }
+ return self->participants;
+}
+
+- (NSArray *)resources {
+ return [self _filteredAttendeesThinkingOfPersons:NO];
+}
+
+- (NSArray *)_filteredAttendeesThinkingOfPersons:(BOOL)_persons {
+ EOQualifier *q;
+ NSString *qs;
+
+ if(_persons)
+ qs = @"role != X-OGo-RESOURCE";
+ else
+ qs = @"role = X-OGo-RESOURCE";
+ q = [EOQualifier qualifierWithQualifierFormat:qs];
+ return [[self attendees] filteredArrayUsingQualifier:q];
+}
+
@end
# $Id$
-SUBMINOR_VERSION:=3
+SUBMINOR_VERSION:=4