org.obeonetwork.dsl.uml2.design.internal.dialogs.ModelElementSelectionDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.obeonetwork.dsl.uml2.design.internal.dialogs.ModelElementSelectionDialog.java

Source

/*******************************************************************************
 * Copyright (c) 2015 Obeo.
 * 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.obeonetwork.dsl.uml2.design.internal.dialogs;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.sirius.business.api.session.Session;
import org.eclipse.sirius.business.api.session.SessionManager;
import org.eclipse.sirius.ui.tools.api.color.VisualBindingManager;
import org.eclipse.sirius.ui.tools.internal.views.common.navigator.SiriusCommonLabelProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.edit.providers.UMLItemProviderAdapterFactory;
import org.obeonetwork.dsl.uml2.design.api.wizards.ModelElementsSelectionDialogPatternMatcher;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;

/**
 * Dialog to ask user to select an element.
 *
 * @author Melanie Bats <a href="mailto:melanie.bats@obeo.fr">melanie.bats@obeo.fr</a>
 */
public class ModelElementSelectionDialog extends org.eclipse.ui.dialogs.SelectionDialog {

    private class SelectionDialogTreeContentProvider extends AdapterFactoryContentProvider {
        /**
         * Constructor.
         *
         * @param adapterFactory
         *            Adapter factory
         */
        public SelectionDialogTreeContentProvider(AdapterFactory adapterFactory) {
            super(adapterFactory);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Object[] getChildren(Object parentElement) {
            return super.getChildren(parentElement);
        }

        @SuppressWarnings("rawtypes")
        @Override
        public Object[] getElements(Object object) {
            if (object instanceof Collection) {
                return ((Collection) object).toArray();
            }
            return super.getElements(object);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public boolean hasChildren(Object element) {
            return super.hasChildren(element);
        }
    }

    private class SelectionDialogTreeLabelProvider extends SiriusCommonLabelProvider {
        /**
         * {@inheritDoc}
         */
        @Override
        public Color getBackground(Object element) {
            return null;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Color getForeground(final Object element) {

            Color foreground = null;

            if (!isSelectable.apply(element)) {
                foreground = VisualBindingManager.getDefault().getColorFromName("light_gray"); //$NON-NLS-1$
            }
            return foreground;
        }

        /**
         * Set the selectable predicate. Predicate to find the selectable elements in the tree viewer.
         *
         * @param isSelectablePredicate
         *            Selectable elements predicate
         * @return Selectable predicate
         */
        public Predicate<Object> setSelectablePredicate(Predicate<Object> isSelectablePredicate) {
            return isSelectable = isSelectablePredicate != null ? isSelectablePredicate : Predicates.alwaysFalse();
        }
    }

    /**
     * Returns the adapter factory used by this viewer.
     *
     * @return The adapter factory used by this viewer.
     */
    private static AdapterFactory getAdapterFactory() {
        final List<AdapterFactory> factories = new ArrayList<AdapterFactory>();
        factories.add(new UMLItemProviderAdapterFactory());
        factories.add(new ResourceItemProviderAdapterFactory());
        factories.add(new EcoreItemProviderAdapterFactory());
        factories.add(new ReflectiveItemProviderAdapterFactory());
        return new ComposedAdapterFactory(factories);
    }

    /**
     * A String used to identify the Text allowing user to type regular expression (can be used for testing).
     */
    public static final String REGEXP_TOOL_TIP = "Expression that will be used to filer elements by name (for example 'abc', 'a?c', '*c'...)"; //$NON-NLS-1$

    /**
     * The title of the Group allowing user to type Regular Expressions and filter the selection.
     */
    private static final String REGEXP_TITLE = "Filter elements by name"; //$NON-NLS-1$

    /**
     * The String explaining to user how to use regular expressions.
     */
    private static final String REGEXP_EXPLANATIONS = "? = any character, * = any String"; //$NON-NLS-1$

    private final SelectionDialogTreeLabelProvider labelProvider;

    private ITreeContentProvider contentProvider;

    private TreeViewer treeViewer;

    private final int width = 60;

    private final int height = 18;

    private Predicate<Object> isSelectable;

    /**
     * A matcher used to determine if a given element is matching the regular expression typed by user. It's
     * updated each time the user modify the regular expression.
     */
    protected ModelElementsSelectionDialogPatternMatcher patternMatcher;

    /**
     * Constructor.
     */
    public ModelElementSelectionDialog() {
        super(PlatformUI.getWorkbench().getDisplay().getActiveShell());
        initContentProvider();
        labelProvider = new SelectionDialogTreeLabelProvider();
        labelProvider.setSelectablePredicate(isSelectable);
        patternMatcher = new ModelElementsSelectionDialogPatternMatcher(""); //$NON-NLS-1$
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        final Composite composite = (Composite) super.createDialogArea(parent);
        createMessageArea(composite);
        treeViewer = createTreeViewer(composite);
        treeViewer.expandAll();
        final GridData data = new GridData(GridData.FILL_BOTH);
        data.widthHint = convertWidthInCharsToPixels(width);
        data.heightHint = convertHeightInCharsToPixels(height);
        final Tree treeWidget = treeViewer.getTree();
        treeWidget.setLayoutData(data);
        treeWidget.setFont(parent.getFont());
        return composite;
    }

    /**
     * This method has been overridden to be able to insert selection buttons between the top label and the
     * tree viewer. {@inheritDoc}
     */
    @Override
    protected Label createMessageArea(Composite composite) {
        final Label createMessageArea = super.createMessageArea(composite);
        // creating a text zone to allow user to type regular expressions
        createRegexpTypeZone(composite);
        return createMessageArea;
    }

    /**
     * Creates a zone in which user will be able to type a Regular Expression to filter the shown elements.
     *
     * @param composite
     *            the parent composite
     */
    private void createRegexpTypeZone(Composite composite) {
        // Step 1 : create Group
        final Group expregGroup = new Group(composite, SWT.NONE);
        expregGroup.setText(REGEXP_TITLE);
        final GridLayout expregLayout = new GridLayout();
        expregGroup.setLayout(expregLayout);
        expregGroup.setFont(composite.getFont());
        expregGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        // Step 2 : create explanations zone
        final Label explanationsLabel = new Label(expregGroup, SWT.NONE);
        explanationsLabel.setText(REGEXP_EXPLANATIONS);

        // Step 3 : create the text zone in which user will type the expreg
        final Text regularExpressionText = new Text(expregGroup, SWT.BORDER);
        regularExpressionText.setToolTipText(REGEXP_TOOL_TIP);
        regularExpressionText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        // Step 4 : add modify listener to this textZone
        regularExpressionText.addModifyListener(new ModifyListener() {

            public void modifyText(ModifyEvent e) {
                final String typedRegex = ((Text) e.getSource()).getText();
                // Each time the regular expression is modified, the
                // patternMatcher is updated
                setPatternMatcher(new ModelElementsSelectionDialogPatternMatcher(typedRegex));
                refresh();
            }
        });
    }

    /**
     * Creates the tree viewer.
     *
     * @param parent
     *            the parent composite
     * @return the tree viewer
     */
    protected TreeViewer createTreeViewer(Composite parent) {
        treeViewer = new TreeViewer(parent);
        treeViewer.setContentProvider(contentProvider);
        treeViewer.setLabelProvider(labelProvider);
        treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            private void doSelectionChanged(Object[] array) {
                setResult(Arrays.asList(array));
            }

            public void selectionChanged(SelectionChangedEvent event) {
                doSelectionChanged(((IStructuredSelection) event.getSelection()).toArray());
            }
        });
        final Collection<EObject> roots = getAllRootsInSessions();
        final Collection<Object> inputs = Sets.newHashSet();
        inputs.addAll(roots);
        treeViewer.setInput(inputs);
        treeViewer.addFilter(new ViewerFilter() {
            @Override
            public boolean select(Viewer viewer, Object parentElement, Object element) {
                final Predicate<Object> isMatchinExpregPredicate = getRegexpMatchPredicate();
                return isOrHasDescendant(element, Predicates.and(isSelectable, isMatchinExpregPredicate));
            }
        });
        return treeViewer;
    }

