0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: *
0017: * $Header:$
0018: */
0019: package org.apache.beehive.netui.tags.databinding.datagrid;
0020:
0021: import java.util.Iterator;
0022: import java.io.IOException;
0023: import java.io.StringWriter;
0024: import javax.servlet.jsp.JspException;
0025: import javax.servlet.jsp.JspContext;
0026: import javax.servlet.jsp.tagext.SimpleTagSupport;
0027: import javax.servlet.jsp.tagext.JspFragment;
0028: import javax.servlet.http.HttpServletRequest;
0029:
0030: import org.apache.beehive.netui.databinding.datagrid.api.rendering.DataGridTagModel;
0031: import org.apache.beehive.netui.databinding.datagrid.api.rendering.StyleModel;
0032: import org.apache.beehive.netui.databinding.datagrid.api.pager.PagerModel;
0033: import org.apache.beehive.netui.databinding.datagrid.api.DataGridConfigFactory;
0034: import org.apache.beehive.netui.databinding.datagrid.api.DataGridConfig;
0035: import org.apache.beehive.netui.databinding.datagrid.api.DataGridResourceProvider;
0036: import org.apache.beehive.netui.databinding.datagrid.runtime.util.PagedDataSet;
0037: import org.apache.beehive.netui.databinding.datagrid.runtime.util.JspUtil;
0038: import org.apache.beehive.netui.databinding.datagrid.runtime.rendering.table.TableRenderer;
0039: import org.apache.beehive.netui.script.common.IDataAccessProvider;
0040: import org.apache.beehive.netui.script.common.DataAccessProviderStack;
0041: import org.apache.beehive.netui.tags.ExpressionHandling;
0042: import org.apache.beehive.netui.tags.IBehaviorConsumer;
0043: import org.apache.beehive.netui.tags.IHtmlI18n;
0044: import org.apache.beehive.netui.tags.IHtmlEvents;
0045: import org.apache.beehive.netui.tags.IHtmlCore;
0046: import org.apache.beehive.netui.tags.html.HtmlConstants;
0047: import org.apache.beehive.netui.tags.rendering.AbstractRenderAppender;
0048: import org.apache.beehive.netui.tags.rendering.StringBuilderRenderAppender;
0049: import org.apache.beehive.netui.tags.rendering.TableTag;
0050: import org.apache.beehive.netui.tags.rendering.AbstractHtmlState;
0051: import org.apache.beehive.netui.util.internal.InternalStringBuilder;
0052: import org.apache.beehive.netui.util.iterator.IteratorFactory;
0053: import org.apache.beehive.netui.util.Bundle;
0054:
0055: /**
0056: * <p>
0057: * This tag is the containing tag for all tags and markup used to render a data grid. In its simplest form, a data
0058: * grid is an HTML table containing an HTML table row for every item in a data set. The data grid also provides
0059: * functionality for rendering the following major regions:
0060: * <ul>
0061: * <li>a header -- a header contains the top-most rows in a data grid's HTML table and is rendered using
0062: * the {@link Header} tag</li>
0063: * <li>data rows -- markup rendered in the data grid for each record in the data set must be contained
0064: * in a {@link Rows} tag</li>
0065: * <li>a footer -- a footer contains the bottom-most rows in a data grid's HTML table and is rendered using the
0066: * {@link Footer} tag</li>
0067: * <li>caption -- an HTML table caption appears at the top of the table and is rendered using the
0068: * {@link Caption} tag.</li>
0069: * </ul>
0070: * In addition, a data grid can also configure and render a pager using the {@link ConfigurePager} and
0071: * {@link RenderPager} tags respectively.
0072: * </p>
0073: * <p>
0074: * Inside of the {@link Header} and {@link Rows} rendering regions, the data grid renders HTML table cells. The
0075: * data grid tag set provides a set of tags that can be used render these cells with varying content including:
0076: * <ul>
0077: * <li>HTML <th> cells -- these are generally used inside the {@link Header}</li>
0078: * <li>anchors -- these can be rendered using the {@link AnchorCell} tag</li>
0079: * <li>images -- these can be rendered using the {@link ImageCell} tag</li>
0080: * <li>image anchors-- these can be rendered using the {@link ImageAnchorCell} tag</li>
0081: * <li>HTML spans -- these can be rendered using the {@link SpanCell} tag</li>
0082: * </ul>
0083: * The {@link TemplateCell} tag can be used as a container for arbitrary content that may be included in a cell's
0084: * contents. The {@link Footer} tag's content can also use these tags.
0085: * </p>
0086: * <p>
0087: * When the data grid renders its data set, the <code>container</code> JSP EL implicit object is exposed in the
0088: * JSP's {@link JspContext} and can be referenced using the <code>${contaimer}</code> JSP EL expression. The
0089: * <i>current</i> item of data from the data set can be referenced using the <code>${container.item}</code>
0090: * expression. If the item had a <code>name</code> property, it could be referenced as
0091: * <code>${container.item.name}</code>. By default, the data grid renders a paged data set which will only
0092: * display a portion of the complete data set. The default page size is {@link PagerModel#DEFAULT_PAGE_SIZE}
0093: * and can be changed by setting the {@link ConfigurePager#setPageSize(int)} attribute.
0094: * </p>
0095: * <p>
0096: * In addition to rendering a data grid, this tag set cooperates with a set of state management services exposed
0097: * via the {@link org.apache.beehive.netui.databinding.datagrid.api.DataGridStateFactory}. These services
0098: * help to manage state related to paging, sorting, and filtering. For example, the first row displayed
0099: * in the grid's current page and the sorts for a particular column of data are can be read / written using these
0100: * state objects. The data grid will use various state information from these classes at reunder time. For example,
0101: * when rendering a paged data set, the data grid will use the
0102: * {@link org.apache.beehive.netui.databinding.datagrid.api.DataGridStateFactory} to obtain a {@link PagerModel}
0103: * which can be used to determine the current
0104: * {@link org.apache.beehive.netui.databinding.datagrid.api.pager.PagerModel#getRow()}. The grid will then
0105: * use this row value to advance the grid to the appropriate page to display.
0106: * </p>
0107: * <p>
0108: * By default, the data grid uses a configuration JavaBean which provides instances of state containers and services
0109: * that are used to maintain state and render grid markup. This config object is a subclass of
0110: * {@link DataGridConfig} and is obtained via the {@link DataGridConfigFactory}. The default implementation is
0111: * {@link org.apache.beehive.netui.databinding.datagrid.runtime.config.DefaultDataGridConfig}. Page authors
0112: * may provide their own implementations of this object and set an instance via
0113: * {@link #setDataGridConfig(org.apache.beehive.netui.databinding.datagrid.api.DataGridConfig)}. This can be
0114: * used to change default behaviors, change the appearance of the pager, and change the messages displayed
0115: * during rendering among other things.
0116: * </p>
0117: * <p>
0118: * A simple, sortable, and pageable data grid that uses a first / previous // next / last pager might be
0119: * written as:
0120: * <pre>
0121: * <netui-data:dataGrid dataSource="pageScope.zooAnimals">
0122: * <netui-data:configurePager disableDefaultPager="true" pageAction="page" pagerFormat="firstPreviousNextLast"/>
0123: * <netui-data:caption>
0124: * <netui-data:renderPager/>
0125: * <netui-data:caption>
0126: * <netui-data:header>
0127: * <netui-data:heaederCell value="Animal" sortExpression="animal"/>
0128: * <netui-data:heaederCell value="Quantity" sortExpression="quantity"/>
0129: * <netui-data:heaederCell value="Details"/>
0130: * </netui-data:header>
0131: * <netui-data:rows>
0132: * <netui-data:spanCell value="${container.item.animalName}"/>
0133: * <netui-data:spanCell value="${container.item.quantity}"/>
0134: * <netui-data:anchorCell action="details" value="Details">
0135: * <netui:parameter name="animalId" value="${container.item.animalId}"/>
0136: * </netui-data:anchorCell>
0137: * </netui-data:rows>
0138: * </netui-data:dataGrid>
0139: * </pre>
0140: * This data grid would render an HTML table with a <caption> that contains a first / previous // next / last
0141: * formated pager. The data grid would display a page with ten data rows and three columns. The header
0142: * contains the column titles with clickable sorting links for sorting by the animal name and quantity. The
0143: * body of the data grid contains three cells per row containing two HTML <span> tags and an HTML anchor
0144: * which will navigate to a Page Flow action caclled <code>details</code> when clicked.
0145: * </p>
0146: *
0147: * @jsptagref.tagdescription
0148: * <p>
0149: * This tag is the containing tag for all tags and markup used to render a data grid. In its simplest form, a data
0150: * grid is an HTML table containing an HTML table row for every item in a data set. The data grid also provides
0151: * functionality for rendering the following major regions:
0152: * <ul>
0153: * <li>a header -- a header contains the top-most rows in a data grid's HTML table and is rendered using
0154: * the {@link Header} tag</li>
0155: * <li>data rows -- markup rendered in the data grid for each record in the data set must be contained
0156: * in a {@link Rows} tag</li>
0157: * <li>a footer -- a footer contains the bottom-most rows in a data grid's HTML table and is rendered using the
0158: * {@link Footer} tag</li>
0159: * <li>caption -- an HTML table caption appears at the top of the table and is rendered using the
0160: * {@link Caption} tag.</li>
0161: * </ul>
0162: * In addition, a data grid can also configure and render a pager using the {@link ConfigurePager} and
0163: * {@link RenderPager} tags respectively.
0164: * </p>
0165: * <p>
0166: * Inside of the {@link Header} and {@link Rows} rendering regions, the data grid renders HTML table cells. The
0167: * data grid tag set provides a set of tags that can be used render these cells with varying content including:
0168: * <ul>
0169: * <li>HTML <th> cells -- these are generally used inside the {@link Header}</li>
0170: * <li>anchors -- these can be rendered using the {@link AnchorCell} tag</li>
0171: * <li>images -- these can be rendered using the {@link ImageCell} tag</li>
0172: * <li>image anchors-- these can be rendered using the {@link ImageAnchorCell} tag</li>
0173: * <li>HTML spans -- these can be rendered using the {@link SpanCell} tag</li>
0174: * </ul>
0175: * The {@link TemplateCell} tag can be used as a container for arbitrary content that may be included in a cell's
0176: * contents. The {@link Footer} tag's content can also use these tags.
0177: * </p>
0178: * <p>
0179: * When the data grid renders its data set, the <code>container</code> JSP EL implicit object is exposed in the
0180: * JSP's {@link JspContext} and can be referenced using the <code>${contaimer}</code> JSP EL expression. The
0181: * <i>current</i> item of data from the data set can be referenced using the <code>${container.item}</code>
0182: * expression. If the item had a <code>name</code> property, it could be referenced as
0183: * <code>${container.item.name}</code>. By default, the data grid renders a paged data set which will only
0184: * display a portion of the complete data set. The default page size is {@link PagerModel#DEFAULT_PAGE_SIZE}
0185: * and can be changed by setting the {@link ConfigurePager#setPageSize(int)} attribute.
0186: * </p>
0187: * <p>
0188: * In addition to rendering a data grid, this tag set cooperates with a set of state management services exposed
0189: * via the {@link org.apache.beehive.netui.databinding.datagrid.api.DataGridStateFactory}. These services
0190: * help to manage state related to paging, sorting, and filtering. For example, the first row displayed
0191: * in the grid's current page and the sorts for a particular column of data are can be read / written using these
0192: * state objects. The data grid will use various state information from these classes at reunder time. For example,
0193: * when rendering a paged data set, the data grid will use the
0194: * {@link org.apache.beehive.netui.databinding.datagrid.api.DataGridStateFactory} to obtain a {@link PagerModel}
0195: * which can be used to determine the current
0196: * {@link org.apache.beehive.netui.databinding.datagrid.api.pager.PagerModel#getRow()}. The grid will then
0197: * use this row value to advance the grid to the appropriate page to display.
0198: * </p>
0199: * <p>
0200: * By default, the data grid uses a configuration JavaBean which provides instances of state containers and services
0201: * that are used to maintain state and render grid markup. This config object is a subclass of
0202: * {@link DataGridConfig} and is obtained via the {@link DataGridConfigFactory}. The default implementation is
0203: * {@link org.apache.beehive.netui.databinding.datagrid.runtime.config.DefaultDataGridConfig}. Page authors
0204: * may provide their own implementations of this object and set an instance via
0205: * {@link #setDataGridConfig(org.apache.beehive.netui.databinding.datagrid.api.DataGridConfig)}. This can be
0206: * used to change default behaviors, change the appearance of the pager, and change the messages displayed
0207: * during rendering among other things.
0208: * </p>
0209: * <p>
0210: * A simple, sortable, and pageable data grid that uses a first / previous // next / last pager might be
0211: * written as:
0212: * <pre>
0213: * <netui-data:dataGrid dataSource="pageScope.zooAnimals">
0214: * <netui-data:configurePager disableDefaultPager="true" pageAction="page" pagerFormat="firstPreviousNextLast"/>
0215: * <netui-data:caption>
0216: * <netui-data:renderPager/>
0217: * <netui-data:caption>
0218: * <netui-data:header>
0219: * <netui-data:heaederCell value="Animal" sortExpression="animal"/>
0220: * <netui-data:heaederCell value="Quantity" sortExpression="quantity"/>
0221: * <netui-data:heaederCell value="Details"/>
0222: * </netui-data:header>
0223: * <netui-data:rows>
0224: * <netui-data:spanCell value="${container.item.animalName}"/>
0225: * <netui-data:spanCell value="${container.item.quantity}"/>
0226: * <netui-data:anchorCell action="details" value="Details">
0227: * <netui:parameter name="animalId" value="${container.item.animalId}"/>
0228: * </netui-data:anchorCell>
0229: * </netui-data:rows>
0230: * </netui-data:dataGrid>
0231: * </pre>
0232: * This data grid would render an HTML table with a <caption> that contains a first / previous // next / last
0233: * formated pager. The data grid would display a page with ten data rows and three columns. The header
0234: * contains the column titles with clickable sorting links for sorting by the animal name and quantity. The
0235: * body of the data grid contains three cells per row containing two HTML <span> tags and an HTML anchor
0236: * which will navigate to a Page Flow action caclled <code>details</code> when clicked.
0237: * </p>
0238: * @netui:tag name="dataGrid" body-content="scriptless"
0239: * description="Containing tag for tags in the data grid tag set.
0240: * Renders a pageable, sortable, and filterable HTML table containing a data set"
0241: */
0242: public class DataGrid extends AbstractDataGridHtmlTag implements
0243: IDataAccessProvider, IBehaviorConsumer, IHtmlCore, IHtmlEvents,
0244: IHtmlI18n {
0245:
0246: private static final String FACET_RESOURCE = "resource";
0247:
0248: private boolean _renderRowGroups = false;
0249: private String _name = null;
0250: private String _styleClassPrefix = null;
0251: private String _stylePolicyName = null;
0252: private String _dataSource = null;
0253: private String _resourceBundlePath = null;
0254: private DataGridConfig _dataGridConfig = null;
0255: private DataGridTagModel _dataGridTagModel = null;
0256: private TableTag.State _tableState = new TableTag.State();
0257:
0258: /**
0259: * The name of this tag; this value is used for error reporting.
0260: * @return the String name of this tag
0261: */
0262: public String getTagName() {
0263: return "DataGrid";
0264: }
0265:
0266: /**
0267: * <p>
0268: * Set the {@link DataGridConfig} instance that this tag will use to create state containers and other
0269: * data grid objects used during rendering. Custom implementations of this class can be provided
0270: * that will override the defaults set in the
0271: * {@link org.apache.beehive.netui.databinding.datagrid.runtime.config.DefaultDataGridConfig}.
0272: * </p>
0273: * @jsptagref.attributedescription
0274: * <p>
0275: * Set the {@link DataGridConfig} instance that this tag will use to create state containers and other
0276: * data grid objects used during rendering. Custom implementations of this class can be provided
0277: * that will override the defaults set in the
0278: * {@link org.apache.beehive.netui.databinding.datagrid.runtime.config.DefaultDataGridConfig}.
0279: * </p>
0280: * @jsptagref.attributesyntaxvalue <i>string_dataGridConfig</i>
0281: * @netui:attribute required="false" rtexprvalue="true"
0282: * description="The DataGridConfig instance used by the data grid to create state containers and objects for rendering"
0283: */
0284: public void setDataGridConfig(DataGridConfig dataGridConfig) {
0285: _dataGridConfig = dataGridConfig;
0286: }
0287:
0288: /**
0289: * Set the name of this data grid. The name should be a simple String that is used to uniquely identify a data
0290: * grid inside of a JSP. This value is also used to namespace state information in the URL that is scoped
0291: * to a data grid. Within a given scope in a page, the page author is responsible for ensuring that this
0292: * name is unique.
0293: * @jsptagref.attributedescription
0294: * Set the name of this data grid. The name should be a simple String that is used to uniquely identify a data
0295: * grid inside of a JSP. This value is also used to namespace state information in the URL that is scoped
0296: * to a data grid. Within a given scope in a page, the page author is responsible for ensuring that this
0297: * name is unique.
0298: * @jsptagref.attributesyntaxvalue <i>string_name</i>
0299: * @netui:attribute required="true"
0300: * description="The name for a data grid"
0301: */
0302: public void setName(String name) {
0303: _name = name;
0304: }
0305:
0306: /**
0307: * <p>
0308: * Set the data source that references a data set to be rendered by the data grid. The data source should be
0309: * a NetUI EL expression and generally looks like a JSP EL expression without the '${' and '}' characters.
0310: * For example, to reference an array of Employee objects exposed via a NetUI page input, the expression
0311: * might look like:
0312: * <pre>
0313: * <netui-data:dataGrid dataSource="pageInput.employeeArray" name="employeeGrid">
0314: * </pre>
0315: * This expression will be evaluated the data grid in order to obtain a reference to the data set.
0316: * </p>
0317: *
0318: * @jsptagref.attributedescription
0319: * <p>
0320: * Set the data source that references a data set to be rendered by the data grid. The data source should be
0321: * a NetUI EL expression and generally looks like a JSP EL expression without the '${' and '}' characters.
0322: * For example, to reference an array of Employee objects exposed via a NetUI page input, the expression
0323: * might look like:
0324: * <pre>
0325: * <netui-data:dataGrid dataSource="pageInput.employeeArray" name="employeeGrid">
0326: * </pre>
0327: * This expression will be evaluated the data grid in order to obtain a reference to the data set.
0328: * </p>
0329: * @jsptagref.attributesyntaxvalue <i>string_dataSource</i>
0330: * @netui:attribute required="true"
0331: * description="The <code>dataSource</code> attribute determines both
0332: * the source of populating data for the tag and the object to which the tag submits data."
0333: */
0334: public void setDataSource(String dataSource) {
0335: _dataSource = dataSource;
0336: }
0337:
0338: /**
0339: * <p>
0340: * Set the style class prefix used to namespace style class names rendered as attributes on HTML tags
0341: * generated by the data grid. For example, when using the default style policy without setting this
0342: * attribute, the style rendered for the generated HTML table tag will be:
0343: * <pre>
0344: * <table class="datagrid">
0345: * </pre>
0346: * With the style class prefix of <code>foo</code>, the rendered HTML style class will be:
0347: * <pre>
0348: * <table class="foo">
0349: * </pre>
0350: * </p>
0351: * @jsptagref.attributedescription
0352: * <p>
0353: * Set the style class prefix used to namespace style class names rendered as attributes on HTML tags
0354: * generated by the data grid. For example, when using the default style policy without setting this
0355: * attribute, the style rendered for the generated HTML table tag will be:
0356: * <pre>
0357: * <table class="datagrid">
0358: * </pre>
0359: * With the style class prefix of <code>foo</code>, the rendered HTML style class will be:
0360: * <pre>
0361: * <table class="foo">
0362: * </pre>
0363: * </p>
0364: * @jsptagref.attributesyntaxvalue <i>string_styleClassPrefix</i>
0365: * @netui:attribute required="false" rtexprvalue="true"
0366: * description="The style class prefix used when setting CSS style classes on HTML elements generated by the data grid."
0367: */
0368: public void setStyleClassPrefix(String styleClassPrefix) {
0369: _styleClassPrefix = styleClassPrefix;
0370: }
0371:
0372: /**
0373: * <p>
0374: * Set the resource bundle path used when getting messages from a {@link DataGridResourceProvider} during
0375: * data grid rendering. The resource bundle provided here will entirely override messages obtained from
0376: * the {@link DataGridResourceProvider} and must include all message keys that are used for rendering.
0377: * In order to replace individual messages, use the behavior available from the
0378: * {@link #setBehavior(String, Object, String)} method.
0379: * </p>
0380: * @jsptagref.attributedescription
0381: * <p>
0382: * Set the resource bundle path used when getting messages from a {@link DataGridResourceProvider} during
0383: * data grid rendering. The resource bundle provided here will entirely override messages obtained from
0384: * the {@link DataGridResourceProvider} and must include all message keys that are used for rendering.
0385: * In order to replace individual messages, use the behavior available from the
0386: * {@link #setBehavior(String, Object, String)} method.
0387: * </p>
0388: * @jsptagref.attributesyntaxvalue <i>string_resourceBundlePath</i>
0389: * @netui:attribute required="false" rtexprvalue="true"
0390: * description="A resource bundle path that can be used to replace the default strings rendered by a data grid"
0391: */
0392: public void setResourceBundlePath(String resourceBundlePath) {
0393: _resourceBundlePath = resourceBundlePath;
0394: }
0395:
0396: /**
0397: * <p>
0398: * Set the name of a CSS policy to use when rendering HTML elements in a data grid. The data grid supports the
0399: * default style policy names defined here
0400: * {@link org.apache.beehive.netui.databinding.datagrid.runtime.config.DefaultDataGridConfig#getStyleModel(String, String)}.
0401: * </p>
0402: * @jsptagref.attributedescription
0403: * <p>
0404: * Set the name of a CSS policy to use when rendering HTML elements in a data grid. The data grid supports the
0405: * default style policy names defined here
0406: * {@link org.apache.beehive.netui.databinding.datagrid.runtime.config.DefaultDataGridConfig#getStyleModel(String, String)}.
0407: * </p>
0408: * @jsptagref.attributesyntaxvalue <i>string_stylePolicy</i>
0409: * @netui:attribute required="false" rtexprvalue="true"
0410: * description="Set the name of a CSS policy used when rendering a data grid."
0411: */
0412: public void setStyleClassPolicy(String stylePolicy) {
0413: _stylePolicyName = stylePolicy;
0414: }
0415:
0416: /**
0417: * <p>
0418: * Sets a boolean that enables / disables rendering of HTML table row groups in the data grid. When
0419: * row group rendering is enabled, the data grid tags will produce the thead, tbody, and tfoot HTML tags
0420: * via the {@link Header}, {@link Rows}, and {@link Footer} tags respectively. In addition, as per the
0421: * <a href="http://www.w3.org/TR/REC-html40/struct/tables.html#h-11.2.3">HTML specification</a>, the data
0422: * grid will reorder the output of the row groups to in order to produce valid HTML. When row group rendering
0423: * is enabled and a page is using JavaScript, the data grid <b>must</b> be nested inside of a NetUI
0424: * {@link org.apache.beehive.netui.tags.javascript.ScriptContainer} in order for JavaScript rendering
0425: * to be ordered correctly. Legacy JavaScript script mode is not supported by the data grid.
0426: * </p>
0427: * @jsptagref.attributedescription
0428: * <p>
0429: * Sets a boolean that enables / disables rendering of HTML table row groups in the data grid. When
0430: * row group rendering is enabled, the data grid tags will produce the thead, tbody, and tfoot HTML tags
0431: * via the {@link Header}, {@link Rows}, and {@link Footer} tags respectively. In addition, as per the
0432: * <a href="http://www.w3.org/TR/REC-html40/struct/tables.html#h-11.2.3">HTML specification</a>, the data
0433: * grid will reorder the output of the row groups to in order to produce valid HTML. When row group rendering
0434: * is enabled and a page is using JavaScript, the data grid <b>must</b> be nested inside of a NetUI
0435: * {@link org.apache.beehive.netui.tags.javascript.ScriptContainer} in order for JavaScript rendering
0436: * to be ordered correctly. Legacy JavaScript script mode is not supported by the data grid.
0437: * </p>
0438: * @jsptagref.attributesyntaxvalue <i>boolean_renderRowGroups</i>
0439: * @netui:attribute required="false" rtexprvalue="true"
0440: * description="Set a boolean flag for enabling / disabling row group rendering"
0441: */
0442: public void setRenderRowGroups(boolean renderRowGroups) {
0443: _renderRowGroups = renderRowGroups;
0444: }
0445:
0446: /**
0447: * Sets the onClick JavaScript event for the HTML table tag.
0448: *
0449: * @param onClick the onClick event.
0450: * @jsptagref.attributedescription The onClick JavaScript event for the HTML table tag.
0451: * @jsptagref.attributesyntaxvalue <i>string_onClick</i>
0452: * @netui:attribute required="false" rtexprvalue="true" description="The onClick JavaScript event for the HTML table tag."
0453: */
0454: public void setOnClick(String onClick) {
0455: _tableState.registerAttribute(
0456: AbstractHtmlState.ATTR_JAVASCRIPT,
0457: HtmlConstants.ONCLICK, onClick);
0458: }
0459:
0460: /**
0461: * Sets the onDblClick JavaScript event for the HTML tag.
0462: *
0463: * @param onDblClick the onDblClick event.
0464: * @jsptagref.attributedescription The onDblClick JavaScript event for the HTML tag.
0465: * @jsptagref.attributesyntaxvalue <i>string_onDblClick</i>
0466: * @netui:attribute required="false" rtexprvalue="true" description="The onDblClick JavaScript event for the HTML tag."
0467: */
0468: public void setOnDblClick(String onDblClick) {
0469: _tableState.registerAttribute(
0470: AbstractHtmlState.ATTR_JAVASCRIPT,
0471: HtmlConstants.ONDBLCLICK, onDblClick);
0472: }
0473:
0474: /**
0475: * Sets the onKeyDown JavaScript event for the HTML tag.
0476: *
0477: * @param onKeyDown the onKeyDown event.
0478: * @jsptagref.attributedescription The onKeyDown JavaScript event for the HTML tag.
0479: * @jsptagref.attributesyntaxvalue <i>string_onKeyDown</i>
0480: * @netui:attribute required="false" rtexprvalue="true" description="The onKeyDown JavaScript event for the HTML tag."
0481: */
0482: public void setOnKeyDown(String onKeyDown) {
0483: _tableState.registerAttribute(
0484: AbstractHtmlState.ATTR_JAVASCRIPT,
0485: HtmlConstants.ONKEYDOWN, onKeyDown);
0486: }
0487:
0488: /**
0489: * Sets the onKeyUp JavaScript event for the HTML tag.
0490: *
0491: * @param onKeyUp the onKeyUp event.
0492: * @jsptagref.attributedescription The onKeyUp JavaScript event for the HTML tag.
0493: * @jsptagref.attributesyntaxvalue <i>string_onKeyUp</i>
0494: * @netui:attribute required="false" rtexprvalue="true" description="The onKeyUp JavaScript event for the HTML tag."
0495: */
0496: public void setOnKeyUp(String onKeyUp) {
0497: _tableState.registerAttribute(
0498: AbstractHtmlState.ATTR_JAVASCRIPT,
0499: HtmlConstants.ONKEYUP, onKeyUp);
0500: }
0501:
0502: /**
0503: * Sets the onKeyPress JavaScript event for the HTML tag.
0504: *
0505: * @param onKeyPress the onKeyPress event.
0506: * @jsptagref.attributedescription The onKeyPress JavaScript event for the HTML tag.
0507: * @jsptagref.attributesyntaxvalue <i>string_onKeyPress</i>
0508: * @netui:attribute required="false" rtexprvalue="true" description="The onKeyPress JavaScript event for the HTML tag."
0509: */
0510: public void setOnKeyPress(String onKeyPress) {
0511: _tableState.registerAttribute(
0512: AbstractHtmlState.ATTR_JAVASCRIPT,
0513: HtmlConstants.ONKEYPRESS, onKeyPress);
0514: }
0515:
0516: /**
0517: * Sets the onMouseDown JavaScript event for the HTML tag.
0518: *
0519: * @param onMouseDown the onMouseDown event.
0520: * @jsptagref.attributedescription The onMouseDown JavaScript event for the HTML tag.
0521: * @jsptagref.attributesyntaxvalue <i>string_onMouseDown</i>
0522: * @netui:attribute required="false" rtexprvalue="true" description="The onMouseDown JavaScript event for the HTML tag."
0523: */
0524: public void setOnMouseDown(String onMouseDown) {
0525: _tableState.registerAttribute(
0526: AbstractHtmlState.ATTR_JAVASCRIPT,
0527: HtmlConstants.ONMOUSEDOWN, onMouseDown);
0528: }
0529:
0530: /**
0531: * Sets the onMouseUp JavaScript event for the HTML tag.
0532: *
0533: * @param onMouseUp the onMouseUp event.
0534: * @jsptagref.attributedescription The onMouseUp JavaScript event for the HTML tag.
0535: * @jsptagref.attributesyntaxvalue <i>string_onMouseUp</i>
0536: * @netui:attribute required="false" rtexprvalue="true" description="The onMouseUp JavaScript event for the HTML tag."
0537: */
0538: public void setOnMouseUp(String onMouseUp) {
0539: _tableState.registerAttribute(
0540: AbstractHtmlState.ATTR_JAVASCRIPT,
0541: HtmlConstants.ONMOUSEUP, onMouseUp);
0542: }
0543:
0544: /**
0545: * Sets the onMouseMove JavaScript event for the HTML tag.
0546: *
0547: * @param onMouseMove the onMouseMove event.
0548: * @jsptagref.attributedescription The onMouseMove JavaScript event for the HTML tag.
0549: * @jsptagref.attributesyntaxvalue <i>string_onMouseMove</i>
0550: * @netui:attribute required="false" rtexprvalue="true" description="The onMouseMove JavaScript event for the HTML tag."
0551: */
0552: public void setOnMouseMove(String onMouseMove) {
0553: _tableState.registerAttribute(
0554: AbstractHtmlState.ATTR_JAVASCRIPT,
0555: HtmlConstants.ONMOUSEMOVE, onMouseMove);
0556: }
0557:
0558: /**
0559: * Sets the onMouseOut JavaScript event for the HTML tag.
0560: *
0561: * @param onMouseOut the onMouseOut event.
0562: * @jsptagref.attributedescription The onMouseOut JavaScript event for the HTML tag.
0563: * @jsptagref.attributesyntaxvalue <i>string_onMouseOut</i>
0564: * @netui:attribute required="false" rtexprvalue="true" description="The onMouseOut JavaScript event for the HTML tag."
0565: */
0566: public void setOnMouseOut(String onMouseOut) {
0567: _tableState.registerAttribute(
0568: AbstractHtmlState.ATTR_JAVASCRIPT,
0569: HtmlConstants.ONMOUSEOUT, onMouseOut);
0570: }
0571:
0572: /**
0573: * Sets the onMouseOver JavaScript event for the HTML tag.
0574: *
0575: * @param onMouseOver the onMouseOver event.
0576: * @jsptagref.attributedescription The onMouseOver JavaScript event for the HTML table tag..
0577: * @jsptagref.attributesyntaxvalue <i>string_onMouseOver</i>
0578: * @netui:attribute required="false" rtexprvalue="true" description="The onMouseOver JavaScript event for the HTML tag."
0579: */
0580: public void setOnMouseOver(String onMouseOver) {
0581: _tableState.registerAttribute(
0582: AbstractHtmlState.ATTR_JAVASCRIPT,
0583: HtmlConstants.ONMOUSEOVER, onMouseOver);
0584: }
0585:
0586: /**
0587: * Sets the style for the HTML table tag.
0588: *
0589: * @param style the html style.
0590: * @jsptagref.attributedescription The style for the HTML table tag.
0591: * @jsptagref.attributesyntaxvalue <i>string_style</i>
0592: * @netui:attribute required="false" rtexprvalue="true" description="The style for the HTML table tag"
0593: */
0594: public void setStyle(String style) {
0595: if ("".equals(style))
0596: return;
0597:
0598: _tableState.style = style;
0599: }
0600:
0601: /**
0602: * Sets the style class for the HTML table tag.
0603: *
0604: * @param styleClass the html style class.
0605: * @jsptagref.attributedescription The style class for the HTML table tag.
0606: * @jsptagref.attributesyntaxvalue <i>string_style_class</i>
0607: * @netui:attribute required="false" rtexprvalue="true" description="The style class for the HTML table tag."
0608: */
0609: public void setStyleClass(String styleClass) {
0610: if ("".equals(styleClass))
0611: return;
0612:
0613: _tableState.styleClass = styleClass;
0614: }
0615:
0616: /**
0617: * Sets the value of the title attribute for the HTML table tag.
0618: *
0619: * @param title the title
0620: * @jsptagref.attributedescription The title for the HTML table tag.
0621: * @jsptagref.attributesyntaxvalue <i>string_title</i>
0622: * @netui:attribute required="false" rtexprvalue="true" description="The title for the HTML table tag."
0623: */
0624: public void setTitle(String title) {
0625: _tableState.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
0626: HtmlConstants.TITLE, title);
0627: }
0628:
0629: /**
0630: * Sets the lang attribute for the HTML table tag.
0631: * @param lang the lang
0632: * @jsptagref.attributedescription The lang for the HTML table tag.
0633: * @jsptagref.attributesyntaxvalue <i>string_lang</i>
0634: * @netui:attribute required="false" rtexprvalue="true" description="The lang for the HTML table tag."
0635: */
0636: public void setLang(String lang) {
0637: _tableState.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
0638: HtmlConstants.LANG, lang);
0639: }
0640:
0641: /**
0642: * Sets the dir attribute for the HTML table tag.
0643: * @param dir the dir
0644: * @jsptagref.attributedescription The dir for the HTML table tag.
0645: * @jsptagref.attributesyntaxvalue <i>string_dir</i>
0646: * @netui:attribute required="false" rtexprvalue="true"
0647: * description="The dir for the HTML table tag."
0648: */
0649: public void setDir(String dir) {
0650: _tableState.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
0651: HtmlConstants.DIR, dir);
0652: }
0653:
0654: /**
0655: * Sets the summary attribute for the HTML table tag.
0656: * @param summary the summary
0657: * @jsptagref.attributedescription The summary for the HTML table tag.
0658: * @jsptagref.attributesyntaxvalue <i>string_summary</i>
0659: * @netui:attribute required="false" rtexprvalue="true"
0660: * description="The summary for the HTML table tag."
0661: */
0662: public void setSummary(String summary) {
0663: _tableState.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
0664: HtmlConstants.SUMMARY, summary);
0665: }
0666:
0667: /**
0668: * Sets the width attribute for the HTML table tag.
0669: * @param width the width
0670: * @jsptagref.attributedescription The width for the HTML table tag.
0671: * @jsptagref.attributesyntaxvalue <i>string_width</i>
0672: * @netui:attribute required="false" rtexprvalue="true" description="The width attribute for the HTML table tag."
0673: */
0674: public void setWidth(String width) {
0675: _tableState.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
0676: HtmlConstants.WIDTH, width);
0677: }
0678:
0679: /**
0680: * Sets the border attribute for the HTML table tag.
0681: * @param border
0682: * @jsptagref.attributedescription The border attribute for the HTML table tag.
0683: * @jsptagref.attributesyntaxvalue <i>string_dir</i>
0684: * @netui:attribute required="false" rtexprvalue="true" description="The border attribute for the HTML table tag."
0685: */
0686: public void setBorder(String border) {
0687: _tableState.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
0688: HtmlConstants.BORDER, border);
0689: }
0690:
0691: /**
0692: * Sets the frame attribute for the HTML table tag.
0693: * @param frame the frame
0694: * @jsptagref.attributedescription The frame attribute for the HTML table tag.
0695: * @jsptagref.attributesyntaxvalue <i>string_frame</i>
0696: * @netui:attribute required="false" rtexprvalue="true"
0697: * description="The frame for the HTML table tag."
0698: */
0699: public void setFrame(String frame) {
0700: _tableState.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
0701: HtmlConstants.FRAME, frame);
0702: }
0703:
0704: /**
0705: * Sets the rules attribute for the HTML table tag.
0706: * @param rules the rules
0707: * @jsptagref.attributedescription The rules attribute for the HTML table tag.
0708: * @jsptagref.attributesyntaxvalue <i>string_rules</i>
0709: * @netui:attribute required="false" rtexprvalue="true" description="The rules attribute for the HTML table tag."
0710: */
0711: public void setRules(String rules) {
0712: _tableState.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
0713: HtmlConstants.RULES, rules);
0714: }
0715:
0716: /**
0717: * Sets the cellspacing attribute for the HTML table tag.
0718: * @param cellspacing the cell spacing
0719: * @jsptagref.attributedescription The cellspacing for the HTML table tag.
0720: * @jsptagref.attributesyntaxvalue <i>string_cellspacing</i>
0721: * @netui:attribute required="false" rtexprvalue="true" description="The cellspacing for the HTML table tag."
0722: */
0723: public void setCellspacing(String cellspacing) {
0724: _tableState.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
0725: HtmlConstants.CELLSPACING, cellspacing);
0726: }
0727:
0728: /**
0729: * Sets the cellpadding attribute for the HTML table tag.
0730: * @param cellpadding the cell padding
0731: * @jsptagref.attributedescription The cellpadding for the HTML table tag.
0732: * @jsptagref.attributesyntaxvalue <i>string_cellpadding</i>
0733: * @netui:attribute required="false" rtexprvalue="true" description="The cellpadding for the HTML table tag."
0734: */
0735: public void setCellpadding(String cellpadding) {
0736: _tableState.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
0737: HtmlConstants.CELLPADDING, cellpadding);
0738: }
0739:
0740: /**
0741: * Set the name of the tagId for the HTML table tag.
0742: *
0743: * @param tagId the the name of the tagId for the table tag.
0744: * @jsptagref.attributedescription The tagId for the HTML table tag.
0745: * @jsptagref.attributesyntaxvalue <i>string_tagId</i>
0746: * @netui:attribute required="false" rtexprvalue="true"
0747: * description="String value. Sets the id (or name) attribute of the rendered HTML tag. "
0748: */
0749: public void setTagId(String tagId) throws JspException {
0750: applyTagId(_tableState, tagId);
0751: }
0752:
0753: /**
0754: * <p>
0755: * Implementation of the {@link IBehaviorConsumer} interface that extends the functionality of this
0756: * tag beyond that exposed via the JSP tag attributes. This method accepts the following facets:
0757: * <table>
0758: * <tr><td>Facet Name</td><td>Operation</td></tr>
0759: * <tr><td><code>resource</code></td><td>Adds or overrides a data grid resource key with a new value.</td></tr>
0760: * </table>
0761: * A new resource key is added in order to override a value defined in
0762: * {@link org.apache.beehive.netui.databinding.datagrid.api.rendering.IDataGridMessageKeys}. When a message
0763: * is overridden or added here, the page author is able to override a single string resource such as a
0764: * pager mesage or sort href.
0765: * </p>
0766: * @param name the name of the behavior
0767: * @param value the value of the behavior
0768: * @param facet th ebehavior's facet
0769: * @throws JspException when the behavior's facet isnot recognized
0770: */
0771: public void setBehavior(String name, Object value, String facet)
0772: throws JspException {
0773: if (facet != null && facet.equals(FACET_RESOURCE)) {
0774: _dataGridTagModel.addResourceOverride(name,
0775: (value != null ? value.toString() : null));
0776: } else {
0777: String s = Bundle.getString(
0778: "Tags_BehaviorFacetNotSupported",
0779: new Object[] { facet });
0780: throw new JspException(s);
0781: }
0782: }
0783:
0784: /**
0785: * <p>
0786: * Render a data grid. This method implements the logic used to iterate through the data grid's rendering states
0787: * defined in {@link DataGridTagModel}.
0788: * </p>
0789: * @throws JspException when an error occurs evaluating the tag's body
0790: * @throws IOException when an error occurs writing to the output strema
0791: */
0792: public void doTag() throws JspException, IOException {
0793:
0794: // ensure the dataSource is a valid expression
0795: String dataSource = getDataSource();
0796: ExpressionHandling expr = new ExpressionHandling(this );
0797: String validExpr = expr.ensureValidExpression(dataSource,
0798: "dataSource", "DataSourceError");
0799: Object ds = expr.evaluateExpression(validExpr, "dataSource",
0800: getPageContext());
0801: Iterator iterator = IteratorFactory.createIterator(ds);
0802:
0803: JspContext jspContext = getJspContext();
0804: HttpServletRequest request = JspUtil.getRequest(jspContext);
0805:
0806: if (_dataGridConfig == null)
0807: _dataGridConfig = DataGridConfigFactory.getInstance();
0808:
0809: TableRenderer tableRenderer = new TableRenderer(request);
0810: PagedDataSet dataSet = new PagedDataSet(dataSource, iterator);
0811:
0812: StyleModel styleModel = _dataGridConfig.getStyleModel(
0813: _stylePolicyName, _styleClassPrefix);
0814:
0815: DataGridResourceProvider resourceProvider = null;
0816: if (_resourceBundlePath == null)
0817: resourceProvider = _dataGridConfig
0818: .getDefaultResourceProvider();
0819: else
0820: resourceProvider = _dataGridConfig
0821: .getResourceProvider(_resourceBundlePath);
0822: resourceProvider.setLocale(JspUtil.getLocale(jspContext));
0823:
0824: _dataGridTagModel = new DataGridTagModel(_name,
0825: _dataGridConfig, jspContext);
0826: _dataGridTagModel.setDataSet(dataSet);
0827: _dataGridTagModel.setStyleModel(styleModel);
0828: _dataGridTagModel.setTableRenderer(tableRenderer);
0829: _dataGridTagModel.setResourceProvider(resourceProvider);
0830: _dataGridTagModel.setRenderRowGroups(_renderRowGroups);
0831:
0832: JspFragment fragment = getJspBody();
0833: if (fragment != null) {
0834: String javascript = null;
0835: /* render any JavaScript needed to support framework features */
0836: if (_tableState.id != null) {
0837: javascript = renderNameAndId(request, _tableState, null);
0838: }
0839:
0840: boolean addedDataAccessProvider = false;
0841: try {
0842: InternalStringBuilder builder = new InternalStringBuilder(
0843: 2048);
0844: AbstractRenderAppender appender = new StringBuilderRenderAppender(
0845: builder);
0846:
0847: /* todo: perf -- this doesn't need to happen when the data set is empty */
0848: DataAccessProviderStack.addDataAccessProvider(this ,
0849: getJspContext());
0850: DataGridUtil.putDataGridTagModel(getJspContext(),
0851: _dataGridTagModel);
0852: addedDataAccessProvider = true;
0853:
0854: StringWriter sw = new StringWriter();
0855: /*
0856: allow sub-tags to do work during START before rendering
0857: this makes it possible to have tags out of order and to
0858: have rendering work correctly
0859: */
0860: /* todo: perf -- should you be able to turn this off for perf? */
0861: fragment.invoke(sw);
0862:
0863: /* todo: this needs to move into the DataGridTagModel */
0864: PagerModel pm = _dataGridTagModel.getState()
0865: .getPagerModel();
0866: _dataGridTagModel.getDataSet().createWindow(
0867: pm.getRow(), pm.getPageSize());
0868:
0869: /* now that the model objects have been initialized, it's time to start rendering */
0870: _dataGridTagModel
0871: .changeRenderState(DataGridTagModel.RENDER_STATE_START);
0872:
0873: if (!_dataGridTagModel.isDisableDefaultPagerRendering())
0874: _dataGridTagModel.renderPager(appender);
0875:
0876: _tableState.styleClass = styleModel.getTableClass();
0877: tableRenderer.openTable(_tableState, appender);
0878:
0879: /* render the caption */
0880: _dataGridTagModel
0881: .changeRenderState(DataGridTagModel.RENDER_STATE_CAPTION);
0882: sw = new StringWriter();
0883: fragment.invoke(sw);
0884: String caption = sw.toString();
0885: if (caption != null)
0886: appender.append(caption);
0887:
0888: /* render the header */
0889: _dataGridTagModel
0890: .changeRenderState(DataGridTagModel.RENDER_STATE_HEADER);
0891: sw = new StringWriter();
0892: fragment.invoke(sw);
0893: String header = sw.toString();
0894: if (header != null)
0895: appender.append(header);
0896:
0897: /* intermediate storage for the body and footer content
0898: these are required by the HTML spec:
0899: http://www.w3.org/TR/REC-html40/struct/tables.html#h-11.2.3
0900: as when the row groups are used, they must be re-ordered so that
0901: <tfoot> preceeds <tbody>
0902: */
0903:
0904: String tbody = null;
0905: String tfoot = null;
0906:
0907: /* render the body */
0908: _dataGridTagModel
0909: .changeRenderState(DataGridTagModel.RENDER_STATE_GRID);
0910: sw = new StringWriter();
0911: fragment.invoke(sw);
0912: tbody = sw.toString();
0913:
0914: /* render the footer */
0915: _dataGridTagModel
0916: .changeRenderState(DataGridTagModel.RENDER_STATE_FOOTER);
0917: sw = new StringWriter();
0918: fragment.invoke(sw);
0919: String footer = sw.toString();
0920: String trimmed = footer.trim();
0921: if (footer != null && !trimmed.trim().equals(""))
0922: tfoot = footer;
0923:
0924: if (_dataGridTagModel.isRenderRowGroups()) {
0925: if (tfoot != null)
0926: appender.append(tfoot);
0927: appender.append(tbody);
0928: } else {
0929: appender.append(tbody);
0930: if (tfoot != null)
0931: appender.append(tfoot);
0932: }
0933:
0934: tableRenderer.closeTable(appender);
0935:
0936: if (javascript != null)
0937: appender.append(javascript);
0938:
0939: _dataGridTagModel
0940: .changeRenderState(DataGridTagModel.RENDER_STATE_END);
0941:
0942: write(builder.toString());
0943: } finally {
0944: if (addedDataAccessProvider) {
0945: DataAccessProviderStack
0946: .removeDataAccessProvider(getJspContext());
0947: DataGridUtil
0948: .removeDataGridTagModel(getJspContext());
0949: }
0950: }
0951: }
0952: }
0953:
0954: /* ===========================================================
0955: *
0956: * IDataAccessProvider implementation
0957: *
0958: * ===========================================================
0959: */
0960:
0961: /**
0962: * Get the index of the current item in the data set. This is a zero-based absolute
0963: * index into the entire data set being rendered by the data grid. This value
0964: * should only be data bound inside of the {@link Rows}.
0965: * @return the index of the current item
0966: */
0967: public int getCurrentIndex() {
0968: return _dataGridTagModel.getCurrentIndex();
0969: }
0970:
0971: /**
0972: * Get the current item in the data set. As the data grid iterates over the data set, this
0973: * value will change to provide access to the current item in the data set. This value
0974: * should only be data bound inside of the {@link Rows}.
0975: * @return the current item
0976: */
0977: public Object getCurrentItem() {
0978: return _dataGridTagModel.getCurrentItem();
0979: }
0980:
0981: /**
0982: * Get metadata for the current item. This operation is unsupported on the data grid.
0983: * @return the metadata for the current item
0984: * @throws UnsupportedOperationException as this method is unsupported
0985: */
0986: public Object getCurrentMetadata() {
0987: throw new UnsupportedOperationException(Bundle.getErrorString(
0988: "Tags_DataAccessProvider_metadataUnsupported",
0989: new Object[] { getTagName() }));
0990: }
0991:
0992: /**
0993: * Get the data source for the data grid. This value returns a NetUI EL expression which can
0994: * be evaluated by the NetUI tag API.
0995: * @return the expression
0996: */
0997: public String getDataSource() {
0998: return "{" + _dataSource + "}";
0999: }
1000:
1001: /**
1002: * Get the parent data access provider. This method requires access to the tag hierarchy and is not
1003: * usable across tag file or JSP include rendering boundaries. The result of this method is used for
1004: * evaluating expressions of the form <code>${container.container}</code> where this tag's parent
1005: * repeating tag is referenced.
1006: * @return the parent data access provider
1007: */
1008: public IDataAccessProvider getProviderParent() {
1009: /* todo: support nested data grids. this should be done via the stack of objects in the PageContext */
1010: return (IDataAccessProvider) SimpleTagSupport
1011: .findAncestorWithClass(this , IDataAccessProvider.class);
1012: }
1013: }
|