org.eclipse.sirius.editor.tools.api.menu.AbstractMenuBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.sirius.editor.tools.api.menu.AbstractMenuBuilder.java

Source

/*******************************************************************************
 * Copyright (c) 2009, 2015 THALES GLOBAL SERVICES and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Obeo - initial API and implementation
 *******************************************************************************/
package org.eclipse.sirius.editor.tools.api.menu;

import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;

import org.eclipse.emf.common.util.ResourceLocator;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.ui.action.CreateChildAction;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.SubContributionItem;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.sirius.business.internal.metamodel.helper.EClassHelper;
import org.eclipse.sirius.editor.editorPlugin.SiriusEditorPlugin;
import org.eclipse.sirius.editor.tools.internal.editor.EditorCustomizationManager;
import org.eclipse.sirius.ext.base.Option;
import org.eclipse.sirius.ext.base.Options;
import org.eclipse.sirius.viewpoint.description.DescriptionPackage;
import org.eclipse.ui.IEditorPart;

import com.google.common.base.Objects;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * Abstract class to dynamically build treeview menus.
 * 
 * @author cbrun
 * 
 */
public abstract class AbstractMenuBuilder {
    /**
     * The priority of the New Conditionnal Style menu.
     */
    protected static final int CONDITIONAL_STYLE;

    /**
     * The priority of the New Customization menu.
     */
    protected static final int CUSTOMIZATION;

    /**
     * The priority of the New Diagram Element menu.
     */
    protected static final int DIAGRAM_ELEMENT;

    /**
     * The priority of the New Element Creation menu.
     */
    protected static final int ELEMENT_CREATION;

    /**
     * The priority of the New Element Edition menu.
     */
    protected static final int ELEMENT_EDITION;

    /**
     * The priority of the New Extension menu.
     */
    protected static final int EXTENSION;

    /**
     * The priority of the New Filter menu.
     */
    protected static final int FILTER;

    /**
     * The priority of the New Import menu.
     */
    protected static final int IMPORT;

    /**
     * The priority of the New Layout menu.
     */
    protected static final int LAYOUT;

    /**
     * The priority of the New Menu menu.
     */
    protected static final int MENU;

    /**
     * The priority of the New Navigation menu.
     */
    protected static final int NAVIGATION;

    /**
     * The priority of the New Operation menu.
     */
    protected static final int OPERATION;

    /**
     * The priority of the New Reorder menu.
     */
    protected static final int REORDER;

    /**
     * The priority of the New Representation menu.
     */
    protected static final int REPRESENTATION;

    /**
     * The priority of the New Representation Creation menu.
     */
    protected static final int REPRESENTATION_CREATION;

    /**
     * The priority of the New Simulation menu.
     */
    protected static final int SIMULATION;

    /**
     * The priority of the New Style menu.
     */
    protected static final int STYLE;

    /**
     * The priority of the New Table Element menu.
     */
    protected static final int TABLE_ELEMENT;

    /**
     * The priority of the New Template menu.
     */
    protected static final int TEMPLATE;

    /**
     * The priority of the New Tool menu.
     */
    protected static final int TOOL;

    /**
     * The priority of the New Tree Element menu.
     */
    protected static final int TREE_ELEMENT;

    /**
     * The priority of the New Validation menu.
     */
    protected static final int VALIDATION;

    /**
     * The priority of the New Variable menu.
     */
    protected static final int VARIABLE;

    /**
     * The priority of the New (Others) menu.
     */
    protected static final int OTHERS;

    /**
     * The priority of the Initialize menu.
     */
    protected static final int INITIALIZE;

    /**
     * The priority of the Refactor menu.
     */
    protected static final int REFACTOR;

    private static final String EDIT = "edit";

    private static final int DEFAULT_PRIORITY = 1000000000;

    static {
        ResourceLocator rl = SiriusEditorPlugin.INSTANCE;
        CONDITIONAL_STYLE = getPriority(rl, "ConditionalStylePriority");
        CUSTOMIZATION = getPriority(rl, "CustomizationPriority");
        DIAGRAM_ELEMENT = getPriority(rl, "DiagramElementPriority");
        ELEMENT_CREATION = getPriority(rl, "ElementCreationPriority");
        ELEMENT_EDITION = getPriority(rl, "ElementEditionPriority");
        EXTENSION = getPriority(rl, "ExtensionPriority");
        FILTER = getPriority(rl, "FilterPriority");
        IMPORT = getPriority(rl, "ImportPriority");
        LAYOUT = getPriority(rl, "LayoutPriority");
        MENU = getPriority(rl, "MenuPriority");
        NAVIGATION = getPriority(rl, "NavigationPriority");
        OPERATION = getPriority(rl, "OperationPriority");
        REORDER = getPriority(rl, "ReorderPriority");
        REPRESENTATION = getPriority(rl, "RepresentationPriority");
        REPRESENTATION_CREATION = getPriority(rl, "RepresentationCreationPriority");
        SIMULATION = getPriority(rl, "SimulationPriority");
        STYLE = getPriority(rl, "StylePriority");
        TABLE_ELEMENT = getPriority(rl, "TableElementPriority");
        TEMPLATE = getPriority(rl, "TemplatePriority");
        TOOL = getPriority(rl, "ToolPriority");
        TREE_ELEMENT = getPriority(rl, "TreeElementPriority");
        VALIDATION = getPriority(rl, "ValidationPriority");
        VARIABLE = getPriority(rl, "VariablePriority");
        OTHERS = getPriority(rl, "OthersPriority");
        INITIALIZE = getPriority(rl, "InitializePriority");
        REFACTOR = getPriority(rl, "RefactorPriority");
    }

