Package org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu

Source Code of org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.ActionLinkFactoryAbstract

/*
*  Licensed to the Apache Software Foundation (ASF) under one
*  or more contributor license agreements.  See the NOTICE file
*  distributed with this work for additional information
*  regarding copyright ownership.  The ASF licenses this file
*  to you under the Apache License, Version 2.0 (the
*  "License"); you may not use this file except in compliance
*  with the License.  You may obtain a copy of the License at
*
*        http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing,
*  software distributed under the License is distributed on an
*  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
*  KIND, either express or implied.  See the License for the
*  specific language governing permissions and limitations
*  under the License.
*/

package org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu;

import org.apache.wicket.Application;
import org.apache.wicket.Component;
import org.apache.wicket.Page;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.link.AbstractLink;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.util.visit.IVisit;
import org.apache.wicket.util.visit.IVisitor;
import org.apache.isis.applib.RecoverableException;
import org.apache.isis.applib.annotation.ActionSemantics;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
import org.apache.isis.core.runtime.system.context.IsisContext;
import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
import org.apache.isis.viewer.wicket.model.models.ActionModel;
import org.apache.isis.viewer.wicket.model.models.ActionPrompt;
import org.apache.isis.viewer.wicket.model.models.ActionPromptProvider;
import org.apache.isis.viewer.wicket.model.models.PageType;
import org.apache.isis.viewer.wicket.ui.ComponentType;
import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistry;
import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistryAccessor;
import org.apache.isis.viewer.wicket.ui.components.actions.ActionPanel;
import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract;
import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.AjaxDeferredBehaviour.OpenUrlStrategy;
import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistry;
import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistryAccessor;
import org.apache.isis.viewer.wicket.ui.pages.actionprompt.ActionPromptPage;
import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
import org.apache.isis.viewer.wicket.ui.util.Links;

public abstract class ActionLinkFactoryAbstract implements ActionLinkFactory {

    private static final long serialVersionUID = 1L;

    public static void addTargetBlankIfActionReturnsUrl(final AbstractLink link, final ObjectAction action) {
        final ObjectSpecification returnType = action.getReturnType();
        if(returnType != null && "java.net.URL".equals(returnType.getFullIdentifier())) {
            link.add(new AttributeAppender("target", Model.of("_blank")));
            link.add(new CssClassAppender("noVeil"));
        }
    }
   
    /**
     * Either creates a link for the action be rendered in a {@link ModalWindow}, or (if none can be
     * {@link ActionPromptProvider#getActionPrompt() provided}, or creates a link to
     * the {@link ActionPromptPage} (ie the {@link PageClassRegistry registered page} for
     * {@link PageType#ACTION_PROMPT action}s).
     *
     * <p>
     * If the action's {@link ObjectAction#getSemantics() semantics} are {@link ActionSemantics.Of#SAFE safe}, then
     * concurrency checking is disabled; otherwise it is enforced.
     */
    protected AbstractLink newLink(
            final String linkId,
            final ObjectAdapter objectAdapter, final ObjectAction action,
            final ActionPromptProvider actionPromptProvider) {
       
        final ActionPrompt actionPrompt = actionPromptProvider.getActionPrompt();
        if(actionPrompt != null) {
            final ActionModel actionModel = ActionModel.create(objectAdapter, action);
            actionModel.setActionPrompt(actionPrompt);
           
            final AjaxDeferredBehaviour ajaxDeferredBehaviour = determineDeferredBehaviour(action, actionModel);

            final AbstractLink link = new AjaxLink<Object>(linkId) {
                private static final long serialVersionUID = 1L;
               
                @Override
                public void onClick(AjaxRequestTarget target) {

                    if(ajaxDeferredBehaviour != null) {
                        ajaxDeferredBehaviour.initiate(target);
                    } else {
                        final ActionPanel actionPanel =
                                (ActionPanel) getComponentFactoryRegistry().createComponent(
                                        ComponentType.ACTION_PROMPT, actionPrompt.getContentId(), actionModel);
                       
                        actionPrompt.setPanel(actionPanel, target);
                        actionPanel.setActionPrompt(actionPrompt);
                        actionPrompt.show(target);

                        focusOnFirstParameter(target, actionPanel);
                    }
                }

                private void focusOnFirstParameter(AjaxRequestTarget target, ActionPanel actionPanel) {

                    // first, force all parameters to build themselves...
                    actionPanel.visitChildren(new IVisitor<Component, Component>() {
                        @Override
                        public void component(Component object, IVisit<Component> visit) {
                            if (object instanceof ScalarPanelAbstract) {
                                ScalarPanelAbstract spa = (ScalarPanelAbstract) object;
                                spa.forceBuildGui();
                                visit.dontGoDeeper();
                            }
                        }
                    });

                    // second, go searching for the first <input> in the action panel.
                    final Component actionPanelFirstParam = actionPanel.visitChildren(new IVisitor<Component, Component>() {
                        @Override
                        public void component(Component object, IVisit<Component> visit) {
                            if (object instanceof FormComponent &&
                                !"scalarIfCompact".equals(object.getId()) &&
                                object.getOutputMarkupId()) {
                                // there are components for 'compact' and 'regular'; we want the 'regular' one
                                // also double check that has outputMarkupId enabled (prereq for setting focus)
                                visit.stop(object);
                            }
                        }
                    });

                    // third, if found then use Wicket API to focus on this component
                    if(actionPanelFirstParam != null) {
                        target.focusComponent(actionPanelFirstParam);
                    }
                }
            };

            if(ajaxDeferredBehaviour != null) {
                link.add(ajaxDeferredBehaviour);
            }

            link.add(new CssClassAppender("noVeil"));

            return link;
           
        } else {
           
            // use the action semantics to determine whether invoking this action will require a concurrency check or not
            // if it's "safe", then we'll just continue without any checking.
            final ConcurrencyChecking concurrencyChecking = ConcurrencyChecking.concurrencyCheckingFor(action.getSemantics());
            final PageParameters pageParameters = ActionModel.createPageParameters(objectAdapter, action, concurrencyChecking);
            final Class<? extends Page> pageClass = getPageClassRegistry().getPageClass(PageType.ACTION_PROMPT);
            AbstractLink link = Links.newBookmarkablePageLink(linkId, pageParameters, pageClass);
           
            // special case handling if this a no-arg action is returning a URL
            if(action.getParameterCount()==0) {
                addTargetBlankIfActionReturnsUrl(link, action);
            }

            return link;
        }
    }

    private static AjaxDeferredBehaviour determineDeferredBehaviour(final ObjectAction action, final ActionModel actionModel) {
        // TODO: should unify with ActionResultResponseType (as used in ActionPanel)
        if(isNoArgReturnTypeRedirect(action)) {
            /**
             * adapted from:
             * @see https://cwiki.apache.org/confluence/display/WICKET/AJAX+update+and+file+download+in+one+blow
             */
            return new AjaxDeferredBehaviour(OpenUrlStrategy.NEW_WINDOW) {
               
                private static final long serialVersionUID = 1L;

                @Override
                protected IRequestHandler getRequestHandler() {
                    ObjectAdapter resultAdapter = executeActionHandlingApplicationExceptions(actionModel);
                    final Object value = resultAdapter.getObject();
                    return ActionModel.redirectHandler(value);
                }
            };
        }
        if(isNoArgReturnTypeDownload(action)) {

            /**
             * adapted from:
             * @see https://cwiki.apache.org/confluence/display/WICKET/AJAX+update+and+file+download+in+one+blow
             */
            return new AjaxDeferredBehaviour(OpenUrlStrategy.SAME_WINDOW) {
               
                private static final long serialVersionUID = 1L;
  
                @Override
                protected IRequestHandler getRequestHandler() {
                    ObjectAdapter resultAdapter = executeActionHandlingApplicationExceptions(actionModel);
                    final Object value = resultAdapter.getObject();
                    return ActionModel.downloadHandler(value);
                }
            };
        }
        return null;
    }

    // TODO: should unify with ActionResultResponseType (as used in ActionPanel)
    private static boolean isNoArgReturnTypeRedirect(final ObjectAction action) {
        return action.getParameterCount() == 0 &&
               action.getReturnType() != null &&
               action.getReturnType().getCorrespondingClass() == java.net.URL.class;
    }

    // TODO: should unify with ActionResultResponseType (as used in ActionPanel)
    private static boolean isNoArgReturnTypeDownload(final ObjectAction action) {
        return action.getParameterCount() == 0 && action.getReturnType() != null &&
                (action.getReturnType().getCorrespondingClass() == org.apache.isis.applib.value.Blob.class ||
                action.getReturnType().getCorrespondingClass() == org.apache.isis.applib.value.Clob.class);
    }
   
    // adapted from similar code in ActionPanel :-(
    private static ObjectAdapter executeActionHandlingApplicationExceptions(final ActionModel actionModel) {
        try {
            return actionModel.getObject();

        } catch (RuntimeException ex) {

            // TODO: some duplication between this code and ActionPanel

            // see if is an application-defined exception
            // if so, is converted to an application error,
            // equivalent to calling DomainObjectContainer#raiseError(...)
            final RecoverableException appEx = ActionModel.getApplicationExceptionIfAny(ex);
            if (appEx != null) {
                IsisContext.getMessageBroker().setApplicationError(appEx.getMessage());
                return null;
            }

            // not handled, so propagate
            throw ex;
        }
    }

    protected LinkAndLabel newLinkAndLabel(final ObjectAction action, final AbstractLink link, final String disabledReasonIfAny) {
        final String label = ObjectAction.Utils.nameFor(action);
        final boolean blobOrClob = CssMenuItem.returnsBlobOrClob(action);
        final boolean prototype = CssMenuItem.isExplorationOrPrototype(action);
        final String actionIdentifier = CssMenuItem.actionIdentifierFor(action);
        final String cssClass = CssMenuItem.cssClassFor(action);
       
        return new LinkAndLabel(link, label, disabledReasonIfAny, blobOrClob, prototype, actionIdentifier, cssClass);
    }


    // ////////////////////////////////////////////////////////////
    // Dependencies
    // ////////////////////////////////////////////////////////////
   
    protected ComponentFactoryRegistry getComponentFactoryRegistry() {
        return ((ComponentFactoryRegistryAccessor)Application.get()).getComponentFactoryRegistry();
    }
   
    protected PageClassRegistry getPageClassRegistry() {
        return ((PageClassRegistryAccessor) Application.get()).getPageClassRegistry();
    }

}
TOP

Related Classes of org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.ActionLinkFactoryAbstract

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.