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

Source Code of org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuItem$Builder

/*
*  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 java.io.Serializable;
import java.util.Collections;
import java.util.List;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.Page;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.SubmitLink;
import org.apache.wicket.markup.html.link.AbstractLink;
import org.apache.wicket.model.Model;
import org.apache.isis.applib.Identifier;
import org.apache.isis.applib.value.Blob;
import org.apache.isis.applib.value.Clob;
import org.apache.isis.core.commons.authentication.AuthenticationSession;
import org.apache.isis.core.commons.ensure.Ensure;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
import org.apache.isis.core.metamodel.consent.Consent;
import org.apache.isis.core.metamodel.facets.SingleStringValueFacet;
import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacet;
import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFacet;
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.mementos.ObjectAdapterMemento;
import org.apache.isis.viewer.wicket.model.models.ActionModel;
import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
import org.apache.isis.viewer.wicket.ui.util.Components;
import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;

import static org.hamcrest.CoreMatchers.is;

;

public class CssMenuItem implements Serializable {


    private static final long serialVersionUID = 1L;

    public static final String ID_MENU_LINK = "menuLink";

    public static class Builder {
        private final CssMenuItem cssMenuItem;

        private Builder(final String name) {
            cssMenuItem = new CssMenuItem(name);
        }

        public Builder parent(final CssMenuItem parent) {
            cssMenuItem.setParent(parent);
            return this;
        }

        public <T extends Page> Builder link(final Class<T> pageClass) {
            final AbstractLink link = new SubmitLink(ID_MENU_LINK);
            return link(link);
        }

        public <T extends Page> Builder link(final AbstractLink link) {
            Ensure.ensureThatArg(link.getId(), is(ID_MENU_LINK));
            cssMenuItem.setLink(link);
            return this;
        }

        public <T extends Page> Builder enabled(final String disabledReasonIfAny) {
            cssMenuItem.setEnabled(disabledReasonIfAny == null);
            cssMenuItem.setDisabledReason(disabledReasonIfAny);
            return this;
        }

        public Builder describedAs(String descriptionIfAny) {
            cssMenuItem.setDescription(descriptionIfAny);
            return this;
        }

        public Builder returnsBlobOrClob(boolean blobOrClob) {
            cssMenuItem.setReturnsBlobOrClob(blobOrClob);
            return this;
        }

        /**
         * Access the {@link CssMenuItem} before it is attached to its parent.
         *
         * @see #build()
         */
        public CssMenuItem itemBeingBuilt() {
            return cssMenuItem;
        }

        public Builder prototyping(boolean prototype) {
            cssMenuItem.setPrototyping(prototype);
            return this;
        }

        public Builder withActionIdentifier(String actionIdentifier) {
            cssMenuItem.setActionIdentifier(actionIdentifier);
            return this;
        }

        public Builder withFacet(CssClassFacet facet) {
            if(facet != null) {
                withCssClass(facet.value());
            }
            return this;
        }

        public Builder withCssClass(String cssClass) {
            cssMenuItem.setCssClass(cssClass);
            return this;
        }

        public Builder withFacet(CssClassFaFacet facet) {
            if(facet != null) {
                withCssClassFa(facet.value());
            }
            return this;
        }

        public Builder withCssClassFa(String cssClassFa) {
            cssMenuItem.setCssClassFa(cssClassFa);
            return this;
        }

        /**
         * Returns the built {@link CssMenuItem}, associating with
         * {@link #parent(CssMenuItem) parent} (if specified).
         */
        public CssMenuItem build() {
            if (cssMenuItem.parent != null) {
                cssMenuItem.parent.subMenuItems.add(cssMenuItem);
            }
            return cssMenuItem;
        }

    }

    private final String name;
    private final List<CssMenuItem> subMenuItems = Lists.newArrayList();
    private CssMenuItem parent;

    private AbstractLink link;
    private boolean enabled = true; // unless disabled
    private String disabledReason;
    private boolean blobOrClob = false; // unless set otherwise
    private boolean prototype = false; // unless set otherwise

    static final String ID_MENU_LABEL = "menuLabel";

    static final String ID_SUB_MENU_ITEMS = "subMenuItems";

    private String actionIdentifier;
    private String cssClass;
    private String cssClassFa;

    private String description;



    /**
     * Factory method returning {@link Builder builder}.
     */
    public static Builder newMenuItem(final String name) {
        return new Builder(name);
    }


    public void setActionIdentifier(String actionIdentifier) {
        this.actionIdentifier = actionIdentifier;
    }

    public void setPrototyping(boolean prototype) {
        this.prototype = prototype;
    }

    public boolean isPrototyping() {
        return prototype;
    }

    private CssMenuItem(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public boolean hasParent() {
        return parent != null;
    }

    private void setParent(final CssMenuItem parent) {
        this.parent = parent;
    }

    public Builder newSubMenuItem(final String name) {
        return CssMenuItem.newMenuItem(name).parent(this);
    }

    public List<CssMenuItem> getSubMenuItems() {
        return Collections.unmodifiableList(subMenuItems);
    }

    public boolean hasSubMenuItems() {
        return subMenuItems.size() > 0;
    }

    public AbstractLink getLink() {
        return link;
    }

    private void setLink(final AbstractLink link) {
        this.link = link;
    }

    public boolean isEnabled() {
        return enabled;
    }

    private void setEnabled(final boolean enabled) {
        this.enabled = enabled;
    }

    public void setReturnsBlobOrClob(boolean blobOrClob) {
        this.blobOrClob = blobOrClob;
    }

    public void setCssClass(String cssClass) {
        this.cssClass = cssClass;
    }

    public void setCssClassFa(String cssClassFa) {
        this.cssClassFa = cssClassFa;
    }

    public String getCssClassFa() {
        return cssClassFa;
    }


    /**
     * Only populated if not {@link #isEnabled() enabled}.
     */
    public String getDisabledReason() {
        return disabledReason;
    }

    public void setDisabledReason(final String disabledReason) {
        this.disabledReason = disabledReason;
    }

    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    // //////////////////////////////////////////////////////////////
    // To add submenu items
    // //////////////////////////////////////////////////////////////

    /**
     * Creates a {@link Builder} for a submenu item invoking an action on the provided
     * {@link ObjectAdapterMemento target adapter}.
     */
    public Builder newSubMenuItem(
            final ObjectAdapterMemento targetAdapterMemento,
            final ObjectAction objectAction,
            final CssMenuBuilder.CssMenuContext cssMenuContext) {

        // check visibility
        final AuthenticationSession session = getAuthenticationSession();
        final ObjectAdapter adapter = targetAdapterMemento.getObjectAdapter(ConcurrencyChecking.CHECK);
        final Consent visibility = objectAction.isVisible(session, adapter, ActionModel.WHERE_FOR_ACTION_INVOCATION);
        if (visibility.isVetoed()) {
            return null;
        }

        // build the link
        final LinkAndLabel linkAndLabel = cssMenuContext.getCssMenuLinkFactory().newLink(
                targetAdapterMemento, objectAction, PageAbstract.ID_MENU_LINK,
                cssMenuContext.getActionPromptProvider());
        if(linkAndLabel==null) {
            // can only get a null if invisible, so this should not happen given guard above
            return null;
        }
        final AbstractLink link = linkAndLabel.getLink();
        final String actionLabel = linkAndLabel.getLabel();

        final Consent usability = objectAction.isUsable(session, adapter, ActionModel.WHERE_FOR_ACTION_INVOCATION);
        final String reasonDisabledIfAny = usability.getReason();
       
        final DescribedAsFacet describedAsFacet = objectAction.getFacet(DescribedAsFacet.class);
        final String descriptionIfAny = describedAsFacet != null? describedAsFacet.value(): null;

        Builder builder = newSubMenuItem(actionLabel)
                .link(link)
                .describedAs(descriptionIfAny)
                .enabled(reasonDisabledIfAny)
                .returnsBlobOrClob(returnsBlobOrClob(objectAction))
                .prototyping(isExplorationOrPrototype(objectAction))
                .withActionIdentifier(actionIdentifierFor(objectAction))
                .withCssClass(cssClassFor(objectAction))
                .withCssClassFa(cssClassFaFor(objectAction));

        return builder;
    }

    public static boolean returnsBlobOrClob(final ObjectAction objectAction) {
        boolean blobOrClob = false;
        final ObjectSpecification returnType = objectAction.getReturnType();
        if(returnType != null) {
            Class<?> cls = returnType.getCorrespondingClass();
            if (Blob.class.isAssignableFrom(cls) || Clob.class.isAssignableFrom(cls)) {
                blobOrClob = true;
            }
        }
        return blobOrClob;
    }

    public static boolean isExplorationOrPrototype(final ObjectAction action) {
        return action.getType().isExploration() || action.getType().isPrototype();
    }

    public static String actionIdentifierFor(final ObjectAction action) {
        @SuppressWarnings("unused")
        final Identifier identifier = action.getIdentifier();
       
        final String className = action.getOnType().getShortIdentifier();
        final String actionId = action.getId();
        return className + "-" + actionId;
    }

    public static String cssClassFor(final ObjectAction action) {
        return facetValueIfAnyFor(action, CssClassFacet.class);
    }

    public static String cssClassFaFor(final ObjectAction action) {
        return facetValueIfAnyFor(action, CssClassFaFacet.class);
    }

    private static String facetValueIfAnyFor(ObjectAction action, Class<? extends SingleStringValueFacet> x) {
        final SingleStringValueFacet singleStringValueFacet = action.getFacet(x);
        return singleStringValueFacet != null ? singleStringValueFacet.value() : null;
    }

    /**
     * Creates a {@link Builder} for a submenu item where the provided {@link ActionLinkFactory} is able to provide the target adapter.
     */
    public Builder newSubMenuItem(
            final ObjectAction objectAction,
            final CssMenuBuilder.CssMenuContext cssMenuContext) {

        final LinkAndLabel linkAndLabel = cssMenuContext.getCssMenuLinkFactory().newLink(null, objectAction, PageAbstract.ID_MENU_LINK, cssMenuContext.getActionPromptProvider());

        final AbstractLink link = linkAndLabel.getLink();
        final String actionLabel = linkAndLabel.getLabel();
        Builder builder = this.newSubMenuItem(actionLabel)
                              .link(link)
                              .prototyping(linkAndLabel.isPrototype())
                              .returnsBlobOrClob(linkAndLabel.isBlobOrClob())
                              .withFacet(objectAction.getFacet(CssClassFacet.class))
                              .withFacet(objectAction.getFacet(CssClassFaFacet.class));
        return builder;
    }

    // //////////////////////////////////////////////////////////////
    // Build wicket components from the menu item.
    // //////////////////////////////////////////////////////////////

    void addTo(final MarkupContainer markupContainer) {

        final Component menuItemComponent = addMenuItemComponentTo(markupContainer);
        addSubMenuItemComponentsIfAnyTo(markupContainer);

        addCssClassAttributesIfRequired(menuItemComponent);
    }

    private Component addMenuItemComponentTo(final MarkupContainer markupContainer) {
        final AbstractLink link = getLink();
        final Label label = new Label(CssMenuItem.ID_MENU_LABEL, Model.of(this.getName()));

        if (this.isEnabled() && link != null) {
            // show link...
            markupContainer.add(link);
            link.add(label);

            if(this.description != null) {
                label.add(new AttributeModifier("title", Model.of(description)));
            }
            if(this.blobOrClob) {
                link.add(new CssClassAppender("noVeil"));
            }
            if(this.prototype) {
                link.add(new CssClassAppender("btn-warning"));
            } else {
                link.add(new CssClassAppender("btn-default"));
            }
            if(this.cssClass != null) {
                link.add(new CssClassAppender(this.cssClass));
            }
            link.add(new CssClassAppender(this.actionIdentifier));

            String cssClassFa = getCssClassFa();
            if (Strings.isNullOrEmpty(cssClassFa)) {
                Components.permanentlyHide(link, "menuLinkFontAwesome");
            } else {
                Label dummy = new Label("menuLinkFontAwesome", "");
                dummy.add(new CssClassAppender(cssClassFa));
                link.add(dummy);
            }

            // .. and hide label
            Components.permanentlyHide(markupContainer, CssMenuItem.ID_MENU_LABEL);
            return link;
        } else {
            // hide link...
            Components.permanentlyHide(markupContainer, ID_MENU_LINK);
            // ... and show label, along with disabled reason
            label.add(new AttributeModifier("title", Model.of(this.getDisabledReason())));
            label.add(new AttributeModifier("class", Model.of("disabled")));

            markupContainer.add(label);

            return label;
        }
    }

    private void addSubMenuItemComponentsIfAnyTo(final MarkupContainer menuItemMarkup) {
        final List<CssMenuItem> subMenuItems = getSubMenuItems();
        if (subMenuItems.isEmpty()) {
            Components.permanentlyHide(menuItemMarkup, CssMenuItem.ID_SUB_MENU_ITEMS);
        } else {
            menuItemMarkup.add(new CssSubMenuItemsPanel(CssMenuItem.ID_SUB_MENU_ITEMS, subMenuItems));
        }
    }

    private void addCssClassAttributesIfRequired(final Component linkComponent) {
        if (!hasSubMenuItems()) {
            return;
        }
        if (this.hasParent()) {
            linkComponent.add(new CssClassAppender("parent"));
        } else {
            linkComponent.add(new CssClassAppender("top-parent"));
        }
    }

    // //////////////////////////////////////////////////////////////
    // dependencies
    // //////////////////////////////////////////////////////////////

    protected AuthenticationSession getAuthenticationSession() {
        return IsisContext.getAuthenticationSession();
    }


}
TOP

Related Classes of org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuItem$Builder

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.