package pt.ist.renderers.extensions; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.commons.collections.Predicate; import pt.ist.renderers.InputRenderer; import pt.ist.renderers.components.HtmlActionLink; import pt.ist.renderers.components.HtmlBlockContainer; import pt.ist.renderers.components.HtmlComponent; import pt.ist.renderers.components.HtmlContainer; import pt.ist.renderers.components.HtmlMultipleHiddenField; import pt.ist.renderers.components.HtmlTable; import pt.ist.renderers.components.HtmlTableRow; import pt.ist.renderers.components.controllers.HtmlActionLinkController; import pt.ist.renderers.components.state.IViewState; import pt.ist.renderers.contexts.PresentationContext; import pt.ist.renderers.extensions.converters.DomainObjectKeyArrayConverter; import pt.ist.renderers.layouts.Layout; import pt.ist.renderers.layouts.TabularLayout; import pt.ist.renderers.model.MetaObject; import pt.ist.renderers.model.MetaObjectFactory; import pt.ist.renderers.model.MetaSlot; import pt.ist.renderers.model.MetaSlotKey; import pt.ist.renderers.schemas.Schema; import pt.ist.renderers.utils.RenderKit; import pt.ist.renderers.utils.RenderMode; import pt.ist.renderers.utils.RenderUtils; /** * This renderer allows you get a list as input but delegates part of the * list's management to an external action. Each one of the slot's values * will be presented in an html list. The renderer manages the removal of * values from the list. So a delete action link will appear next to each * object's presentation. An add action link will allow the user to start the * external use-case that will add a new value to the list. * *
* Example: *
* The action can obtain a representation of the viewstate suitable for * including in a hidden field by doing: *
* IViewState viewState = RenderUtils.getViewState(); * String encoded = ViewState.encodeToBase64(viewState); ** Retrieving the viewstate from it's encoded state and preparing before * sending control to the inicial page can be done with: *
* IViewState viewState = ViewState.decodeFromBase64(<encoded viewstate>); * viewState.setUser(UserIdentityFactory.create(request)); * // update slot in viewstate * RenderUtils.setViewState(viewState); ** * Updating the viewstate consists of adding a new value to the slot's. * This must only be done through the meta-object contained in the viewstate: *
* MetaSlot slot = <find slot in viewState.getMetaObject().getSlots()>; * List values = new ArrayList((List) slot.getObject()); * values.add(<the new value>); * slot.setObject(values); ** * The slot that was beeing managed is available in viewstate attributes. You can * get information about the slot with: *
* String slotName = viewState.getAttribute(ManageableListRenderer.MANAGED_SLOT_NAME); * MetaSlotKey slotKey = viewState.getAttribute(ManageableListRenderer.MANAGED_SLOT_KEY); ** * @property */ public void setDestination(String destination) { this.destination = destination; } @Override protected Layout getLayout(Object object, Class type) { MetaObject metaObject = getInputContext().getMetaObject(); return new ManageableListLayout((Collection) metaObject.getObject()); } private class ManageableListLayout extends TabularLayout { private final List objects; private final HtmlMultipleHiddenField hiddenValues; public ManageableListLayout(Collection collection) { this.objects = new ArrayList(collection); this.hiddenValues = new HtmlMultipleHiddenField(); this.hiddenValues.setTargetSlot((MetaSlotKey) getInputContext().getMetaObject().getKey()); // HACK: severe dependecy with fenix project this.hiddenValues.setConverter(new DomainObjectKeyArrayConverter()); } @Override protected int getNumberOfColumns() { return 2; } @Override protected int getNumberOfRows() { return this.objects == null ? 0 : this.objects.size(); } @Override protected HtmlComponent getHeaderComponent(int columnIndex) { return null; } @Override public HtmlComponent createComponent(Object object, Class type) { HtmlComponent component = super.createComponent(object, type); HtmlContainer container = new HtmlBlockContainer(); container.addChild(component); container.addChild(this.hiddenValues); HtmlActionLink link = new HtmlActionLink(); link.setName(getInputContext().getMetaObject().getKey().toString() + "/add"); link.setText(RenderUtils.getResourceString("renderers.list.management.add")); link.setController(new FollowDestinationController((MetaSlot) getInputContext().getMetaObject())); container.addChild(link); return container; } @Override public void applyStyle(HtmlComponent component) { HtmlContainer container = (HtmlContainer) component; super.applyStyle(container.getChildren().get(0)); } @Override protected HtmlComponent getComponent(int rowIndex, int columnIndex) { Object object = this.objects.get(rowIndex); Schema schema = RenderKit.getInstance().findSchema(getEachSchema()); String layout = getEachLayout(); MetaObject metaObject = MetaObjectFactory.createObject(object, schema); if (columnIndex == 0) { this.hiddenValues.addValue(metaObject.getKey().toString()); PresentationContext newContext = getContext().createSubContext(metaObject); newContext.setLayout(layout); newContext.setRenderMode(RenderMode.getMode("output")); RenderKit kit = RenderKit.getInstance(); return kit.render(newContext, object); } else { HtmlActionLink link = new HtmlActionLink(); String prefix = getInputContext().getMetaObject().getKey().toString(); link.setName(prefix + "/delete/" + rowIndex); link.setText(RenderUtils.getResourceString("renderers.list.management.delete")); HtmlTableRow row = getTable().getRows().get(rowIndex); link.setController(new RemoveLineController(getTable(), this.hiddenValues, row, prefix)); return link; } } } class RemoveLineController extends HtmlActionLinkController { private final HtmlTable table; private final HtmlTableRow row; private final HtmlMultipleHiddenField values; private final String prefix; public RemoveLineController(HtmlTable table, HtmlMultipleHiddenField values, HtmlTableRow row, String prefix) { this.table = table; this.values = values; this.row = row; this.prefix = prefix; } @Override public void linkPressed(IViewState viewState, HtmlActionLink link) { int index = this.table.getRows().indexOf(row); this.table.removeRow(this.row); this.values.removeValue(index); renameLinks(); } private void renameLinks() { List