]> err.no Git - sope/blob - sope-appserver/NGObjWeb/DynamicElements/WOImage.m
e51a99a69ec534c477e7fbd379740119d3fa33a9
[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     : (id)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:
174               (atype != nil ? atype : (NSString *)@"application/octet-stream")
175             forKey:@"content-type"];
176     
177   return response;
178 }
179
180 /* HTML generation */
181
182 - (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
183   WOResourceManager *rm;
184   WOComponent *sComponent;
185   NSString *kk, *url;
186
187   sComponent = [_ctx component];
188   
189   if ((kk = [self->key stringValueInComponent:sComponent]) == nil) {
190     WOResponse_AddString(_resp, [_ctx componentActionURL]);
191     return;
192   }
193
194   if ((rm = [[_ctx component] resourceManager]) == nil)
195     rm = [[_ctx application] resourceManager];
196     
197   [rm setData:[self->data valueInComponent:sComponent] forKey:kk
198       mimeType:[self->mimeType stringValueInComponent:sComponent]
199       session:[_ctx hasSession] ? [_ctx session] : nil];
200     
201   url = [_ctx urlWithRequestHandlerKey:
202                 [WOApplication resourceRequestHandlerKey]
203               path:[@"/" stringByAppendingString:kk]
204               queryString:nil];
205     
206   WOResponse_AddString(_resp, url);
207 }
208
209 /* description */
210
211 - (NSString *)associationDescription {
212   NSMutableString *str = [NSMutableString stringWithCapacity:64];
213   if (self->data)      [str appendFormat:@" data=%@",      self->data];
214   if (self->mimeType)  [str appendFormat:@" mimeType=%@",  self->mimeType];
215   if (self->key)       [str appendFormat:@" key=%@",       self->key];
216   [str appendString:[super associationDescription]];
217   return str;
218 }
219
220 @end /* _WODynamicImage */
221
222 @implementation _WOElementImage
223
224 - (id)initWithName:(NSString *)_name
225   associations:(NSDictionary *)_config
226   template:(WOElement *)_t
227 {
228   if ((self = [super initWithName:_name associations:_config template:_t])) {
229     self->value = OWGetProperty(_config, @"value");
230
231 #if DEBUG
232     if ([_config objectForKey:@"data"]      ||
233         [_config objectForKey:@"mimeType"]  ||
234         [_config objectForKey:@"key"]       ||
235         [_config objectForKey:@"filename"]  ||
236         [_config objectForKey:@"framework"] ||
237         [_config objectForKey:@"src"]) {
238       NSLog(@"WARNING: inconsistent association settings in WOImage !"
239             @" (assign only one of value, src, data or filename)");
240     }
241 #endif
242   }
243   return self;
244 }
245
246 - (void)dealloc {
247   RELEASE(self->value);
248   [super dealloc];
249 }
250
251 /* dynamic delivery */
252
253 - (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
254   WOElement *element;
255   
256   if ((element = [self->value valueInComponent:[_ctx component]]) == nil) {
257     NSLog(@"WARNING: missing element value for WOImage %@", self);
258     return nil;
259   }
260
261   [element appendToResponse:[_ctx response] inContext:_ctx];
262   return [_ctx response];
263 }
264
265 /* HTML generation */
266
267 - (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
268   WOResponse_AddString(_resp, [_ctx componentActionURL]);
269 }
270
271 /* description */
272
273 - (NSString *)associationDescription {
274   NSMutableString *str = [NSMutableString stringWithCapacity:64];
275
276   [str appendFormat:@" value=%@", self->value];
277   [str appendString:[super associationDescription]];
278   return str;
279 }
280
281 @end /* _WOElementImage */
282
283 @implementation _WOExternalImage
284
285 - (id)initWithName:(NSString *)_name
286   associations:(NSDictionary *)_config
287   template:(WOElement *)_t
288 {
289   if ((self = [super initWithName:_name associations:_config template:_t])) {
290     self->src = OWGetProperty(_config, @"src");
291
292 #if DEBUG
293     if ([_config objectForKey:@"data"]      ||
294         [_config objectForKey:@"mimeType"]  ||
295         [_config objectForKey:@"key"]       ||
296         [_config objectForKey:@"filename"]  ||
297         [_config objectForKey:@"framework"] ||
298         [_config objectForKey:@"value"]) {
299       NSLog(@"WARNING: inconsistent association settings in WOImage !"
300             @" (assign only one of value, src, data or filename)");
301     }
302 #endif
303   }
304   return self;
305 }
306
307 - (void)dealloc {
308   [self->src release];
309   [super dealloc];
310 }
311
312 /* HTML generation */
313
314 - (void)_appendSrcToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
315   NSString *s;
316   
317   s = [self->src stringValueInComponent:[_ctx component]];
318   if (s != nil) [_resp appendContentHTMLAttributeValue:s];
319 }
320
321 /* description */
322
323 - (NSString *)associationDescription {
324   NSMutableString *str;
325   
326   str = [NSMutableString stringWithCapacity:64];
327   [str appendFormat:@" src=%@", self->src];
328   [str appendString:[super associationDescription]];
329   return str;
330 }
331
332 @end /* _WOExternalImage */
333
334 @implementation _WOTemporaryImage
335
336 - (id)initWithName:(NSString *)_n
337   associations:(NSDictionary *)_config
338   template:(WOElement *)_t
339 {
340   // TODO: cache class objects?
341   Class imageClass = Nil;
342   WOAssociation *a;
343   
344   if ((a = [_config objectForKey:@"filename"])) {
345     if ([a isValueConstant] && [_config objectForKey:@"framework"] == nil)
346       imageClass = NSClassFromString(@"_WOConstResourceImage");
347     else
348       imageClass = NSClassFromString(@"_WOResourceImage");
349   }
350   else if ([_config objectForKey:@"src"])
351     imageClass = [_WOExternalImage class];
352   else if ([_config objectForKey:@"value"])
353     imageClass = [_WOElementImage class];
354   else if ([_config objectForKey:@"data"])
355     imageClass = [_WODynamicImage class];
356   else {
357     NSLog(@"WARNING: missing data source association for WOImage !");
358   }
359   
360   return [[imageClass alloc] initWithName:_n associations:_config template:_t];
361 }
362
363 - (id)initWithName:(NSString *)_name
364   associations:(NSDictionary *)_associations
365   contentElements:(NSArray *)_contents
366 {
367   WOAssociation *a;
368   Class imageClass = Nil;
369   
370   if ((a = [_associations objectForKey:@"filename"])) {
371     if ([a isValueConstant] && [_associations objectForKey:@"framework"]==nil)
372       imageClass = NSClassFromString(@"_WOConstResourceImage");
373     else
374       imageClass = NSClassFromString(@"_WOResourceImage");
375   }
376   else if ([_associations objectForKey:@"src"])
377     imageClass = [_WOExternalImage class];
378   else if ([_associations objectForKey:@"value"])
379     imageClass = [_WOElementImage class];
380   else if ([_associations objectForKey:@"data"])
381     imageClass = [_WODynamicImage class];
382   else {
383     NSLog(@"WARNING: missing data source association for WOImage !");
384   }
385   
386   return [[imageClass alloc] initWithName:_name
387                              associations:_associations
388                              contentElements:_contents];
389 }
390
391 - (void)dealloc {
392   [self errorWithFormat:@"called dealloc on %@", self];
393 #if DEBUG
394   abort();
395 #endif
396   return;
397   
398   // same issue with gcc 4.1 on Linux ..., make Tiger GCC happy
399   if (0) [super dealloc];
400 }
401
402 @end /* _WOTemporaryImage */