KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > tags > databinding > cellrepeater > CellRepeater


1 /*
2  * Copyright 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  * $Header:$
17  */

18 package org.apache.beehive.netui.tags.databinding.cellrepeater;
19
20 import java.util.ArrayList JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Collections JavaDoc;
24 import javax.servlet.jsp.JspException JavaDoc;
25 import javax.servlet.jsp.tagext.TryCatchFinally JavaDoc;
26 import javax.servlet.jsp.tagext.SimpleTagSupport JavaDoc;
27 import javax.servlet.ServletRequest JavaDoc;
28
29 import org.apache.beehive.netui.script.common.IDataAccessProvider;
30 import org.apache.beehive.netui.script.common.DataAccessProviderStack;
31 import org.apache.beehive.netui.tags.AbstractClassicTag;
32 import org.apache.beehive.netui.tags.ExpressionHandling;
33 import org.apache.beehive.netui.tags.rendering.TagRenderingBase;
34 import org.apache.beehive.netui.tags.rendering.TableTag;
35 import org.apache.beehive.netui.tags.rendering.TdTag;
36 import org.apache.beehive.netui.tags.rendering.TrTag;
37 import org.apache.beehive.netui.tags.rendering.AbstractRenderAppender;
38 import org.apache.beehive.netui.tags.rendering.StringBuilderRenderAppender;
39 import org.apache.beehive.netui.tags.rendering.ConstantRendering;
40 import org.apache.beehive.netui.util.Bundle;
41 import org.apache.beehive.netui.util.exception.LocalizedUnsupportedOperationException;
42 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
43 import org.apache.beehive.netui.util.iterator.IteratorFactory;
44 import org.apache.beehive.netui.util.logging.Logger;
45
46 /**
47  * <p/>
48  * This tag is a repeating, databound tag that renders its body each cell of a table of the specified dimensions.
49  * The tag is bound to a dataset that is specified in the <code>dataSource</code> attribute. For each item in
50  * the data set, the body of this tag is rendered, and NetUI tags in the body that are databound
51  * can use the <code>container.item</code> syntax to access the "current" data item in the iteration.
52  * Properties on this data item can be accessed using expressions.
53  * </p>
54  * <p>
55  * The tag will automatically insert the open and close table, row, and cell tags which will comprise
56  * the table that is rendered. Style attributes may be set using attributes on this tag in order to
57  * cusotmize the tag's final appearance. The dimensions of the table are specified by using at least
58  * one of the attributes columns and rows. If only one is specified, the other will be inferred by
59  * using the size of the given data set. As a result, the entire dataset will be rendered. For example,
60  * if a table should be four columns wide and the data set has twenty items, the resulting table will
61  * have five rows. If the data set is fewer items than the number of cells that should be rendered,
62  * the cells are padded with HTML table cells:
63  * </p>
64  * <pre>
65  * &lt;td&gt;&amp;nbsp;&lt;/td&gt;
66  * </pre>
67  * <p/>
68  * This will prevent rendering a malformed HTML table. If the number of cells to render is smaller than
69  * the fully specified dimensions of the table, only this number of cells will be rendered. For example,
70  * if the data set is size fifty but the <code>rows</code> and the <code>columns</code> attributes are
71  * both seven, only the first forty-nine items in the dataset will be rendered and the fiftieth
72  * will not be shown. The values of the <code>rows</code> and the <code>columns</code> can be databound with
73  * an expression; in this case, each value will be converted into an integer. An error will be reported
74  * on the page if this conversion fails.
75  * </p><p>
76  * This tag implements the {@link IDataAccessProvider} interface which provides tags access to the "current"
77  * data item. Properties on the <code>IDataAccessProvider</code> interface are available through the
78  * "container" binding context, which can be used inside of the body of the CellRepeater. Properties of
79  * the <code>IDataAccessProvider</code> interface that are available include:
80  * <table border="1" cellspacing="0" cellpadding="5" width="75%">
81  * <tr><td><b>Name</b></td><td><b>Description</b></td></tr>
82  * <tr><td>index</td><td>the current index in the iteration; this index is absolute to the dataset</td></tr>
83  * <tr><td>parent</td><td>any <code>IDataAccessProvider</code> parent of this tag</td></tr>
84  * <tr><td>item</td><td>the current data item</td></tr>
85  * </table>
86  * </p>
87  * <p/>
88  * <b>Note:</b> the metadata property of the <code>container</code> binding context is not supported
89  * on the CellRepeater.
90  * </p>
91  *
92  * @jsptagref.tagdescription
93  * <p/>
94  * This tag is a repeating, databound tag that renders its body each cell of a table of the specified dimensions.
95  * The tag is bound to a dataset that is specified in the <code>dataSource</code> attribute. For each item in
96  * the data set, the body of this tag is rendered, and NetUI tags in the body that are databound
97  * can use the <code>container.item</code> syntax to access the "current" data item in the iteration.
98  * Properties on this data item can be accessed using expressions.
99  * </p>
100  * <p>
101  * The tag will automatically insert the open and close table, row, and cell tags which will comprise
102  * the table that is rendered. Style attributes may be set using attributes on this tag in order to
103  * cusotmize the tag's final appearance. The dimensions of the table are specified by using at least
104  * one of the attributes columns and rows. If only one is specified, the other will be inferred by
105  * using the size of the given data set. As a result, the entire dataset will be rendered. For example,
106  * if a table should be four columns wide and the data set has twenty items, the resulting table will
107  * have five rows. If the data set is fewer items than the number of cells that should be rendered,
108  * the cells are padded with HTML table cells:
109  * </p>
110  * <pre>
111  * &lt;td&gt;&amp;nbsp;&lt;/td&gt;
112  * </pre>
113  * <p/>
114  * This will prevent rendering a malformed HTML table. If the number of cells to render is smaller than
115  * the fully specified dimensions of the table, only this number of cells will be rendered. For example,
116  * if the data set is size fifty but the <code>rows</code> and the <code>columns</code> attributes are
117  * both seven, only the first forty-nine items in the dataset will be rendered and the fiftieth
118  * will not be shown. The values of the <code>rows</code> and the <code>columns</code> can be databound with
119  * an expression; in this case, each value will be converted into an integer. An error will be reported
120  * on the page if this conversion fails.
121  * </p><p>
122  * This tag implements the {@link IDataAccessProvider} interface which provides tags access to the "current"
123  * data item. Properties on the <code>IDataAccessProvider</code> interface are available through the
124  * "container" binding context, which can be used inside of the body of the CellRepeater. Properties of
125  * the <code>IDataAccessProvider</code> interface that are available include:
126  * <table border="1" cellspacing="0" cellpadding="5" width="75%">
127  * <tr><td><b>Name</b></td><td><b>Description</b></td></tr>
128  * <tr><td>index</td><td>the current index in the iteration; this index is absolute to the dataset</td></tr>
129  * <tr><td>parent</td><td>any <code>IDataAccessProvider</code> parent of this tag</td></tr>
130  * <tr><td>item</td><td>the current data item</td></tr>
131  * </table>
132  * </p>
133  * <p/>
134  * <b>Note:</b> the metadata property of the <code>container</code> binding context is not supported
135  * on the CellRepeater.
136  * </p>
137  *
138  * @example
139  * In this example, the &lt;netui-data:cellRepeater> tag creates a table with the number of columns set
140  * given as <code>${pageFlow.numColumns}</code> and as many rows as necessary to display all the items in the
141  * <code>pageFlow.itemArray</code> data set.
142  * <pre>
143  * &lt;netui-data:cellRepeater dataSource="pageFlow.itemArray" columns="pageFlow.numColumns">
144  * Item: &lt;netui:span value="${container.item}"/>
145  * &lt;/netui-data:cellRepeater>
146  * </pre>
147  * @netui:tag name="cellRepeater"
148  * description="A repeating, databound tag that renders its body into each cell of a table of the specified dimensions."
149  */

