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