    /**
     * Child actions for the advanced menu.
     */
    protected Collection advancedChildActions;

    /**
     * Descriptors for the menu action.
     */
    protected Collection descriptors;

    /**
     * Menu manager for the advanced menu.
     */
    protected IMenuManager myMenuManager;

    /**
     * Map associating type keys (as computed by EClassHelper.getPath()), with
     * the priority of the corresponding type.
     */
    private Map<String, Integer> priorityMap = Maps.newHashMap();

    /**
     * Create a new builder.
     */
    public AbstractMenuBuilder() {
        super();
        descriptors = new LinkedHashSet();
        getMenu();
    }

    private static int getPriority(ResourceLocator rl, String id) {
        try {
            return Integer.parseInt(rl.getString(id).trim());
        } catch (NumberFormatException nfe) {
        } catch (MissingResourceException mre) {
        }
        return 100000;
    }

    /**
     * Return the menu child descriptors.
     * 
     * @return the menu child descriptors
     */
    public Collection getMyDescriptors() {
        return descriptors;
    }

    /**
     * Return the menu manager.
     * 
     * @return the menu manager.
     */
    protected Option<IMenuManager> getMenu() {
        return Options.newSome(myMenuManager);
    }

    private void createMenuManager() {
        myMenuManager = new MenuManager(getLabel());
        // Force an update because Eclipse hides empty menus now.
        //
        myMenuManager.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager menuManager) {
                menuManager.updateAll(true);
            }
        });
    }

    /**
     * Return the menu label.
     * 
     * @return the menu label.
     */
    public abstract String getLabel();

    /**
     * Return the priority of the menu.
     * 
     * @return the priority.
     */
    public abstract int getPriority();

    /**
     * Attach the menu to its parent.
     * 
     * @param parent
     *            parent to attach to.
     */
    public void attach(final IMenuManager parent) {
        // parent.add(getMenu());
    }

    /**
     * Update the menu considering the new descriptor and the current selection.
     * 
     * @param newChildDescriptors
     *            new descriptors.
     * @param selection
     *            current selection.
     * @param editor
     *            current editor.
     */
    public void update(final Collection newChildDescriptors, final ISelection selection, final IEditorPart editor) {
        depopulate();
        advancedChildActions = generateCreateChildActions(filter(newChildDescriptors), selection, editor);
    }

    private Collection filter(final Collection newChildDescriptors) {
        for (final Object object : newChildDescriptors) {
            if (object instanceof CommandParameter) {
                if (!isDeprecated((CommandParameter) object) && isMine((CommandParameter) object)) {
                    descriptors.add(object);
                }
            } else {
                descriptors.add(object);
            }
        }
        return descriptors;
    }

    /**
     * Return true if the command parameter is valid for the current builder.
     * 
     * @param object
     *            a command parameter to create new childs.
     * @return true if the command parameter is valid for the current builder.
     */
    protected abstract boolean isMine(CommandParameter object);

    /**
     * Return true if the command parameter is deprecated and should be hidden.
     * 
     * @param param
     *            a command parameter
     * @return true if the command parameter is deprecated and should be hidden
     */
    protected boolean isDeprecated(final CommandParameter param) {
        return (param.getEStructuralFeature() != null && isDeprecated(param.getEStructuralFeature()))
                || (param.getValue() instanceof EObject && isDeprecated(((EObject) param.getValue()).eClass()));
    }

    private boolean isDeprecated(final EModelElement owner) {
        return isGlobalyDisabled(owner) || EditorCustomizationManager.getInstance().isHidden(owner);
    }

    private boolean isGlobalyDisabled(EModelElement owner) {
        return owner == DescriptionPackage.eINSTANCE.getRepresentationTemplate_OwnedRepresentations();
    }

    /**
     * Depopulate the menu.
     */
    protected void depopulate() {
        descriptors = new LinkedHashSet();
        if (myMenuManager != null) {
            depopulateManager(myMenuManager, advancedChildActions);
        }
    }

    /**
     * This removes from the specified <code>manager</code> all
     * {@link org.eclipse.jface.action.ActionContributionItem}s based on the
     * {@link org.eclipse.jface.action.IAction}s contained in the
     * <code>actions</code> collection.
     * 
     * @param manager
     *            the manager to update.
     * @param actions
     *            the actions to remove from the manager.
     */
    protected void depopulateManager(final IContributionManager manager, final Collection actions) {
        if (actions != null) {
            final IContributionItem[] items = manager.getItems();
            for (IContributionItem item : items) {
                // Look into SubContributionItems
                //
                IContributionItem contributionItem = item;
                while (contributionItem instanceof SubContributionItem) {
                    contributionItem = ((SubContributionItem) contributionItem).getInnerItem();
                }

                // Delete the ActionContributionItems with matching action.
                //
                if (contributionItem instanceof ActionContributionItem) {
                    final IAction action = ((ActionContributionItem) contributionItem).getAction();
                    if (actions.contains(action)) {
                        manager.remove(contributionItem);
                    }
                }
            }
        }
    }

    /**
     * Generate the create child actions and return them.
     * 
     * @param actionDescriptors
     *            descriptor to create the actions from.
     * @param selection
     *            the current selection.
     * @param editor
     *            the current editor.
     * @return the list of actions.
     */
    protected Collection generateCreateChildActions(final Collection actionDescriptors, final ISelection selection,
            final IEditorPart editor) {
        final Collection actions = new ArrayList();
        if (actionDescriptors != null) {
            for (final Object actionDescriptor : actionDescriptors) {
                final CreateChildAction cca;
                if (actionDescriptor instanceof CommandParameter) {
                    cca = new CustomCreateChildAction(editor, selection, (CommandParameter) actionDescriptor);
                } else {
                    cca = new CreateChildAction(editor, selection, actionDescriptor);
                }
                actions.add(cca);
            }
        }
        return actions;
    }

    /**
     * Populate the menu.
     */
    public void populateMenu() {
        if (getMenu().some()) {
            populateManager(getMenu().get(), advancedChildActions, null);
        }
    }

    /**
     * Depopulate the menu.
     */
    public void depopulateMenu() {
        if (getMenu().some()) {
            depopulateManager(getMenu().get(), advancedChildActions);
        }
    }

    /**
     * Populate the menumanager with the given actions.
     * 
     * @param manager
     *            manager to populate.
     * @param actions
     *            actions to populate.
     * @param contributionID
     *            the Id for the contribution.
     */
    protected void populateManager(final IContributionManager manager, final Collection actions,
            final String contributionID) {
        if (actions != null) {
            List<IAction> sortedActions = Lists.newArrayList(Iterables.filter(actions, IAction.class));
            Comparator<IAction> comparator = new Comparator<IAction>() {
                @Override
                public int compare(IAction a1, IAction a2) {
                    int diff = getPriority(a1) - getPriority(a2);
                    if (diff == 0) {
                        // if both actions have no priority associated, or if
                        // they have the same priority, we compare the text
                        diff = Collator.getInstance().compare(a1.getText(), a2.getText());
                    }
                    return diff;
                }
            };
            Collections.sort(sortedActions, comparator);

            for (final IAction action : sortedActions) {
                if (contributionID != null) {
                    manager.insertBefore(contributionID, action);
                } else {
                    manager.add(action);
                }
            }
        }
        manager.update(true);
    }

    private int getPriority(IAction action) {
        if (action instanceof CustomCreateChildAction) {
            return getPriority(((CustomCreateChildAction) action).getCreatedElementType());
        } else {
            return AbstractMenuBuilder.DEFAULT_PRIORITY;
        }
    }

    private int getPriority(String key) {
        if (key != null && !priorityMap.containsKey(key)) {
            int priority = AbstractMenuBuilder.DEFAULT_PRIORITY;
            try {
                priority = Integer.parseInt(SiriusEditorPlugin.INSTANCE.getString(key).trim());
            } catch (MissingResourceException mre) {
            } catch (NumberFormatException nfe) {
            }
            priorityMap.put(key, priority);
        }
        return Objects.firstNonNull(priorityMap.get(key), DEFAULT_PRIORITY);
    }

    /**
     * Inserts this menu before the EDIT item.
     * 
     * @param parent
     *            the parent in which to inset this menu.
     */
    public void insertBeforeInContainer(IMenuManager parent) {
        createMenuManager();
        populateMenu();
        parent.insertBefore(EDIT, myMenuManager);
    }

    /**
     * Inserts this menu after the EDIT item.
     * 
     * @param parent
     *            the parent in which to inset this menu.
     */
    public void insertAfterInContainer(IMenuManager parent) {
        createMenuManager();
        populateMenu();
        parent.insertAfter(EDIT, myMenuManager);
    }

    /**
     * Custom sub-class of CreateChildAction which knows what kind of element it
     * will create when the descriptor is a CommandParameter.
     */
    private final class CustomCreateChildAction extends CreateChildAction {
        private final String key;

        private CustomCreateChildAction(IEditorPart editorPart, ISelection selection, CommandParameter descriptor) {
            super(editorPart, selection, descriptor);
            if (descriptor.getValue() instanceof EObject) {
                key = EClassHelper.getPath(((EObject) descriptor.getValue()).eClass());
            } else {
                key = null;
            }
        }

        public String getCreatedElementType() {
            return this.key;
        }

        @Override
        public String toString() {
            return "CustomCreateChildAction[key = " + key + "]";
        }
    }
}