Index: icefaces/ace/component/src/org/icefaces/ace/api/UIData.java =================================================================== --- icefaces/ace/component/src/org/icefaces/ace/api/UIData.java (revision 25241) +++ icefaces/ace/component/src/org/icefaces/ace/api/UIData.java (revision ) @@ -31,18 +31,18 @@ import javax.faces.context.FacesContext; public class UIData extends javax.faces.component.UIData { - private String baseClientId = null; + //private String baseClientId = null; private StringBuilder builder; - @Override - public String getClientId(FacesContext context) { - if(baseClientId == null) { - baseClientId = super.getClientId(context); - } +// @Override +// public String getClientId(FacesContext context) { +// if(baseClientId == null) { +// baseClientId = super.getClientId(context); +// } +// +// return baseClientId; +// } - return baseClientId; - } - @Override public String getContainerClientId(FacesContext context) { String containerClientId = getStandardContainerClientId(context); Index: icefaces/ace/component/src/org/icefaces/ace/component/datatable/DataTable.java =================================================================== --- icefaces/ace/component/src/org/icefaces/ace/component/datatable/DataTable.java (revision 25809) +++ icefaces/ace/component/src/org/icefaces/ace/component/datatable/DataTable.java (revision ) @@ -568,31 +568,132 @@ if (tableWrapper == null) tableWrapper = (getDataModel() instanceof TreeDataModel); return tableWrapper; } - // Overridden from custom UIData impl because build process requires UIData, at - // a point where TreeDataModel will not have the dependencies required for compilation. + + private String baseClientId = null; + private int baseClientIdLength; + private StringBuilder clientIdBuilder = null; + private Boolean isNested = null; + public String getBaseClientId(FacesContext context) { + if (baseClientId == null && clientIdBuilder == null) { + if (!isNestedWithinUIData()) { + clientIdBuilder = new StringBuilder(super.getClientId(context)); + baseClientId = clientIdBuilder.toString(); + baseClientIdLength = (baseClientId.length() + 1); + clientIdBuilder.append(UINamingContainer.getSeparatorChar(context)); + clientIdBuilder.setLength(baseClientIdLength); + } else { + clientIdBuilder = new StringBuilder(); + } + } + return baseClientId; + } + @Override public String getContainerClientId(FacesContext context) { - String containerClientId = getStandardContainerClientId(context); + if (context == null) { + throw new NullPointerException(); + } + return this.getClientId(context); + } - int rowIndex; - String rowId = ""; - if (isTreeRootNode()) { - TreeDataModel rootModel = (TreeDataModel)getDataModel(); - rowIndex = getRowIndex(); - if (rootModel.isRootIndexSet()) rowId = rootModel.getRootIndex() + "." + rowIndex; - else rowId += rowIndex; + @Override + public String getClientId(FacesContext context) { + + if (context == null) { + throw new NullPointerException(); + } + + // If baseClientId and clientIdBuilder are both null, this is the + // first time that getClientId() has been called. + // If we're not nested within another UIData, then: + // - create a new StringBuilder assigned to clientIdBuilder containing + // our client ID. + // - toString() the builder - this result will be our baseClientId + // for the duration of the component + // - append UINamingContainer.getSeparatorChar() to the builder + // If we are nested within another UIData, then: + // - create an empty StringBuilder that will be used to build + // this instance's ID + if (baseClientId == null && clientIdBuilder == null) { + if (!isNestedWithinUIData()) { + clientIdBuilder = new StringBuilder(super.getClientId(context)); + baseClientId = clientIdBuilder.toString(); + baseClientIdLength = (baseClientId.length() + 1); + clientIdBuilder.append(UINamingContainer.getSeparatorChar(context)); + clientIdBuilder.setLength(baseClientIdLength); } else { - rowIndex = getRowIndex(); - rowId += rowIndex; + clientIdBuilder = new StringBuilder(); } + } + int rowIndex = getRowIndex(); + if (rowIndex >= 0) { + String cid; + if (!isNestedWithinUIData()) { + // we're not nested, so the clientIdBuilder is already + // primed with clientID + + // UINamingContainer.getSeparatorChar(). Append the + // current rowIndex, and toString() the builder. reset + // the builder to it's primed state. + if (isTreeRootNode()) { + String rootIndex = ((TreeDataModel)getDataModel()).getRootIndex(); + if (rootIndex != null && !rootIndex.equals("")) + rootIndex += "."+rowIndex; + else rootIndex = ""+rowIndex; + cid = clientIdBuilder.append(rootIndex).toString(); + } else + cid = clientIdBuilder.append(rowIndex).toString(); - //TODO: raise reliability. - if (rowIndex == -1) return containerClientId; + clientIdBuilder.setLength(baseClientIdLength); + } else { + // we're nested, so we have to build the ID from scratch + // each time. Reuse the same clientIdBuilder instance + // for each call by resetting the length to 0 after + // the ID has been computed. + if (isTreeRootNode()) { + String rootIndex = ((TreeDataModel)getDataModel()).getRootIndex(); + if (rootIndex != null && !rootIndex.equals("")) + rootIndex += "."+rowIndex; + else rootIndex = ""+rowIndex; + cid = clientIdBuilder.append(super.getClientId(context)) + .append(UINamingContainer.getSeparatorChar(context)).append(rootIndex) + .toString(); + } else + cid = clientIdBuilder.append(super.getClientId(context)) + .append(UINamingContainer.getSeparatorChar(context)).append(rowIndex) + .toString(); - StringBuilder bld = getBuilder(); - return bld.append(containerClientId).append(UINamingContainer.getSeparatorChar(context)).append(rowId).toString(); + clientIdBuilder.setLength(0); - } + } + return (cid); + } else { + if (!isNestedWithinUIData()) { + // Not nested and no row available, so just return our baseClientId + return (baseClientId); + } else { + // nested and no row available, return the result of getClientId(). + // this is necessary as the client ID will reflect the row that + // this table represents + return super.getClientId(context); + } + } + } + private Boolean isNestedWithinUIData() { + if (isNested == null) { + UIComponent parent = this; + while (null != (parent = parent.getParent())) { + if (parent instanceof UIData) { + isNested = Boolean.TRUE; + break; + } + } + if (isNested == null) { + isNested = Boolean.FALSE; + } + return isNested; + } else return isNested; + } + public void setColumnOrdering(String[] indexes) { ArrayList ints = new ArrayList(); int i;