It's very common that the objects underpinning specialized use
cases have custom ComponentFactory
s so that they
are rendered in a particular way. This is the case for
ClaimWizard
(see Section 2.8, “Specialized Use Cases”); for
ClaimExpenseSummary
the specialized view is
provided by the googlecharts custom component (see Section 5.3, “Google Charts”).
It's good practice to create a new Maven submodule for any custom
components; you'll find this component in the
claims-ui
module.
package org.nakedobjects.examples.claims.ui.claimwizard; import org.apache.wicket.Component; import org.apache.wicket.model.IModel; import org.nakedobjects.examples.claims.dom.claim.ClaimWizard; import org.nakedobjects.metamodel.spec.NakedObjectSpecification; import org.starobjects.wicket.viewer.components.ComponentType; import org.starobjects.wicket.viewer.components.entity.EntityComponentFactoryAbstract; import org.starobjects.wicket.viewer.components.entity.EntityModel; public class ClaimWizardComponentFactory extends EntityComponentFactoryAbstract { private static final long serialVersionUID = 1L; private static final String NAME = "wizard"; public ClaimWizardComponentFactory() { super(ComponentType.ENTITY, NAME); } @Override protected ApplicationAdvice appliesTo(IModel<?> model) { return appliesExclusivelyIf(super.appliesTo(model).applies() && isModelForWizard((EntityModel)model)); } private boolean isModelForWizard(EntityModel model) { final NakedObjectSpecification typeOfSpec = model.getTypeOfSpecification(); final NakedObjectSpecification claimWizardSpec = getSpecificationLoader().loadSpecification(ClaimWizard.class); return typeOfSpec.isOfType(claimWizardSpec); } @Override public Component createComponent(String id, IModel<?> model) { final EntityModel entityModel = (EntityModel)model; return new ClaimWizardPanel(id, entityModel); } }
package org.nakedobjects.examples.claims.ui.claimwizard; import java.util.List; import org.apache.wicket.Session; import org.apache.wicket.feedback.FeedbackMessage; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.FormComponent; import org.apache.wicket.markup.html.form.validation.AbstractFormValidator; import org.apache.wicket.markup.html.panel.ComponentFeedbackPanel; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.markup.repeater.RepeatingView; import org.apache.wicket.model.Model; import org.nakedobjects.metamodel.adapter.NakedObject; import org.nakedobjects.metamodel.commons.filters.Filter; import org.nakedobjects.metamodel.facets.object.validate.ValidateObjectFacet; import org.nakedobjects.metamodel.spec.NakedObjectSpecification; import org.nakedobjects.metamodel.spec.feature.NakedObjectAssociation; import org.nakedobjects.metamodel.spec.feature.NakedObjectAssociationFilters; import org.nakedobjects.metamodel.spec.feature.OneToOneAssociation; import org.starobjects.wicket.viewer.common.ProcessObjectPanelAbstract; import org.starobjects.wicket.viewer.common.scalars.ScalarModel; import org.starobjects.wicket.viewer.components.ComponentType; import org.starobjects.wicket.viewer.components.entity.EntityModel; import org.starobjects.wicket.viewer.mementos.PropertyMemento; import org.starobjects.wicket.viewer.util.Mementos; import com.google.common.collect.Lists; public class ClaimWizardPanel extends ProcessObjectPanelAbstract { private static final long serialVersionUID = 1L; private static final String ID_CLAIM_WIZARD_PROPERTIES_FORM = "claimWizardPropertiesForm"; private static final String ID_PROPERTIES = "properties"; public ClaimWizardPanel(String id, EntityModel model) { super(id, model); buildGui(); } private ClaimWizardForm claimWizardForm; private void buildGui() { EntityModel entityModel = getModel(); entityModel.toEditMode(); claimWizardForm = new ClaimWizardForm(ID_CLAIM_WIZARD_PROPERTIES_FORM, getModel()); addOrReplace(claimWizardForm); } class ClaimWizardForm extends Form<NakedObject> { private static final long serialVersionUID = 1L; private static final String ID_FEEDBACK = "feedback"; private static final String ID_PREVIOUS = "previous"; private static final String ID_NEXT = "next"; private static final String ID_FINISH = "finish"; private static final String PREVIOUS_ACTION_ID = "previous()"; private static final String NEXT_ACTION_ID = "next()"; private static final String FINISH_ACTION_ID = "finish()"; private FeedbackPanel feedback; public ClaimWizardForm(String id, EntityModel entityModel) { super(id, entityModel); buildFormGui(); } private void buildFormGui() { addProperties(); addButtons(); addFeedbackGui(); addValidator(); } private void addProperties() { EntityModel entityModel = (EntityModel) getModel(); NakedObject adapter = entityModel.getObject(); NakedObjectSpecification noSpec = adapter.getSpecification(); List<OneToOneAssociation> properties = visibleProperties(adapter, noSpec); RepeatingView rv = new RepeatingView(ID_PROPERTIES); add(rv); List<PropertyMemento> mementos = buildPropertyMementos(properties); for (PropertyMemento pm : mementos) { WebMarkupContainer container = new WebMarkupContainer(rv .newChildId()); rv.add(container); ScalarModel scalarModel = entityModel.getPropertyModel(pm); getComponentFactoryRegistry().addOrReplaceComponent(container, ComponentType.SCALAR, scalarModel); } } @SuppressWarnings("unchecked") private List<OneToOneAssociation> visibleProperties( NakedObject adapter, NakedObjectSpecification noSpec) { return (List<OneToOneAssociation>) noSpec .getAssociationList(visiblePropertyFilter(adapter)); } private Filter<NakedObjectAssociation> visiblePropertyFilter( NakedObject adapter) { return NakedObjectAssociationFilters.PROPERTIES .and(NakedObjectAssociationFilters.dynamicallyVisible( getAuthenticationSession(), adapter)); } private List<PropertyMemento> buildPropertyMementos( List<OneToOneAssociation> properties) { List<PropertyMemento> transform = Lists.transform(properties, Mementos.fromProperty()); // we copy into a new array list otherwise we get lazy evaluation = // reference to a non-serializable object return Lists.newArrayList(transform); } private void addButtons() { add(createButton(ID_PREVIOUS, "Previous", PREVIOUS_ACTION_ID)); add(createButton(ID_NEXT, "Next", NEXT_ACTION_ID)); add(createButton(ID_FINISH, "Finish", FINISH_ACTION_ID)); } private Button createButton(final String id, final String label, final String actionId) { return new Button(id, Model.of(label)) { private static final long serialVersionUID = 1L; @Override public void onSubmit() { boolean isValid = ClaimWizardPanel.this.isValid(getForm()); if (!isValid) { return; } executeNoArgAction(actionId); } }; } private void addFeedbackGui() { final FeedbackPanel feedback = addOrReplaceFeedback(); NakedObject adapter = getModel().getObject(); if (adapter == null) { feedback.error("cannot locate object:" + getEntityModel().getNakedObjectMemento().toString()); } } private FeedbackPanel addOrReplaceFeedback() { feedback = new ComponentFeedbackPanel(ID_FEEDBACK, this); feedback.setOutputMarkupPlaceholderTag(true); addOrReplace(feedback); return feedback; } private void addValidator() { add(new AbstractFormValidator() { private static final long serialVersionUID = 1L; @Override public FormComponent<?>[] getDependentFormComponents() { return new FormComponent<?>[0]; } @Override public void validate(Form<?> form) { EntityModel entityModel = (EntityModel) getModel(); NakedObject adapter = entityModel.getObject(); ValidateObjectFacet facet = adapter.getSpecification() .getFacet(ValidateObjectFacet.class); if (facet == null) { return; } String invalidReasonIfAny = facet.invalidReason(adapter); if (invalidReasonIfAny != null) { Session.get().getFeedbackMessages().add( new FeedbackMessage(form, invalidReasonIfAny, FeedbackMessage.ERROR)); } } }); } } }
<html> <body> <wicket:panel> <div class="claimWizard"> <form wicket:id="claimWizardPropertiesForm" class="inputForm"> <fieldset class="inputFormTable properties"> <div wicket:id="properties"> <div wicket:id="scalarNameAndValue">[scalar]</div> </div> <div class="feedbackPanel"> <span wicket:id="feedback"/> </div> <input class="submit" type="submit" wicket:id="previous"/> <input class="submit" type="submit" wicket:id="next"/> <input class="submit" type="submit" wicket:id="finish"/> </fieldset> </form> </div> </wicket:panel> </body> </html>