150 public class CellRepeater
151     extends AbstractClassicTag
152     implements IDataAccessProvider, TryCatchFinally JavaDoc {
153
154     private static final Logger LOGGER = Logger.getInstance(CellRepeater.class);
155     private static final int DIMENSION_DEFAULT_VALUE = -1;
156     private static final TableTag.State STATE_TABLE = new TableTag.State();
157     private static final TrTag.State STATE_TR = new TrTag.State();
158     private static final TdTag.State STATE_TD = new TdTag.State();
159
160     private boolean _valid = true;
161     private boolean _verticalRepeat = false;
162     private boolean _containerInPageContext = false;
163     private int _columns = DIMENSION_DEFAULT_VALUE;
164     private int _rows = DIMENSION_DEFAULT_VALUE;
165     private int _currentIndex = -1;
166     private int _currentRow = -1;
167     private int _currentColumn = -1;
168
169     private ArrayList JavaDoc _dataList = null;
170     private Object JavaDoc _currentItem = null;
171     private String JavaDoc _dataSource = null;
172     private String JavaDoc _altCellClass = null;
173     private String JavaDoc _cellClass = null;
174     private ConstantRendering _htmlConstantRendering = null;
175     private TagRenderingBase _tableRenderer = null;
176     private TagRenderingBase _trRenderer = null;
177     private TagRenderingBase _tdRenderer = null;
178     private TableTag.State _tableState = null;
179     private TdTag.State _tdState = null;
180     private TrTag.State _trState = null;
181     private InternalStringBuilder _sb = null;
182     private AbstractRenderAppender _appender = null;
183
184     /**
185      * Get the name of this tag. This is used to identify the type of this tag
186      * for reporting tag errors.
187      *
188      * @return a constant String representing the name of this tag.
189      */

190     public String JavaDoc getTagName() {
191         return "CellRepeater";
192     }
193
194     /**
195      * The HTML style class that is rendered on the HTML table. For example, if the row class is "tableClass",
196      * each opening table tag is:
197      * <pre>
198      * &lt;table class="tableClass"&gt;
199      * </pre>
200      *
201      * @param tableClass the name of a style class in a CSS
202      * @jsptagref.attributedescription
203      * The HTML style class that is rendered on the HTML table. For example, if the row class is "tableClass",
204      * each opening table tag is:
205      * <pre>
206      * &lt;table class="tableClass"&gt;
207      * </pre>
208      * @jsptagref.attributesyntaxvalue <i>string_class</i>
209      * @netui:attribute required="false"
210      */

211     public void setTableClass(String JavaDoc tableClass) {
212         if("".equals(tableClass))
213             return;
214         _tableState = new TableTag.State();
215         _tableState.styleClass = tableClass;
216     }
217
218     /**
219      * Set the HTML style class that is rendered on each HTML table row that
220      * is opened by this tag. For example, if the row class is "rowClass",
221      * each opening table row tag is:
222      * <pre>
223      * &lt;tr class="rowClass"&gt;
224      * </pre>
225      *
226      * @param rowClass the name of a style class in the CSS
227      * @jsptagref.attributedescription
228      * Set the HTML style class that is rendered on each HTML table row that
229      * is opened by this tag. For example, if the row class is "rowClass",
230      * each opening table row tag is:
231      * <pre>
232      * &lt;tr class="rowClass"&gt;
233      * </pre>
234      * @jsptagref.attributesyntaxvalue <i>string_class</i>
235      * @netui:attribute required="false"
236      */

237     public void setRowClass(String JavaDoc rowClass) {
238         if("".equals(rowClass))
239             return;
240         _trState = new TrTag.State();
241         _trState.styleClass = rowClass;
242     }
243
244     /**
245      * Set the HTML style class that is rendered on each HTML table cell that
246      * is opened by this tag. For example, if the cell class is "cellClass",
247      * each opening table cell tag is:
248      * <pre>
249      * &lt;td class="cellClass"&gt;
250      * </pre>
251      *
252      * @param cellClass the name of a style class in a CSS
253      * @jsptagref.attributedescription
254      * Set the HTML style class that is rendered on each HTML table cell that
255      * is opened by this tag. For example, if the cell class is "cellClass",
256      * each opening table cell tag is:
257      * <pre>
258      * &lt;td class="cellClass"&gt;
259      * </pre>
260      * @jsptagref.attributesyntaxvalue <i>string_class</i>
261      * @netui:attribute required="false"
262      */

263     public void setCellClass(String JavaDoc cellClass) {
264         if("".equals(cellClass))
265             return;
266         _cellClass = cellClass;
267     }
268
269     /**
270      * Set the HTML style class that is rendered on each HTML table cell that
271      * is opened by this tag. The starting cell is alternated for each row, which
272      * results in a checkerboard colored table being displayed. For example, if the
273      * alteranting cell class is \"alternatingCellClass\", every other table cell
274      * tag is:
275      * <pre>
276      * &lt;td cell="alternatingCellClass"&gt;
277      * </pre>
278      *
279      * @param alternatingCellClass the name of a style class in a CSS
280      * @jsptagref.attributedescription
281      * The HTML style class that is rendered on alternating table cells.
282      * The starting cell is alternated for each row, which
283      * results in a checkerboard colored table being displayed. For example, if the
284      * alteranting cell class is "alternatingCellClass", every other table cell
285      * tag is:
286      * <pre>
287      * &lt;td cell="alternatingCellClass"&gt;</pre>
288      * @jsptagref.attributesyntaxvalue <i>string_class</i>
289      * @netui:attribute required="false"
290      */

291     public void setAlternatingCellClass(String JavaDoc alternatingCellClass) {
292         if("".equals(alternatingCellClass))
293             return;
294         _altCellClass = alternatingCellClass;
295     }
296
297     /**
298      * This tag can render the items in its dataset horizontally or vertically. If
299      * the rows are rendered horizontally, the items in the dataset are rendered
300      * across each row from top to bottom. Otherwise, they are rendered down each
301      * column from left to right. The default is to render the items horizontally.
302      *
303      * @param verticalRepeat if set to <code>true</code>, the dataset is rendered down
304      * each column; otherwise it is rendered across each row, the default.
305      * @jsptagref.attributedescription
306      * Boolean. If true the data set is rendered vertically, otherwise it is rendered horizontally. If
307      * the rows are rendered horizontally, the items in the data set are rendered
308      * across each row from top to bottom. Otherwise, they are rendered down each
309      * column from left to right. The default is to render the items horizontally.
310      * @jsptagref.attributesyntaxvalue <i>boolean_verticalRepeat</i>
311      * @netui:attribute required="false"
312      */

313     public void setVerticalRepeat(boolean verticalRepeat) {
314         _verticalRepeat = verticalRepeat;
315     }
316
317     /**
318      * Set the number of columns that should be rendered in the table
319      * generated by the tag. If the columns attribute is specified but
320      * the rows attribute is not, the rows attribute will be inferred
321      * using the size of the dataset.
322      *
323      * @param columns an integer or an expression
324      * @jsptagref.attributedescription
325      * Integer. The number of columns that should be rendered in the HTML table.
326      * If the <code>columns</code> attribute is specified but
327      * the <code>rows</code> attribute is not, the <code>rows</code> attribute will be inferred
328      * using the size of the data set.
329      * @jsptagref.attributesyntaxvalue <i>integer_columns</i>
330      * @netui:attribute required="false" rtexprvalue="true"
331      */

332     public void setColumns(int columns) {
333         _columns = columns;
334     }
335
336     /**
337      * Set the number of rows that should be rendered in the table
338      * generated by the tag. If the rows attribute is specified but
339      * the columns attribute is not, the columns attribute will be
340      * inferred using the size of the dataset.
341      *
342      * @param rows an integer or an expression whose value can be
343      * converted into an integer.
344      * @jsptagref.attributedescription
345      * Integer. The number of rows that should be rendered in the HTML table.
346      * If the <code>rows</code> attribute is specified but
347      * the <code>columns</code> attribute is not, the <code>columns</code> attribute will be
348      * inferred using the size of the data set.
349      * @jsptagref.attributesyntaxvalue <i>integer_rows</i>
350      * @netui:attribute required="false" rtexprvalue="true"
351      */

352     public void setRows(int rows) {
353         _rows = rows;
354     }
355
356     /**
357      * <p>The <code>dataSource</code> attribute determines both
358      * (1) the source of populating data for the tag and
359      * (2) the object to which the tag submits data.
360      *
361      * <p>For example, assume that the Controller file (= JPF file) contains
362      * a Form Bean with the property foo. Then the following &lt;netui:textBox> tag will
363      * (1) draw populating data from the Form Bean's foo property and (2)
364      * submit user defined data to the same property.
365      *
366      * <p>&nbsp;&nbsp;&nbsp;&nbsp;<code>&lt;netui:textBox dataSource="actionForm.foo" /></code>
367      *
368      * <p>When the tag is used to submit data, the data binding expression must
369      * refer to a Form Bean property.
370      * In cases where the tag is not used to submit data, but is used for
371      * displaying data only, the data
372      * binding expression need not refer to a Form Bean property. For example,
373      * assume that myIterativeData is a member variable on
374      * the Controller file ( = JPF file). The following &lt;netui-data:repeater>
375      * tag draws its data from myIterativeData.
376
377      * @param dataSource the data source
378      * @jsptagref.attributedescription
379      * <p>The <code>dataSource</code> attribute determines both
380      * (1) the source of populating data for the tag and
381      * (2) the object to which the tag submits data.
382      *
383      * <p>For example, assume that the Controller file (= JPF file) contains
384      * a Form Bean with the property foo. Then the following &lt;netui:textBox> tag will
385      * (1) draw populating data from the Form Bean's foo property and (2)
386      * submit user defined data to the same property.
387      *
388      * <p>&nbsp;&nbsp;&nbsp;&nbsp;<code>&lt;netui:textBox dataSource="actionForm.foo" /></code>
389      *
390      * <p>When the tag is used to submit data, the data binding expression must
391      * refer to a Form Bean property.
392      * In cases where the tag is not used to submit data, but is used for
393      * displaying data only, the data
394      * binding expression need not refer to a Form Bean property. For example,
395      * assume that myIterativeData is a member variable on
396      * the Controller file ( = JPF file). The following &lt;netui-data:repeater>
397      * tag draws its data from myIterativeData.
398      *
399      * <p>&nbsp;&nbsp;&nbsp;&nbsp;<code>&lt;netui-data:cellRepeater dataSource="pageFlow.myIterativeData"></code>
400      * @jsptagref.attributesyntaxvalue <i>expression_datasource</i>
401      * @netui:attribute required="true"
402      */

403     public void setDataSource(String JavaDoc dataSource) {
404         _dataSource = dataSource;
405     }
406
407     /**
408      * Prepare to render the dataset that was specified in the dataSource attribute. The
409      * dataSource expression is evaluated and the table's dimensions are computed. If
410      * there is no data in the dataset but the rows and columns attributes were specified,
411      * an empty table of the given dimensions is rendered.
412      *
413      * @return EVAL_BODY_BUFFERED or SKIP_BODY if errors are reported, the data set
414      * is null, or there is no data in the data set
415      * @throws JspException if errors occurred that could not be reported in the page
416      */

417     public int doStartTag()
418             throws JspException JavaDoc {
419         ServletRequest JavaDoc request = pageContext.getRequest();
420
421         _tableRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.TABLE_TAG, request);
422         _trRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.TR_TAG, request);
423         _tdRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.TD_TAG, request);
424         _htmlConstantRendering = TagRenderingBase.Factory.getConstantRendering(request);
425
426         _sb = new InternalStringBuilder(1024);
427         _appender = new StringBuilderRenderAppender(_sb);
428
429         Object JavaDoc source = evaluateDataSource();
430
431         if(hasErrors())
432             return SKIP_BODY;
433
434         if(source != null) {
435             Iterator JavaDoc iterator = IteratorFactory.createIterator(source);
436             if(iterator == null) {
437                 LOGGER.info("CellRepeater: The data structure from which to create an iterator is null.");
438                 iterator = Collections.EMPTY_LIST.iterator();
439             }
440
441             if(iterator != null) {
442                 _dataList = new ArrayList JavaDoc();
443                 while(iterator.hasNext()) {
444                     _dataList.add(iterator.next());
445                 }
446             }
447         }
448
449         if(_rows == DIMENSION_DEFAULT_VALUE || _columns == DIMENSION_DEFAULT_VALUE) {
450             /* try to guess the dimensions of the table */
451             if(_dataList != null && _dataList.size() > 0) {
452                 guessDimensions(_dataList);
453
454                 if(hasErrors())
455                     return SKIP_BODY;
456             }
457             /* the size of the data set isn't guessable */
458             else {
459                 _valid = false;
460                 return SKIP_BODY;
461             }
462         }
463
464         /* check to make sure the rows / columns are actually valid before starting to render */
465         if(_rows <= 0) {
466             String JavaDoc msg = Bundle.getString("Tags_CellRepeater_invalidRowValue", new Object JavaDoc[]{getTagName(), new Integer JavaDoc(_rows)});
467             registerTagError(msg, null);
468         }
469
470         if(_columns <= 0) {
471             String JavaDoc msg = Bundle.getString("Tags_CellRepeater_invalidColumnValue", new Object JavaDoc[]{getTagName(), new Integer JavaDoc(_columns)});
472             registerTagError(msg, null);
473         }
474
475         if(hasErrors())
476             return SKIP_BODY;
477
478         openTableTag(_appender, _tableState);
479
480         _currentRow = 0;
481         _currentColumn = 0;
482
483         DataAccessProviderStack.addDataAccessProvider(this, pageContext);
484         _containerInPageContext = true;
485
486         boolean haveItem = ensureItem(0, _dataList);
487         if(haveItem) {
488             openRowTag(_appender, _trState);
489             openCellTag(_appender, _currentColumn);
490             return EVAL_BODY_BUFFERED;
491         }
492         else {
493             // special case -- with no items, render the entire table here
494
for(int i = 0; i < _rows; i++) {
495                 openRowTag(_appender, _trState);
496                 for(int j = 0; j < _columns; j++) {
497                     openCellTag(_appender, computeStyleIndex(i, j));
498                     _htmlConstantRendering.NBSP(_appender);
499                     closeCellTag(_appender);
500                 }
501                 closeRowTag(_appender);
502                 _appender.append("\n");
503             }
504             _currentRow = _rows;
505             _currentColumn = _columns;
506             return SKIP_BODY;
507         }
508     }
509
510     /**
511      * Continue rendering the body of this tag until the dimensions of the table have been reached or
512      * the entire dataset has been rendered. The buffered body content from the previous iteration
513      * of the body is added to the content this tag will render, @see addContent(java.lang.String).
514      * Pad the table if the dimensions have not been met but the dataset is empty.
515      *
516      * @return EVAL_BODY_BUFFERED if there is more data to render in the dataset or
517      * SKIP_BODY if the end of the dataset is reached or an error occurs
518      */

