/* AbstractListModelConverter.java Purpose: Description: History: 2011/12/12 Created by Dennis Chen Copyright (C) 2011 Potix Corporation. All Rights Reserved. */ package org.zkoss.bind.converter.sys; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import org.zkoss.bind.BindContext; import org.zkoss.bind.Converter; import org.zkoss.bind.xel.zel.BindELContext; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.UiException; import org.zkoss.zul.GroupsModel; import org.zkoss.zul.ListModel; import org.zkoss.zul.ListModelArray; import org.zkoss.zul.ListModelList; import org.zkoss.zul.ListModelMap; import org.zkoss.zul.ListModelSet; import org.zkoss.zul.ext.Selectable; import org.zkoss.zul.impl.GroupsListModel; /** * The abstract {@link Converter} implementation for converting collection to ListModel and vice versa. * @author dennis * @since 6.0.0 */ public abstract class AbstractListModelConverter<C extends Component> implements Converter<Object, Object, C>, Serializable { private static final long serialVersionUID = 201108171744L; /** * @param comp the component that has listmodel * @return null if no list model for the component */ protected abstract ListModel<?> getComponentModel(C comp); /** * post processing the wrapped model. default return original one * @param ctx the context * @param comp the component of the converter * @param model the wrapped model * @return the list model */ protected ListModel<?> handleWrappedModel(BindContext ctx, C comp, ListModel<?> model) { return model; } /** Convert a Set, Map, List, Object[], Enum, or other kind of ListModel to associated {@link ListModel}. * @param val must be instanceof Set, Map, List, Object[], Enum Class, or other kind of ListModel implementation. * @param comp associated component * @param ctx bind context */ @SuppressWarnings({ "rawtypes", "unchecked" }) public Object coerceToUi(Object val, C comp, BindContext ctx) { if (val == null) { val = new ArrayList(); } ListModel model = null; if (val instanceof ListModel) { BindELContext.addModel(comp, val); //ZK-758. @see AbstractRenderer#addItemReference return val; } else if (val instanceof Set) { model = new ListModelSet((Set) val, false); //ZK-1528, doesn't use live } else if (val instanceof List) { //ZK-1528, doesn't use live, //user should use ListModel if he want to dynamically change inside element. model = new ListModelList((List) val, false); } else if (val instanceof Map) { model = new ListModelMap((Map) val, false); //ZK-1528, doesn't use live } else if (val instanceof Object[]) { model = new ListModelArray((Object[]) val, false); //ZK-1528, doesn't use live } else if ((val instanceof Class) && Enum.class.isAssignableFrom((Class) val)) { model = new ListModelArray((Object[]) ((Class) val).getEnumConstants(), false); //ZK-1528, doesn't use live } else if (val instanceof GroupsModel) { //feature#2866506: Data Binding shall support GroupsModel with Listbox/Grid model = GroupsListModel.toListModel((GroupsModel) val); return model; } else { throw new UiException( "Expects java.util.Set, java.util.List, java.util.Map, Object[], Enum Class, GroupsModel, or ListModel only. " + val.getClass()); } // final Container container = new Container(model); final ListModel compModel = getComponentModel(comp); if (compModel instanceof Selectable) { Selectable selectable = ((Selectable) compModel); ((Selectable) model).setMultiple(selectable.isMultiple()); //Should we check the contains? it has O(m) issue and O(mn) in array case //if not, there is a issue if the new data doesn't contains the selected obj // for(Object selected:container.contains(selectable.getSelection())){ // ((Selectable) model).addToSelection(selected); // } //no need to check contains, user should remove the selection if it is not in current list anymore //that could be done by binding to selectedItem or selectedItems for (Object selected : selectable.getSelection()) { ((Selectable) model).addToSelection(selected); } } model = handleWrappedModel(ctx, comp, model); BindELContext.addModel(comp, model); //ZK-758. @see AbstractRenderer#addItemReference return model; } /** Convert a {@link ListModel} to Set, Map, List, or ListModel (itself). * @param val must be ListModelSet, ListModelList, ListModelMap, or other kind of ListModel * @param comp associated component * @param ctx bind context */ @SuppressWarnings("rawtypes") public Object coerceToBean(Object val, C comp, BindContext ctx) { if (val == null) { throw new NullPointerException("value"); } if (val instanceof ListModelSet) { return ((ListModelSet) val).getInnerSet(); } else if (val instanceof ListModelList) { return ((ListModelList) val).getInnerList(); } else if (val instanceof ListModelMap) { return ((ListModelMap) val).getInnerMap(); } else if (val instanceof ListModelArray) { return ((ListModelArray) val).getInnerArray(); } else if (val instanceof GroupsListModel) { return ((GroupsListModel) val).getGroupsModel(); } else if (val instanceof ListModel) { return val; } else { throw new UiException( "Expects ListModelSet, ListModelList, ListModelMap, GroupsListModel or ListModel only." + val.getClass()); } } }