/* * � Copyright IBM Corp. 2010, 2011 * * Licensed 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 com.ibm.xsp.extlib.renderkit.html_extended.data; import java.io.IOException; import java.util.Iterator; import java.util.List; import javax.faces.application.Application; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.convert.Converter; import javax.faces.el.PropertyResolver; import javax.faces.event.ActionEvent; import javax.faces.model.DataModel; import com.ibm.commons.util.NotImplementedException; import com.ibm.commons.util.StringUtil; import com.ibm.xsp.component.UIDataIterator; import com.ibm.xsp.component.UIEventHandler; import com.ibm.xsp.component.UIViewColumnHeader; import com.ibm.xsp.context.FacesContextEx; import com.ibm.xsp.extlib.component.data.UIDataSourceIterator; import com.ibm.xsp.extlib.component.data.ValueColumn; import com.ibm.xsp.extlib.renderkit.dojo.DojoRendererUtil; import com.ibm.xsp.extlib.renderkit.html_extended.FacesRendererEx; import com.ibm.xsp.extlib.renderkit.html_extended.data.AbstractDataViewRenderer.ViewDefinition; import com.ibm.xsp.model.TabularDataModel; import com.ibm.xsp.model.ViewRowData; import com.ibm.xsp.renderkit.ContentTypeRendererUtil; import com.ibm.xsp.renderkit.html_extended.IteratorAjaxRenderer; import com.ibm.xsp.util.AjaxUtilEx; import com.ibm.xsp.util.FacesUtil; import com.ibm.xsp.util.HtmlUtil; import com.ibm.xsp.util.JSUtil; import com.ibm.xsp.util.JavaScriptUtil; /** * {@link UIDataSourceIterator} renderer. * <p> * Provides some common * </p> */ public abstract class DataSourceIteratorRenderer extends FacesRendererEx implements IteratorAjaxRenderer { // The following delimiter properties are appended to the HTML // IDs of the elements that are activated in order to perform the // associated function. // TODO: Investigate if a less insane method of message passing might work // Expand/collapse all the rows protected final String EXPAND_DELIMITER = "__expand:"; //$NON-NLS-1$ protected final String SHRINK_DELIMITER = "__shrink:"; //$NON-NLS-1$ // Show/Hide the details protected final String SHOW_DELIMITER = "__show:"; //$NON-NLS-1$ protected final String HIDE_DELIMITER = "__hide:"; //$NON-NLS-1$ // Click on a column to sort it protected final String SORT_DELIMITER = "__asc:"; //$NON-NLS-1$ protected final String SORT_SUMMARY = "$s"; //$NON-NLS-1$ // Prefix for the show/hide hidden field protected static final String ID_HIDDEN = "_shfld"; // $NON-NLS-1$ // ints returned by getDominoSortIconCode protected static final int SORT_0_NOT_SORTABLE_COLUMN = 0; protected static final int SORT_1_COLUMN_SORTABLE_BOTH_CURRENTLY_NOT_SORTED = 1; protected static final int SORT_2_COLUMN_SORTABLE_BOTH_CURRENTLY_SORTED_ASCENDING = 2; protected static final int SORT_3_COLUMN_SORTABLE_BOTH_CURRENTLY_SORTED_DESCENDING = 3; protected static final int SORT_4_COLUMN_SORTABLE_ASCENDING_CURRENTLY_NOT_SORTED = 4; protected static final int SORT_5_COLUMN_SORTABLE_ASCENDING_CURRENTLY_SORTED_ASCENDING = 5; protected static final int SORT_6_COLUMN_SORTABLE_DESCENDING_CURRENTLY_NOT_SORTED = 6; protected static final int SORT_7_COLUMN_SORTABLE_DESCENDING_CURRENTLY_SORTED_DESCENDING = 7; // // Theme properties // protected static final int PROP_BLANKIMG = 1; protected static final int PROP_BLANKIMGALT = 2; protected static final int PROP_ALTTEXTCLASS = 3; protected static final int PROP_COLLAPSEICON = 10; protected static final int PROP_COLLAPSEICONSTYLE = 11; protected static final int PROP_COLLAPSEICONCLASS = 12; protected static final int PROP_COLLAPSEICONALT = 13; protected static final int PROP_EXPANDICON = 14; protected static final int PROP_EXPANDICONSTYLE = 15; protected static final int PROP_EXPANDICONCLASS = 16; protected static final int PROP_EXPANDICONALT = 17; protected static final int PROP_EMPTYICON = 18; protected static final int PROP_EMPTYICONSTYLE = 19; protected static final int PROP_EMPTYICONCLASS = 20; protected static final int PROP_EMPTYICONALT = 21; protected static final int PROP_SHOWHIDEONCLIENT = 25; protected static final int PROP_TABLEHDRCOLIMAGE_SORTBOTH_ASCENDING = 30; protected static final int PROP_TABLEHDRCOLIMAGE_SORTBOTH_DESCENDING = 31; protected static final int PROP_TABLEHDRCOLIMAGE_SORTBOTH = 32; protected static final int PROP_TABLEHDRCOLIMAGE_SORTED_ASCENDING = 33; protected static final int PROP_TABLEHDRCOLIMAGE_SORTED_DESCENDING = 34; protected static final int PROP_TABLEHDRCOLIMAGE_SORT_WIDTH = 35; protected static final int PROP_TABLEHDRCOLIMAGE_SORT_HEIGHT = 36; @Override protected Object getProperty(int prop) { switch(prop) { case PROP_BLANKIMGALT: return ""; // //$NON-NLS-1$ case PROP_COLLAPSEICON: return "/.ibmxspres/global/theme/common/images/collapse.gif"; // $NON-NLS-1$ // TODO style should be set through a styleClass, not hardcoded styles case PROP_COLLAPSEICONSTYLE: return "width:13.0px;height:13.0px;padding-right:3px"; // $NON-NLS-1$ case PROP_COLLAPSEICONALT: return "Collapse the current row"; // $NLS-DataSourceIteratorRenderer.Collapsethecurrentrow-1$ case PROP_EXPANDICON: return "/.ibmxspres/global/theme/common/images/expand.gif"; // $NON-NLS-1$ // TODO style should be set through a styleClass, not hardcoded styles case PROP_EXPANDICONSTYLE: return "width:13.0px;height:13.0px;padding-right:3px"; // $NON-NLS-1$ case PROP_EXPANDICONALT: return "Expand the current row"; // $NLS-DataSourceIteratorRenderer.Expandthecurrentrow-1$ case PROP_EMPTYICON: return "/.ibmxspres/global/theme/common/images/transparent.gif"; // $NON-NLS-1$ // TODO style should be set through a styleClass, not hardcoded styles case PROP_EMPTYICONSTYLE: return "width:16.0px;height:13.0px"; // $NON-NLS-1$ // note, for an Alt, there's a difference between the empty string and null case PROP_EMPTYICONALT: return ""; //$NON-NLS-1$ // Hide on client doesn't propagate well after a click on a link, or a page // change as the pager is partial executing itself // Should send a request instead of filling a hidden field case PROP_SHOWHIDEONCLIENT: return false; //true; //href = ; case PROP_TABLEHDRCOLIMAGE_SORTBOTH_ASCENDING: return UIViewColumnHeader.IMAGE_SORT_BOTH_ASCENDING; case PROP_TABLEHDRCOLIMAGE_SORTBOTH_DESCENDING: return UIViewColumnHeader.IMAGE_SORT_BOTH_DESCENDING; case PROP_TABLEHDRCOLIMAGE_SORTBOTH: return UIViewColumnHeader.IMAGE_SORT_BOTH; case PROP_TABLEHDRCOLIMAGE_SORTED_ASCENDING: return UIViewColumnHeader.IMAGE_SORTED_ASCENDING; case PROP_TABLEHDRCOLIMAGE_SORTED_DESCENDING: return UIViewColumnHeader.IMAGE_SORTED_DESCENDING; // the domino sort header icons are 16x16 px case PROP_TABLEHDRCOLIMAGE_SORT_WIDTH: return "16"; //$NON-NLS-1$ case PROP_TABLEHDRCOLIMAGE_SORT_HEIGHT: return "16"; //$NON-NLS-1$ } return super.getProperty(prop); } // ================================================================ // Decoding methods // ================================================================ /** * Decode methods that handle the known actions (like expand/collapse). */ @Override public void decode(FacesContext context, UIComponent component) { if (context == null || component == null) throw new NullPointerException(); if (!component.isRendered()) return; super.decode(context, component); UIDataSourceIterator dataComponent = (component instanceof UIDataSourceIterator) ? (UIDataSourceIterator)component : null; if(null == dataComponent){ // Might be the row component return; } String hiddenValue = FacesUtil.getHiddenFieldValue(context); if (isToggleAction(context, dataComponent,hiddenValue)) { ActionEvent ev = createToggleEvent(dataComponent, hiddenValue); dataComponent.queueEvent(ev); } // Decode the show/hide hidden field String showHideId = dataComponent.getClientId(context)+ID_HIDDEN; String showHideValue = (String)context.getExternalContext().getRequestParameterMap().get(showHideId); if(StringUtil.isNotEmpty(showHideValue)) { String[] v = StringUtil.splitString(showHideValue, ','); ToggleDetailEvent ev = new ToggleDetailEvent(component); ev.setTogglePositions(v); dataComponent.queueEvent(ev); } // decode any event handlers... if (component.getRendersChildren()) { List<?> children = component.getChildren(); for (Iterator<?> i = children.iterator(); i.hasNext();) { UIComponent child = (UIComponent) i.next(); if (child instanceof UIEventHandler) child.decode(context); } } } private boolean isToggleAction(FacesContext context, UIDataSourceIterator component, String submitterId){ // The id must be an expand/collapse action if (StringUtil.isNotEmpty(submitterId)) { if( submitterId.contains(EXPAND_DELIMITER) || submitterId.contains(SHRINK_DELIMITER) || submitterId.contains(SHOW_DELIMITER) || submitterId.contains(HIDE_DELIMITER) || submitterId.contains(SORT_DELIMITER)) { String parentId = component.getClientId(context); if (submitterId.startsWith(parentId)) { return true; } } } return false; } private ActionEvent createToggleEvent(UIDataSourceIterator component, String catRowId) { if (catRowId.lastIndexOf(EXPAND_DELIMITER) != -1) { int delimiter_len = EXPAND_DELIMITER.length(); ToggleRowEvent ev = new ToggleRowEvent(component); ev.setPosition(catRowId.substring(catRowId.lastIndexOf(EXPAND_DELIMITER) + delimiter_len)); ev.setExpand(true); //>tmg:a11y ev.setClientId(catRowId); //<tmg:a11y return ev; } if (catRowId.lastIndexOf(SHRINK_DELIMITER) != -1) { int delimiter_len = SHRINK_DELIMITER.length(); ToggleRowEvent ev = new ToggleRowEvent(component); ev.setPosition(catRowId.substring(catRowId.lastIndexOf(SHRINK_DELIMITER) + delimiter_len)); ev.setExpand(false); //>tmg:a11y ev.setClientId(catRowId); //<tmg:a11y return ev; } if (catRowId.lastIndexOf(SHOW_DELIMITER) != -1) { int delimiter_len = SHOW_DELIMITER.length(); ToggleDetailEvent ev = new ToggleDetailEvent(component); ev.setTogglePositions(new String[]{catRowId.substring(catRowId.lastIndexOf(SHOW_DELIMITER) + delimiter_len)}); //>tmg:a11y ev.setClientId(catRowId); //<tmg:a11y return ev; } if (catRowId.lastIndexOf(HIDE_DELIMITER) != -1) { int delimiter_len = HIDE_DELIMITER.length(); ToggleDetailEvent ev = new ToggleDetailEvent(component); ev.setTogglePositions(new String[]{catRowId.substring(catRowId.lastIndexOf(HIDE_DELIMITER) + delimiter_len)}); //>tmg:a11y ev.setClientId(catRowId); //<tmg:a11y return ev; } if (catRowId.lastIndexOf(SORT_DELIMITER) != -1) { int delimiter_len = SORT_DELIMITER.length(); ToggleSortColumnEvent ev = new ToggleSortColumnEvent(component); String columnName = catRowId.substring(catRowId.lastIndexOf(SORT_DELIMITER) + delimiter_len); ev.setColumnName(columnName); //>tmg:a11y ev.setClientId(catRowId); //<tmg:a11y return ev; } return null; } // ================================================================ // Rendering methods // ================================================================ @Override public void encodeBegin(FacesContext context, UIComponent component) throws IOException { ResponseWriter w = context.getResponseWriter(); UIDataSourceIterator c = (UIDataSourceIterator)component; boolean rendered = component.isRendered(); if(!rendered) { return; } writeMainContainer(context, w, c); } @Override public boolean getRendersChildren() { return true; } @Override public void encodeChildren(FacesContext context, UIComponent component) throws IOException { } @Override public void encodeEnd(FacesContext context, UIComponent component) throws IOException { //>tmg:a11y super.encodeEnd(context, component); // the regular expand/collapse actionevent and the column sort action event work in here... String _toggleActionClientId = (String)HtmlUtil.readEncodeParameter(context, component, UIDataSourceIterator.TOGGLE_ACTION_CLIENT_ID, /*remove*/ true); if(null != _toggleActionClientId){ // for the expand/collapse action event, flip the client id... expand/collapse vs collapse/expand... if(_toggleActionClientId.contains(SHRINK_DELIMITER)){ _toggleActionClientId = _toggleActionClientId.replaceAll(SHRINK_DELIMITER, EXPAND_DELIMITER); }else if(_toggleActionClientId.contains(EXPAND_DELIMITER)){ _toggleActionClientId = _toggleActionClientId.replaceAll(EXPAND_DELIMITER, SHRINK_DELIMITER); } StringBuilder js = new StringBuilder(); js.append("XSP.setFocus("); //$NON-NLS-1$ JavaScriptUtil.addString(js, _toggleActionClientId); js.append(");\n"); //$NON-NLS-1$ JavaScriptUtil.addScriptOnLoad(js.toString()); } //<tmg:a11y } // ================================================================ // Ajax Support // ================================================================ public void encodeRows(FacesContext context, UIDataIterator iterator, int first, int rows) throws IOException { throw new NotImplementedException(); } // ================================================================ // Main Container // ================================================================ protected void writeMainContainer(FacesContext context, ResponseWriter w, UIDataSourceIterator c) throws IOException { throw new NotImplementedException(); } // ================================================================ // Row properties // ================================================================ protected boolean isCategoryRow(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef) { DataModel dm = viewDef.dataModel; if(dm instanceof TabularDataModel) { TabularDataModel tbm = (TabularDataModel)dm; return tbm.isRowCategory(); } return false; } protected boolean isTotalRow(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef) { DataModel dm = viewDef.dataModel; if(dm instanceof TabularDataModel) { TabularDataModel tbm = (TabularDataModel)dm; return tbm.isRowTotal(); } return false; } protected boolean isRowExpanded(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef) { DataModel dm = viewDef.dataModel; if(dm instanceof TabularDataModel) { TabularDataModel tbm = (TabularDataModel)dm; return tbm.isRowExpanded(); } return false; } protected boolean isRowDetailVisible(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef) { if( viewDef.rowDisableHideRow ){ return true; } String rowPosition = viewDef.rowPosition; if(StringUtil.isNotEmpty(rowPosition)) { return c.isDetailVisible(rowPosition,viewDef.expandedDetailDefault); } return viewDef.expandedDetailDefault; } protected String getRowPosition(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef) { DataModel dm = viewDef.dataModel; if(dm instanceof TabularDataModel) { TabularDataModel tbm = (TabularDataModel)dm; return tbm.getRowPosition(); } return null; } protected boolean isRowLeaf(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef) { DataModel dm = viewDef.dataModel; if(dm instanceof TabularDataModel) { TabularDataModel tbm = (TabularDataModel)dm; return tbm.isRowLeaf(); } return true; } protected boolean isColumnSortable(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef, String columnName) { DataModel dm = viewDef.dataModel; if(dm instanceof TabularDataModel) { TabularDataModel tbm = (TabularDataModel)dm; return tbm.isColumnSortable(columnName); } return false; } protected int getColumnSortState(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef, String columnName) { DataModel dm = viewDef.dataModel; if(dm instanceof TabularDataModel) { TabularDataModel tbm = (TabularDataModel)dm; String sortColumn = tbm.getResortColumn(); if(sortColumn==null) { int sortState = tbm.getResortState(columnName); return sortState; } else if(StringUtil.equals(columnName, sortColumn)) { int sortState = tbm.getResortState(columnName); return sortState; } //System.out.println("SortColumn: "+sortColumn); return tbm.getResortType(columnName); } return TabularDataModel.RESORT_NONE; } /** * Unused, kept for backward compatibility * @param context * @param c * @param viewDef * @param columnName * @return * @deprecated */ public String getDominoSortIcon(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef, String columnName){ int dominoSortIconCode = getDominoSortIconCode(context, c, viewDef, columnName); return getDominoSortIcon(context, c, viewDef, dominoSortIconCode); } protected String getDominoSortIcon(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef, int dominoSortIconCode){ switch(dominoSortIconCode){ case SORT_1_COLUMN_SORTABLE_BOTH_CURRENTLY_NOT_SORTED:{ String href = (String)getProperty(PROP_TABLEHDRCOLIMAGE_SORTBOTH); return href; } case SORT_2_COLUMN_SORTABLE_BOTH_CURRENTLY_SORTED_ASCENDING:{ String href = (String)getProperty(PROP_TABLEHDRCOLIMAGE_SORTBOTH_ASCENDING); return href; } case SORT_3_COLUMN_SORTABLE_BOTH_CURRENTLY_SORTED_DESCENDING:{ String href = (String)getProperty(PROP_TABLEHDRCOLIMAGE_SORTBOTH_DESCENDING); return href; } case SORT_4_COLUMN_SORTABLE_ASCENDING_CURRENTLY_NOT_SORTED: case SORT_7_COLUMN_SORTABLE_DESCENDING_CURRENTLY_SORTED_DESCENDING:{ String href = (String)getProperty(PROP_TABLEHDRCOLIMAGE_SORTED_DESCENDING); return href; } case SORT_5_COLUMN_SORTABLE_ASCENDING_CURRENTLY_SORTED_ASCENDING: case SORT_6_COLUMN_SORTABLE_DESCENDING_CURRENTLY_NOT_SORTED:{ String href = (String)getProperty(PROP_TABLEHDRCOLIMAGE_SORTED_ASCENDING); return href; } } return null; } protected String getDominoSortAlt(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef, int dominoSortIconCode){ // TODO extract strings to getProperty method switch(dominoSortIconCode){ case SORT_1_COLUMN_SORTABLE_BOTH_CURRENTLY_NOT_SORTED:{ String sortIconAlt; sortIconAlt = "Sort Toggle"; // $NLS-DataViewRenderer_SortToggle-1$ return sortIconAlt; } case SORT_2_COLUMN_SORTABLE_BOTH_CURRENTLY_SORTED_ASCENDING: case SORT_5_COLUMN_SORTABLE_ASCENDING_CURRENTLY_SORTED_ASCENDING:{ String sortIconAlt; sortIconAlt = "Ascending"; // $NLS-DataViewRenderer_SortAscending-1$ return sortIconAlt; } case SORT_3_COLUMN_SORTABLE_BOTH_CURRENTLY_SORTED_DESCENDING: case SORT_7_COLUMN_SORTABLE_DESCENDING_CURRENTLY_SORTED_DESCENDING:{ String sortIconAlt; sortIconAlt = "Descending" ; // $NLS-DataViewRenderer_SortDescending-1$ return sortIconAlt; } case SORT_4_COLUMN_SORTABLE_ASCENDING_CURRENTLY_NOT_SORTED: case SORT_6_COLUMN_SORTABLE_DESCENDING_CURRENTLY_NOT_SORTED:{ String sortIconAlt; sortIconAlt = "Not Sorted"; // $NLS-DataViewRenderer_NotSorted-1$ return sortIconAlt; } } return null; } /** * There are 8 states: * <ul> * <li>0: Not a sortable column.</li> * <li>1: Column resortable in both directions, corrently not sorted.</li> * <li>2: Column resortable in both directions, corrently sorted ascending.</li> * <li>3: Column resortable in both directions, corrently sorted descending.</li> * <li>4: Column can be unsorted or sorted ascending, currently not sorted.</li> * <li>5: Column can be unsorted or sorted ascending, corrently sorted ascending.</li> * <li>6: Column can be unsorted or sorted descending, currently not sorted.</li> * <li>7: Column can be unsorted or sorted descending, currently sorted descending.</li> * </ul> */ protected int getDominoSortIconCode(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef, String columnName) { // Note the fix for: // SPR# BGLN85FFWC sort state only maintained on current column // has been moved to UIDataSourceIterator.broadcast(FacesEvent) int dominoSortIconProperty = SORT_0_NOT_SORTABLE_COLUMN; DataModel dm = viewDef.dataModel; if(null != dm && dm instanceof TabularDataModel) { TabularDataModel dataModel = (TabularDataModel)dm; int resort = dataModel.getResortType(columnName); if (resort == TabularDataModel.RESORT_BOTH) { if ( ! StringUtil.equalsIgnoreCase(columnName, dataModel.getResortColumn())) { dominoSortIconProperty = SORT_1_COLUMN_SORTABLE_BOTH_CURRENTLY_NOT_SORTED; } else { int resortState = dataModel.getResortState(columnName); if (resortState == TabularDataModel.RESORT_ASCENDING){ dominoSortIconProperty = SORT_2_COLUMN_SORTABLE_BOTH_CURRENTLY_SORTED_ASCENDING; }else if (resortState == TabularDataModel.RESORT_DESCENDING){ dominoSortIconProperty = SORT_3_COLUMN_SORTABLE_BOTH_CURRENTLY_SORTED_DESCENDING; }else{ dominoSortIconProperty = SORT_1_COLUMN_SORTABLE_BOTH_CURRENTLY_NOT_SORTED; } } } else if (resort == TabularDataModel.RESORT_ASCENDING || resort == TabularDataModel.RESORT_DESCENDING) { int resortState = dataModel.getResortState(columnName); if( resort == TabularDataModel.RESORT_ASCENDING ){ // 4 or 5 if( resortState == TabularDataModel.RESORT_ASCENDING ){ // the meaning of resortState == RESORT_ASCENDING is counter-intuative, // it doesn't give the current state, but rather the action that would // be performed if you clicked the header. dominoSortIconProperty = SORT_4_COLUMN_SORTABLE_ASCENDING_CURRENTLY_NOT_SORTED; }else{ dominoSortIconProperty = SORT_5_COLUMN_SORTABLE_ASCENDING_CURRENTLY_SORTED_ASCENDING; } }else{ // resort == TabularDataModel.RESORT_DESCENDING // 6 or 7 if (resortState == TabularDataModel.RESORT_DESCENDING){ // the meaning of resortState == RESORT_DESCENDING is counter-intuative, // it doesn't give the current state, but rather the action that would // be performed if you clicked the header. dominoSortIconProperty = SORT_6_COLUMN_SORTABLE_DESCENDING_CURRENTLY_NOT_SORTED; }else{ dominoSortIconProperty = SORT_7_COLUMN_SORTABLE_DESCENDING_CURRENTLY_SORTED_DESCENDING; } } } } return dominoSortIconProperty; } protected int getColumnIndentLevel(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef) { // If the view is forced as flat... if(viewDef.showItemsFlat) { return 0; } // Else get it from the data model DataModel dm = viewDef.dataModel; if(dm instanceof TabularDataModel) { TabularDataModel tbm = (TabularDataModel)dm; return tbm.getColumnIndentLevel()-viewDef.indentOffset; } return 0; } // This is for an 852 temp fix protected int calculateIndentOffset(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef) { // Else get it from the data model DataModel dm = viewDef.dataModel; if(dm instanceof TabularDataModel) { TabularDataModel tbm = (TabularDataModel)dm; return tbm.getColumnIndentLevel(); } return 0; } // ================================================================ // Write/Access the column value // ================================================================ protected void writeColumnValue(FacesContext context, ResponseWriter w, UIDataSourceIterator c, ViewDefinition viewDef, ValueColumn vc) throws IOException { String value = formatColumnValue(context, c, viewDef, vc); if(StringUtil.isNotEmpty(value)) { String contentType = vc.getContentType(); if( "html".equalsIgnoreCase(contentType) ){//$NON-NLS-1$ // TODO allow different filters, not just the default "acf" filter String filterName = "acf"; //$NON-NLS-1$ value = ((FacesContextEx)context).filterHtml(filterName, value); } ContentTypeRendererUtil.render(context, c, w, contentType, value); //w.writeText(value, null); } else { writeColumnEmptyValue(context, w, c, viewDef, vc); } } protected void writeColumnEmptyValue(FacesContext context, ResponseWriter w, UIDataSourceIterator c, ViewDefinition viewDef, ValueColumn vc) throws IOException { JSUtil.writeTextBlank(w); //   } protected String formatColumnValue(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef, ValueColumn vc) throws IOException { Object value = getColumnValue(context, c, viewDef, vc); if(value!=null) { Converter cv = findConverter(context, c, viewDef, vc, value); String v = cv!=null ? cv.getAsString(context, c, value) : value.toString(); return v; } return null; } protected Converter findConverter(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef, ValueColumn vc, Object value) { // Explicit converter Converter converter = vc.getConverter(); if(converter!=null) { return converter; } Class<?> converterType = value.getClass(); if (converterType == null || converterType == String.class || converterType == Object.class) { return null; } // Acquire an appropriate converter instance. try { Application application = context.getApplication(); return application.createConverter(converterType); } catch (Exception e) { } return null; } protected Object getColumnValue(FacesContext context, UIDataSourceIterator c, ViewDefinition viewDef, ValueColumn vc) throws IOException { // Look for a computed value Object value = vc.getValue(); if(value!=null) { return value; } // Look for a column name String colName = vc.getColumnName(); if(StringUtil.isNotEmpty(colName)) { // Read from a rowData object Object rowData = viewDef.dataModel.getRowData(); if(rowData instanceof ViewRowData) { ViewRowData vr = (ViewRowData)rowData; return vr.getColumnValue(colName); } // Use the JSF property resolver PropertyResolver pr = context.getApplication().getPropertyResolver(); return pr.getValue(rowData, colName); } // Ok no value found return null; } // clientId: The id of the component that will receive the event // targetId: The component to attach the event on the client protected void setupSubmitOnClick(FacesContext context, UIDataSourceIterator component, String clientId, String targetId, String refreshId) { boolean immediate = false; UIComponent subTree = ((FacesContextEx)context).getSubTreeComponent(); boolean partialExec = component.isPartialExecute(); String execId = null; if(partialExec) { // The exec ID must be the actual table id, as there is not sub component for // handling collapse/expand. Moreover, because this method is called per row // the table client id has a trailing row number that should be removed. // Also, because there isn't a sub component, processDecode() is called on the // table, which implies that all the rows are decoded. But the other phases // are skipped. execId = component.getClientId(context); execId = execId.substring(0,execId.lastIndexOf(':')); immediate = true; } else { if(subTree!=null) { partialExec = true; execId = subTree.getClientId(context); immediate = true; } } boolean partialRefresh = component.isPartialRefresh(); if(partialRefresh) { if(StringUtil.isEmpty(refreshId)) { refreshId = component.getRefreshId(); if (StringUtil.isEmpty(refreshId)) { refreshId = AjaxUtilEx.getRefreshId(context, component); } } } else { if(subTree!=null) { partialRefresh = true; refreshId = subTree.getClientId(context); } } /// call some javascript in xspClient.js final String event = "onclick"; // $NON-NLS-1$ // Note, the onclick event is also triggered if the user tabs to the // image and presses enter. (Not just when clicked with a mouse.) // when the span is clicked, put its id in the hidden field and submit the form. StringBuilder buff = new StringBuilder(); if (partialRefresh) { JavaScriptUtil.appendAttachPartialRefreshEvent( buff, clientId, targetId, execId, event, /* clientSideScriptName */null, immediate?JavaScriptUtil.VALIDATION_NONE:JavaScriptUtil.VALIDATION_FULL, /*refreshId*/refreshId, /*onstart*/null, /*oncomplete*/null, /*onerror*/null ); } else { JavaScriptUtil.appendAttachEvent( buff, clientId, targetId, execId, event, /* clientSideScriptName */null, /*submit*/true, immediate?JavaScriptUtil.VALIDATION_NONE:JavaScriptUtil.VALIDATION_FULL); } String script = buff.toString(); // then add the script block we just generated. JavaScriptUtil.addScriptOnLoad(script); } protected void startElement(ResponseWriter w, Object tag, Object style, Object clazz, Object dojoType) throws IOException { String sTag = getString(tag); if(StringUtil.isNotEmpty(sTag)) { w.startElement(sTag,null); String sDojoType = getString(dojoType); if(StringUtil.isNotEmpty(sDojoType)) { DojoRendererUtil.writeDojoHtmlAttributes(FacesContext.getCurrentInstance(), null, sDojoType); //w.writeAttribute("dojoType", sDojoType, null); // $NON-NLS-1$ } String sStyle = getString(style); if(StringUtil.isNotEmpty(sStyle)) { w.writeAttribute("style", sStyle, null); // $NON-NLS-1$ } String sClazz = getString(clazz); if(StringUtil.isNotEmpty(sClazz)) { w.writeAttribute("class", sClazz, null); // $NON-NLS-1$ } } } protected final String getString(Object o) { if(o==null) { return null; } if(o instanceof String) { return (String)o; } if(o instanceof Number) { int prop = ((Number)o).intValue(); return (String)getProperty(prop); } throw new IllegalArgumentException(); } }