519     public int doAfterBody() {
520         if(bodyContent != null) {
521             _appender.append(bodyContent.getString());
522             bodyContent.clearBody();
523         }
524
525         /*
526            this loop exists so that the table is filled out correctly up to the specified
527            or guessed table dimensions. this is a little bit of a kludge; this logic should be done
528            in doEndTag()
529          */

530         boolean haveNext = false;
531         while(!haveNext) {
532             _currentColumn++;
533
534             /* close the previous cell whose content was rendered the last time the tag body was executed */
535             closeCellTag(_appender);
536
537             /* open a new table row */
538             if(_currentColumn == _columns) {
539                 _currentRow++;
540                 _currentColumn = 0;
541                 closeRowTag(_appender);
542                 _appender.append("\n");
543             }
544
545             /* reached the end of the table as the current row is now equal to the total number of rows */
546             if(_currentRow == _rows)
547                 return SKIP_BODY;
548
549             if(_currentColumn == 0)
550                 openRowTag(_appender, _trState != null ? _trState : STATE_TR);
551
552             int itemIndex = -1;
553             if(_verticalRepeat)
554                 itemIndex = _currentColumn * _rows + _currentRow;
555             else itemIndex = _currentRow * _columns + _currentColumn;
556
557             haveNext = ensureItem(itemIndex, _dataList);
558
559             openCellTag(_appender, computeStyleIndex(_currentRow, _currentColumn)) ;
560
561             /* render empty cell and continue filling the table */
562             if(!haveNext)
563                 _htmlConstantRendering.NBSP(_appender);
564             /* open a new table cell and render the body once again. note, this exits the while loop above */
565             else return EVAL_BODY_AGAIN;
566         }
567
568         /* default is to skip the tag body */
569         return SKIP_BODY;
570     }
571
572     /**
573      * Complete rendering the tag. If no errors have occurred, the content that
574      * the tag buffered is rendered.
575      *
576      * @return EVAL_PAGE to continue evaluating the page
577      * @throws JspException if an error occurs that can not be reported on the page
578      */

579     public int doEndTag()
580             throws JspException JavaDoc {
581         if(hasErrors())
582             reportErrors();
583         else if(_valid) {
584             closeTableTag(_appender);
585             write(_sb.toString());
586         }
587
588         return EVAL_PAGE;
589     }
590
591     public void doFinally() {
592         localRelease();
593     }
594
595     public void doCatch(Throwable JavaDoc t)
596             throws Throwable JavaDoc {
597         throw t;
598     }
599
600     /**
601      * Gets the tag's data source (can be an expression).
602      * @return the data source
603      */

604     public String JavaDoc getDataSource() {
605         return "{" + _dataSource + "}";
606     }
607     
608     /**
609      * Get the index of the current iteration through the body of this tag. This
610      * data can be accessed using the expression <code>container.index</code>
611      * on an attribute of a databindable NetUI tag that is contained within the
612      * repeating body of this tag. This expression is only valid when the dataset
613      * is being rendered.
614      *
615      * @return the integer index of the current data item in the data set
616      * @see org.apache.beehive.netui.script.common.IDataAccessProvider
617      */

618     public int getCurrentIndex() {
619         return _currentIndex;
620     }
621
622     /**
623      * Get the item that is currently being rendered by this repeating tag.
624      * This can be accessed using the expression <code>expression.item</code>
625      * on an attribute of a databindable netUI tag that is contained within
626      * the repeating body of this tag. The expression is only valid when the dataset
627      * is being rendered.
628      *
629      * @return the current item in the data set
630      * @see org.apache.beehive.netui.script.common.IDataAccessProvider
631      */