    private Collection<EObject> getAllRootsInSessions() {
        final Collection<EObject> roots = new ArrayList<EObject>();
        for (final Session session : SessionManager.INSTANCE.getSessions()) {
            for (final Resource childRes : session.getSemanticResources()) {
                for (final EObject eObject : childRes.getContents()) {
                    if (eObject instanceof Element) {
                        roots.add(eObject);
                    }
                }
            }
        }
        return roots;
    }

    /**
     * Returns a Predicate indicating if an object is matching the Regular Expression currently typed by user.
     *
     * @return a Predicate indicating if an object is matching the Regular Expression currently typed by user
     */
    public Predicate<Object> getRegexpMatchPredicate() {
        return patternMatcher.getMatchPredicate();
    }

    /**
     * Init the content provider.
     *
     * @param notifications
     * @param includeNodeLabel
     *            include node label (if there are on border) in the tree content
     */
    protected void initContentProvider() {
        final AdapterFactory adapterFactory = getAdapterFactory();
        contentProvider = new SelectionDialogTreeContentProvider(adapterFactory);
    }

    private boolean isOrHasDescendant(Object element, final Predicate<Object> pred) {
        final boolean matches = pred.apply(element);
        if (matches) {
            return true;
        }
        return Iterables.any(Arrays.asList(contentProvider.getChildren(element)), new Predicate<Object>() {
            public boolean apply(Object input) {
                return isOrHasDescendant(input, pred);
            }
        });
    }

    /**
     * Refreshes this dialog's viewer.
     */
    public void refresh() {
        treeViewer.refresh();
    }

    /**
     * Sets the matcher used to determine if a given DDiagramElement is matching the regular expression typed
     * by user.
     *
     * @param patternMatcher
     *            the patternMatcher to set
     */
    public void setPatternMatcher(ModelElementsSelectionDialogPatternMatcher patternMatcher) {
        this.patternMatcher = patternMatcher;
    }

    /**
     * Set selectable predicate.
     *
     * @param isSelectablePredicate
     *            Selectable elements.
     */
    public void setSelectablePredicate(Predicate isSelectablePredicate) {
        isSelectable = isSelectablePredicate;
    }
}