001: /* BindingListitemRenderer.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Sat Feb 3 14:18:27 2007, Created by Henri
010: }}IS_NOTE
011:
012: Copyright (C) 2007 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: }}IS_RIGHT
016: */
017: package org.zkoss.zkplus.databind;
018:
019: import org.zkoss.zk.ui.Component;
020: import org.zkoss.zk.ui.sys.ComponentsCtrl;
021:
022: import org.zkoss.zul.Grid;
023: import org.zkoss.zul.Listbox;
024: import org.zkoss.zul.Listitem;
025: import org.zkoss.zul.Listcell;
026: import org.zkoss.zul.ListitemRenderer;
027: import org.zkoss.zul.ListitemRendererExt;
028:
029: import java.util.Map;
030: import java.util.HashMap;
031: import java.util.List;
032: import java.util.ArrayList;
033: import java.util.Iterator;
034:
035: import java.io.Serializable;
036:
037: /*package*/class BindingListitemRenderer implements
038: org.zkoss.zul.ListitemRenderer,
039: org.zkoss.zul.ListitemRendererExt, Serializable {
040: private static final String KIDS = "zkplus.databind.KIDS";
041: private Listitem _template;
042: private DataBinder _binder;
043: private int x = 0;
044:
045: public BindingListitemRenderer(Listitem template, DataBinder binder) {
046: _template = template;
047: _binder = binder;
048: }
049:
050: //-- ListitemRendererExt --//
051: public Listitem newListitem(Listbox listbox) {
052: //clone from template
053: final Listitem clone = (Listitem) _template.clone();
054: //TODO: see if databinder has this kind of Listitem, if not, add new CollectionListItem
055: //avoid duplicate id error, will set to new id when render()
056: if (!ComponentsCtrl.isAutoId(clone.getId())) {
057: clone.setId("@" + clone.getUuid() + x++);
058: }
059:
060: //link cloned component with template
061: //each Listitem and and it decendants share the same templatemap
062: Map templatemap = new HashMap(7);
063: linkTemplates(clone, _template, templatemap);
064:
065: //link this template map to parent templatemap (Listbox in Listbox)
066: Map parenttemplatemap = (Map) listbox
067: .getAttribute(_binder.TEMPLATEMAP);
068: if (parenttemplatemap != null) {
069: templatemap.put(_binder.TEMPLATEMAP, parenttemplatemap);
070: }
071: //kept clone kids somewhere to avoid create too many components in browser
072: final List kids = new ArrayList(clone.getChildren());
073: clone.setAttribute(KIDS, kids);
074: clone.getChildren().clear();
075: return clone;
076: }
077:
078: public Listcell newListcell(Listitem item) {
079: return null;
080: }
081:
082: public int getControls() {
083: //bug1826736, add DETACH_ON_UNLOAD to aviod such bug.
084: //That is, never reuse Listitem: Listbox will clear the kids of the
085: //first Listcell and the binding assoicated with the kids are lost.
086: return DETACH_ON_RENDER | DETACH_ON_UNLOAD;
087: }
088:
089: //-- ListitemRenderer --//
090: public void render(Listitem item, java.lang.Object bean) {
091: final List kids = (List) item.getAttribute(KIDS);
092: item.getChildren().addAll(kids);
093: // item.removeAttribute(KIDS);
094:
095: //remove template mark of cloned component and its decendant
096: _binder.setupTemplateComponent(item, null);
097:
098: //setup clone id
099: setupCloneIds(item);
100:
101: //bind bean to the associated listitem and its decendant
102: final String varname = (String) _template
103: .getAttribute(_binder.VARNAME);
104: final Map templatemap = (Map) item
105: .getAttribute(_binder.TEMPLATEMAP);
106: templatemap.put(varname, bean);
107:
108: //apply the data binding
109: _binder.loadComponent(item);
110: }
111:
112: //link cloned components with bindings of templates
113: private void linkTemplates(Component clone, Component template,
114: Map templatemap) {
115: if (_binder.existsBindings(template)) {
116: templatemap.put(template, clone);
117: clone.setAttribute(_binder.TEMPLATEMAP, templatemap);
118: clone.setAttribute(_binder.TEMPLATE, template);
119: }
120:
121: //Listbox in Listbox, Listbox in Grid, Grid in Listbox, Grid in Grid, no need to process
122: if (template instanceof Grid || template instanceof Listbox) {
123: return;
124: }
125:
126: final Iterator itt = template.getChildren().iterator();
127: final Iterator itc = clone.getChildren().iterator();
128: while (itt.hasNext()) {
129: final Component t = (Component) itt.next();
130: final Component c = (Component) itc.next();
131: linkTemplates(c, t, templatemap); //recursive
132: }
133: }
134:
135: //setup id of cloned components (cannot called until the component is attached to Listbox)
136: private void setupCloneIds(Component clone) {
137: //bug #1813271: Data binding generates duplicate ids in grids/listboxes
138: clone.setId("@" + clone.getUuid() + x++); //init id to @uuid to avoid duplicate id issue
139:
140: //Listbox in Listbox, Listbox in Grid, Grid in Listbox, Grid in Grid, no need to process
141: if (clone instanceof Grid || clone instanceof Listbox) {
142: return;
143: }
144:
145: for (final Iterator it = clone.getChildren().iterator(); it
146: .hasNext();) {
147: setupCloneIds((Component) it.next()); //recursive
148: }
149: }
150: }
|