632     public Object JavaDoc getCurrentItem() {
633         return _currentItem;
634     }
635
636     /**
637      * Get the metadata for the current item. This method is not supported by
638      * this tag.
639      *
640      * @throws UnsupportedOperationException this tag does not support this method from the IDataAccessProvider interface
641      * @see org.apache.beehive.netui.script.common.IDataAccessProvider
642      */

643     public Object JavaDoc getCurrentMetadata() {
644         LocalizedUnsupportedOperationException uoe =
645                 new LocalizedUnsupportedOperationException("The " + getTagName() + "does not export metadata for its iterated items.");
646         uoe.setLocalizedMessage(Bundle.getErrorString("Tags_DataAccessProvider_metadataUnsupported", new Object JavaDoc[]{getTagName()}));
647         throw uoe;
648     }
649
650     /**
651      * Get the parent IDataAccessProvider for this tag. If this tag is contained within
652      * a IDataAccessProvider, the containing IDataAccessProvider is available through the
653      * expression <code>container.container</code>. Any valid properties of the
654      * parent IDataAccessProvider can be accessed through this expression. This method
655      * will return null if there is no parent IDataAccessProvider
656      *
657      * @return a containing IDataAccessProvider if one exists, null otherwise.
658      * @see org.apache.beehive.netui.script.common.IDataAccessProvider
659      */

