]> err.no Git - scalable-opengroupware.org/blob - UI/SOGoUI/UIxComponent.m
1e4f65f69a8b02e99a425af96ae1173f8bade4a2
[scalable-opengroupware.org] / UI / SOGoUI / UIxComponent.m
1 /*
2   Copyright (C) 2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
6   OGo is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "UIxComponent.h"
23 #include "SOGoJSStringFormatter.h"
24 #include "common.h"
25 #include <NGObjWeb/SoHTTPAuthenticator.h>
26
27 @interface UIxComponent (PrivateAPI)
28 - (void)_parseQueryString:(NSString *)_s;
29 - (NSMutableDictionary *)_queryParameters;
30 @end
31
32 @implementation UIxComponent
33
34 static NSTimeZone *MET = nil;
35 static NSTimeZone *GMT = nil;
36
37 static NSMutableArray *dayLabelKeys       = nil;
38 static NSMutableArray *abbrDayLabelKeys   = nil;
39 static NSMutableArray *monthLabelKeys     = nil;
40 static NSMutableArray *abbrMonthLabelKeys = nil;
41
42 static BOOL uixDebugEnabled = NO;
43
44 + (int)version {
45   return [super version] + 0 /* v2 */;
46 }
47
48 + (void)initialize {
49   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
50
51   NSAssert2([super version] == 2,
52             @"invalid superclass (%@) version %i !",
53             NSStringFromClass([self superclass]), [super version]);
54   
55   uixDebugEnabled = [ud boolForKey:@"SOGoUIxDebugEnabled"];
56
57   if (MET == nil) {
58     MET = [[NSTimeZone timeZoneWithAbbreviation:@"MET"] retain];
59     GMT = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
60   }
61   if (dayLabelKeys == nil) {
62     dayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
63     [dayLabelKeys addObject:@"Sunday"];
64     [dayLabelKeys addObject:@"Monday"];
65     [dayLabelKeys addObject:@"Tuesday"];
66     [dayLabelKeys addObject:@"Wednesday"];
67     [dayLabelKeys addObject:@"Thursday"];
68     [dayLabelKeys addObject:@"Friday"];
69     [dayLabelKeys addObject:@"Saturday"];
70
71     abbrDayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
72     [abbrDayLabelKeys addObject:@"a2_Sunday"];
73     [abbrDayLabelKeys addObject:@"a2_Monday"];
74     [abbrDayLabelKeys addObject:@"a2_Tuesday"];
75     [abbrDayLabelKeys addObject:@"a2_Wednesday"];
76     [abbrDayLabelKeys addObject:@"a2_Thursday"];
77     [abbrDayLabelKeys addObject:@"a2_Friday"];
78     [abbrDayLabelKeys addObject:@"a2_Saturday"];
79
80     monthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
81     [monthLabelKeys addObject:@"January"];
82     [monthLabelKeys addObject:@"February"];
83     [monthLabelKeys addObject:@"March"];
84     [monthLabelKeys addObject:@"April"];
85     [monthLabelKeys addObject:@"May"];
86     [monthLabelKeys addObject:@"June"];
87     [monthLabelKeys addObject:@"July"];
88     [monthLabelKeys addObject:@"August"];
89     [monthLabelKeys addObject:@"September"];
90     [monthLabelKeys addObject:@"October"];
91     [monthLabelKeys addObject:@"November"];
92     [monthLabelKeys addObject:@"December"];
93
94     abbrMonthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
95     [abbrMonthLabelKeys addObject:@"a3_January"];
96     [abbrMonthLabelKeys addObject:@"a3_February"];
97     [abbrMonthLabelKeys addObject:@"a3_March"];
98     [abbrMonthLabelKeys addObject:@"a3_April"];
99     [abbrMonthLabelKeys addObject:@"a3_May"];
100     [abbrMonthLabelKeys addObject:@"a3_June"];
101     [abbrMonthLabelKeys addObject:@"a3_July"];
102     [abbrMonthLabelKeys addObject:@"a3_August"];
103     [abbrMonthLabelKeys addObject:@"a3_September"];
104     [abbrMonthLabelKeys addObject:@"a3_October"];
105     [abbrMonthLabelKeys addObject:@"a3_November"];
106     [abbrMonthLabelKeys addObject:@"a3_December"];
107   }
108 }
109
110 - (void)dealloc {
111   [self->queryParameters release];
112   [super dealloc];
113 }
114
115 /* query parameters */
116
117 - (void)_parseQueryString:(NSString *)_s {
118   NSEnumerator *e;
119   NSString *part;
120     
121   e = [[_s componentsSeparatedByString:@"&"] objectEnumerator];
122   while ((part = [e nextObject]) != nil) {
123     NSRange  r;
124     NSString *key, *value;
125         
126     r = [part rangeOfString:@"="];
127     if (r.length == 0) {
128       /* missing value of query parameter */
129       key   = [part stringByUnescapingURL];
130       value = @"1";
131     }
132     else {
133       key   = [[part substringToIndex:r.location] stringByUnescapingURL];
134       value = [[part substringFromIndex:(r.location + r.length)] 
135                 stringByUnescapingURL];
136     }
137     [self->queryParameters setObject:value forKey:key];
138   }
139 }
140 - (void)addKeepAliveFormValuesToQueryParameters {
141 }
142
143 - (NSString *)queryParameterForKey:(NSString *)_key {
144   return [[self _queryParameters] objectForKey:_key];
145 }
146
147 - (void)setQueryParameter:(NSString *)_param forKey:(NSString *)_key {
148   if(_key == nil)
149     return;
150
151   if(_param != nil)
152     [[self _queryParameters] setObject:_param forKey:_key];
153   else
154     [[self _queryParameters] removeObjectForKey:_key];
155 }
156
157 - (NSMutableDictionary *)_queryParameters {
158   // TODO: this code is weird, should use WORequest methods for parsing
159   WORequest *req;
160   NSString  *uri;
161   NSRange   r;
162   
163   if (self->queryParameters)
164     return self->queryParameters;
165
166   self->queryParameters = [[NSMutableDictionary alloc] initWithCapacity:8];
167     
168   req = [[self context] request];
169   uri = [req uri];
170   r   = [uri rangeOfString:@"?" options:NSBackwardsSearch];
171   if (r.length > 0) {
172     NSString *qs;
173     
174     qs = [uri substringFromIndex:NSMaxRange(r)];
175     [self _parseQueryString:qs];
176   }
177   
178   /* add form values */
179   [self addKeepAliveFormValuesToQueryParameters];
180
181   return self->queryParameters;
182 }
183
184 - (NSDictionary *)queryParameters {
185   return [self _queryParameters];
186 }
187
188 - (NSDictionary *)queryParametersBySettingSelectedDate:(NSCalendarDate *)_date{
189   NSMutableDictionary *qp;
190     
191   qp = [[self queryParameters] mutableCopy];
192   [self setSelectedDateQueryParameter:_date inDictionary:qp];
193   return [qp autorelease];
194 }
195
196 - (void)setSelectedDateQueryParameter:(NSCalendarDate *)_newDate
197   inDictionary:(NSMutableDictionary *)_qp;
198 {
199   if(_newDate != nil)
200     [_qp setObject:[self dateStringForDate:_newDate] forKey:@"day"];
201   else
202     [_qp removeObjectForKey:@"day"];
203 }
204
205 - (NSString *)completeHrefForMethod:(NSString *)_method {
206   WOContext    *ctx;
207   NSDictionary *qp;
208   NSString     *qs, *qps;
209
210   qp = [self queryParameters];
211   if([qp count] == 0)
212     return _method;
213
214   ctx = [self context];
215   qps = [ctx queryPathSeparator];
216   [ctx setQueryPathSeparator:@"&"];
217   qs = [ctx queryStringFromDictionary:qp];
218   [ctx setQueryPathSeparator:qps];
219   return [_method stringByAppendingFormat:@"?%@", qs];
220 }
221
222 - (NSString *)ownMethodName {
223   NSString *uri;
224   NSRange  r;
225     
226   uri = [[[self context] request] uri];
227     
228   /* first: cut off query parameters */
229     
230   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
231   if (r.length > 0)
232     uri = [uri substringToIndex:r.location];
233     
234   /* next: strip trailing slash */
235     
236   if ([uri hasSuffix:@"/"]) uri = [uri substringToIndex:([uri length] - 1)];
237   r = [uri rangeOfString:@"/" options:NSBackwardsSearch];
238     
239   /* then: cut of last path component */
240     
241   if (r.length == 0) // no slash? are we at root?
242     return @"/";
243     
244   return [uri substringFromIndex:(r.location + 1)];
245 }
246
247 - (NSString *)userFolderPath {
248   WOContext *ctx;
249   NSArray   *traversalObjects;
250   NSString  *url;
251   NSString  *path;
252
253   ctx = [self context];
254   traversalObjects = [ctx objectTraversalStack];
255   url = [[traversalObjects objectAtIndex:0]
256                            baseURLInContext:ctx];
257   path = [[NSURL URLWithString:url] path];
258   path = [path stringByAppendingPathComponent:[[ctx activeUser] login]];
259   return path;
260 }
261
262 - (NSString *)ownPath {
263   NSString *uri;
264   NSRange  r;
265   
266   uri = [[[self context] request] uri];
267   
268   /* first: cut off query parameters */
269   
270   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
271   if (r.length > 0)
272     uri = [uri substringToIndex:r.location];
273   return uri;
274 }
275
276 - (NSString *)relativePathToUserFolderSubPath:(NSString *)_sub {
277   NSString *dst, *rel;
278
279   dst = [[self userFolderPath] stringByAppendingPathComponent:_sub];
280   rel = [dst urlPathRelativeToPath:[self ownPath]];
281   return rel;
282 }
283   
284 /* date */
285
286 - (NSTimeZone *)viewTimeZone {
287   // Note: also in the folder, should be based on a cookie?
288   return MET;
289 }
290
291 - (NSTimeZone *)backendTimeZone {
292   return GMT;
293 }
294
295 - (NSCalendarDate *)selectedDate {
296   NSString       *s;
297   NSCalendarDate *cdate;
298
299   s = [self queryParameterForKey:@"day"];
300   cdate = ([s length] > 0)
301     ? [self dateForDateString:s]
302     : [NSCalendarDate date];
303   [cdate setTimeZone:[self viewTimeZone]];
304   s = [self queryParameterForKey:@"hm"];
305   if([s length] == 4) {
306     unsigned hour, minute;
307       
308     hour = [[s substringToIndex:2] unsignedIntValue];
309     minute = [[s substringFromIndex:2] unsignedIntValue];
310     cdate = [cdate hour:hour minute:minute];
311   }
312   else {
313     cdate = [cdate hour:12 minute:0];
314   }
315   return cdate;
316 }
317
318 - (NSString *)dateStringForDate:(NSCalendarDate *)_date {
319   [_date setTimeZone:[self viewTimeZone]];
320   return [_date descriptionWithCalendarFormat:@"%Y%m%d"];
321 }
322
323 - (NSCalendarDate *)dateForDateString:(NSString *)_dateString {
324   return [NSCalendarDate dateWithString:_dateString 
325                          calendarFormat:@"%Y%m%d"];
326 }
327
328
329 /* SoUser */
330
331 - (SoUser *)user {
332   WOContext *ctx;
333   
334   ctx = [self context];
335   return [[[self clientObject] authenticatorInContext:ctx] userInContext:ctx];
336 }
337
338 - (NSString *)shortUserNameForDisplay {
339   // TODO: better use a SoUser formatter?
340   // TODO: who calls that?
341   NSString *s;
342   NSRange  r;
343   
344   // TODO: USE USER MANAGER INSTEAD!
345   
346   s = [[self user] login];
347   if ([s length] < 10)
348     return s;
349     
350   // TODO: algorithm might be inappropriate, depends on the actual UID
351     
352   r = [s rangeOfString:@"."];
353   if (r.length == 0)
354     return s;
355     
356   return [s substringToIndex:r.location];
357 }
358
359 /* labels */
360
361 - (NSString *)labelForKey:(NSString *)_str {
362   WOResourceManager *rm;
363   NSArray           *languages;
364   NSString          *label;
365   NSString          *lKey, *lTable, *lVal;
366   NSRange r;
367
368   if ([_str length] == 0)
369     return nil;
370   
371   /* lookup languages */
372     
373   languages = [[self context] resourceLookupLanguages];
374     
375   /* find resource manager */
376     
377   if ((rm = [self resourceManager]) == nil)
378     rm = [[WOApplication application] resourceManager];
379   if (rm == nil)
380     [self warnWithFormat:@"missing resource manager!"];
381     
382   /* get parameters */
383     
384   r = [_str rangeOfString:@"/"];
385   if (r.length > 0) {
386     lTable = [_str substringToIndex:r.location];
387     lKey   = [_str substringFromIndex:(r.location + r.length)];
388   }
389   else {
390     lTable = nil;
391     lKey   = _str;
392   }
393   lVal = lKey;
394
395   if ([lKey hasPrefix:@"$"])
396     lKey = [self valueForKeyPath:[lKey substringFromIndex:1]];
397   
398   if ([lTable hasPrefix:@"$"])
399     lTable = [self valueForKeyPath:[lTable substringFromIndex:1]];
400   
401 #if 0
402   if ([lVal hasPrefix:@"$"])
403     lVal = [self valueForKeyPath:[lVal substringFromIndex:1]];
404   
405 #endif
406   
407   /* lookup string */
408   
409   label = [rm stringForKey:lKey inTableNamed:lTable withDefaultValue:lVal
410               languages:languages];
411   return label;
412 }
413
414 - (NSString *)localizedNameForDayOfWeek:(unsigned)_dayOfWeek {
415   NSString *key =  [dayLabelKeys objectAtIndex:_dayOfWeek % 7];
416   return [self labelForKey:key];
417 }
418
419 - (NSString *)localizedAbbreviatedNameForDayOfWeek:(unsigned)_dayOfWeek {
420   NSString *key =  [abbrDayLabelKeys objectAtIndex:_dayOfWeek % 7];
421   return [self labelForKey:key];
422 }
423
424 - (NSString *)localizedNameForMonthOfYear:(unsigned)_monthOfYear {
425   NSString *key =  [monthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
426   return [self labelForKey:key];
427 }
428
429 - (NSString *)localizedAbbreviatedNameForMonthOfYear:(unsigned)_monthOfYear {
430   NSString *key =  [abbrMonthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
431   return [self labelForKey:key];
432 }
433
434 /* HTTP method safety */
435
436 - (BOOL)isInvokedBySafeMethod {
437   // TODO: move to WORequest?
438   NSString *m;
439   
440   m = [[[self context] request] method];
441   if ([m isEqualToString:@"GET"])  return YES;
442   if ([m isEqualToString:@"HEAD"]) return YES;
443   return NO;
444 }
445
446 /* locale */
447
448 - (NSDictionary *)locale {
449   /* we need no fallback here, as locale is guaranteed to be set by sogod */
450   return [[self context] valueForKey:@"locale"];
451 }
452
453 /* debugging */
454
455 - (BOOL)isUIxDebugEnabled {
456   return uixDebugEnabled;
457 }
458
459 @end /* UIxComponent */