All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.myfaces.component.html.ext.AbstractHtmlDataTable Maven / Gradle / Ivy

Go to download

JSF components and utilities that can be used with any JSF implementation. This library is based on the JSF1.1 version of Tomahawk, but with minor source code and build changes to take advantage of JSF1.2 features. A JSF1.2 implementation is required to use this version of the Tomahawk library.

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.myfaces.component.html.ext;

import java.io.IOException;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.Application;
import javax.faces.component.ContextCallback;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIColumn;
import javax.faces.component.UIComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.model.DataModel;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.component.NewspaperTable;
import org.apache.myfaces.component.UserRoleAware;
import org.apache.myfaces.component.UserRoleUtils;
import org.apache.myfaces.custom.column.HtmlSimpleColumn;
import org.apache.myfaces.custom.crosstable.UIColumns;
import org.apache.myfaces.custom.sortheader.HtmlCommandSortHeader;
import org.apache.myfaces.renderkit.html.ext.HtmlTableRenderer;
import org.apache.myfaces.renderkit.html.util.TableContext;
import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
import org.apache.myfaces.shared_tomahawk.util.ClassUtils;

/**
 * The MyFacesDataTable extends the standard JSF DataTable by two
 * important features:
 * 
*
    *
  • Possiblity to save the state of the DataModel.
  • * *
  • Support for clickable sort headers (see SortHeader * component).
  • *
*
* Extended data_table that adds some additional features to the * standard data_table action: see attribute descriptions for * preserveDataModel, sortColumn, sortAscending and preserveSort. *
* Unless otherwise specified, all attributes accept static values or EL expressions. * * @JSFComponent * name = "t:dataTable" * class = "org.apache.myfaces.component.html.ext.HtmlDataTable" * tagClass = "org.apache.myfaces.generated.taglib.html.ext.HtmlDataTableTag" * @since 1.1.7 * @author Thomas Spiegl (latest modification by $Author: lu4242 $) * @author Manfred Geiler * @version $Revision: 986177 $ $Date: 2010-08-16 22:20:38 -0500 (Lun, 16 Ago 2010) $ */ public abstract class AbstractHtmlDataTable extends HtmlDataTableHack implements UserRoleAware, NewspaperTable { private static final Log log = LogFactory.getLog(AbstractHtmlDataTable.class); private static final int PROCESS_DECODES = 1; private static final int PROCESS_VALIDATORS = 2; private static final int PROCESS_UPDATES = 3; private static final boolean DEFAULT_SORTASCENDING = true; private static final boolean DEFAULT_SORTABLE = false; private static final boolean DEFAULT_EMBEDDED = false; private static final boolean DEFAULT_DETAILSTAMP_EXPANDED = false; private static final Class OBJECT_ARRAY_CLASS = (new Object[0]).getClass(); private static final Integer DEFAULT_NEWSPAPER_COLUMNS = new Integer(1); private static final String DEFAULT_NEWSPAPER_ORIENTATION = "vertical"; private static final String DEFAULT_DETAILSTAMP_LOCATION = "after"; /** * the property names */ public static final String NEWSPAPER_COLUMNS_PROPERTY = "newspaperColumns"; public static final String SPACER_FACET_NAME = "spacer"; public static final String NEWSPAPER_ORIENTATION_PROPERTY = "newspaperOrientation"; public static final String DETAIL_STAMP_FACET_NAME = "detailStamp"; private _SerializableDataModel _preservedDataModel; private String _forceIdIndexFormula = null; private String _sortColumn = null; private Boolean _sortAscending = null; private String _sortProperty = null; private String _rowStyleClass = null; private String _rowStyle = null; private String _varDetailToggler = null; private int _sortColumnIndex = -1; private boolean _isValidChildren = true; private Map _expandedNodes = new HashMap(); //private Map _detailRowStates = new HashMap(); private TableContext _tableContext = null; public TableContext getTableContext() { if (_tableContext == null) { _tableContext = new TableContext(); } return _tableContext; } public void setDetailStamp(UIComponent facet) { getFacets().put(DETAIL_STAMP_FACET_NAME, facet); } /** * This facet renders an additional row after or before (according * to detailStampLocation value) the current row, usually containing * additional information of the related row. It is toggled usually * using varDetailToggle variable and the method toggleDetail(). * * @JSFFacet name="detailStamp" */ public UIComponent getDetailStamp() { return (UIComponent) getFacets().get(DETAIL_STAMP_FACET_NAME); } public String getClientId(FacesContext context) { String standardClientId = super.getClientId(context); int rowIndex = getRowIndex(); if (rowIndex == -1) { return standardClientId; } String forcedIdIndex = getForceIdIndexFormula(); if (forcedIdIndex == null || forcedIdIndex.length() == 0) return standardClientId; // Trick : Remove the last part starting with NamingContainer.SEPARATOR_CHAR that contains the rowIndex. // It would be best to not resort to String manipulation, // but we can't get super.super.getClientId() :-( int indexLast_ = standardClientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR); if (indexLast_ == -1) { log.info("Could not parse super.getClientId. forcedIdIndex will contain the rowIndex."); return standardClientId + NamingContainer.SEPARATOR_CHAR + forcedIdIndex; } //noinspection UnnecessaryLocalVariable String parsedForcedClientId = standardClientId.substring(0, indexLast_ + 1) + forcedIdIndex; return parsedForcedClientId; } public UIComponent findComponent(String expr) { if (expr.length() > 0 && Character.isDigit(expr.charAt(0))) { int separatorIndex = expr.indexOf(NamingContainer.SEPARATOR_CHAR); String rowIndexStr = expr; String remainingPart = null; if (separatorIndex != -1) { rowIndexStr = expr.substring(0, separatorIndex); remainingPart = expr.substring(separatorIndex + 1); } int rowIndex = Integer.valueOf(rowIndexStr).intValue(); if (remainingPart == null) { log.error("Wrong syntax of expression : " + expr + " rowIndex was provided, but no component name."); return null; } UIComponent comp = super.findComponent(remainingPart); if (comp == null) return null; //noinspection UnnecessaryLocalVariable UIComponentPerspective perspective = new UIComponentPerspective(this, comp, rowIndex); return perspective; } else { return super.findComponent(expr); } } @Override public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback) throws FacesException { if (context == null || clientId == null || callback == null) { throw new NullPointerException(); } final String baseClientId = getClientId(context); // searching for this component? boolean returnValue = baseClientId.equals(clientId); if (returnValue) { try { callback.invokeContextCallback(context, this); return true; } catch (Exception e) { throw new FacesException(e); } } // Now Look throught facets on this UIComponent for (Iterator it = this.getFacets().values().iterator(); !returnValue && it.hasNext();) { returnValue = it.next().invokeOnComponent(context, clientId, callback); } if (returnValue) { return returnValue; } // is the component an inner component? if (clientId.startsWith(baseClientId)) { // Check if the clientId for the component, which we // are looking for, has a rowIndex attached char separator = UINamingContainer.SEPARATOR_CHAR; ValueExpression rowKeyVE = getValueExpression("rowKey"); boolean rowKeyFound = false; if (rowKeyVE != null) { int oldRow = this.getRowIndex(); try { // iterate over the rows int rowsToProcess = getRows(); // if getRows() returns 0, all rows have to be processed if (rowsToProcess == 0) { rowsToProcess = getRowCount(); } int rowIndex = getFirst(); for (int rowsProcessed = 0; rowsProcessed < rowsToProcess; rowsProcessed++, rowIndex++) { setRowIndex(rowIndex); if (!isRowAvailable()) { break; } if (clientId.startsWith(getContainerClientId(context))) { rowKeyFound = true; break; } } if (rowKeyFound) { returnValue = invokeOnComponentTraverseRow(context, clientId, callback); } } finally { this.setRowIndex(oldRow); } } if (rowKeyVE == null && clientId.matches(baseClientId + separator+"[0-9]+"+separator+".*")) { String subId = clientId.substring(baseClientId.length() + 1); String clientRow = subId.substring(0, subId.indexOf(separator)); //Now we save the current position int oldRow = this.getRowIndex(); // try-finally --> make sure, that the old row index is restored try { //The conversion is safe, because its already checked on the //regular expresion this.setRowIndex(Integer.parseInt(clientRow)); // check, if the row is available if (!isRowAvailable()) { return false; } returnValue = invokeOnComponentTraverseRow(context, clientId, callback); } finally { //Restore the old position. Doing this prevent //side effects. this.setRowIndex(oldRow); } } else { // MYFACES-2370: search the component in the childrens' facets too. // We have to check the childrens' facets here, because in MyFaces // the rowIndex is not attached to the clientId for the children of // facets of the UIColumns. However, in RI the rowIndex is // attached to the clientId of UIColumns' Facets' children. for (Iterator itChildren = this.getChildren().iterator(); !returnValue && itChildren.hasNext();) { UIComponent child = itChildren.next(); // This is the only part different to UIData.invokeOnComponent. Since we have // an auto wrapping on columns feature, it is necessary to check columns ids // without row for invokeOnComponent, but do not traverse all elements, so // save/restore algorithm could be able to remove / add them. if (child instanceof UIColumn && clientId.equals(child.getClientId(context))) { try { callback.invokeContextCallback(context, child); } catch (Exception e) { throw new FacesException(e); } returnValue = true; } // process the child's facets for (Iterator itChildFacets = child.getFacets().values().iterator(); !returnValue && itChildFacets.hasNext();) { //recursive call to find the component returnValue = itChildFacets.next().invokeOnComponent(context, clientId, callback); } } } } return returnValue; } private boolean invokeOnComponentTraverseRow(FacesContext context, String clientId, ContextCallback callback) { boolean returnValue = false; for (Iterator it1 = getChildren().iterator(); !returnValue && it1.hasNext();) { //recursive call to find the component returnValue = it1.next().invokeOnComponent(context, clientId, callback); } if (!returnValue) { UIComponent detailStampFacet = getFacet(DETAIL_STAMP_FACET_NAME); if (detailStampFacet != null) { returnValue = detailStampFacet.invokeOnComponent(context, clientId, callback); } } return returnValue; } public void setRowIndex(int rowIndex) { //FacesContext facesContext = FacesContext.getCurrentInstance(); if (rowIndex < -1) { throw new IllegalArgumentException("rowIndex is less than -1"); } //UIComponent facet = getFacet(HtmlTableRenderer.DETAIL_STAMP_FACET_NAME); /*Just for obtaining an iterator which must be passed to saveDescendantComponentStates()*/ //Set set = new HashSet(); //set.add(facet); //if (getRowIndex() != -1 && facet != null) //{ // _detailRowStates.put(getClientId(facesContext), saveDescendantComponentStates(set.iterator(), false)); //} String rowIndexVar = getRowIndexVar(); String rowCountVar = getRowCountVar(); String previousRowDataVar = getPreviousRowDataVar(); if (rowIndexVar != null || rowCountVar != null || previousRowDataVar != null) { Map requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap(); if (previousRowDataVar != null && rowIndex >= 0) //we only need to provide the previousRowDataVar for a valid rowIndex { if (isRowAvailable()) { //previous row is available requestMap.put(previousRowDataVar, getRowData()); } else { //no previous row available requestMap.put(previousRowDataVar, null); } } super.setRowIndex(rowIndex); if (rowIndex >= 0) { //regular row index, update request scope variables if (rowIndexVar != null) { requestMap.put(rowIndexVar, new Integer(rowIndex)); } if (rowCountVar != null) { requestMap.put(rowCountVar, new Integer(getRowCount())); } } else { //rowIndex == -1 means end of loop --> remove request scope variables if (rowIndexVar != null) { requestMap.remove(rowIndexVar); } if (rowCountVar != null) { requestMap.remove(rowCountVar); } if (previousRowDataVar != null) { requestMap.remove(previousRowDataVar); } } } else { // no extended var attributes defined, no special treatment super.setRowIndex(rowIndex); } //if (rowIndex != -1 && facet != null) //{ // Object rowState = _detailRowStates.get(getClientId(facesContext)); // restoreDescendantComponentStates(set.iterator(), // rowState, false); //} if (_varDetailToggler != null) { Map requestMap = getFacesContext().getExternalContext().getRequestMap(); requestMap.put(_varDetailToggler, this); } } protected Object saveDescendantComponentStates() { if (!getFacets().isEmpty()) { UIComponent detailStampFacet = getFacet(DETAIL_STAMP_FACET_NAME); if (detailStampFacet != null) { return saveDescendantComponentStates(new _DetailStampFacetAndChildrenIterator(detailStampFacet, getChildren()), false); } } return super.saveDescendantComponentStates(); } protected void restoreDescendantComponentStates(Object state) { if (!getFacets().isEmpty()) { UIComponent detailStampFacet = getFacet(DETAIL_STAMP_FACET_NAME); if (detailStampFacet != null) { restoreDescendantComponentStates(new _DetailStampFacetAndChildrenIterator(detailStampFacet, getChildren()), state, false); return; } } super.restoreDescendantComponentStates(state); } public void processDecodes(FacesContext context) { if (!isRendered()) { return; } // We must remove and then replace the facet so that // it is not processed by default facet handling code // //Object facet = getFacets().remove(HtmlTableRenderer.DETAIL_STAMP_FACET_NAME); //super.processDecodes(context); //if ( facet != null ) getFacets().put(HtmlTableRenderer.DETAIL_STAMP_FACET_NAME, (UIComponent)facet); setRowIndex(-1); processFacets(context, PROCESS_DECODES); processColumnFacets(context, PROCESS_DECODES); processColumnChildren(context, PROCESS_DECODES); setRowIndex(-1); try { decode(context); } catch (RuntimeException e) { context.renderResponse(); throw e; } setRowIndex(-1); processColumns(context, PROCESS_DECODES); setRowIndex(-1); processDetails(context, PROCESS_DECODES); setRowIndex(-1); } private void processFacets(FacesContext context, int processAction) { for (Iterator it = getFacets().entrySet().iterator(); it.hasNext(); ) { Map.Entry entry = (Map.Entry) it.next(); if (!DETAIL_STAMP_FACET_NAME.equals((String)entry.getKey())) { process(context, (UIComponent) entry.getValue(), processAction); } } } /** * Invoke the specified phase on all facets of all UIColumn children of this component. Note that no methods are * called on the UIColumn child objects themselves. * * @param context * is the current faces context. * @param processAction * specifies a JSF phase: decode, validate or update. */ private void processColumnFacets(FacesContext context, int processAction) { for (Iterator childIter = getChildren().iterator(); childIter.hasNext();) { UIComponent child = (UIComponent) childIter.next(); if (child instanceof UIColumn) { if (!child.isRendered()) { //Column is not visible continue; } for (Iterator facetsIter = child.getFacets().values() .iterator(); facetsIter.hasNext();) { UIComponent facet = (UIComponent) facetsIter.next(); process(context, facet, processAction); } } } } /** * Invoke the specified phase on all non-facet children of all UIColumn children of this component. Note that no * methods are called on the UIColumn child objects themselves. * * @param context * is the current faces context. * @param processAction * specifies a JSF phase: decode, validate or update. */ private void processColumnChildren(FacesContext context, int processAction) { int first = getFirst(); int rows = getRows(); int last; if (rows == 0) { last = getRowCount(); } else { last = first + rows; } for (int rowIndex = first; last==-1 || rowIndex < last; rowIndex++) { setRowIndex(rowIndex); //scrolled past the last row if (!isRowAvailable()) break; for (Iterator it = getChildren().iterator(); it.hasNext();) { UIComponent child = (UIComponent) it.next(); if (child instanceof UIColumn) { if (!child.isRendered()) { //Column is not visible continue; } for (Iterator columnChildIter = child.getChildren() .iterator(); columnChildIter.hasNext();) { UIComponent columnChild = (UIComponent) columnChildIter .next(); process(context, columnChild, processAction); } } } } } /** * @param context * @param processAction */ private void processDetails(FacesContext context, int processAction) { UIComponent facet = getFacet(HtmlTableRenderer.DETAIL_STAMP_FACET_NAME); if (facet != null) { int first = getFirst(); int rows = getRows(); int last; if (rows == 0) { last = getRowCount(); } else { last = first + rows; } for (int rowIndex = first; last == -1 || rowIndex < last; rowIndex++) { setRowIndex(rowIndex); //scrolled past the last row if (!isRowAvailable()) { break; } if (!isCurrentDetailExpanded()) { continue; } // If we are in the decode phase, the values restored into our // facet in setRowIndex() may be incorrect. This will happen // if some input fields are rendered in some rows, but not // rendered in others. In this case the input field components // will still contain the _submittedValue from the previous row // that had that input field and _submittedValue will not be set to // null by the process() method if there was no value submitted. // Thus, an invalid component state for that row will be saved in // _detailRowStates. The validation phase will not put a null into // _sumbittedValue either, b/c the component is not rendered, so // validation code doesn't run. This erroneous value will propagate all the way // to the render phase, and result in all rows on the current page being // rendered with the "stuck" _submittedValue, rather than evaluating the // value to render for every row. // // We can fix this by initializing _submittedValue of all input fields in the facet // to null before calling the process() method below during the decode phase. // if (PROCESS_DECODES == processAction) { resetAllSubmittedValues(facet); } process(context, facet, processAction); // This code comes from TOMAHAWK-493, but really the problem was caused by // TOMAHAWK-1534, by a bad comparison of rowIndex. The solution proposed is override // the default iterator for save/restore on HtmlDataTableHack.setRowIndex(), to // include the detailStamp. In this way, we'll be sure that the state is correctly // saved and the component clientId is reset for all components that requires it //if ( rowIndex == (last - 1) ) //{ // Set set = new HashSet(); // set.add(facet); // _detailRowStates.put( // getClientId(FacesContext.getCurrentInstance()), // saveDescendantComponentStates(set.iterator(),false)); //} } } } private void resetAllSubmittedValues(UIComponent component) { if (component instanceof EditableValueHolder) { ((EditableValueHolder) component).setSubmittedValue(null); } for (Iterator it = component.getFacetsAndChildren(); it.hasNext();) { resetAllSubmittedValues((UIComponent) it.next()); } } /** * @param context * @param processAction */ private void processColumns(FacesContext context, int processAction) { for (Iterator it = getChildren().iterator(); it.hasNext();) { UIComponent child = (UIComponent) it.next(); if (child instanceof UIColumns) { process(context, child, processAction); } } } private void process(FacesContext context, UIComponent component, int processAction) { switch (processAction) { case PROCESS_DECODES: component.processDecodes(context); break; case PROCESS_VALIDATORS: component.processValidators(context); break; case PROCESS_UPDATES: component.processUpdates(context); break; } } public void processValidators(FacesContext context) { if (!isRendered()) { return; } // We must remove and then replace the facet so that // it is not processed by default facet handling code // //Object facet = getFacets().remove(HtmlTableRenderer.DETAIL_STAMP_FACET_NAME); //super.processValidators(context); //if ( facet != null ) getFacets().put(HtmlTableRenderer.DETAIL_STAMP_FACET_NAME,(UIComponent) facet); setRowIndex(-1); processFacets(context, PROCESS_VALIDATORS); processColumnFacets(context, PROCESS_VALIDATORS); processColumnChildren(context, PROCESS_VALIDATORS); setRowIndex(-1); processColumns(context, PROCESS_VALIDATORS); setRowIndex(-1); processDetails(context, PROCESS_VALIDATORS); setRowIndex(-1); if (context.getRenderResponse()) { _isValidChildren = false; } } public void processUpdates(FacesContext context) { if (!isRendered()) { return; } // We must remove and then replace the facet so that // it is not processed by default facet handling code // //Object facet = getFacets().remove(HtmlTableRenderer.DETAIL_STAMP_FACET_NAME); //super.processUpdates(context); //if ( facet != null ) getFacets().put(HtmlTableRenderer.DETAIL_STAMP_FACET_NAME,(UIComponent) facet); setRowIndex(-1); processFacets(context, PROCESS_UPDATES); processColumnFacets(context, PROCESS_UPDATES); processColumnChildren(context, PROCESS_UPDATES); setRowIndex(-1); processColumns(context, PROCESS_UPDATES); setRowIndex(-1); processDetails(context, PROCESS_UPDATES); setRowIndex(-1); if (isPreserveDataModel()) { updateModelFromPreservedDataModel(context); } if (context.getRenderResponse()) { _isValidChildren = false; } } private void updateModelFromPreservedDataModel(FacesContext context) { ValueBinding vb = getValueBinding("value"); if (vb != null && !vb.isReadOnly(context)) { _SerializableDataModel dm = (_SerializableDataModel) getDataModel(); Class type = (getValueType() == null) ? vb.getType(context) : ClassUtils.simpleClassForName(getValueType()); Class dmType = dm.getClass(); if (DataModel.class.isAssignableFrom(type)) { vb.setValue(context, dm); } else if (List.class.isAssignableFrom(type) || _SerializableListDataModel.class.isAssignableFrom(dmType)) { vb.setValue(context, dm.getWrappedData()); } else if (OBJECT_ARRAY_CLASS.isAssignableFrom(type)) { List lst = (List) dm.getWrappedData(); vb.setValue(context, lst.toArray(new Object[lst.size()])); } else if (ResultSet.class.isAssignableFrom(type)) { throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException"); } else { //Assume scalar data model List lst = (List) dm.getWrappedData(); if (lst!= null && lst.size() > 0) { vb.setValue(context, lst.get(0)); } else { vb.setValue(context, null); } } } _preservedDataModel = null; } public void encodeBegin(FacesContext context) throws IOException { if (!isRendered()) return; if (_isValidChildren && !hasErrorMessages(context)) { _preservedDataModel = null; } for (Iterator iter = getChildren().iterator(); iter.hasNext();) { UIComponent component = (UIComponent) iter.next(); if (component instanceof UIColumns) { // Merge the columns from the tomahawk dynamic component // into this object. ((UIColumns) component).encodeTableBegin(context); } } //replace facet header content component of the columns, with a new command sort header component //if sortable=true, replace it for all, if not just for the columns marked as sortable for (Iterator iter = getChildren().iterator(); iter.hasNext();) { UIComponent component = (UIComponent) iter.next(); if (component instanceof UIColumn) { UIColumn aColumn = (UIColumn) component; UIComponent headerFacet = aColumn.getHeader(); boolean replaceHeaderFacets = isSortable(); //if the table is sortable, all //header facets can be changed if needed String columnName = null; String propertyName = null; boolean defaultSorted = false; if (aColumn instanceof HtmlSimpleColumn) { HtmlSimpleColumn asColumn = (HtmlSimpleColumn) aColumn; propertyName = asColumn.getSortPropertyName(); defaultSorted = asColumn.isDefaultSorted(); if (asColumn.isSortable()) replaceHeaderFacets = true; } //replace header facet with a sortable header component if needed if (replaceHeaderFacets && isSortHeaderNeeded(aColumn, headerFacet)) { propertyName = propertyName != null ? propertyName : getSortPropertyFromEL(aColumn); if (propertyName == null) log.warn("Couldn't determine sort property for column [" + aColumn.getId() + "]."); if (headerFacet != null) { HtmlCommandSortHeader sortHeader = createSortHeaderComponent(context, aColumn, headerFacet, propertyName); columnName = sortHeader.getColumnName(); aColumn.setHeader(sortHeader); sortHeader.setParent(aColumn); } } else if (headerFacet instanceof HtmlCommandSortHeader) { //command sort headers are already in place, just store the column name and sort property name HtmlCommandSortHeader sortHeader = (HtmlCommandSortHeader) headerFacet; columnName = sortHeader.getColumnName(); propertyName = sortHeader.getPropertyName(); //if the command sort header component doesn't specify a sort property, determine it if (propertyName == null) { propertyName = getSortPropertyFromEL(aColumn); sortHeader.setPropertyName(propertyName); } if (propertyName == null) log.warn("Couldn't determine sort property for column [" + aColumn.getId() + "]."); } //make the column marked as default sorted be the current sorted column if (defaultSorted && getSortColumn() == null) { setSortColumn(columnName); setSortProperty(propertyName); } } } // Now invoke the superclass encodeBegin, which will eventually // execute the encodeBegin for the associated renderer. super.encodeBegin(context); } /** * */ protected boolean isSortHeaderNeeded(UIColumn parentColumn, UIComponent headerFacet) { return !(headerFacet instanceof HtmlCommandSortHeader); } /** * */ protected HtmlCommandSortHeader createSortHeaderComponent(FacesContext context, UIColumn parentColumn, UIComponent initialHeaderFacet, String propertyName) { Application application = context.getApplication(); HtmlCommandSortHeader sortHeader = (HtmlCommandSortHeader) application.createComponent(HtmlCommandSortHeader.COMPONENT_TYPE); String id = context.getViewRoot().createUniqueId(); sortHeader.setId(id); sortHeader.setColumnName(id); sortHeader.setPropertyName(propertyName); sortHeader.setArrow(true); sortHeader.setImmediate(true); //needed to work when dataScroller is present sortHeader.getChildren().add(initialHeaderFacet); initialHeaderFacet.setParent(sortHeader); return sortHeader; } /** * */ protected String getSortPropertyFromEL(UIComponent component) { if (getVar() == null) { log.warn("There is no 'var' specified on the dataTable, sort properties cannot be determined automaticaly."); return null; } for (Iterator iter = component.getChildren().iterator(); iter.hasNext();) { UIComponent aChild = (UIComponent) iter.next(); if (aChild.isRendered()) { ValueBinding vb = aChild.getValueBinding("value"); if (vb != null) { String expressionString = vb.getExpressionString(); int varIndex = expressionString.indexOf(getVar() + "."); if (varIndex != -1) { int varEndIndex = varIndex + getVar().length(); String tempProp = expressionString.substring(varEndIndex + 1, expressionString.length()); StringTokenizer tokenizer = new StringTokenizer(tempProp, " +[]{}-/*|?:&<>!=()%"); if (tokenizer.hasMoreTokens()) return tokenizer.nextToken(); } } else { String sortProperty = getSortPropertyFromEL(aChild); if (sortProperty != null) return sortProperty; } } } return null; } /** * @return the index coresponding to the given column name. */ protected int columnNameToIndex(String columnName) { int index = 0; for (Iterator iter = getChildren().iterator(); iter.hasNext();) { UIComponent aChild = (UIComponent) iter.next(); if (aChild instanceof UIColumn) { UIComponent headerFacet = ((UIColumn) aChild).getHeader(); if (headerFacet != null && headerFacet instanceof HtmlCommandSortHeader) { HtmlCommandSortHeader sortHeader = (HtmlCommandSortHeader) headerFacet; if (columnName != null && columnName.equals(sortHeader.getColumnName())) return index; } } index += 1; } return -1; } /** * @see javax.faces.component.UIData#encodeEnd(javax.faces.context.FacesContext) */ public void encodeEnd(FacesContext context) throws IOException { super.encodeEnd(context); for (Iterator iter = getChildren().iterator(); iter.hasNext();) { UIComponent component = (UIComponent) iter.next(); if (component instanceof UIColumns) { ((UIColumns) component).encodeTableEnd(context); } } } /** * The index of the first row to be displayed, where 0 is the first row. * * @JSFProperty */ public int getFirst() { if (_preservedDataModel != null) { //Rather get the currently restored DataModel attribute return _preservedDataModel.getFirst(); } else { return super.getFirst(); } } public void setFirst(int first) { if (_preservedDataModel != null) { //Also change the currently restored DataModel attribute _preservedDataModel.setFirst(first); } super.setFirst(first); } /** * The number of rows to be displayed. Specify zero for all remaining rows in the table. * * @JSFProperty */ public int getRows() { if (_preservedDataModel != null) { //Rather get the currently restored DataModel attribute return _preservedDataModel.getRows(); } else { return super.getRows(); } } public void setRows(int rows) { if (_preservedDataModel != null) { //Also change the currently restored DataModel attribute _preservedDataModel.setRows(rows); } super.setRows(rows); } public Object saveState(FacesContext context) { boolean preserveSort = isPreserveSort(); Object[] values = new Object[15]; values[0] = super.saveState(context); values[1] = _preserveDataModel; if (isPreserveDataModel()) { _preservedDataModel = getSerializableDataModel(); values[2] = saveAttachedState(context, _preservedDataModel); } else { values[2] = null; } values[3] = _preserveSort; values[4] = _forceIdIndexFormula; values[5] = _sortColumn; values[6] = _sortAscending; values[7] = _sortProperty; values[8] = _rowStyleClass; values[9] = _rowStyle; values[10] = preserveSort ? getSortColumn() : null; values[11] = preserveSort ? Boolean.valueOf(isSortAscending()) : null; values[12] = _varDetailToggler; values[13] = _expandedNodes; values[14] = new Integer(_sortColumnIndex); return values; } /** * @see org.apache.myfaces.component.html.ext.HtmlDataTableHack#getDataModel() */ protected DataModel getDataModel() { if (_preservedDataModel != null) { setDataModel(_preservedDataModel); _preservedDataModel = null; } return super.getDataModel(); } /** * @see org.apache.myfaces.component.html.ext.HtmlDataTableHack#createDataModel() */ protected DataModel createDataModel() { DataModel dataModel = super.createDataModel(); boolean isSortable = isSortable(); if (!(dataModel instanceof SortableModel)) { //if sortable=true make each column sortable //if sortable=false, check to see if at least one column sortable case in which //the current model needs to be wrapped by a sortable one. for (Iterator iter = getChildren().iterator(); iter.hasNext();) { UIComponent component = (UIComponent) iter.next(); if (component instanceof HtmlSimpleColumn) { HtmlSimpleColumn aColumn = (HtmlSimpleColumn) component; if (isSortable()) aColumn.setSortable(true); if (aColumn.isSortable()) isSortable = true; if (aColumn.isDefaultSorted() && getSortColumn() == null) setSortProperty(aColumn.getSortPropertyName()); } } if (isSortable) dataModel = new SortableModel(dataModel); } if (isSortable && getSortProperty() != null) { SortCriterion criterion = new SortCriterion(getSortProperty(), isSortAscending()); List criteria = new ArrayList(); criteria.add(criterion); ((SortableModel) dataModel).setSortCriteria(criteria); } return dataModel; } public void restoreState(FacesContext context, Object state) { Object[] values = (Object[]) state; super.restoreState(context, values[0]); _preserveDataModel = (Boolean) values[1]; if (isPreserveDataModel()) { _preservedDataModel = (_SerializableDataModel) restoreAttachedState(context, values[2]); } else { _preservedDataModel = null; } _preserveSort = (Boolean) values[3]; _forceIdIndexFormula = (String) values[4]; _sortColumn = (String) values[5]; _sortAscending = (Boolean) values[6]; _sortProperty = (String) values[7]; _rowStyleClass = (String) values[8]; _rowStyle = (String) values[9]; if (isPreserveSort()) { String sortColumn = (String) values[10]; Boolean sortAscending = (Boolean) values[11]; if (sortColumn != null && sortAscending != null) { ValueBinding vb = getValueBinding("sortColumn"); if (vb != null && !vb.isReadOnly(context)) { vb.setValue(context, sortColumn); } vb = getValueBinding("sortAscending"); if (vb != null && !vb.isReadOnly(context)) { vb.setValue(context, sortAscending); } } } _varDetailToggler = (String) values[12]; _expandedNodes = (Map) values[13]; _sortColumnIndex = values[14] != null ? ((Integer) values[14]).intValue() : -1; } public _SerializableDataModel getSerializableDataModel() { DataModel dm = getDataModel(); if (dm instanceof _SerializableDataModel) { return (_SerializableDataModel) dm; } return createSerializableDataModel(); } /** * @return _SerializableDataModel */ private _SerializableDataModel createSerializableDataModel() { Object value = getValue(); if (value == null) { return null; } else if (value instanceof DataModel) { return new _SerializableDataModel(getFirst(), getRows(), (DataModel) value); } else if (value instanceof List) { return new _SerializableListDataModel(getFirst(), getRows(), (List) value); } // accept a Collection is not supported in the Spec else if (value instanceof Collection) { return new _SerializableListDataModel(getFirst(), getRows(), new ArrayList((Collection) value)); } else if (OBJECT_ARRAY_CLASS.isAssignableFrom(value.getClass())) { return new _SerializableArrayDataModel(getFirst(), getRows(), (Object[]) value); } else if (value instanceof ResultSet) { return new _SerializableResultSetDataModel(getFirst(), getRows(), (ResultSet) value); } else if (value instanceof javax.servlet.jsp.jstl.sql.Result) { return new _SerializableResultDataModel(getFirst(), getRows(), (javax.servlet.jsp.jstl.sql.Result) value); } else { return new _SerializableScalarDataModel(getFirst(), getRows(), value); } } public boolean isRendered() { if (!UserRoleUtils.isVisibleOnUserRole(this)) return false; return super.isRendered(); } public void setForceIdIndexFormula(String forceIdIndexFormula) { _forceIdIndexFormula = forceIdIndexFormula; ValueBinding vb = getValueBinding("forceIdIndexFormula"); if (vb != null) { vb.setValue(getFacesContext(), _forceIdIndexFormula); _forceIdIndexFormula = null; } } /** * A formula that overrides the default row index in the * construction of table's body components. * * Example : #{myRowVar.key} Warning, the EL should * evaluate to a unique value for each row ! * * @JSFProperty */ public String getForceIdIndexFormula() { if (_forceIdIndexFormula != null) return _forceIdIndexFormula; ValueBinding vb = getValueBinding("forceIdIndexFormula"); if (vb == null) return null; Object eval = vb.getValue(getFacesContext()); return eval == null ? null : eval.toString(); } /** * Specify what column the data should be sorted on. *

* Note that calling this method immediately stores the value * via any value-binding with name "sortColumn". This is done because * this method is called by the HtmlCommandSortHeader component when * the user has clicked on a column's sort header. In this case, the * the model getter method mapped for name "value" needs to read this * value in able to return the data in the desired order - but the * HtmlCommandSortHeader component is usually "immediate" in order to * avoid validating the enclosing form. Yes, this is rather hacky - * but it works. */ public void setSortColumn(String sortColumn) { _sortColumn = sortColumn; // update model is necessary here, because processUpdates is never called // reason: HtmlCommandSortHeader.isImmediate() == true ValueBinding vb = getValueBinding("sortColumn"); if (vb != null) { vb.setValue(getFacesContext(), _sortColumn); _sortColumn = null; } setSortColumnIndex(columnNameToIndex(sortColumn)); } /** * Value reference to a model property that gives the current * sort column name. The target String property is set to * the "columnName" of whichever column has been chosen * to sort by, and the method which is bound to the "value" * attribute of this table (ie which provides the DataModel used) * is expected to use this property to determine how to sort * the DataModel's contents. * * @JSFProperty */ public String getSortColumn() { if (_sortColumn != null) return _sortColumn; ValueBinding vb = getValueBinding("sortColumn"); return vb != null ? (String) vb.getValue(getFacesContext()) : null; } public void setSortAscending(boolean sortAscending) { _sortAscending = Boolean.valueOf(sortAscending); // update model is necessary here, because processUpdates is never called // reason: HtmlCommandSortHeader.isImmediate() == true ValueBinding vb = getValueBinding("sortAscending"); if (vb != null) { vb.setValue(getFacesContext(), _sortAscending); _sortAscending = null; } } /** * Value reference to a model property that gives the current * sort direction. The target Boolean property is set to true * when the selected sortColumn should be sorted in ascending * order, and false otherwise. The method which is bound to * the "value" attribute of this table (ie which provides the * DataModel used) is expected to use this property to * determine how to sort the DataModel's contents. * * @JSFProperty * defaultValue = "true" */ public boolean isSortAscending() { if (_sortAscending != null) return _sortAscending.booleanValue(); ValueBinding vb = getValueBinding("sortAscending"); Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null; return v != null ? v.booleanValue() : DEFAULT_SORTASCENDING; } /** * The name of a javabean property on which the table is sorted. *

* The datamodel should contain objects that have this property; * reflection will be used to sort the datamodel on that property * using the default comparator for that type. *

* This value is part of the component state. However it is not * directly settable by users; instead it is set by other components * such as a CommandSortHeader. */ public void setSortProperty(String sortProperty) { _sortProperty = sortProperty; } /** * @JSFProperty * literalOnly="true" * tagExcluded="true" */ public String getSortProperty() { return _sortProperty; } /** * Define if the table is sortable or not * * @JSFProperty * defaultValue="false" */ public abstract boolean isSortable(); /** * Avoids rendering the html table tags, thus, giving you a * table rendering just rows. You can use this together * with the detailStamp faces of the parent datatable * to render child-tables using the same layout as the parent. * * Notice: You have to ensure both tables do have the same * number of columns. Using the colspan attribute of the * column tag might help alot. * * @JSFProperty * defaultValue="false" */ public abstract boolean isEmbedded(); /** * true|false - true if the detailStamp should be expanded by default. default: false * * @JSFProperty * defaultValue="false" */ public abstract boolean isDetailStampExpandedDefault(); /** * before|after - where to render the detailStamp, before the * actual row or after it. default: after * * @JSFProperty * defaultValue="after" */ public abstract String getDetailStampLocation(); /** * Defines a JavaScript onmouseover event handler for each table row * * @JSFProperty */ public abstract String getRowOnMouseOver(); /** * Defines a JavaScript onmouseout event handler for each table row * * @JSFProperty */ public abstract String getRowOnMouseOut(); /** * Defines a JavaScript onclick event handler for each table row * * @JSFProperty */ public abstract String getRowOnClick(); /** * Defines a JavaScript ondblclick event handler for each table row * * @JSFProperty */ public abstract String getRowOnDblClick(); /** * Defines a JavaScript onkeydown event handler for each table row * * @JSFProperty */ public abstract String getRowOnKeyDown(); /** * Defines a JavaScript onkeypress event handler for each table row * * @JSFProperty */ public abstract String getRowOnKeyPress(); /** * Defines a JavaScript onkeyup event handler for each table row * * @JSFProperty */ public abstract String getRowOnKeyUp(); /** * Corresponds to the HTML class attribute for the row tr tag. * * @JSFProperty */ public String getRowStyleClass() { if (_rowStyleClass != null) return _rowStyleClass; // TODO: temporarily support fully-qualified ext. dataTable attribute names. ValueBinding vb = getValueBinding("org.apache.myfaces.dataTable.ROW_STYLECLASS"); if (vb != null) log.warn("org.apache.myfaces.dataTable.ROW_STYLECLASS is deprecated. Please use rowStyleClass instead."); else vb = getValueBinding(JSFAttr.ROW_STYLECLASS_ATTR); if(vb == null) return null; String bindingValue = (String) vb.getValue(getFacesContext()); if(bindingValue == "") return null; // Fix for JSF 1.2 EL coercing nulls to empty string return bindingValue; } public void setRowStyleClass(String rowStyleClass) { _rowStyleClass = rowStyleClass; } /** * Corresponds to the HTML style attribute for the row tr tag. * * @JSFProperty */ public String getRowStyle() { if (_rowStyle != null) return _rowStyle; // TODO: temporarily support fully-qualified ext. dataTable attribute names. ValueBinding vb = getValueBinding("org.apache.myfaces.dataTable.ROW_STYLE"); if (vb != null) log.warn("org.apache.myfaces.dataTable.ROW_STYLE is deprecated. Please use rowStyle instead."); else vb = getValueBinding(JSFAttr.ROW_STYLE_ATTR); if(vb == null) return null; String bindingValue = (String) vb.getValue(getFacesContext()); if(bindingValue == "") return null; // Fix for JSF 1.2 EL coercing nulls to empty string return bindingValue; } public void setRowStyle(String rowStyle) { _rowStyle = rowStyle; } /** * Defines a JavaScript onmpusedown event handler for each table row * * @JSFProperty */ public abstract String getRowOnMouseDown(); /** * Defines a JavaScript onmousemove event handler for each table row * * @JSFProperty */ public abstract String getRowOnMouseMove(); /** * Defines a JavaScript onmouseup event handler for each table row * * @JSFProperty */ public abstract String getRowOnMouseUp(); /** * @JSFProperty * tagExcluded = "true" */ protected boolean isValidChildren() { return _isValidChildren; } protected void setIsValidChildren(boolean isValidChildren) { _isValidChildren = isValidChildren; } protected _SerializableDataModel getPreservedDataModel() { return _preservedDataModel; } protected void setPreservedDataModel(_SerializableDataModel preservedDataModel) { _preservedDataModel = preservedDataModel; } public boolean isCurrentDetailExpanded() { Boolean expanded = (Boolean) _expandedNodes.get(getClientId(getFacesContext())); if (expanded != null) { return expanded.booleanValue(); } return isDetailStampExpandedDefault(); } public void setVarDetailToggler(String varDetailToggler) { _varDetailToggler = varDetailToggler; } /** * This variable has the boolean property "currentdetailExpanded" * which is true if the current detail row is expanded and the * action method "toggleDetail" which expand/collapse the current * detail row. * * @JSFProperty */ public String getVarDetailToggler() { if (_varDetailToggler != null) return _varDetailToggler; ValueBinding vb = getValueBinding("varDetailToggler"); return vb != null ? (String) vb.getValue(getFacesContext()) : null; } /** * Corresponds to the HTML style attribute for grouped rows. * * @JSFProperty */ public abstract String getRowGroupStyle(); /** * StyleClass for grouped rows. * * @JSFProperty */ public abstract String getRowGroupStyleClass(); /** * Corresponds to the HTML style attribute for the table body tag * * @JSFProperty */ public abstract String getBodyStyle(); /** * Corresponds to the HTML class attribute for the table body tag. * * @JSFProperty */ public abstract String getBodyStyleClass(); public AbstractHtmlDataTable() { setRendererType(DEFAULT_RENDERER_TYPE); } /** * Change the status of the current detail row from collapsed to expanded or * viceversa. */ public void toggleDetail() { String derivedRowKey = getClientId(getFacesContext()); // get the current expanded state of the row boolean expanded = isDetailExpanded(); if (expanded) { // toggle to "collapsed" if (isDetailStampExpandedDefault()) { // if default is expanded we have to override with FALSE here _expandedNodes.put(derivedRowKey, Boolean.FALSE); } else { // if default is collapsed we can fallback to this default _expandedNodes.remove(derivedRowKey); } } else { // toggle to "expanded" if (isDetailStampExpandedDefault()) { // if default is expanded we can fallback to this default _expandedNodes.remove(derivedRowKey); } else { // if default is collapsed we have to override with TRUE _expandedNodes.put(derivedRowKey, Boolean.TRUE); } } } /** * Return true if the current detail row is expanded. * * @return true if the current detail row is expanded. */ public boolean isDetailExpanded() { Boolean expanded = (Boolean) _expandedNodes.get(getClientId(getFacesContext())); if (expanded == null) { return isDetailStampExpandedDefault(); } return expanded.booleanValue(); } public int getSortColumnIndex() { if (_sortColumnIndex == -1) _sortColumnIndex = columnNameToIndex(getSortColumn()); return _sortColumnIndex; } public void setSortColumnIndex(int sortColumnIndex) { _sortColumnIndex = sortColumnIndex; } /** * The number of columns to wrap the table over. Default: 1 * * Set the number of columns the table will be divided over. * * @JSFProperty * defaultValue="1" */ public abstract int getNewspaperColumns(); /** * The orientation of the newspaper columns in the newspaper * table - "horizontal" or "vertical". Default: vertical * * @JSFProperty * defaultValue = "vertical" */ public abstract String getNewspaperOrientation(); /** * Gets the spacer facet, between each pair of newspaper columns. * * @JSFFacet * name="spacer" */ public UIComponent getSpacer() { return (UIComponent) getFacets().get(SPACER_FACET_NAME); } public void setSpacer(UIComponent spacer) { getFacets().put(SPACER_FACET_NAME, spacer); } /** * Expand all details */ public void expandAllDetails() { int rowCount = getRowCount(); _expandedNodes.clear(); if (getRowKey() != null) { int oldRow = getRowIndex(); try { for (int row = 0; row < rowCount; row++) { setRowIndex(row); _expandedNodes.put(getClientId(getFacesContext()), Boolean.TRUE); } } finally { setRowIndex(oldRow); } } else { for (int row = 0; row < rowCount; row++) { _expandedNodes.put(new Integer(row).toString(), Boolean.TRUE); } } } /** * Collapse all details */ public void collapseAllDetails() { _expandedNodes.clear(); } /** * @return true is any of the details is expanded */ public boolean isExpandedEmpty() { boolean expandedEmpty = true; if (_expandedNodes != null) { expandedEmpty = _expandedNodes.isEmpty(); } return expandedEmpty; } /** * Clears expanded nodes set if expandedEmpty is true * * @param expandedEmpty */ public void setExpandedEmpty(boolean expandedEmpty) { if (expandedEmpty) { if (_expandedNodes != null) { _expandedNodes.clear(); } } } //------------------ GENERATED CODE BEGIN (do not modify!) -------------------- public static final String COMPONENT_TYPE = "org.apache.myfaces.HtmlDataTable"; public static final String DEFAULT_RENDERER_TYPE = "org.apache.myfaces.Table"; private static final boolean DEFAULT_PRESERVEDATAMODEL = false; private static final boolean DEFAULT_PRESERVESORT = true; private static final boolean DEFAULT_RENDEREDIFEMPTY = true; private Boolean _preserveDataModel = null; private Boolean _preserveSort = null; public void setPreserveDataModel(boolean preserveDataModel) { _preserveDataModel = Boolean.valueOf(preserveDataModel); } /** * Indicates whether the state of the whole DataModel should * be saved and restored. When set to false, the value-binding * for the "value" attribute of this table is executed each * time the page is rendered. When set to true, that * value-binding is only executed when the component is first * created, and the DataModel state is thereafter saved/restored * automatically by the component. When column sorting is * used for a table this property needs to be false so that * the DataModel can be updated to reflect any changes in the * sort criteria. Default: false * * @JSFProperty */ public boolean isPreserveDataModel() { if (_preserveDataModel != null) return _preserveDataModel.booleanValue(); ValueBinding vb = getValueBinding("preserveDataModel"); Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null; return v != null ? v.booleanValue() : DEFAULT_PRESERVEDATAMODEL; } public void setPreserveSort(boolean preserveSort) { _preserveSort = Boolean.valueOf(preserveSort); } /** * Indicates whether the state of the sortColumn and sortAscending * attribute should be saved and restored and written back to the * model during the update model phase. Default: true * * @JSFProperty * defaultValue = "true" */ public boolean isPreserveSort() { if (_preserveSort != null) return _preserveSort.booleanValue(); ValueBinding vb = getValueBinding("preserveSort"); Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null; return v != null ? v.booleanValue() : DEFAULT_PRESERVESORT; } /** * Indicates whether this table should be rendered if the * underlying DataModel is empty. You could as well use * rendered="#{not empty bean.list}", but this one causes * the getList method of your model bean beeing called up * to five times per request, which is not optimal when * the list is backed by a DB table. Using * renderedIfEmpty="false" solves this problem, because * the MyFaces extended HtmlDataTable automatically caches * the DataModel and calles the model getter only once * per request. Default: true * * @JSFProperty * defaultValue = "true" */ public abstract boolean isRenderedIfEmpty(); /** * A parameter name, under which the current rowIndex is set * in request scope similar to the var parameter. * * @JSFProperty */ public abstract String getRowIndexVar(); /** * A parameter name, under which the rowCount is set in * request scope similar to the var parameter. * * @JSFProperty */ public abstract String getRowCountVar(); /** * A parameter name, under which the previous RowData Object * is set in request scope similar to the rowIndexVar and * rowCountVar parameters. Mind that the value of this * request scope attribute is null in the first row or * when isRowAvailable returns false for the previous row. * * @JSFProperty */ public abstract String getPreviousRowDataVar(); /** * A parameter name, under which the a boolean is set in request * scope similar to the var parameter. TRUE for the column that * is currently sorted, FALSE otherwise. * * @JSFProperty */ public abstract String getSortedColumnVar(); /** * HTML: Specifies the horizontal alignment of this element. * Deprecated in HTML 4.01. * * @JSFProperty */ public abstract String getAlign(); /** * The id to use for * * @JSFProperty */ public abstract String getRowId(); /** * Reserved for future use. * * @JSFProperty */ public abstract String getDatafld(); /** * Reserved for future use. * * @JSFProperty */ public abstract String getDatasrc(); /** * Reserved for future use. * * @JSFProperty */ public abstract String getDataformatas(); /** * Indicate the expected type of the EL expression pointed * by value property. It is useful when vb.getType() cannot * found the type, like when a map value is resolved on * the expression. * * @JSFProperty */ public abstract String getValueType(); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy