package pt.ist.renderers; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.commons.lang.StringUtils; import pt.ist.renderers.components.HtmlCheckBox; import pt.ist.renderers.components.HtmlComponent; import pt.ist.renderers.components.HtmlContainer; import pt.ist.renderers.components.HtmlInlineContainer; import pt.ist.renderers.components.HtmlMultipleHiddenField; import pt.ist.renderers.components.HtmlText; import pt.ist.renderers.components.controllers.HtmlController; import pt.ist.renderers.components.state.IViewState; import pt.ist.renderers.layouts.Layout; import pt.ist.renderers.layouts.TabularLayout; import pt.ist.renderers.model.MetaObject; import pt.ist.renderers.model.MetaObjectCollection; import pt.ist.renderers.model.MetaObjectFactory; import pt.ist.renderers.model.MetaSlot; import pt.ist.renderers.schemas.Schema; import pt.ist.renderers.utils.RenderUtils; /** * 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.renderers.DataProvider data provider}. * *

* Example: * * * * * * * * * * * * * * * * * * * * * * * * * *
NameAgeGender
Name A20Female
Name B22Male
Name C21Female
* * @author pcma */ public class TabularOptionInputRenderer extends SelectionRenderer { private String classes; private String emptyMessageKey; private String emptyMessageBundle; private String columnClasses; /** * Selects column classes * * @property * */ public String getColumnClasses() { return columnClasses; } public void setColumnClasses(String columnClasses) { this.columnClasses = columnClasses; } @Override protected Layout getLayout(Object object, Class type) { List metaObjects = 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 = getContext().getSchema(); for (Object object : collection) { metaObjects.add(MetaObjectFactory.createObject(object, schema)); } } return metaObjects; } @Override public String getClasses() { return classes; } @Override 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 { protected List metaObjects; protected Collection objectsReceived; protected HtmlMultipleHiddenField hiddenField; protected 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); if (metaObjects.isEmpty() && !StringUtils.isEmpty(getEmptyMessageKey())) { HtmlText emptyMessage = new HtmlText( RenderUtils.getResourceString(getEmptyMessageBundle(), getEmptyMessageKey()), false); container.addChild(emptyMessage); } 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 } 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; } 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; } }; }