]> err.no Git - sope/blob - sope-appserver/NGObjWeb/DynamicElements/WOBrowser.m
hotfix
[sope] / sope-appserver / NGObjWeb / DynamicElements / WOBrowser.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 "WOInput.h"
23 #include "decommon.h"
24
25 @interface WOBrowser : WOInput
26 {
27   // WODynamicElement: extraAttributes
28   // WODynamicElement: otherTagString
29   // inherited: name
30   // inherited: value
31   // inherited: disabled
32 @protected
33   WOAssociation *list;
34   WOAssociation *item;
35   WOAssociation *selection;         // => use 'selections'!
36   WOAssociation *string;            // WO4 => use 'displayString'!
37   WOAssociation *noSelectionString; // WO4
38   
39   // non-WO:
40   WOAssociation *singleSelection; // selection contains an item, not an array
41   
42   // WO 4.5
43   WOAssociation *multiple; // multiple selections allowed
44   WOAssociation *size;
45
46   // TODO: WO 4.5: selectedValues, escapeHTML
47 }
48
49 @end /* WOBrowser */
50
51 @implementation WOBrowser
52
53 + (int)version {
54   return [super version] + 0 /* v2 */;
55 }
56
57 + (void)initialize {
58   NSAssert2([super version] == 2,
59             @"invalid superclass (%@) version %i !",
60             NSStringFromClass([self superclass]), [super version]);
61 }
62
63 - (id)initWithName:(NSString *)_name
64   associations:(NSDictionary *)_config
65   template:(WOElement *)_c
66 {
67   if ((self = [super initWithName:_name associations:_config template:_c])) {
68     self->list              = OWGetProperty(_config, @"list");
69     self->item              = OWGetProperty(_config, @"item");
70     self->singleSelection   = OWGetProperty(_config, @"singleSelection");
71     self->multiple          = OWGetProperty(_config, @"multiple");
72     self->size              = OWGetProperty(_config, @"size");
73     self->noSelectionString = OWGetProperty(_config, @"noSelectionString");
74     
75     if ((self->string = OWGetProperty(_config, @"displayString")) == nil) {
76       if ((self->string = OWGetProperty(_config, @"string")) != nil) {
77         [self debugWithFormat:
78                 @"Note: using deprecated 'string' binding, "
79                 @"use 'displayString' instead."];
80       }
81     }
82     else if (OWGetProperty(_config, @"string") != nil) {
83       [self debugWithFormat:@"WARNING: 'displayString' AND 'string' bindings "
84               @"are set, use only one! ('string' is deprecated!)"];
85     }
86     
87     if ((self->selection = OWGetProperty(_config, @"selections")) == nil) {
88       if ((self->selection = OWGetProperty(_config, @"selection")) != nil) {
89         [self debugWithFormat:
90                 @"Note: using deprecated 'selection' binding, "
91                 @"use 'selections' instead."];
92       }
93     }
94     else if (OWGetProperty(_config, @"selection") != nil) {
95       [self debugWithFormat:@"WARNING: 'selections' AND 'selection' bindings "
96               @"are set, use only one! ('selection' is deprecated!)"];
97     }
98     
99     // compatiblity
100     if (self->noSelectionString == nil)
101       self->noSelectionString = OWGetProperty(_config, @"nilString");
102     
103     if (self->multiple == nil) {
104       self->multiple =
105         [WOAssociation associationWithValue:[NSNumber numberWithBool:YES]];
106       self->multiple = [self->multiple retain];
107     }
108   }
109   return self;
110 }
111
112 - (void)dealloc {
113   [self->noSelectionString release];
114   [self->singleSelection   release];
115   [self->list      release];
116   [self->item      release];
117   [self->selection release];
118   [self->string    release];
119   [self->size      release];
120   [self->multiple  release];
121   [super dealloc];
122 }
123
124 /* handling request */
125
126 - (void)_takeSingleFormValue:(id)formValue fromRequest:(WORequest *)_request
127   inContext:(WOContext *)_ctx
128 {
129   WOComponent *sComponent;
130   NSArray *objects;
131   id      object;
132       
133   sComponent = [_ctx component];
134   objects = [self->list valueInComponent:sComponent];
135       
136   if ([[formValue stringValue] isEqualToString:@"$"])
137     object = nil; // nil item selected
138   else {
139     int idx;
140       
141     object = nil;
142     if ((idx = [formValue intValue]) >= 0) {
143       if (idx < (int)[objects count])
144         object = [objects objectAtIndex:idx];
145       else {
146         [sComponent logWithFormat:
147                       @"WOBrowser got invalid index '%i' (formvalue='%@') "
148                     @"for list with count %i !",
149                     idx, formValue, [objects count]];
150       }
151     }
152     else
153       [sComponent logWithFormat:@"WOBrowser got invalid index '%i' !", idx];
154   }
155     
156   if ([self->selection isValueSettable]) {
157     NSArray *sel;
158         
159     if ([self->item isValueSettable])
160       [self->item setValue:object inComponent:sComponent];
161
162     if (object) {
163       sel = [self->singleSelection boolValueInComponent:sComponent]
164         ? [object retain]
165         : [[NSArray alloc] initWithObjects:object,nil];
166     }
167     else // nil item selected
168       sel = nil;
169           
170     [self->selection setValue:sel inComponent:sComponent];
171     [sel release]; sel = nil;
172   }
173 }
174
175 - (void)_takeMultiFormValue:(NSArray *)formValue fromRequest:(WORequest *)_rq
176   inContext:(WOContext *)_ctx
177 {
178   WOComponent *sComponent;
179   NSEnumerator   *values;
180   NSString       *v;
181   NSArray        *objects;
182   id             object;
183   
184   values     = [formValue objectEnumerator];
185   sComponent = [_ctx component];
186   objects    = [self->list valueInComponent:sComponent];
187     
188   if ([self->selection isValueSettable]) {
189     NSMutableArray *sel;
190     unsigned objCount;
191       
192     sel      = [[NSMutableArray alloc] initWithCapacity:[formValue count]];
193     objCount = [objects count];
194       
195     while ((v = [values nextObject])) {
196         int idx;
197
198         object = nil;
199         if ((idx = [v intValue]) >= 0) {
200           if (idx < (int)objCount)
201             object = [objects objectAtIndex:idx];
202           else {
203             [sComponent logWithFormat:
204                           @"WOBrowser got invalid index '%i'(formValue='%@' "
205                           @"for list with count %i !",
206                           idx, objCount, v];
207           }
208           
209           if ([self->item isValueSettable])
210             [self->item setValue:object inComponent:sComponent];
211         }
212         else {
213           [sComponent logWithFormat:@"WOBrowser got invalid index '%i' !",
214                         idx];
215         }
216         
217         if (object) [sel addObject:object];
218     }
219
220     if ([self->singleSelection boolValueInComponent:sComponent]) {
221         if ([sel count] > 1) {
222           NSLog(@"WARNING(%@): "
223                 @"using singleSelection with multiple selected values",
224                 self);
225         }
226         [self->selection setValue:[sel lastObject] inComponent:sComponent];
227     }
228     else
229       [self->selection setValue:sel inComponent:sComponent];
230     [sel release]; sel = nil;
231   }
232 }
233
234 - (void)takeValuesFromRequest:(WORequest *)_request
235   inContext:(WOContext *)_ctx
236 {
237   WOComponent *sComponent;
238   id formValue = nil;
239   
240   sComponent = [_ctx component];
241   if ([self->disabled boolValueInComponent:sComponent])
242     return;
243   
244   formValue = [_request formValuesForKey:OWFormElementName(self, _ctx)];
245 #if 0
246   [self logWithFormat:@"value=%@ ..", formValue];
247 #endif
248   
249   if ([self->value isValueSettable])
250     // TODO: is this correct?
251     [self->value setValue:formValue inComponent:sComponent];
252   
253   if ([formValue count] == 1) {
254     [self _takeSingleFormValue:[formValue lastObject] fromRequest:_request
255           inContext:_ctx];
256   }
257   else if (formValue != nil) {
258     [self _takeMultiFormValue:formValue fromRequest:_request
259           inContext:_ctx];
260   }
261   else {
262     // nothing selected
263     if ([self->item isValueSettable])
264       [self->item setValue:nil inComponent:sComponent];
265     if ([self->selection isValueSettable])
266       [self->selection setValue:nil inComponent:sComponent];
267   }
268 }
269
270 /* generate response */
271
272 - (void)appendOptionsToResponse:(WOResponse *)_response
273   inContext:(WOContext *)_ctx
274 {
275   WOComponent *sComponent;
276   BOOL     isSingle;
277   NSString *nilStr;
278   NSArray  *array;
279   id       selArray;
280   int      i, toGo;
281     
282   sComponent = [_ctx component];
283
284   nilStr   = [self->noSelectionString stringValueInComponent:sComponent];
285   isSingle = [self->singleSelection boolValueInComponent:sComponent];
286   array    = [self->list            valueInComponent:sComponent];
287   selArray = [self->selection       valueInComponent:sComponent];
288   toGo     = [array count];
289
290   if (nilStr != nil) {
291     WOResponse_AddCString(_response, "<option value=\"$\">");
292     WOResponse_AddHtmlString(_response, nilStr);
293     WOResponse_AddCString(_response, "</option>");
294   }
295   
296   for (i = 0; i < toGo; i++) {
297     NSString *v, *displayV;
298     id       object;
299     BOOL     isSelected;
300
301     object = [array objectAtIndex:i];
302
303     if ([self->item isValueSettable])
304       [self->item setValue:object inComponent:sComponent];
305
306     isSelected = NO;
307     if (selArray != nil) {
308       isSelected = isSingle 
309         ? [selArray isEqual:object] : [selArray containsObject:object];
310     }
311     
312     v = (self->value != nil)
313       ? [self->value stringValueInComponent:sComponent]
314       : (NSString *)[NSString stringWithFormat:@"%i", i]; // TODO: slow
315
316     displayV = self->string
317       ? [self->string stringValueInComponent:sComponent]
318       : [object stringValue];
319     
320     if (displayV == nil) displayV = @"";
321     
322     WOResponse_AddCString(_response, "<option value=\"");
323     WOResponse_AddString(_response, v);
324     if (isSelected) {
325       WOResponse_AddString(_response, _ctx->wcFlags.allowEmptyAttributes 
326                            ? @"\" selected>" : @"\" selected=\"selected\">");
327     }
328     else {
329       WOResponse_AddString(_response, @"\">");
330     }
331     WOResponse_AddHtmlString(_response, displayV);
332     WOResponse_AddCString(_response, "</option>");
333   }
334 }
335
336 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
337   BOOL     isMultiple;
338   unsigned s;
339   
340   if ([[_ctx request] isFromClientComponent])
341     return;
342
343   isMultiple = [self->multiple boolValueInComponent:[_ctx component]];
344   s          = [self->size unsignedIntValueInComponent:[_ctx component]];
345     
346   WOResponse_AddCString(_response, "<select name=\"");
347   [_response appendContentHTMLAttributeValue:OWFormElementName(self, _ctx)];
348   if (self->otherTagString) {
349     WOResponse_AddChar(_response, ' ');
350     WOResponse_AddString(_response,
351                          [self->otherTagString stringValueInComponent:
352                            [_ctx component]]);
353   }
354   WOResponse_AddCString(_response, "\"");
355       
356   if (s > 0) {
357     WOResponse_AddCString(_response, " size=\"");
358     WOResponse_AddUInt(_response, s);
359     [_response appendContentCharacter:'"'];
360   }
361
362   if ([self->disabled boolValueInComponent:[_ctx component]])
363     WOResponse_AddCString(_response, " disabled=\"disabled\"");
364       
365   if (isMultiple)
366     WOResponse_AddCString(_response, " multiple=\"multiple\"");
367     
368   [self appendExtraAttributesToResponse:_response inContext:_ctx];
369   WOResponse_AddCString(_response, ">\n");
370   
371   [self appendOptionsToResponse:_response inContext:_ctx];
372   
373   WOResponse_AddCString(_response, "</select>");
374 }
375
376 /* description */
377
378 - (NSString *)associationDescription {
379   NSMutableString *str;
380   
381   str = [NSMutableString stringWithCapacity:256];
382   [str appendString:[super associationDescription]];
383   
384   if (self->list)      [str appendFormat:@" list=%@",      self->list];
385   if (self->item)      [str appendFormat:@" item=%@",      self->item];
386   if (self->selection) [str appendFormat:@" selection=%@", self->selection];
387   if (self->string)    [str appendFormat:@" string=%@",    self->string];
388   if (self->noSelectionString)
389     [str appendFormat:@" noselection=%@", self->noSelectionString];
390   if (self->singleSelection)
391     [str appendFormat:@" singleSelection=%@", self->singleSelection];
392
393   if (self->size)     [str appendFormat:@" size=%@",     self->size];
394   if (self->multiple) [str appendFormat:@" multiple=%@", self->multiple];
395
396   return str;
397 }
398
399 @end /* WOBrowser */