/* SelectedItemConverter.java {{IS_NOTE Purpose: Description: History: Tue Dec 12 15:43:28 2006, Created by Henri }}IS_NOTE Copyright (C) 2006 Potix Corporation. All Rights Reserved. {{IS_RIGHT }}IS_RIGHT */ package org.zkoss.zkplus.databind; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.zkoss.lang.Library; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Executions; import org.zkoss.zk.ui.UiException; import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.event.SelectEvent; import org.zkoss.zul.ListModel; import org.zkoss.zul.Listbox; import org.zkoss.zul.Listitem; import org.zkoss.zul.ext.Selectable; /** * Convert selected item to bean and vice versa. * * <p>Before ZK version 3.6.2(included), when use data binding with selectedItem * attribute of Listbox and/or Combobox, data binder will fire "onSelect" * event automatically when the page is first loaded or model is changed. * This is not consistent with ZK specification: only user action shall trigger * component event. So since version 3.6.3, no longer the "onSelect" event * will be fired(refer to Bug 2728704). However, some already implemented * application might count on such "side effects". User can specify in * application's WEB-INF/zk.xml following library-property to true to make it * backward compatible (i.e. still fire the "onSelect" event when page is first * loaded or model is changed)</p> * * <code><pre> * <library-property> * <name>org.zkoss.zkplus.databind.onSelectWhenLoad</name> * <value>true</value> * </library-property> * </pre></code> * @author Henri Chen * @deprecated As of release 7.0.0, replace with new ZK binding. */ public class SelectedItemConverter implements TypeConverter, java.io.Serializable { private static final long serialVersionUID = 200808191439L; @SuppressWarnings("unchecked") public Object coerceToUi(Object val, Component comp) { //load Listbox lbx = (Listbox) comp; final ListModel xmodel = lbx.getModel(); if (val != null) { if (xmodel instanceof BindingListModel) { final BindingListModel model = (BindingListModel) xmodel; int index = model.indexOf(val); if (index >= 0) { final Listitem item = lbx.getItemAtIndex(index); //Bug #2728704: Listbox with databinding generates onSelect w/o user action //Shall not fire event by spec. For backward compatibility(still want to //fire onSelect event as usual), user can specifies in zk.xml //<library-property> // <name>org.zkoss.zkplus.databind.onSelectWhenLoad</name> // <value>true</value> //</library-property> //then data binder will still fire the onSelect event as usual. if (SelectedItemConverter.isOnSelectWhenLoad()) { final int selIndex = lbx.getSelectedIndex(); //We need this to support load-when:onSelect when first load //the page in (so it is called only once). if (item != null && selIndex != index) { // bug 1647817, avoid endless-loop Set<Listitem> items = new HashSet<Listitem>(); items.add(item); //bug #2140491 Executions.getCurrent().setAttribute("zkoss.zkplus.databind.ON_SELECT" + lbx.getUuid(), Boolean.TRUE); Events.postEvent(new SelectEvent<Listitem, Object>("onSelect", lbx, items, item)); } } //ZK-927 zkplus databinding1 should auto-wrapping BindingListModelXxx with setMultiple() and Selectable handled if (model instanceof Selectable) { ((Selectable) model).addToSelection(val); return TypeConverter.IGNORE; } return item; } } else if (xmodel == null) { //no model case, assume Listitem.value to be used with selectedItem //iterate to find the selected item assume the value (select mold) for (final Iterator it = lbx.getItems().iterator(); it.hasNext();) { final Listitem li = (Listitem) it.next(); if (val.equals(li.getValue())) { return li; } } } else { throw new UiException("model of the databind listbox " + lbx + " must be an instanceof of org.zkoss.zkplus.databind.BindingListModel." + xmodel); } } //Bug ZK-1714: clear selection if value is null if (xmodel != null && xmodel instanceof Selectable) { ((Selectable) xmodel).clearSelection(); } return null; } private static Boolean _onSelectWhenLoad; /*package*/ static boolean isOnSelectWhenLoad() { if (_onSelectWhenLoad == null) { final String str = Library.getProperty("org.zkoss.zkplus.databind.onSelectWhenLoad", "false"); _onSelectWhenLoad = Boolean.valueOf("true".equals(str)); } return _onSelectWhenLoad.booleanValue(); } public Object coerceToBean(Object val, Component comp) { //save final Listbox lbx = (Listbox) comp; if (Executions.getCurrent().getAttribute("zkoss.zkplus.databind.ON_SELECT" + lbx.getUuid()) != null) { //bug #2140491 //triggered by coerceToUi(), ignore this Executions.getCurrent().removeAttribute("zkoss.zkplus.databind.ON_SELECT" + lbx.getUuid()); return TypeConverter.IGNORE; } if (val != null) { final ListModel model = lbx.getModel(); //no model case, assume Listitem.value to be used with selectedItem return model != null ? model.getElementAt(((Listitem) val).getIndex()) : ((Listitem) val).getValue(); } return null; } }