package pt.ist.fenixWebFramework.renderers; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import pt.ist.fenixWebFramework.renderers.components.HtmlCheckBox; import pt.ist.fenixWebFramework.renderers.components.HtmlComponent; import pt.ist.fenixWebFramework.renderers.components.HtmlContainer; import pt.ist.fenixWebFramework.renderers.components.HtmlInlineContainer; import pt.ist.fenixWebFramework.renderers.components.HtmlMultipleHiddenField; import pt.ist.fenixWebFramework.renderers.components.HtmlText; import pt.ist.fenixWebFramework.renderers.components.controllers.HtmlController; import pt.ist.fenixWebFramework.renderers.components.converters.Converter; import pt.ist.fenixWebFramework.renderers.components.state.IViewState; import pt.ist.fenixWebFramework.renderers.layouts.Layout; import pt.ist.fenixWebFramework.renderers.layouts.TabularLayout; import pt.ist.fenixWebFramework.renderers.model.MetaObject; import pt.ist.fenixWebFramework.renderers.model.MetaObjectCollection; import pt.ist.fenixWebFramework.renderers.model.MetaObjectFactory; import pt.ist.fenixWebFramework.renderers.model.MetaSlot; import pt.ist.fenixWebFramework.renderers.schemas.Schema; import pt.ist.fenixWebFramework.renderers.utils.RenderKit; import org.apache.commons.beanutils.BeanComparator; /** * This renderer allows you choose several object from a list of choices. The list of choices is * presented in a table but each row has a checkbox that allows you to select the object in that * row. * *

* The list of options is given by a {@link pt.ist.fenixWebFramework.renderers.DataProvider data provider}. * *

* Example: * * * * * * * * * * * * * * * * * * * * * * * * * *
NameAgeGender
Name A20Female
Name B22Male
Name C21Female
* * @author pcma */ public class TabularOptionInputRenderer extends InputRenderer { private String providerClass; private DataProvider provider; private String classes; private String emptyMessageKey; private String emptyMessageBundle; private String columnClasses; private String sortBy; public String getSortBy() { return sortBy; } /** * Selects column classes * * @property * */ public String getColumnClasses() { return columnClasses; } public void setColumnClasses(String columnClasses) { this.columnClasses = columnClasses; } /** * Selects the sorting criteria to apply to the collection of objects before presenting them. * * @property * @see pt.ist.fenixWebFramework.renderers.utils.RenderUtils#sortCollectionWithCriteria(Collection, String) */ public void setSortBy(String sort) { sortBy = sort; } public String getProviderClass() { return providerClass; } /** * Chooses the class of the provider that will be used to determine the list of options. * * @property */ public void setProviderClass(String providerClass) { this.providerClass = providerClass; } protected DataProvider getProvider() { if (this.provider == null) { String className = getProviderClass(); try { Class providerCass = (Class) Class.forName(className); this.provider = (DataProvider) providerCass.newInstance(); } catch (Exception e) { throw new RuntimeException("could not get a data provider instance", e); } } return this.provider; } protected Converter getConverter() { DataProvider provider = getProvider(); return provider.getConverter(); } protected Collection getPossibleObjects() { Object object = getInputContext().getParentContext().getMetaObject().getObject(); Object value = getInputContext().getMetaObject().getObject(); if (getProviderClass() != null) { try { DataProvider provider = getProvider(); Collection collection = (Collection) provider.provide(object, value); if (getSortBy() != null) { Collections.sort((List) collection, new BeanComparator(getSortBy())); } return collection; } catch (Exception e) { throw new RuntimeException("exception while executing data provider", e); } } else { throw new RuntimeException("a data provider must be supplied"); } } @Override protected Layout getLayout(Object object, Class type) { List metaObjects = (List) getMetaObjects(getPossibleObjects()); Collection objectsReceived = (Collection) object; HtmlMultipleHiddenField hiddenField = new HtmlMultipleHiddenField(); hiddenField.bind((MetaSlot) getContext().getMetaObject()); hiddenField.setConverter(getConverter()); return new CheckableTabularLayout(metaObjects,objectsReceived,hiddenField); } private List getMetaObjects(Collection collection) { List metaObjects = new ArrayList(); MetaObject contextMetaObject = getContext().getMetaObject(); if (contextMetaObject instanceof MetaObjectCollection) { // reuse meta objects MetaObjectCollection multipleMetaObject = (MetaObjectCollection) getContext() .getMetaObject(); for (Object object : collection) { for (MetaObject metaObject : multipleMetaObject.getAllMetaObjects()) { if (object.equals(metaObject.getObject())) { metaObjects.add(metaObject); break; } } } } else { Schema schema = RenderKit.getInstance().findSchema(getContext().getSchema()); for (Object object : collection) { metaObjects.add(MetaObjectFactory.createObject(object, schema)); } } return metaObjects; } public String getClasses() { return classes; } public void setClasses(String classes) { this.classes = classes; } public String getEmptyMessageBundle() { return emptyMessageBundle; } public void setEmptyMessageBundle(String emptyMessageBundle) { this.emptyMessageBundle = emptyMessageBundle; } public String getEmptyMessageKey() { return emptyMessageKey; } public void setEmptyMessageKey(String emptyMessageKey) { this.emptyMessageKey = emptyMessageKey; } public class CheckableTabularLayout extends TabularLayout { private List metaObjects; private Collection objectsReceived; private HtmlMultipleHiddenField hiddenField; private List checkboxes = new ArrayList(); public CheckableTabularLayout(List metaObjects, Collection collection, HtmlMultipleHiddenField hiddenField) { this.metaObjects = metaObjects; this.objectsReceived = collection; this.hiddenField = hiddenField; } public HtmlMultipleHiddenField getHiddenField() { return hiddenField; } public List getCheckBoxes() { return checkboxes; } @Override public HtmlComponent createLayout(Object object, Class type) { HtmlContainer container = new HtmlInlineContainer(); HtmlComponent component = super.createLayout(object, type); container.addChild(hiddenField); container.addChild(component); hiddenField.setController(new HtmlController() { @Override public void execute(IViewState viewState) { List values = new ArrayList(); for (HtmlCheckBox checkBox : checkboxes) { if (checkBox.isChecked()) { values.add(checkBox.getValue()); } } hiddenField.setValues(values.toArray(new String[0])); } }); return container; } @Override protected boolean hasHeader() { return metaObjects.size() > 0; } @Override protected HtmlComponent getHeaderComponent(int columnIndex) { String text = ""; if (columnIndex != 0) { text = metaObjects.get(0).getSlots().get(columnIndex - 1).getLabel(); } return new HtmlText(text, false); } @Override protected int getNumberOfColumns() { if (metaObjects.size() > 0) { MetaObject metaObject = metaObjects.get(0); return metaObject.getSlots().size() + 1; // +1 due to the // checkbox } else { return 0; } } @Override protected int getNumberOfRows() { return metaObjects.size(); } @Override protected HtmlComponent getComponent(int rowIndex, int columnIndex) { if (columnIndex == 0) { HtmlCheckBox checkBox = new HtmlCheckBox(); this.checkboxes.add(checkBox); MetaObject metaObject = metaObjects.get(rowIndex); checkBox.setUserValue(metaObject.getKey().toString()); checkBox.setName(hiddenField.getName() + "/" + metaObject.getKey().toString()); if (objectsReceived != null && objectsReceived.contains(metaObject.getObject())) { checkBox.setChecked(true); } return checkBox; } else { MetaSlot slot = getSlotUsingName(metaObjects.get(rowIndex), columnIndex - 1); slot.setReadOnly(true); return renderSlot(slot); } } protected MetaSlot getSlotUsingName(MetaObject object, int columnIndex) { MetaObject referenceObject = metaObjects.get(0); MetaSlot referenceSlot = referenceObject.getSlots().get(columnIndex); MetaSlot directSlot = object.getSlots().get(columnIndex); // common // case if (directSlot.getName().equals(referenceSlot.getName())) { return directSlot; } for (MetaSlot slot : object.getSlots()) { if (slot.getName().equals(referenceSlot.getName())) { return slot; } } return null; } }; }