2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
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
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.
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
23 #include <NGObjDOM/ODNodeRenderer.h>
24 #include <NGObjDOM/ODNodeRendererFactory.h>
25 #include <NGObjDOM/ODNamespaces.h>
28 //#define WITH_EXCEPTION_HANDLER 1
29 #if NeXT_RUNTIME || APPLE_RUNTIME
30 # define sel_get_name sel_getName
33 @implementation ODNodeRenderer
35 static int profileRenderers = -1;
36 static double profRenderMin = 0.0009;
37 static Class NSDateClass = Nil;
40 if (NSDateClass == Nil)
41 NSDateClass = [NSDate class];
43 if (profileRenderers == -1) {
46 profileRenderers = [[[NSUserDefaults standardUserDefaults]
47 objectForKey:@"ODProfileRenderer"]
50 if ((tmp = [[NSUserDefaults standardUserDefaults]
51 objectForKey:@"ODProfileRendererMin"])) {
52 double d = [tmp doubleValue];
54 if (d > profRenderMin) {
57 NSLog(@"profRenderMin: %0.3fs", profRenderMin);
67 - (NSString *)_idForNode:(id)_node {
68 if ([_node nodeType] == DOM_ELEMENT_NODE) {
71 if ((s = [_node attribute:@"id" namespaceURI:@"*"]))
74 return [_node tagName];
77 return [_node nodeName];
82 - (ODNodeRenderer *)rendererForNode:(id)_domNode inContext:(WOContext *)_ctx {
83 id<ODNodeRendererFactory> factory;
84 ODNodeRenderer *renderer = nil;
85 NSTimeInterval st = 0.0;
88 st = [[NSDateClass date] timeIntervalSince1970];
90 if ((factory = [_ctx objectForKey:@"domRenderFactory"]))
91 renderer = [factory rendererForNode:_domNode inContext:_ctx];
93 if (profileRenderers) {
95 diff = [[NSDateClass date] timeIntervalSince1970] - st;
96 if (diff > profRenderMin) {
97 printf("[renderer lookup: %s %s]: %0.3fs id='%s'\n",
98 [[_domNode nodeName] cString],
99 sel_get_name(_cmd), diff,
100 [[self _idForNode:_domNode] cString]);
107 /* request phase operations on children */
109 - (void)takeValuesForChildNodes:(id)_nodeList
110 fromRequest:(WORequest *)_request
111 inContext:(WOContext *)_ctx
115 NSTimeInterval st = 0.0;
116 static int profDepth = 0;
118 if (profileRenderers) {
119 st = [[NSDateClass date] timeIntervalSince1970];
123 if ([_nodeList count] == 0) {
128 [_ctx appendZeroElementIDComponent];
130 children = [_nodeList objectEnumerator];
131 while ((child = [children nextObject])) {
132 if ([self includeChildNode:child ofNode:[child parentNode] inContext:_ctx]) {
133 ODNodeRenderer *renderer;
135 if ((renderer = [self rendererForNode:child inContext:_ctx])) {
136 [renderer takeValuesForNode:child
141 [_ctx incrementLastElementIDComponent];
144 [_ctx deleteLastElementIDComponent];
146 if (profileRenderers) {
149 diff = [[NSDateClass date] timeIntervalSince1970] - st;
150 if (diff > profRenderMin) {
153 dn = [[_nodeList lastObject] parentNode];
155 for (i = profDepth; i >= 0; i--)
157 printf("[list: %s %s]: %0.3fs '%s'\n",
158 [[dn nodeName] cString],
159 sel_get_name(_cmd), diff,
160 [[self _idForNode:dn] cString]);
166 - (id)invokeActionForChildNodes:(id)_nodeList
167 fromRequest:(WORequest *)_request
168 inContext:(WOContext *)_ctx
172 NSTimeInterval st = 0.0;
173 static int profDepth = 0;
175 if (profileRenderers) {
176 st = [[NSDateClass date] timeIntervalSince1970];
180 if ([_nodeList count] == 0) {
183 NSLog(@"%s: no child nodes to invoke upon ..", __PRETTY_FUNCTION__);
188 if ((idxId = [_ctx currentElementID])) {
192 count = [_nodeList count];
194 if (isdigit([idxId characterAtIndex:0])) {
195 /* lookup by index */
197 idx = [idxId intValue];
200 NSLog(@"%s: ERROR, click index is out of range "
201 @"(idx=%i, count=%d, eid=%@, sid=%@)",
202 __PRETTY_FUNCTION__, idx, count,
203 [_ctx elementID], [_ctx senderID]);
206 else if ((node = [_nodeList objectAtIndex:idx]) == nil) {
208 NSLog(@"%s: ERROR, did not find node at index %i (tag=%@, list=%@) ..",
209 __PRETTY_FUNCTION__, idx,
210 [[_nodeList parentNode] nodeName], _nodeList);
216 NSLog(@"%s: ERROR, LOOK FOR NAME %@ ..", __PRETTY_FUNCTION__, idxId);
220 [_ctx consumeElementID]; // consume index-id
222 /* this updates the element-id path */
223 [_ctx appendElementIDComponent:idxId];
226 NSLog(@"%s: invoke action on node:\n %@\n id=%@", __PRETTY_FUNCTION__,
227 node, [_ctx currentElementID]);
230 result = [[self rendererForNode:node inContext:_ctx]
231 invokeActionForNode:node
235 [_ctx deleteLastElementIDComponent];
241 @" MISSING INDEX ID in URL\n eid: %@\n nodelist: %@ !",
243 self, [_ctx elementID], _nodeList];
247 if (profileRenderers) {
250 diff = [[NSDateClass date] timeIntervalSince1970] - st;
251 if (diff > profRenderMin) {
252 for (i = profDepth; i >= 0; i--)
254 printf("[list: %s %s]: %0.3fs\n",
255 [[[[_nodeList lastObject] parentNode] nodeName] cString],
256 sel_get_name(_cmd), diff);
264 - (void)appendChildNodes:(id)_nodeList
265 toResponse:(WOResponse *)_response
266 inContext:(WOContext *)_ctx
270 static unsigned profDepth = 0;
271 NSTimeInterval st = 0.0;
273 if (profileRenderers) {
274 st = [[NSDateClass date] timeIntervalSince1970];
278 if ([_nodeList count] == 0) {
283 [_ctx appendZeroElementIDComponent];
286 children = [_nodeList objectEnumerator];
287 while ((child = [children nextObject])) {
288 if (parent == nil) parent = [child parentNode];
290 if ([self includeChildNode:child ofNode:parent inContext:_ctx]) {
291 ODNodeRenderer *renderer;
292 NSTimeInterval st = 0.0;
294 if (profileRenderers) {
295 st = [[NSDateClass date] timeIntervalSince1970];
299 renderer = [self rendererForNode:child inContext:_ctx];
301 [renderer appendNode:child
305 if (profileRenderers) {
308 diff = [[NSDateClass date] timeIntervalSince1970] - st;
309 if (diff > profRenderMin) {
310 for (i = profDepth; i >= 0; i--)
312 printf("[child: %s %s]: %0.3fs '%s'\n",
313 [[child nodeName] cString],
314 sel_get_name(_cmd), diff,
315 [[self _idForNode:child] cString]);
320 [_ctx incrementLastElementIDComponent];
323 [_ctx deleteLastElementIDComponent];
326 if (profileRenderers) {
329 diff = [[NSDateClass date] timeIntervalSince1970] - st;
330 if (diff > profRenderMin) {
333 dn = [[_nodeList lastObject] parentNode];
335 for (i = profDepth; i >= 0; i--)
337 printf("[list: %s %s]: %0.3fs '%s'\n",
338 [[dn nodeName] cString],
339 sel_get_name(_cmd), diff,
340 [[self _idForNode:dn] cString]);
346 /* the three WO request phase operations */
348 - (void)takeValuesForNode:(id)_domNode
349 fromRequest:(WORequest *)_request
350 inContext:(WOContext *)_context
353 NSLog(@"take values for node: %@", _domNode);
356 #if WITH_EXCEPTION_HANDLER
358 if ([_domNode hasChildNodes]) {
359 [self takeValuesForChildNodes:[_domNode childNodes]
365 fprintf(stderr, "%s\n", [[localException description] cString]);
370 if ([_domNode hasChildNodes]) {
371 [self takeValuesForChildNodes:[_domNode childNodes]
378 - (id)invokeActionForNode:(id)_domNode
379 fromRequest:(WORequest *)_request
380 inContext:(WOContext *)_context
382 if ([_domNode hasChildNodes]) {
383 return [self invokeActionForChildNodes:[_domNode childNodes]
389 NSLog(@"%s: node %@ has no child nodes:\n sid=%@\n eid=%@",
390 __PRETTY_FUNCTION__, _domNode,
391 [_context senderID], [_context elementID]);
397 - (void)appendNode:(id)_domNode
398 toResponse:(WOResponse *)_response
399 inContext:(WOContext *)_context
401 if ([_domNode hasChildNodes]) {
402 [self appendChildNodes:[_domNode childNodes]
408 /* requires HTML form */
410 - (BOOL)requiresFormForChildNodes:(id)_nodeList inContext:(WOContext *)_ctx {
414 if ([_nodeList count] == 0)
420 children = [_nodeList objectEnumerator];
422 while ((child = [children nextObject])) {
423 if ([self includeChildNode:child ofNode:[child parentNode] inContext:_ctx]) {
424 ODNodeRenderer *renderer;
426 if ((renderer = [self rendererForNode:child inContext:_ctx])) {
427 if ([renderer requiresFormForNode:child inContext:_ctx])
435 - (BOOL)requiresFormForNode:(id)_domNode inContext:(WOContext *)_ctx {
436 if ([_domNode hasChildNodes]) {
437 return [self requiresFormForChildNodes:[_domNode childNodes]
444 /* generating node ids unique in DOM tree */
446 - (NSString *)uniqueIDForNode:(id)_node inContext:(WOContext *)_ctx {
447 NSMutableArray *nodePath;
448 NSMutableString *uid;
449 NSEnumerator *topDown;
453 if (_node == nil) return nil;
455 nodePath = [NSMutableArray arrayWithCapacity:16];
457 /* collect all parent nodes in bottom-up form */
459 for (node = _node; node; node = [node parentNode])
460 [nodePath addObject:node];
464 uid = [NSMutableString stringWithCapacity:64];
465 topDown = [nodePath reverseObjectEnumerator];
469 for (isFirst = YES; (node = [topDown nextObject]); parent = node) {
474 [uid appendString:@"."];
476 /* determine index of _node */
478 children = (NSArray *)[parent childNodes];
479 for (i = 0, count = [children count]; i < count; i++) {
480 if ([children objectAtIndex:i] == node)
483 [uid appendFormat:@"%d", i];
486 [uid appendString:@"R"];
491 return [[uid copy] autorelease];
494 /* selecting children */
496 - (BOOL)includeChildNode:(id)_childNode
498 inContext:(WOContext *)_ctx
500 /* check 'if' attribute .. */
502 if ([_childNode nodeType] != DOM_ELEMENT_NODE)
505 if ([_childNode hasAttribute:@"if" namespaceURI:@"*"])
506 return [self boolFor:@"if" node:_childNode ctx:_ctx];
508 if ([_childNode hasAttribute:@"ifnot" namespaceURI:@"*"])
509 return [self boolFor:@"ifnot" node:_childNode ctx:_ctx] ? NO : YES;
514 @end /* ODNodeRenderer */