]> err.no Git - scalable-opengroupware.org/blob - UI/SOGoUI/UIxComponent.m
initial sync
[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 #import "SOGoJSStringFormatter.h"
23 #import "common.h"
24
25 #import <NGObjWeb/SoHTTPAuthenticator.h>
26 #import <NGObjWeb/WOResourceManager.h>
27
28 #import <SOGo/NSString+URL.h>
29
30 #import <SOGo/SOGoUser.h>
31 #import <SOGo/SOGoObject.h>
32 #import <SOGo/SOGoCustomGroupFolder.h>
33 #import <SOGo/NSCalendarDate+SOGo.h>
34
35 #import "../Common/UIxJSClose.h"
36
37 #import "UIxComponent.h"
38
39 @interface UIxComponent (PrivateAPI)
40 - (void)_parseQueryString:(NSString *)_s;
41 - (NSMutableDictionary *)_queryParameters;
42 @end
43
44 @implementation UIxComponent
45
46 static NSMutableArray *dayLabelKeys       = nil;
47 static NSMutableArray *abbrDayLabelKeys   = nil;
48 static NSMutableArray *monthLabelKeys     = nil;
49 static NSMutableArray *abbrMonthLabelKeys = nil;
50
51 static BOOL uixDebugEnabled = NO;
52
53 + (int)version {
54   return [super version] + 0 /* v2 */;
55 }
56
57 + (void)initialize {
58   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
59
60   NSAssert2([super version] == 2,
61             @"invalid superclass (%@) version %i !",
62             NSStringFromClass([self superclass]), [super version]);
63   
64   uixDebugEnabled = [ud boolForKey:@"SOGoUIxDebugEnabled"];
65
66   if (dayLabelKeys == nil) {
67     dayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
68     [dayLabelKeys addObject:@"Sunday"];
69     [dayLabelKeys addObject:@"Monday"];
70     [dayLabelKeys addObject:@"Tuesday"];
71     [dayLabelKeys addObject:@"Wednesday"];
72     [dayLabelKeys addObject:@"Thursday"];
73     [dayLabelKeys addObject:@"Friday"];
74     [dayLabelKeys addObject:@"Saturday"];
75
76     abbrDayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
77     [abbrDayLabelKeys addObject:@"a2_Sunday"];
78     [abbrDayLabelKeys addObject:@"a2_Monday"];
79     [abbrDayLabelKeys addObject:@"a2_Tuesday"];
80     [abbrDayLabelKeys addObject:@"a2_Wednesday"];
81     [abbrDayLabelKeys addObject:@"a2_Thursday"];
82     [abbrDayLabelKeys addObject:@"a2_Friday"];
83     [abbrDayLabelKeys addObject:@"a2_Saturday"];
84
85     monthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
86     [monthLabelKeys addObject:@"January"];
87     [monthLabelKeys addObject:@"February"];
88     [monthLabelKeys addObject:@"March"];
89     [monthLabelKeys addObject:@"April"];
90     [monthLabelKeys addObject:@"May"];
91     [monthLabelKeys addObject:@"June"];
92     [monthLabelKeys addObject:@"July"];
93     [monthLabelKeys addObject:@"August"];
94     [monthLabelKeys addObject:@"September"];
95     [monthLabelKeys addObject:@"October"];
96     [monthLabelKeys addObject:@"November"];
97     [monthLabelKeys addObject:@"December"];
98
99     abbrMonthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
100     [abbrMonthLabelKeys addObject:@"a3_January"];
101     [abbrMonthLabelKeys addObject:@"a3_February"];
102     [abbrMonthLabelKeys addObject:@"a3_March"];
103     [abbrMonthLabelKeys addObject:@"a3_April"];
104     [abbrMonthLabelKeys addObject:@"a3_May"];
105     [abbrMonthLabelKeys addObject:@"a3_June"];
106     [abbrMonthLabelKeys addObject:@"a3_July"];
107     [abbrMonthLabelKeys addObject:@"a3_August"];
108     [abbrMonthLabelKeys addObject:@"a3_September"];
109     [abbrMonthLabelKeys addObject:@"a3_October"];
110     [abbrMonthLabelKeys addObject:@"a3_November"];
111     [abbrMonthLabelKeys addObject:@"a3_December"];
112   }
113 }
114
115 - (id) init
116 {
117   if ((self = [super init]))
118     {
119       _selectedDate = nil;
120     }
121
122   return self;
123 }
124
125 - (void) dealloc
126 {
127   [self->queryParameters release];
128   if (_selectedDate)
129     [_selectedDate release];
130   [super dealloc];
131 }
132
133 /* query parameters */
134
135 - (void) _parseQueryString: (NSString *) _s
136 {
137   NSEnumerator *e;
138   NSString *part;
139   NSRange  r;
140   NSString *key, *value;
141
142   e = [[_s componentsSeparatedByString:@"&"] objectEnumerator];
143   part = [e nextObject];
144   while (part)
145     {
146       r = [part rangeOfString:@"="];
147       if (r.length == 0)
148         {
149       /* missing value of query parameter */
150           key   = [part stringByUnescapingURL];
151           value = @"1";
152         }
153       else
154         {
155           key   = [[part substringToIndex:r.location] stringByUnescapingURL];
156           value = [[part substringFromIndex:(r.location + r.length)] 
157                     stringByUnescapingURL];
158         }
159       [self->queryParameters setObject:value forKey:key];
160       part = [e nextObject];
161     }
162 }
163
164 - (void) addKeepAliveFormValuesToQueryParameters
165 {
166 }
167
168 - (NSString *) queryParameterForKey: (NSString *) _key
169 {
170   return [[self _queryParameters] objectForKey:_key];
171 }
172
173 - (void) setQueryParameter: (NSString *) _param
174                     forKey: (NSString *) _key
175 {
176   if (_key)
177     {
178       if (_param)
179         [[self _queryParameters] setObject: _param forKey: _key];
180       else
181         [[self _queryParameters] removeObjectForKey: _key];
182     }
183 }
184
185 - (NSMutableDictionary *) _queryParameters
186 {
187   // TODO: this code is weird, should use WORequest methods for parsing
188   WORequest *req;
189   NSString  *uri;
190   NSRange   r;
191   NSString *qs;
192   
193   if (self->queryParameters)
194     return self->queryParameters;
195
196   self->queryParameters = [[NSMutableDictionary alloc] initWithCapacity:8];
197
198   req = [[self context] request];
199   uri = [req uri];
200   r   = [uri rangeOfString:@"?" options:NSBackwardsSearch];
201   if (r.length > 0)
202     {
203       qs = [uri substringFromIndex:NSMaxRange(r)];
204       [self _parseQueryString:qs];
205     }
206   
207   /* add form values */
208   [self addKeepAliveFormValuesToQueryParameters];
209
210   return self->queryParameters;
211 }
212
213 - (NSDictionary *) queryParameters
214 {
215   return [self _queryParameters];
216 }
217
218 - (NSDictionary *) queryParametersBySettingSelectedDate: (NSCalendarDate *) _date
219 {
220   NSMutableDictionary *qp;
221     
222   qp = [[self queryParameters] mutableCopy];
223   [self setSelectedDateQueryParameter:_date inDictionary:qp];
224   return [qp autorelease];
225 }
226
227 - (void) setSelectedDateQueryParameter: (NSCalendarDate *) _newDate
228                           inDictionary: (NSMutableDictionary *) _qp
229 {
230   if (_newDate)
231     [_qp setObject: [self dateStringForDate: _newDate] forKey: @"day"];
232   else
233     [_qp removeObjectForKey:@"day"];
234 }
235
236 - (NSString *) completeHrefForMethod: (NSString *) _method
237 {
238   WOContext *ctx;
239   NSDictionary *qp;
240   NSString *qs, *qps, *href;
241
242   qp = [self queryParameters];
243   if ([qp count] > 0)
244     {
245       ctx = [self context];
246       qps = [ctx queryPathSeparator];
247       [ctx setQueryPathSeparator: @"&"];
248       qs = [ctx queryStringFromDictionary: qp];
249       [ctx setQueryPathSeparator: qps];
250       href = [_method stringByAppendingFormat:@"?%@", qs];
251     }
252   else
253     href = _method;
254
255   return href;
256 }
257
258 - (NSString *) ownMethodName
259 {
260   NSString *uri;
261   NSRange  r;
262     
263   uri = [[[self context] request] uri];
264     
265   /* first: cut off query parameters */
266     
267   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
268   if (r.length > 0)
269     uri = [uri substringToIndex:r.location];
270     
271   /* next: strip trailing slash */
272     
273   if ([uri hasSuffix: @"/"])
274     uri = [uri substringToIndex: ([uri length] - 1)];
275   r = [uri rangeOfString:@"/" options: NSBackwardsSearch];
276     
277   /* then: cut of last path component */
278     
279   if (r.length == 0) // no slash? are we at root?
280     return @"/";
281     
282   return [uri substringFromIndex: (r.location + 1)];
283 }
284
285 - (NSString *) userFolderPath
286 {
287   WOContext *ctx;
288   NSString  *url, *path;
289   NSEnumerator *objects;
290   SOGoObject *currentObject;
291   BOOL found;
292
293   ctx = [self context];
294   objects = [[ctx objectTraversalStack] objectEnumerator];
295   currentObject = [objects nextObject];
296   found = NO;
297   while (currentObject
298          && !found)
299     if ([currentObject isKindOfClass: [SOGoUserFolder class]])
300       found = YES;
301     else
302       currentObject = [objects nextObject];
303
304   url = [currentObject baseURLInContext:ctx];
305   path = [[NSURL URLWithString:url] path];
306
307   return path;
308 }
309
310 - (NSString *) applicationPath
311 {
312   SOGoObject *currentClient, *parent;
313   NSString *url;
314   BOOL found;
315   Class objectClass, groupFolderClass, userFolderClass;
316   WOContext *ctx;
317
318   groupFolderClass = [SOGoCustomGroupFolder class];
319   userFolderClass = [SOGoUserFolder class];
320
321   currentClient = [self clientObject];
322   objectClass = [currentClient class];
323   found = (objectClass == groupFolderClass || objectClass == userFolderClass);
324   while (!found && currentClient)
325     {
326       parent = [currentClient container];
327       objectClass = [parent class];
328       if (objectClass == groupFolderClass
329           || objectClass == userFolderClass)
330         found = YES;
331       else
332         currentClient = parent;
333     }
334
335   ctx = [self context];
336   url = [currentClient baseURLInContext: ctx];
337
338   return [[NSURL URLWithString: url] path];
339 }
340
341 - (NSString *) resourcesPath
342 {
343   WOResourceManager *rm;
344
345   if ((rm = [self resourceManager]) == nil)
346     rm = [[WOApplication application] resourceManager];
347
348   return [rm webServerResourcesPath];
349 }
350
351 - (NSString *) ownPath
352 {
353   NSString *uri;
354   NSRange  r;
355   
356   uri = [[[self context] request] uri];
357   
358   /* first: cut off query parameters */
359   
360   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
361   if (r.length > 0)
362     uri = [uri substringToIndex:r.location];
363
364   return uri;
365 }
366
367 - (NSString *) relativePathToUserFolderSubPath: (NSString *) _sub
368 {
369   NSString *dst, *rel;
370
371   dst = [[self userFolderPath] stringByAppendingPathComponent:_sub];
372   rel = [dst urlPathRelativeToPath:[self ownPath]];
373
374   return rel;
375 }
376
377 - (NSCalendarDate *) selectedDate
378 {
379   if (!_selectedDate)
380     {
381       _selectedDate
382         = [NSCalendarDate
383             dateFromShortDateString: [self queryParameterForKey: @"day"]
384             andShortTimeString: [self queryParameterForKey: @"hm"]
385             inTimeZone: [[self clientObject] userTimeZone]];
386       [_selectedDate retain];
387     }
388
389   return _selectedDate;
390 }
391
392 - (NSString *) dateStringForDate: (NSCalendarDate *) _date
393 {
394   [_date setTimeZone: [[self clientObject] userTimeZone]];
395
396   return [_date descriptionWithCalendarFormat:@"%Y%m%d"];
397 }
398
399 - (BOOL) hideFrame
400 {
401   return ([[self queryParameterForKey: @"noframe"] boolValue]);
402 }
403
404 - (UIxComponent *) jsCloseWithRefreshMethod: (NSString *) methodName
405 {
406   UIxJSClose *jsClose;
407
408   jsClose = [UIxJSClose new];
409   [jsClose autorelease];
410   [jsClose setRefreshMethod: methodName];
411
412   return jsClose;
413 }
414
415 /* SoUser */
416
417 - (SoUser *) user
418 {
419   WOContext *ctx;
420   
421   ctx = [self context];
422
423   return [[[self clientObject] authenticatorInContext: ctx] userInContext: ctx];
424 }
425
426 - (NSString *) shortUserNameForDisplay
427 {
428   // TODO: better use a SoUser formatter?
429   // TODO: who calls that?
430   NSString *s;
431   NSRange  r;
432   
433   // TODO: USE USER MANAGER INSTEAD!
434   
435   s = [[self user] login];
436   if ([s length] < 10)
437     return s;
438     
439   // TODO: algorithm might be inappropriate, depends on the actual UID
440     
441   r = [s rangeOfString:@"."];
442   if (r.length == 0)
443     return s;
444     
445   return [s substringToIndex:r.location];
446 }
447
448 /* labels */
449
450 - (NSString *) labelForKey: (NSString *) _str
451 {
452   WOResourceManager *rm;
453   NSArray *languages;
454   NSString *lKey, *lTable, *lVal;
455   NSRange r;
456
457   if ([_str length] == 0)
458     return nil;
459   
460   /* lookup languages */
461     
462   languages = [[self context] resourceLookupLanguages];
463     
464   /* find resource manager */
465     
466   if ((rm = [self pageResourceManager]) == nil)
467     rm = [[WOApplication application] resourceManager];
468   if (rm == nil)
469     [self warnWithFormat:@"missing resource manager!"];
470     
471   /* get parameters */
472     
473   r = [_str rangeOfString:@"/"];
474   if (r.length > 0) {
475     lTable = [_str substringToIndex:r.location];
476     lKey   = [_str substringFromIndex:(r.location + r.length)];
477   }
478   else {
479     lTable = nil;
480     lKey   = _str;
481   }
482   lVal = lKey;
483
484   if ([lKey hasPrefix:@"$"])
485     lKey = [self valueForKeyPath:[lKey substringFromIndex:1]];
486   
487   if ([lTable hasPrefix:@"$"])
488     lTable = [self valueForKeyPath:[lTable substringFromIndex:1]];
489   
490 #if 0
491   if ([lVal hasPrefix:@"$"])
492     lVal = [self valueForKeyPath:[lVal substringFromIndex:1]];
493   
494 #endif
495   
496   /* lookup string */
497   return [rm stringForKey: lKey
498              inTableNamed: lTable
499              withDefaultValue: lVal
500              languages: languages];
501 }
502
503 - (NSString *) localizedNameForDayOfWeek:(unsigned)_dayOfWeek {
504   NSString *key =  [dayLabelKeys objectAtIndex:_dayOfWeek % 7];
505   return [self labelForKey:key];
506 }
507
508 - (NSString *)localizedAbbreviatedNameForDayOfWeek:(unsigned)_dayOfWeek {
509   NSString *key =  [abbrDayLabelKeys objectAtIndex:_dayOfWeek % 7];
510   return [self labelForKey:key];
511 }
512
513 - (NSString *)localizedNameForMonthOfYear:(unsigned)_monthOfYear {
514   NSString *key =  [monthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
515   return [self labelForKey:key];
516 }
517
518 - (NSString *)localizedAbbreviatedNameForMonthOfYear:(unsigned)_monthOfYear {
519   NSString *key =  [abbrMonthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
520   return [self labelForKey:key];
521 }
522
523 /* HTTP method safety */
524
525 - (BOOL)isInvokedBySafeMethod {
526   // TODO: move to WORequest?
527   NSString *m;
528   
529   m = [[[self context] request] method];
530   if ([m isEqualToString:@"GET"])  return YES;
531   if ([m isEqualToString:@"HEAD"]) return YES;
532   return NO;
533 }
534
535 /* locale */
536
537 - (NSDictionary *)locale {
538   /* we need no fallback here, as locale is guaranteed to be set by sogod */
539   return [[self context] valueForKey:@"locale"];
540 }
541
542 - (WOResourceManager *) pageResourceManager
543 {
544   WOResourceManager *rm;
545   
546   if ((rm = [[[self context] page] resourceManager]) == nil)
547     rm = [[WOApplication application] resourceManager];
548
549   return rm;
550 }
551
552 - (NSString *) urlForResourceFilename: (NSString *) filename
553 {
554   static NSMutableDictionary *pageToURL = nil;
555   NSString *url;
556   WOComponent *page;
557   WOResourceManager *rm;
558   NSBundle *pageBundle;
559
560   if (filename)
561     {
562       if (!pageToURL)
563         pageToURL = [[NSMutableDictionary alloc] initWithCapacity: 32];
564
565       url = [pageToURL objectForKey: filename];
566       if (!url)
567         {
568           rm = [self pageResourceManager];
569           page = [[self context] page];
570           pageBundle = [NSBundle bundleForClass: [page class]];
571           url = [rm urlForResourceNamed: filename
572                     inFramework: [pageBundle bundlePath]
573                     languages: nil
574                     request: [[self context] request]];
575           if (!url)
576             url = @"";
577           else
578             if ([url hasPrefix: @"http"])
579               url = [url hostlessURL];
580           [pageToURL setObject: url forKey: filename];
581         }
582
583 //   NSLog (@"url for '%@': '%@'", filename, url);
584     }
585   else
586     url = @"";
587
588   return url;
589 }
590
591 /* debugging */
592
593 - (BOOL)isUIxDebugEnabled {
594   return uixDebugEnabled;
595 }
596
597 @end /* UIxComponent */