/* BindTreeitemRenderer.java Purpose: Description: History: Aug 17, 2011 3:35:42 PM, Created by henrichen Copyright (C) 2011 Potix Corporation. All Rights Reserved. */ package org.zkoss.bind.impl; import org.zkoss.bind.sys.TemplateResolver; import org.zkoss.lang.Objects; import org.zkoss.lang.Strings; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.UiException; import org.zkoss.zk.ui.util.ForEachStatus; import org.zkoss.zk.ui.util.Template; import org.zkoss.zul.Attributes; import org.zkoss.zul.Tree; import org.zkoss.zul.Treecell; import org.zkoss.zul.Treeitem; import org.zkoss.zul.TreeitemRenderer; import org.zkoss.zul.Treerow; /** * Treeitem renderer for binding. * @author henrichen * @since 6.0.0 */ public class BindTreeitemRenderer extends AbstractRenderer implements TreeitemRenderer<Object> { private static final long serialVersionUID = 1463169907348730644L; public void render(final Treeitem item, final Object data, final int index) throws Exception { final Tree tree = item.getTree(); final Component parent = item.getParent(); final Template tm = resolveTemplate(tree, parent, data, index, -1, "model"); // ZK-2859: to replace the id of the the original treeitem that is not from the template final String oldId = item.getId(); if (!Strings.isEmpty(oldId)) { item.setId("$$FAKE_ID$$"); } if (tm == null) { Treecell tc = new Treecell(Objects.toString(data)); Treerow tr = null; item.setValue(data); if (item.getTreerow() == null) { tr = new Treerow(); tr.setParent(item); } else { tr = item.getTreerow(); tr.getChildren().clear(); } tc.setParent(tr); } else { final ForEachStatus iterStatus = new AbstractForEachStatus() { //provide iteration status in this context private static final long serialVersionUID = 1L; public int getIndex() { return index; } public Object getCurrent() { return data; } public Integer getEnd() { throw new UiException("end attribute is not supported"); } }; final String var = (String) tm.getParameters().get(EACH_ATTR); final String varnm = var == null ? EACH_VAR : var; //var is not specified, default to "each" final String itervar = (String) tm.getParameters().get(STATUS_ATTR); final String itervarnm = itervar == null ? (var == null ? EACH_STATUS_VAR : varnm + STATUS_POST_VAR) : itervar; //provide default value if not specified //bug 1188, EL when nested var and itervar Object oldVar = parent.getAttribute(varnm); Object oldIter = parent.getAttribute(itervarnm); parent.setAttribute(varnm, data); parent.setAttribute(itervarnm, iterStatus); final Component[] items = filterOutShadows(parent, tm.create(parent, item, null, null)); // Bug ZK-2882 if (oldVar == null) { parent.removeAttribute(varnm); } else { parent.setAttribute(varnm, oldVar); } if (oldIter == null) { parent.removeAttribute(itervarnm); } else { parent.setAttribute(itervarnm, oldIter); } if (items.length != 1) throw new UiException("The model template must have exactly one item, not " + items.length); final Treeitem ti = (Treeitem) items[0]; ti.setAttribute(BinderImpl.VAR, varnm); // for the converter to get the value //zk-1698, mvvm tree performance issue, //no need to use reference binding for tree because we don't allow it to notify a path change also. ti.setAttribute(varnm, data); ti.setAttribute(itervarnm, iterStatus); //ZK-1787 When the viewModel tell binder to reload a list, the other component that bind a bean in the list will reload again //move TEMPLATE_OBJECT (was set in resoloveTemplate) to current for check in addTemplateTracking ti.setAttribute(TemplateResolver.TEMPLATE_OBJECT, parent.removeAttribute(TemplateResolver.TEMPLATE_OBJECT)); //add template dependency addTemplateTracking(tree, ti, data, index, -1); if (ti.getValue() == null) //template might set it ti.setValue(data); // ZK-2859: change the id back if ti is actually the original treeitem which is not from the template if ("$$FAKE_ID$$".equals(ti.getId())) { ti.setId(oldId); } item.setAttribute(Attributes.MODEL_RENDERAS, ti); //indicate a new item is created to replace the existent one item.detach(); } } }