KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > woody > formmodel > Repeater


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.woody.formmodel;
17
18 import java.util.ArrayList JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.Locale JavaDoc;
22
23 import org.apache.cocoon.woody.Constants;
24 import org.apache.cocoon.woody.FormContext;
25 import org.apache.cocoon.woody.event.WidgetEvent;
26 import org.apache.cocoon.xml.AttributesImpl;
27 import org.xml.sax.ContentHandler JavaDoc;
28 import org.xml.sax.SAXException JavaDoc;
29
30 /**
31  * A repeater is a widget that repeats a number of other widgets.
32  *
33  * <p>Technically, the Repeater widget is a ContainerWidget whose children are
34  * {@link RepeaterRow}s, and the RepeaterRows in turn are ContainerWidgets
35  * containing the actual repeated widgets. However, in practice, you won't need
36  * to use the RepeaterRow widget directly.
37  *
38  * <p>Using the methods {@link #getSize()} and {@link #getWidget(int, java.lang.String)}
39  * you can access all of the repeated widget instances.
40  *
41  * @version $Id: Repeater.java 30932 2004-07-29 17:35:38Z vgritsenko $
42  */

43 public class Repeater extends AbstractWidget implements ContainerWidget {
44     private RepeaterDefinition repeaterDefinition;
45     private List JavaDoc rows = new ArrayList JavaDoc();
46
47     public Repeater(RepeaterDefinition repeaterDefinition) {
48         this.repeaterDefinition = repeaterDefinition;
49         super.setDefinition(repeaterDefinition);
50         setLocation(definition.getLocation());
51         // setup initial size
52
removeRows();
53     }
54
55     public String JavaDoc getId() {
56         return definition.getId();
57     }
58
59     public int getSize() {
60         return rows.size();
61     }
62
63     public void addWidget(Widget widget) {
64         throw new RuntimeException JavaDoc("Repeater.addWidget(): Please use addRow() instead.");
65     }
66
67     public RepeaterRow addRow() {
68         RepeaterRow repeaterRow = new RepeaterRow(definition);
69         rows.add(repeaterRow);
70         return repeaterRow;
71     }
72     
73     public RepeaterRow addRow(int index) {
74         RepeaterRow repeaterRow = new RepeaterRow(definition);
75         if (index >= this.rows.size()) {
76             rows.add(repeaterRow);
77         } else {
78             rows.add(index, repeaterRow);
79         }
80         return repeaterRow;
81     }
82
83     public RepeaterRow getRow(int index) {
84         return (RepeaterRow)rows.get(index);
85     }
86     
87     /**
88      * Crawls up the parents of a widget up to finding a repeater row.
89      *
90      * @param widget the widget whose row is to be found
91      * @return the repeater row
92      */

93     public static RepeaterRow getParentRow(Widget widget) {
94         Widget result = widget;
95         while(result != null && ! (result instanceof Repeater.RepeaterRow)) {
96             result = result.getParent();
97         }
98         
99         if (result == null) {
100             throw new RuntimeException JavaDoc("Could not find a parent row for widget " + widget);
101
102         } else {
103             return (Repeater.RepeaterRow)result;
104         }
105     }
106     
107     /**
108      * Get the position of a row in this repeater.
109      * @param row the row which we search the index for
110      * @return the row position or -1 if this row is not in this repeater
111      */

112     public int indexOf(RepeaterRow row) {
113         return this.rows.indexOf(row);
114     }
115
116     /**
117      * @throws IndexOutOfBoundsException if the the index is outside the range of existing rows.
118      */

119     public void removeRow(int index) {
120         rows.remove(index);
121     }
122     
123     public void moveRowLeft(int index) {
124         if (index == 0 || index >= this.rows.size()) {
125             // do nothing
126
} else {
127             Object JavaDoc temp = this.rows.get(index-1);
128             this.rows.set(index-1, this.rows.get(index));
129             this.rows.set(index, temp);
130         }
131     }
132
133     public void moveRowRight(int index) {
134         if (index < 0 || index >= this.rows.size() - 1) {
135             // do nothing
136
} else {
137             Object JavaDoc temp = this.rows.get(index+1);
138             this.rows.set(index+1, this.rows.get(index));
139             this.rows.set(index, temp);
140         }
141     }
142
143     /**
144      * Clears all rows from the repeater and go back to the initial size
145      */

146     public void removeRows() {
147         rows.clear();
148         
149         // and reset to initial size
150
for (int i = 0; i < this.repeaterDefinition.getInitialSize(); i++) {
151             addRow();
152         }
153     }
154
155     /**
156      * Gets a widget on a certain row.
157      * @param rowIndex startin from 0
158      * @param id a widget id
159      * @return null if there's no such widget
160      */

161     public Widget getWidget(int rowIndex, String JavaDoc id) {
162         RepeaterRow row = (RepeaterRow)rows.get(rowIndex);
163         return row.getWidget(id);
164     }
165
166     public boolean hasWidget(String JavaDoc id) {
167         int row;
168         try {
169             row = Integer.parseInt(id);
170         } catch (NumberFormatException JavaDoc e) {
171             // TODO: Use i18n.
172
throw new RuntimeException JavaDoc("Repeater: Row id is not a valid integer: " + id);
173         }
174         return row >= 0 && row < rows.size();
175     }
176
177     public Widget getWidget(String JavaDoc id) {
178         int row;
179         try {
180             row = Integer.parseInt(id);
181         } catch (NumberFormatException JavaDoc e) {
182             // TODO: Use i18n.
183
throw new RuntimeException JavaDoc("Repeater: Row id is not a valid integer: " + id);
184         }
185         return (RepeaterRow)rows.get(row);
186     }
187
188     public void readFromRequest(FormContext formContext) {
189         // read number of rows from request, and make an according number of rows
190
String JavaDoc sizeParameter = formContext.getRequest().getParameter(getFullyQualifiedId() + ".size");
191         if (sizeParameter != null) {
192             int size = 0;
193             try {
194                 size = Integer.parseInt(sizeParameter);
195             } catch (NumberFormatException JavaDoc exc) {
196                 // do nothing
197
}
198
199             // some protection against people who might try to exhaust the server by supplying very large
200
// size parameters
201
if (size > 500)
202                 throw new RuntimeException JavaDoc("Client is not allowed to specify a repeater size larger than 500.");
203
204             int currentSize = getSize();
205             if (currentSize < size) {
206                 for (int i = currentSize; i < size; i++) {
207                     addRow();
208                 }
209             } else if (currentSize > size) {
210                 for (int i = currentSize - 1; i >= size; i--) {
211                     removeRow(i);
212                 }
213             }
214         }
215
216         // let the rows read their data from the request
217
Iterator JavaDoc rowIt = rows.iterator();
218         while (rowIt.hasNext()) {
219             RepeaterRow row = (RepeaterRow)rowIt.next();
220             row.readFromRequest(formContext);
221         }
222     }
223
224     public boolean validate(FormContext formContext) {
225         boolean valid = true;
226         Iterator JavaDoc rowIt = rows.iterator();
227         while (rowIt.hasNext()) {
228             RepeaterRow row = (RepeaterRow)rowIt.next();
229             valid = valid & row.validate(formContext);
230         }
231         return valid ? super.validate(formContext) : false;
232     }
233
234     private static final String JavaDoc REPEATER_EL = "repeater";
235     private static final String JavaDoc HEADINGS_EL = "headings";
236     private static final String JavaDoc HEADING_EL = "heading";
237     private static final String JavaDoc LABEL_EL = "label";
238     private static final String JavaDoc REPEATER_SIZE_EL = "repeater-size";
239
240     public void generateSaxFragment(ContentHandler JavaDoc contentHandler, Locale JavaDoc locale) throws SAXException JavaDoc {
241         AttributesImpl repeaterAttrs = new AttributesImpl();
242         repeaterAttrs.addCDATAAttribute("id", getFullyQualifiedId());
243         repeaterAttrs.addCDATAAttribute("size", String.valueOf(getSize()));
244         contentHandler.startElement(Constants.WI_NS, REPEATER_EL, Constants.WI_PREFIX_COLON + REPEATER_EL, repeaterAttrs);
245
246         // the repeater's label
247
contentHandler.startElement(Constants.WI_NS, LABEL_EL, Constants.WI_PREFIX_COLON + LABEL_EL, Constants.EMPTY_ATTRS);
248         definition.generateLabel(contentHandler);
249         contentHandler.endElement(Constants.WI_NS, LABEL_EL, Constants.WI_PREFIX_COLON + LABEL_EL);
250
251         // heading element -- currently contains the labels of each widget in the repeater
252
contentHandler.startElement(Constants.WI_NS, HEADINGS_EL, Constants.WI_PREFIX_COLON + HEADINGS_EL, Constants.EMPTY_ATTRS);
253         Iterator JavaDoc widgetDefinitionIt = repeaterDefinition.getWidgetDefinitions().iterator();
254         while (widgetDefinitionIt.hasNext()) {
255             WidgetDefinition widgetDefinition = (WidgetDefinition)widgetDefinitionIt.next();
256             contentHandler.startElement(Constants.WI_NS, HEADING_EL, Constants.WI_PREFIX_COLON + HEADING_EL, Constants.EMPTY_ATTRS);
257             widgetDefinition.generateLabel(contentHandler);
258             contentHandler.endElement(Constants.WI_NS, HEADING_EL, Constants.WI_PREFIX_COLON + HEADING_EL);
259         }
260         contentHandler.endElement(Constants.WI_NS, HEADINGS_EL, Constants.WI_PREFIX_COLON + HEADINGS_EL);
261
262         // the actual rows in the repeater
263
Iterator JavaDoc rowIt = rows.iterator();
264         while (rowIt.hasNext()) {
265             RepeaterRow row = (RepeaterRow)rowIt.next();
266             row.generateSaxFragment(contentHandler, locale);
267         }
268         contentHandler.endElement(Constants.WI_NS, REPEATER_EL, Constants.WI_PREFIX_COLON + REPEATER_EL);
269     }
270
271     public void generateLabel(ContentHandler JavaDoc contentHandler) throws SAXException JavaDoc {
272         definition.generateLabel(contentHandler);
273     }
274
275     /**
276      * Generates the label of a certain widget in this repeater.
277      */

278     public void generateWidgetLabel(String JavaDoc widgetId, ContentHandler JavaDoc contentHandler) throws SAXException JavaDoc {
279         WidgetDefinition widgetDefinition = repeaterDefinition.getWidgetDefinition(widgetId);
280         if (widgetDefinition == null)
281             throw new SAXException JavaDoc("Repeater \"" + getFullyQualifiedId() + "\" contains no widget with id \"" + widgetId + "\".");
282         widgetDefinition.generateLabel(contentHandler);
283     }
284
285     /**
286      * Generates a repeater-size element with a size attribute indicating the size of this repeater.
287      */

288     public void generateSize(ContentHandler JavaDoc contentHandler) throws SAXException JavaDoc {
289         AttributesImpl attrs = new AttributesImpl();
290         attrs.addCDATAAttribute("id", getFullyQualifiedId());
291         attrs.addCDATAAttribute("size", String.valueOf(getSize()));
292         contentHandler.startElement(Constants.WI_NS, REPEATER_SIZE_EL, Constants.WI_PREFIX_COLON + REPEATER_SIZE_EL, attrs);
293         contentHandler.endElement(Constants.WI_NS, REPEATER_SIZE_EL, Constants.WI_PREFIX_COLON + REPEATER_SIZE_EL);
294     }
295
296     public class RepeaterRow extends AbstractContainerWidget {
297
298         public RepeaterRow(AbstractWidgetDefinition definition) {
299             super(definition);
300             ((ContainerDefinition)definition).createWidgets(this);
301         }
302
303         public String JavaDoc getLocation() {
304             return Repeater.this.getLocation();
305         }
306
307         public String JavaDoc getId() {
308             // id of a RepeaterRow is the position of the row in the list of rows.
309
return String.valueOf(rows.indexOf(this));
310         }
311
312         public Widget getParent() {
313             return Repeater.this;
314         }
315         
316         public Form getForm() {
317             return Repeater.this.getForm();
318         }
319
320         public String JavaDoc getNamespace() {
321             return getParent().getNamespace() + "." + getId();
322         }
323
324         public String JavaDoc getFullyQualifiedId() {
325             return getParent().getNamespace() + "." + getId();
326         }
327
328         public void setParent(Widget widget) {
329             throw new RuntimeException JavaDoc("Parent of RepeaterRow is fixed, and cannot be set.");
330         }
331
332         public boolean validate(FormContext formContext) {
333             // Validate only child widtgets, as the definition's validators are those of the parent repeater
334
return widgets.validate(formContext);
335         }
336         
337         private static final String JavaDoc ROW_EL = "repeater-row";
338
339         public void generateLabel(ContentHandler JavaDoc contentHandler) throws SAXException JavaDoc {
340             // this widget has no label
341
}
342
343         public void generateSaxFragment(ContentHandler JavaDoc contentHandler, Locale JavaDoc locale) throws SAXException JavaDoc {
344             AttributesImpl rowAttrs = new AttributesImpl();
345             rowAttrs.addCDATAAttribute("id", getFullyQualifiedId());
346             contentHandler.startElement(Constants.WI_NS, ROW_EL, Constants.WI_PREFIX_COLON + ROW_EL, rowAttrs);
347             Iterator JavaDoc widgetIt = widgets.iterator();
348             while (widgetIt.hasNext()) {
349                 Widget widget = (Widget)widgetIt.next();
350                 widget.generateSaxFragment(contentHandler, locale);
351             }
352             contentHandler.endElement(Constants.WI_NS, ROW_EL, Constants.WI_PREFIX_COLON + ROW_EL);
353         }
354         
355         public void broadcastEvent(WidgetEvent event) {
356             throw new UnsupportedOperationException JavaDoc("Widget " + this.getFullyQualifiedId() + " doesn't handle events.");
357         }
358     }
359
360     /* (non-Javadoc)
361      * @see org.apache.cocoon.woody.formmodel.ContainerWidget#getChildren()
362      */

363     public Iterator JavaDoc getChildren() {
364         // TODO Auto-generated method stub to make this compile again
365
return null;
366     }
367
368     
369 }
370
Popular Tags