]> err.no Git - sope/blob - sope-appserver/NGObjWeb/DynamicElements/WOImage.m
started TAL element builder
[sope] / sope-appserver / NGObjWeb / DynamicElements / WOImage.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE 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   SOPE 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 SOPE; 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 "WOImage.h"
23
24 @interface _WOTemporaryImage : NSObject
25 @end
26
27 @interface _WODynamicImage : WOImage /* new in WO4 */
28 {
29   WOAssociation *data;
30   WOAssociation *mimeType;
31   WOAssociation *key;
32 }
33 @end
34
35 @interface _WOElementImage : WOImage
36 {
37   WOAssociation *value;     // image data (eg from a database)
38 }
39 @end
40
41 @interface _WOExternalImage : WOImage
42 {
43   WOAssociation *src;       // absolute URL
44 }
45 @end
46
47 @interface WOImage(PrivateMethods)
48
49 - (NSString *)associationDescription;
50
51 @end
52
53 #include "WOElement+private.h"
54 #include <NGObjWeb/WOApplication.h>
55 #include <NGObjWeb/WOResourceManager.h>
56 #include "decommon.h"
57
58 #if NeXT_Foundation_LIBRARY || APPLE_FOUNDATION_LIBRARY
59 @interface NSObject(Miss)
60 - (void)subclassResponsibility:(SEL)cmd;
61 @end
62 #endif
63
64 @implementation WOImage
65
66 + (id)allocWithZone:(NSZone *)zone {
67   static Class WOImageClass = Nil;
68   static _WOTemporaryImage *temporaryImage = nil;
69   
70   if (WOImageClass == Nil)
71     WOImageClass = [WOImage class];
72   if (temporaryImage == nil)
73     temporaryImage = [_WOTemporaryImage allocWithZone:zone];
74   
75   return (self == WOImageClass)
76     ? (id)temporaryImage
77     : NSAllocateObject(self, 0, zone);
78 }
79
80 /* request handling */
81
82 - (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
83   NSLog(@"no value configured for WOImage %@", self);
84   return nil;
85 }
86
87 - (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
88   [self subclassResponsibility:_cmd];
89 }
90
91 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
92   if ([[_ctx request] isFromClientComponent])
93     return;
94
95   WOResponse_AddCString(_response, "<img src=\"");
96   
97 #if DEBUG && USE_EXCEPTION_HANDLER
98   NS_DURING {
99     [self _appendSrcToResponse:_response inContext:_ctx];
100   }
101   NS_HANDLER {
102     fprintf(stderr, "exception in %s: %s\n",
103             [[self description] cString],
104             [[localException description] cString]);
105     [localException raise];
106   }
107   NS_ENDHANDLER;
108 #else
109   [self _appendSrcToResponse:_response inContext:_ctx];
110 #endif
111   
112   WOResponse_AddChar(_response, '"');
113   
114   [self appendExtraAttributesToResponse:_response inContext:_ctx];
115     
116   if (self->otherTagString) {
117     WOResponse_AddChar(_response, ' ');
118     WOResponse_AddString(_response,
119                          [self->otherTagString stringValueInComponent:
120                               [_ctx component]]);
121   }
122   
123   WOResponse_AddEmptyCloseParens(_response, _ctx);
124 }
125
126 @end /* WOImage */
127
128 @implementation _WODynamicImage
129
130 - (id)initWithName:(NSString *)_name
131   associations:(NSDictionary *)_config
132   template:(WOElement *)_t
133 {
134   if ((self = [super initWithName:_name associations:_config template:_t])) {
135     self->data     = OWGetProperty(_config, @"data");
136     self->mimeType = OWGetProperty(_config, @"mimeType");
137     self->key      = OWGetProperty(_config, @"key");
138     
139 #if DEBUG
140     if ([_config objectForKey:@"value"]     ||
141         [_config objectForKey:@"filename"]  ||
142         [_config objectForKey:@"framework"] ||
143         [_config objectForKey:@"src"]) {
144       NSLog(@"WARNING: inconsistent association settings in WOImage !"
145             @" (assign only one of value, src, data or filename)");
146     }
147 #endif
148   }
149   return self;
150 }
151
152 - (void)dealloc {
153   [self->key      release];
154   [self->data     release];
155   [self->mimeType release];
156   [super dealloc];
157 }
158
159 /* dynamic delivery */
160
161 - (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
162   WOComponent *sComponent = [_ctx component];
163   NSData     *adata;
164   NSString   *atype;
165   WOResponse *response;
166
167   adata = [self->data     valueInComponent:sComponent];
168   atype = [self->mimeType stringValueInComponent:sComponent];
169
170   response = [_ctx response];
171     
172   [response setContent:adata];
173   [response setHeader:atype ? atype : @"application/octet-stream"
174             forKey:@"content-type"];
175     
176   return response;
177 }
178
179 /* HTML generation */
180
181 - (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
182   WOResourceManager *rm;
183   WOComponent *sComponent;
184   NSString *kk, *url;
185
186   sComponent = [_ctx component];
187   
188   if ((kk = [self->key stringValueInComponent:sComponent]) == nil) {
189     WOResponse_AddString(_resp, [_ctx componentActionURL]);
190     return;
191   }
192
193   if ((rm = [[_ctx component] resourceManager]) == nil)
194     rm = [[_ctx application] resourceManager];
195     
196   [rm setData:[self->data valueInComponent:sComponent] forKey:kk
197       mimeType:[self->mimeType stringValueInComponent:sComponent]
198       session:[_ctx hasSession] ? [_ctx session] : nil];
199     
200   url = [_ctx urlWithRequestHandlerKey:
201                 [WOApplication resourceRequestHandlerKey]
202               path:[@"/" stringByAppendingString:kk]
203               queryString:nil];
204     
205   WOResponse_AddString(_resp, url);
206 }
207
208 /* description */
209
210 - (NSString *)associationDescription {
211   NSMutableString *str = [NSMutableString stringWithCapacity:64];
212   if (self->data)      [str appendFormat:@" data=%@",      self->data];
213   if (self->mimeType)  [str appendFormat:@" mimeType=%@",  self->mimeType];
214   if (self->key)       [str appendFormat:@" key=%@",       self->key];
215   [str appendString:[super associationDescription]];
216   return str;
217 }
218
219 @end /* _WODynamicImage */
220
221 @implementation _WOElementImage
222
223 - (id)initWithName:(NSString *)_name
224   associations:(NSDictionary *)_config
225   template:(WOElement *)_t
226 {
227   if ((self = [super initWithName:_name associations:_config template:_t])) {
228     self->value = OWGetProperty(_config, @"value");
229
230 #if DEBUG
231     if ([_config objectForKey:@"data"]      ||
232         [_config objectForKey:@"mimeType"]  ||
233         [_config objectForKey:@"key"]       ||
234         [_config objectForKey:@"filename"]  ||
235         [_config objectForKey:@"framework"] ||
236         [_config objectForKey:@"src"]) {
237       NSLog(@"WARNING: inconsistent association settings in WOImage !"
238             @" (assign only one of value, src, data or filename)");
239     }
240 #endif
241   }
242   return self;
243 }
244
245 - (void)dealloc {
246   RELEASE(self->value);
247   [super dealloc];
248 }
249
250 /* dynamic delivery */
251
252 - (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
253   WOElement *element;
254   
255   if ((element = [self->value valueInComponent:[_ctx component]]) == nil) {
256     NSLog(@"WARNING: missing element value for WOImage %@", self);
257     return nil;
258   }
259
260   [element appendToResponse:[_ctx response] inContext:_ctx];
261   return [_ctx response];
262 }
263
264 /* HTML generation */
265
266 - (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
267   WOResponse_AddString(_resp, [_ctx componentActionURL]);
268 }
269
270 /* description */
271
272 - (NSString *)associationDescription {
273   NSMutableString *str = [NSMutableString stringWithCapacity:64];
274
275   [str appendFormat:@" value=%@", self->value];
276   [str appendString:[super associationDescription]];
277   return str;
278 }
279
280 @end /* _WOElementImage */
281
282 @implementation _WOExternalImage
283
284 - (id)initWithName:(NSString *)_name
285   associations:(NSDictionary *)_config
286   template:(WOElement *)_t
287 {
288   if ((self = [super initWithName:_name associations:_config template:_t])) {
289     self->src = OWGetProperty(_config, @"src");
290
291 #if DEBUG
292     if ([_config objectForKey:@"data"]      ||
293         [_config objectForKey:@"mimeType"]  ||
294         [_config objectForKey:@"key"]       ||
295         [_config objectForKey:@"filename"]  ||
296         [_config objectForKey:@"framework"] ||
297         [_config objectForKey:@"value"]) {
298       NSLog(@"WARNING: inconsistent association settings in WOImage !"
299             @" (assign only one of value, src, data or filename)");
300     }
301 #endif
302   }
303   return self;
304 }
305
306 - (void)dealloc {
307   [self->src release];
308   [super dealloc];
309 }
310
311 /* HTML generation */
312
313 - (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
314   NSString *s;
315   
316   s = [self->src stringValueInComponent:[_ctx component]];
317   if (s != nil) [_resp appendContentHTMLAttributeValue:s];
318 }
319
320 /* description */
321
322 - (NSString *)associationDescription {
323   NSMutableString *str;
324   
325   str = [NSMutableString stringWithCapacity:64];
326   [str appendFormat:@" src=%@", self->src];
327   [str appendString:[super associationDescription]];
328   return str;
329 }
330
331 @end /* _WOExternalImage */
332
333 @implementation _WOTemporaryImage
334
335 - (id)initWithName:(NSString *)_n
336   associations:(NSDictionary *)_config
337   template:(WOElement *)_t
338 {
339   // TODO: cache class objects?
340   Class imageClass = Nil;
341   WOAssociation *a;
342   
343   if ((a = [_config objectForKey:@"filename"])) {
344     if ([a isValueConstant] && [_config objectForKey:@"framework"] == nil)
345       imageClass = NSClassFromString(@"_WOConstResourceImage");
346     else
347       imageClass = NSClassFromString(@"_WOResourceImage");
348   }
349   else if ([_config objectForKey:@"src"])
350     imageClass = [_WOExternalImage class];
351   else if ([_config objectForKey:@"value"])
352     imageClass = [_WOElementImage class];
353   else if ([_config objectForKey:@"data"])
354     imageClass = [_WODynamicImage class];
355   else {
356     NSLog(@"WARNING: missing data source association for WOImage !");
357   }
358   
359   return [[imageClass alloc] initWithName:_n associations:_config template:_t];
360 }
361
362 - (id)initWithName:(NSString *)_name
363   associations:(NSDictionary *)_associations
364   contentElements:(NSArray *)_contents
365 {
366   WOAssociation *a;
367   Class imageClass = Nil;
368   
369   if ((a = [_associations objectForKey:@"filename"])) {
370     if ([a isValueConstant] && [_associations objectForKey:@"framework"]==nil)
371       imageClass = NSClassFromString(@"_WOConstResourceImage");
372     else
373       imageClass = NSClassFromString(@"_WOResourceImage");
374   }
375   else if ([_associations objectForKey:@"src"])
376     imageClass = [_WOExternalImage class];
377   else if ([_associations objectForKey:@"value"])
378     imageClass = [_WOElementImage class];
379   else if ([_associations objectForKey:@"data"])
380     imageClass = [_WODynamicImage class];
381   else {
382     NSLog(@"WARNING: missing data source association for WOImage !");
383   }
384   
385   return [[imageClass alloc] initWithName:_name
386                              associations:_associations
387                              contentElements:_contents];
388 }
389
390 - (void)dealloc {
391   [self errorWithFormat:@"called dealloc on %@", self];
392 #if DEBUG
393   abort();
394 #endif
395   return;
396   
397 #if __APPLE__  
398   // make Tiger GCC happy
399   [super dealloc];
400 #endif
401 }
402
403 @end /* _WOTemporaryImage */