660     public IDataAccessProvider getProviderParent() {
661         return (IDataAccessProvider)SimpleTagSupport.findAncestorWithClass(this, IDataAccessProvider.class);
662     }
663
664     /**
665      * Reset all of the fields of this tag.
666      */

667     protected void localRelease() {
668         super.localRelease();
669
670         if(bodyContent != null)
671             bodyContent.clearBody();
672
673         _rows = DIMENSION_DEFAULT_VALUE;
674         _columns = DIMENSION_DEFAULT_VALUE;
675         _currentRow = -1;
676         _currentColumn = -1;
677         _currentIndex = -1;
678         _verticalRepeat = false;
679         _dataList = null;
680         _currentItem = null;
681         _valid = true;
682         _dataSource = null;
683
684         if(_tdState != null)
685             _tdState.clear();
686         if(_trState != null)
687             _trState.clear();
688         if(_tableState != null)
689             _tableState.clear();
690
691         _tableRenderer = null;
692         _tdRenderer = null;
693         _trRenderer = null;
694
695         _sb = null;
696         _appender = null;
697
698         if(_containerInPageContext) {
699             DataAccessProviderStack.removeDataAccessProvider(pageContext);
700             _containerInPageContext = false;
701         }
702     }
703
704     private final void guessDimensions(ArrayList JavaDoc data)
705         throws JspException JavaDoc {
706
707         if(_rows == 0 || _columns == 0)
708             registerTagError(Bundle.getString("Tags_CellRepeater_missingRowsOrColumns"), null);
709
710         if(data == null)
711             return;
712
713         int dataSize = data.size();
714         if(_rows == DIMENSION_DEFAULT_VALUE && _columns == DIMENSION_DEFAULT_VALUE) {
715             registerTagError(Bundle.getString("Tags_CellRepeater_invalidRowOrColumn"), null);
716         }
717         else if(_rows == DIMENSION_DEFAULT_VALUE) {
718             int remainder = dataSize % _columns;
719             _rows = (dataSize / _columns) + (remainder > 0 ? 1 : 0);
720             LOGGER.debug("guessed row size: " + _rows);
721         }
722         else if(_columns == DIMENSION_DEFAULT_VALUE) {
723             int remainder = dataSize % _rows;
724             _columns = (dataSize / _rows) + (remainder > 0 ? 1 : 0);
725             LOGGER.debug("guessed column size: " + _columns);
726         }
727     }
728
729     private final void openTableTag(AbstractRenderAppender appender, TableTag.State tableState) {
730         if(tableState == null)
731             tableState = STATE_TABLE;
732         _tableRenderer.doStartTag(appender, tableState);
733     }
734
735     private final void closeTableTag(AbstractRenderAppender appender) {
736         assert appender != null;
737         assert _tableRenderer != null;
738         _tableRenderer.doEndTag(appender);
739     }
740
741     private final void openRowTag(AbstractRenderAppender appender, TrTag.State trState) {
742         if(trState == null)
743             trState = STATE_TR;
744         _trRenderer.doStartTag(appender, trState);
745     }
746
747     private final void closeRowTag(AbstractRenderAppender appender) {
748         assert _trRenderer != null;
749         assert appender != null;
750         _trRenderer.doEndTag(appender);
751     }
752
753     private final void openCellTag(AbstractRenderAppender appender, int index) {
754         assert appender != null;
755         assert index >= 0;
756         assert _tdRenderer != null;
757
758         TdTag.State tdState = STATE_TD;
759         if(_cellClass != null) {
760             if(_tdState != null)
761                 _tdState.clear();
762             else _tdState = new TdTag.State();
763             if(index % 2 == 0)
764                 _tdState.styleClass = _cellClass;
765             else _tdState.styleClass = (_altCellClass != null ? _altCellClass : _cellClass);
766             tdState = _tdState;
767         }
768
769         _tdRenderer.doStartTag(appender, tdState);
770     }
771
772     private final void closeCellTag(AbstractRenderAppender appender) {
773         assert _tdRenderer != null;
774         assert appender != null;
775         _tdRenderer.doEndTag(appender);
776     }
777
778     private final int computeStyleIndex(int r, int c) {
779         return c + (r % 2);
780     }
781
782     private boolean ensureItem(int index, ArrayList JavaDoc data) {
783         LOGGER.debug("item: " + 0 + " data: " + (data == null ? "null data" :
784                      (index < data.size() ? "" + index : "index out of bounds for size " + data.size())));
785
786         if(data != null && index < data.size()) {
787             _currentItem = data.get(index);
788             _currentIndex = index;
789             return true;
790         }
791         else return false;
792     }
793
794     /**
795      * Return an <code>ArrayList</code> which represents a chain of <code>INameInterceptor</code>
796      * objects. This method by default returns <code>null</code> and should be overridden
797      * by objects that support naming.
798      * @return an <code>ArrayList</code> that will contain <code>INameInterceptor</code> objects.
799      */

800     protected List JavaDoc getNamingChain() {
801         return AbstractClassicTag.DefaultNamingChain;
802     }
803
804     /**
805      * Return the Object that is represented by the specified data source.
806      * @return Object
807      * @throws JspException
808      */

809     private Object JavaDoc evaluateDataSource()
810         throws JspException JavaDoc {
811         ExpressionHandling expr = new ExpressionHandling(this);
812         String JavaDoc dataSource = getDataSource();
813         String JavaDoc ds = expr.ensureValidExpression(dataSource, "dataSource", "DataSourceError");
814         if (ds == null)
815             return null;
816
817         Object JavaDoc o = expr.evaluateExpression(dataSource, "dataSource", pageContext);
818         return o;
819     }
820 }
821
Popular Tags