package org.apache.isis.viewer.wicket.ui.components.actions;
import java.util.List;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.IModel;
import org.apache.isis.applib.annotation.SemanticsOf;
import org.apache.isis.applib.services.message.MessageService;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
import org.apache.isis.core.metamodel.services.ServicesInjector;
import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
import org.apache.isis.viewer.wicket.model.hints.IsisActionCompletedEvent;
import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
import org.apache.isis.viewer.wicket.model.mementos.ActionParameterMemento;
import org.apache.isis.viewer.wicket.model.models.ActionArgumentModel;
import org.apache.isis.viewer.wicket.model.models.ActionModel;
import org.apache.isis.viewer.wicket.ui.ComponentType;
import org.apache.isis.viewer.wicket.ui.components.scalars.PanelWithChoices;
import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract2;
import org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage;
import org.apache.isis.viewer.wicket.ui.panels.PanelUtil;
import org.apache.isis.viewer.wicket.ui.panels.PromptFormAbstract;
import de.agilecoders.wicket.extensions.markup.html.bootstrap.confirmation.ConfirmationBehavior;
class ActionParametersForm extends PromptFormAbstract<ActionModel> {
private static final long serialVersionUID = 1L;
public ActionParametersForm(
final String id,
final Component parentPanel,
final WicketViewerSettings settings,
final ActionModel actionModel) {
super(id, parentPanel, settings, actionModel);
}
private ActionModel getActionModel() {
return (ActionModel) super.getModel();
}
@Override
protected void addParameters() {
final ActionModel actionModel = getActionModel();
final RepeatingView rv = new RepeatingView(ActionParametersFormPanel.ID_ACTION_PARAMETERS);
add(rv);
paramPanels.clear();
List<ActionParameterMemento> parameterMementos = actionModel.primeArgumentModels();
for (final ActionParameterMemento apm : parameterMementos) {
final WebMarkupContainer container = new WebMarkupContainer(rv.newChildId());
rv.add(container);
final ActionArgumentModel actionArgumentModel = actionModel.getArgumentModel(apm);
actionArgumentModel.setActionArgsHint(actionModel.getArgumentsAsArray());
final ScalarPanelAbstract2 paramPanel = newParamPanel(container, actionArgumentModel);
paramPanels.add(paramPanel);
}
}
private ScalarPanelAbstract2 newParamPanel(final WebMarkupContainer container, final IModel<?> model) {
final Component component = getComponentFactoryRegistry()
.addOrReplaceComponent(container, ComponentType.SCALAR_NAME_AND_VALUE, model);
final ScalarPanelAbstract2 paramPanel =
component instanceof ScalarPanelAbstract2
? (ScalarPanelAbstract2) component
: null;
if (paramPanel != null) {
paramPanel.setOutputMarkupId(true);
paramPanel.notifyOnChange(this);
}
return paramPanel;
}
@Override
protected Object newCompletedEvent(final AjaxRequestTarget target, final Form<?> form) {
return new IsisActionCompletedEvent(getActionModel(), target, form);
}
@Override
protected void doConfigureOkButton(final AjaxButton okButton) {
applyAreYouSure(okButton);
}
/**
* If the {@literal @}Action has "are you sure?" semantics then apply {@link ConfirmationBehavior}
* that will ask for confirmation before executing the Ajax request.
*
* @param button The button which action should be confirmed
*/
private void applyAreYouSure(AjaxButton button) {
ActionModel actionModel = getActionModel();
final ObjectAction action = actionModel.getActionMemento().getAction(getSpecificationLoader());
SemanticsOf semanticsOf = SemanticsOf.from(action.getSemantics());
final ServicesInjector servicesInjector = getPersistenceSession().getServicesInjector();
PanelUtil.addConfirmationDialogIfAreYouSureSemantics(button, semanticsOf, servicesInjector);
}
@Override
public void onUpdate(AjaxRequestTarget target, ScalarPanelAbstract2 scalarPanel) {
final ActionModel actionModel = getActionModel();
final ObjectAdapter[] pendingArguments = actionModel.getArgumentsAsArray();
try {
final ObjectAction action = actionModel.getActionMemento().getAction(getSpecificationLoader());
final int numParams = action.getParameterCount();
for (int i = 0; i < numParams; i++) {
final ScalarPanelAbstract2 paramPanel = paramPanels.get(i);
if (paramPanel != null && paramPanel instanceof PanelWithChoices) {
final PanelWithChoices panelWithChoices = (PanelWithChoices) paramPanel;
// this could throw a ConcurrencyException as we may have to reload the
// object adapter of the action in order to compute the choices
// (and that object adapter might have changed)
if (panelWithChoices.updateChoices(pendingArguments)) {
paramPanel.repaint(target);
}
}
}
} catch (ConcurrencyException ex) {
// second attempt should succeed, because the Oid would have
// been updated in the attempt
ObjectAdapter targetAdapter = getActionModel().getTargetAdapter();
// forward onto the target page with the concurrency exception
final EntityPage entityPage = new EntityPage(targetAdapter, ex);
setResponsePage(entityPage);
final MessageService messageService = getServicesInjector().lookupService(MessageService.class);
messageService.warnUser(ex.getMessage());
return;
}
// previously this method was also doing:
// target.add(this);
// ie to update the entire form (in addition to the updates to the individual impacted parameter fields
// done in the loop above). However, that logic is wrong, because any values entered in the browser
// get trampled over (ISIS-629).
}
}