org.eclipse.sirius.ui.business.api.viewpoint.ViewpointSelection.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.sirius.ui.business.api.viewpoint.ViewpointSelection.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 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.ui.business.api.viewpoint;

import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxCellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.DecorationOverlayIcon;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.IWizardContainer;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.sirius.business.api.componentization.ViewpointRegistry;
import org.eclipse.sirius.business.api.helper.SiriusResourceHelper;
import org.eclipse.sirius.business.api.query.IdentifiedElementQuery;
import org.eclipse.sirius.business.api.query.ViewpointQuery;
import org.eclipse.sirius.business.api.session.Session;
import org.eclipse.sirius.business.api.session.danalysis.DAnalysisSession;
import org.eclipse.sirius.business.api.session.danalysis.DAnalysisSessionHelper;
import org.eclipse.sirius.business.internal.movida.Movida;
import org.eclipse.sirius.common.tools.api.util.EqualityHelper;
import org.eclipse.sirius.common.tools.api.util.StringUtil;
import org.eclipse.sirius.common.ui.tools.api.util.SWTUtil;
import org.eclipse.sirius.ext.base.Option;
import org.eclipse.sirius.ui.business.internal.commands.ChangeViewpointSelectionCommand;
import org.eclipse.sirius.viewpoint.description.RepresentationExtensionDescription;
import org.eclipse.sirius.viewpoint.description.Viewpoint;
import org.eclipse.sirius.viewpoint.provider.Messages;
import org.eclipse.sirius.viewpoint.provider.SiriusEditPlugin;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.IProgressService;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;

/**
 * A class which to show swt widgets with available viewpoints.
 *
 * @author mchauvin
 */
public final class ViewpointSelection {

    private static final String VIEWPOINT_SELECTION_WIZARD_PAGE_TITLE = Messages.ViewpointSelection_wizardTitle;

    private static final String VIEWPOINTS_SELECTION_WIZARD_PAGE_ID = "viewpointsSelection"; //$NON-NLS-1$

    private static final String[] COLUMNS = { " ", Messages.ViewpointSelection_iconColumn, //$NON-NLS-1$
            Messages.ViewpointSelection_viewpointColumn };

    /**
     * Avoid instantiation.
     */
    private ViewpointSelection() {

    }

    /**
     * Return the lists of corresponding viewpoints.
     *
     * @param fileExtension
     *            The extension of the semantic model
     * @return The set of corresponding viewpoints, sorted with workspace
     *         viewpoints before plug-in viewpoints, and otherwise by name.
     */
    public static Set<Viewpoint> getViewpoints(final String fileExtension) {
        final Predicate<Viewpoint> isValidViewpoint = new Predicate<Viewpoint>() {
            @Override
            public boolean apply(final Viewpoint viewpoint) {
                return new ViewpointQuery(viewpoint).handlesSemanticModelExtension(
                        fileExtension != null ? fileExtension : StringUtil.JOKER_STRING);
            }
        };

        final Set<Viewpoint> allViewpoints = ViewpointRegistry.getInstance().getViewpoints();
        final Set<Viewpoint> validViewpoints = new HashSet<Viewpoint>();
        validViewpoints.addAll(Collections2.filter(allViewpoints, isValidViewpoint));
        return validViewpoints;
    }

    /**
     * Return the lists of corresponding viewpoints.
     *
     * @param fileExtensions
     *            The extensions of the semantic models
     * @return The list of corresponding viewpoints
     */
    private static Set<Viewpoint> getViewpoints(final Collection<String> fileExtensions) {
        final SortedSet<Viewpoint> validViewpoints = new TreeSet<Viewpoint>(
                new ViewpointRegistry.ViewpointComparator());
        for (final String extension : fileExtensions) {
            validViewpoints.addAll(ViewpointSelection.getViewpoints(extension));
        }
        return validViewpoints;
    }

    /**
     * Returns the semantic extensions of the given session.
     *
     * @param session
     *            the session.
     * @return the semantic extensions of the given session.
     */
    private static Collection<String> getSemanticFileExtensions(final Session session) {
        final Collection<String> fileExtensions = new HashSet<String>();
        for (final Resource resource : session.getSemanticResources()) {
            if (resource != null && resource.getURI() != null) {
                final String currentFileExtension = resource.getURI().fileExtension();
                if (currentFileExtension != null) {
                    fileExtensions.add(currentFileExtension);
                }
            }
        }
        return fileExtensions;
    }

    /**
     * Create a selection wizard page to select a viewpoint.
     *
     * @param fileExtension
     *            the semantic file extension.
     * @param viewpointsMap
     *            an empty map, which will be filled
     * @return the wizard page
     * @since 0.9.0
     */
    public static WizardPage createWizardPage(final String fileExtension,
            final SortedMap<Viewpoint, Boolean> viewpointsMap) {
        final SortedSet<Viewpoint> viewpoints = new TreeSet<Viewpoint>(new ViewpointRegistry.ViewpointComparator());
        viewpoints.addAll(ViewpointSelection.getViewpoints(fileExtension));

        for (final Viewpoint viewpoint : viewpoints) {
            viewpointsMap.put(viewpoint, Boolean.FALSE);
        }

        final WizardPage page = new WizardPage(ViewpointSelection.VIEWPOINTS_SELECTION_WIZARD_PAGE_ID,
                ViewpointSelection.VIEWPOINT_SELECTION_WIZARD_PAGE_TITLE, null) {

            @Override
            public void createControl(final Composite parent) {
                setControl(ViewpointSelection.createViewpointsTableControl(parent, this.getContainer(),
                        viewpointsMap));
            }

            private boolean isThereOneSelectedViewpoint() {
                return Maps.filterValues(viewpointsMap, new Predicate<Boolean>() {
                    @Override
                    public boolean apply(final Boolean input) {
                        return input.booleanValue();
                    }
                }).entrySet().iterator().hasNext();
            }

            @Override
            public boolean isPageComplete() {
                return super.isPageComplete() && isThereOneSelectedViewpoint();
            }

        };
        return page;
    }

    private static Control createViewpointsTableControl(final Composite parent,
            final IWizardContainer wizardContainer, final Map<Viewpoint, Boolean> viewpoints) {
        return ViewpointSelection.createViewpointsTableControl(parent, viewpoints.keySet(),
                new WizardViewpointsTableLazyCellModifier(viewpoints, wizardContainer),
                new ViewpointsTableLabelProvider(viewpoints));
    }

    /**
     * A cell modifier which applies to a wizard page.
     *
     * @author mchauvin
     */
    private static class WizardViewpointsTableLazyCellModifier extends ViewpointsTableLazyCellModifier {

        private final IWizardContainer wizardContainer;

        /**
         * Constructor.
         */
        public WizardViewpointsTableLazyCellModifier(final Map<Viewpoint, Boolean> viewpoints,
                final IWizardContainer wizardContainer) {
            super(viewpoints);
            this.wizardContainer = wizardContainer;
        }

        @Override
        public void modify(final Object element, final String property, final Object value) {
            super.modify(element, property, value);

            if (property.equals(ViewpointSelection.COLUMNS[0])) {
                this.wizardContainer.updateButtons();
            }
        }
    }

    /**
     * Create a selection wizard page to select a viewpoint.
     *
     * @param semanticModel
     *            the semantic model or null.
     * @param viewpointsMap
     *            an empty map which will be filled
     * @return the wizard page
     * @since 0.9.0
     */
    public static WizardPage createWizardPage(final IFile semanticModel,
            final SortedMap<Viewpoint, Boolean> viewpointsMap) {

        String semanticExtension = null;

        if (semanticModel != null) {
            semanticExtension = semanticModel.getFileExtension();
        }

        return ViewpointSelection.createWizardPage(semanticExtension, viewpointsMap);
    }

    /**
     * Create and open a new dialog to change the viewpoints selection status.
     *
     * @param session
     *            the session
     */
    public static void openViewpointsSelectionDialog(final Session session) {
        ViewpointSelection.openViewpointsSelectionDialog(session, true);
    }

    /**
     * Create and open a new dialog to change the viewpoints selection status.
     *
     * @param session
     *            the session
     * @param createNewRepresentations
     *            true to create new DRepresentation for
     *            RepresentationDescription having their initialization
     *            attribute at true for selected {@link Viewpoint}.
     */
    public static void openViewpointsSelectionDialog(final Session session, boolean createNewRepresentations) {
        if (Movida.isEnabled()) {
            session.getSemanticCrossReferencer();
            org.eclipse.sirius.business.internal.movida.registry.ViewpointRegistry registry = (org.eclipse.sirius.business.internal.movida.registry.ViewpointRegistry) ViewpointRegistry
                    .getInstance();
            org.eclipse.sirius.business.internal.movida.ViewpointSelection selection = DAnalysisSessionHelper
                    .getViewpointSelection(registry, (DAnalysisSession) session);
            Set<URI> selectedBefore = selection.getSelected();
            ViewpointSelectionDialog vsd = new ViewpointSelectionDialog(
                    PlatformUI.getWorkbench().getDisplay().getActiveShell(), registry, selection,
                    ViewpointSelection.getSemanticFileExtensions(session));
            if (vsd.open() == Window.OK) {
                ViewpointSelection.applyViewpointSelectionChange(session, selection, selectedBefore);
            }
        } else {
            session.getSemanticCrossReferencer();
            final SortedMap<Viewpoint, Boolean> viewpointsMap = ViewpointSelection
                    .getViewpointsWithMonitor(session);
            org.eclipse.sirius.ui.business.internal.viewpoint.ViewpointSelectionDialog vsd = new org.eclipse.sirius.ui.business.internal.viewpoint.ViewpointSelectionDialog(
                    PlatformUI.getWorkbench().getDisplay().getActiveShell(), viewpointsMap);
            if (vsd.open() == Window.OK) {
                ViewpointSelection.applyNewViewpointSelection(viewpointsMap, vsd.getSelection(), session,
                        createNewRepresentations);
            }
        }
    }

    /**
     * Compute the error message for the given missing dependencies which
     * indicates the required viewpoinst activation to complete the current
     * selection.
     *
     * @param missingDependencies
     *            a map with an entry for each select viewpoint which has
     *            missing dependencies. The entry's key is the viewpoint name,
     *            and the value is the list of names of all the missing
     *            viewpoints it depends on.
     * @return an error message which indicates the required viewpoint
     *         activation to complete the current selection.
     */
    public static String getMissingDependenciesErrorMessage(Map<String, Collection<String>> missingDependencies) {
        Function<Collection<String>, String> toStringList = new Function<Collection<String>, String>() {
            @Override
            public String apply(java.util.Collection<String> from) {
                return Joiner.on(", ").join(from); //$NON-NLS-1$
            }
        };
        StringBuilder sb = new StringBuilder(Messages.ViewpointSelection_missingDependencies_header).append("\n"); //$NON-NLS-1$
        List<String> lines = Lists.newArrayList();
        for (Map.Entry<String, Collection<String>> entry : missingDependencies.entrySet()) {
            lines.add("- " + MessageFormat.format(Messages.ViewpointSelection_missingDependencies_requirements, //$NON-NLS-1$
                    entry.getKey(), toStringList.apply(entry.getValue())));
        }
        sb.append(Joiner.on("\n").join(lines)); //$NON-NLS-1$
        return sb.toString();
    }

    private static void applyViewpointSelectionChange(final Session session,
            org.eclipse.sirius.business.internal.movida.ViewpointSelection selection, Set<URI> selectedBefore) {
        Set<URI> selectedAfter = selection.getSelected();
        Set<URI> newSelected = Sets.difference(selectedAfter, selectedBefore);
        Set<URI> newDeselected = Sets.difference(selectedBefore, selectedAfter);
        final ViewpointSelection.Callback callback = new ViewpointSelectionCallbackWithConfimation();
        final Set<Viewpoint> newSelectedViewpoints = Sets
                .newHashSet(Iterables.transform(newSelected, new Function<URI, Viewpoint>() {
                    @Override
                    public Viewpoint apply(URI from) {
                        return SiriusResourceHelper.getCorrespondingViewpoint(session, from, true).get();
                    }
                }));
        final Set<Viewpoint> newDeselectedViewpoints = Sets
                .newHashSet(Iterables.transform(newDeselected, new Function<URI, Viewpoint>() {
                    @Override
                    public Viewpoint apply(URI from) {
                        return SiriusResourceHelper.getCorrespondingViewpoint(session, from, true).get();
                    }
                }));
        // Only if there is something to do
        if (!newSelected.isEmpty() || !newDeselected.isEmpty()) {

            try {
                Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
                IRunnableContext context = new ProgressMonitorDialog(shell);
                IRunnableWithProgress runnable = new IRunnableWithProgress() {
                    @Override
                    public void run(final IProgressMonitor monitor) {
                        try {
                            monitor.beginTask(Messages.ViewpointSelection_applySelectionTask, 1);
                            Command command = new ChangeViewpointSelectionCommand(session, callback,
                                    newSelectedViewpoints, newDeselectedViewpoints,
                                    new SubProgressMonitor(monitor, 1));
                            TransactionalEditingDomain domain = session.getTransactionalEditingDomain();
                            domain.getCommandStack().execute(command);
                        } finally {
                            monitor.done();
                        }
                    }

                };
                PlatformUI.getWorkbench().getProgressService().runInUI(context, runnable, null);
            } catch (final InvocationTargetException e) {
                if (e.getCause() instanceof RuntimeException) {
                    throw (RuntimeException) e.getCause();
                }
                throw new RuntimeException(e);
            } catch (final InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * Compute the missing viewpoint dependencies (if any) for all the
     * viewpoints enabled by the user.
     *
     * @param selected
     *            the viewpoints selection request by the user.
     * @return for each selected viewpoint which has missing dependencies, an
     *         entry with the selected viewpoint's name as key and the list of
     *         the missing viewpoints' names as value.
     */
    public static Map<String, Collection<String>> getMissingDependencies(Set<Viewpoint> selected) {
        Set<String> selectedURIs = Sets
                .newHashSet(Iterables.filter(Iterables.transform(selected, new Function<Viewpoint, String>() {
                    @Override
                    public String apply(Viewpoint from) {
                        Option<URI> uri = new ViewpointQuery(from).getViewpointURI();
                        if (uri.some()) {
                            return uri.get().toString();
                        } else {
                            return null;
                        }
                    }
                }), Predicates.notNull()));

        Multimap<String, String> result = HashMultimap.create();
        for (Viewpoint viewpoint : selected) {
            for (RepresentationExtensionDescription extension : new ViewpointQuery(viewpoint)
                    .getAllRepresentationExtensionDescriptions()) {
                String extended = extension.getViewpointURI();
                Pattern pattern = Pattern.compile(extended);
                if (!ViewpointSelection.atLeastOneUriMatchesPattern(selectedURIs, pattern)) {
                    result.put(viewpoint.getName(), extended.trim().replaceFirst("^viewpoint:/[^/]+/", "")); //$NON-NLS-1$ //$NON-NLS-2$
                }
            }
        }
        return result.asMap();
    }

    private static boolean atLeastOneUriMatchesPattern(Set<String> selectedURIs, Pattern pattern) {
        for (String uriToMatch : selectedURIs) {
            Matcher matcher = pattern.matcher(uriToMatch);
            if (matcher.matches()) {
                return true;
            }
        }
        return false;
    }

    private static void applyNewViewpointSelection(final Map<Viewpoint, Boolean> originalMap,
            final Map<Viewpoint, Boolean> newMap, final Session session, final boolean createNewRepresentations) {

        // newMap is a copy of originalMap with modifications on values.
        // No elements should have been added.
        if (originalMap.size() != newMap.size()) {
            throw new IllegalArgumentException(Messages.ViewpointSelection_viewpointsMapNotReused);
        }

        final Set<Viewpoint> newSelectedViewpoints = Sets.newHashSet();
        final Set<Viewpoint> newDeselectedViewpoints = Sets.newHashSet();

        /*
         * newMap and originalMap are sorted with the same comparator and keys
         * haven't changed. We can iterate on the 2 maps together.
         */
        final Iterator<Entry<Viewpoint, Boolean>> originalIterator = originalMap.entrySet().iterator();
        final Iterator<Entry<Viewpoint, Boolean>> newIterator = newMap.entrySet().iterator();

        while (originalIterator.hasNext() && newIterator.hasNext()) {
            final Entry<Viewpoint, Boolean> originalEntry = originalIterator.next();
            final Entry<Viewpoint, Boolean> newEntry = newIterator.next();

            /* XOR : only if original and new booleans are different */
            if (originalEntry.getValue().booleanValue() ^ newEntry.getValue().booleanValue()) {

                // originalEntry and newEntry booleans are differents
                // Just need to test one of them

                // true : has been selected
                if (newEntry.getValue().booleanValue()) {
                    // We can use here originalEntry or newEntry indifferently
                    newSelectedViewpoints.add(originalEntry.getKey());
                } else {
                    // We can use here originalEntry or newEntry indifferently
                    newDeselectedViewpoints.add(originalEntry.getKey());
                }
            }
        }

        final ViewpointSelection.Callback callback = new ViewpointSelectionCallbackWithConfimation();

        // Only if there is something to do
        if (!newSelectedViewpoints.isEmpty() || !newDeselectedViewpoints.isEmpty()) {

            try {
                IRunnableWithProgress runnable = new IRunnableWithProgress() {
                    @Override
                    public void run(final IProgressMonitor monitor) {
                        Command command = new ChangeViewpointSelectionCommand(session, callback,
                                newSelectedViewpoints, newDeselectedViewpoints, createNewRepresentations, monitor);
                        TransactionalEditingDomain domain = session.getTransactionalEditingDomain();
                        domain.getCommandStack().execute(command);
                    }

                };
                new ProgressMonitorDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()).run(true,
                        false, runnable);
            } catch (final InvocationTargetException e) {
                if (e.getCause() instanceof RuntimeException) {
                    throw (RuntimeException) e.getCause();
                }
                throw new RuntimeException(e);
            } catch (final InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private static SortedMap<Viewpoint, Boolean> getViewpointsWithMonitor(final Session session) {
        final SortedSet<Viewpoint> allViewpoints = new TreeSet<Viewpoint>(
                new ViewpointRegistry.ViewpointComparator());
        final SortedMap<Viewpoint, Boolean> viewpointsMap = Maps
                .newTreeMap(new ViewpointRegistry.ViewpointComparator());
        final IProgressService ps = PlatformUI.getWorkbench().getProgressService();
        try {
            ps.busyCursorWhile(new IRunnableWithProgress() {
                @Override
                public void run(final IProgressMonitor pm) {
                    pm.beginTask(Messages.ViewpointSelection_loadingViewpointsTask, 4);

                    final Collection<String> semanticFileExtensions = ViewpointSelection
                            .getSemanticFileExtensions(session);
                    pm.worked(1);

                    final Set<Viewpoint> viewpoints = ViewpointSelection.getViewpoints(semanticFileExtensions);
                    pm.worked(1);

                    allViewpoints.addAll(viewpoints);
                    pm.worked(1);

                    Collection<Viewpoint> selectedViewpoints = session.getSelectedViewpoints(false);

                    for (final Viewpoint viewpoint : allViewpoints) {
                        boolean selected = false;

                        for (Viewpoint selectedViewpoint : selectedViewpoints) {
                            if (EqualityHelper.areEquals(selectedViewpoint, viewpoint)) {
                                selected = true;
                                break;
                            }
                        }

                        viewpointsMap.put(viewpoint, Boolean.valueOf(selected));
                    }

                    pm.done();
                }
            });
            return viewpointsMap;
        } catch (final InvocationTargetException e) {
            if (e.getCause() instanceof RuntimeException) {
                throw (RuntimeException) e.getCause();
            }
            throw new RuntimeException(e.getCause());
        } catch (final InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private static Control createViewpointsTableControl(final Composite parent, final Set<Viewpoint> viewpoints,
            final TableViewerAwareCellModifier cellModifier, final IBaseLabelProvider labelProvider) {

        final Composite control = SWTUtil.createCompositeBothFill(parent, 1, false);
        final TableViewer tableViewer = new TableViewer(control, SWT.BORDER | SWT.FULL_SELECTION);
        ColumnViewerToolTipSupport.enableFor(tableViewer, ToolTip.NO_RECREATE);

        final Table table = tableViewer.getTable();

        table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        final TableColumn tc0 = new TableColumn(table, SWT.CENTER, 0);
        tc0.setWidth(30);

        final TableColumn tc1 = new TableColumn(table, SWT.CENTER, 1);
        tc1.setWidth(30);

        final TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.LEFT, 2);
        column.getColumn().setWidth(450);

        table.setSize(new Point(table.getSize().x, 510));

        // Can only changes the first column - the visible column
        final CellEditor[] editors = new CellEditor[3];
        editors[0] = new CheckboxCellEditor(table);
        for (int i = 1; i < 3; i++) {
            editors[i] = null;
        }

        tableViewer.setColumnProperties(ViewpointSelection.COLUMNS);

        tableViewer.setCellEditors(editors);
        cellModifier.setViewer(tableViewer);
        tableViewer.setCellModifier(cellModifier);
        tableViewer.setContentProvider(new ViewpointsTableContentProvider());
        tableViewer.setLabelProvider(labelProvider);
        tableViewer.setComparator(new ViewerComparator());

        tableViewer.setInput(viewpoints);

        /* Lines and headers are not visible */
        table.setLinesVisible(false);
        table.setHeaderVisible(false);

        return control;
    }

    /**
     * A simple callback.
     *
     * @author mchauvin
     */
    public interface Callback {

        /**
         * Select a {@link Viewpoint}.
         *
         * @param viewpoint
         *            the {@link Viewpoint} to select
         * @param session
         *            the current session
         * @param monitor
         *            a {@link IProgressMonitor} to show progression
         */
        void selectViewpoint(Viewpoint viewpoint, Session session, IProgressMonitor monitor);

        /**
         * Select a {@link Viewpoint}.
         *
         * @param viewpoint
         *            the {@link Viewpoint} to select
         * @param session
         *            the current session
         * @param createNewRepresentations
         *            true to create new DRepresentation for
         *            RepresentationDescription having their initialization
         *            attribute at true for selected {@link Viewpoint}s.
         * @param monitor
         *            a {@link IProgressMonitor} to show progression
         */
        void selectViewpoint(Viewpoint viewpoint, Session session, boolean createNewRepresentations,
                IProgressMonitor monitor);

        /**
         * deselect a viewpoint.
         *
         * @param deselectedViewpoint
         *            the deselected viewpoint
         * @param session
         *            the current session
         * @param monitor
         *            a {@link IProgressMonitor} to show progression
         */
        void deselectViewpoint(Viewpoint deselectedViewpoint, Session session, IProgressMonitor monitor);

    }

    /**
     * The label provider
     *
     * @author mchauvin
     */
    private static final class ViewpointsTableLabelProvider extends ColumnLabelProvider {

        private final Map<Viewpoint, Boolean> viewpoints;

        private int columnIndex;

        /**
         * Constructor.
         *
         * @param viewpoints
         *            the viewpoints
         */
        public ViewpointsTableLabelProvider(final Map<Viewpoint, Boolean> viewpoints) {
            super();
            this.viewpoints = viewpoints;
        }

        private boolean findViewpoint(final Viewpoint vp) {
            for (final Map.Entry<Viewpoint, Boolean> entry : viewpoints.entrySet()) {
                if (EqualityHelper.areEquals(entry.getKey(), vp) && entry.getValue()) {
                    return true;
                }
            }
            return false;
        }

        private ImageDescriptor getOverlayedDescriptor(final Image baseImage, final String decoratorPath) {
            final ImageDescriptor decoratorDescriptor = SiriusEditPlugin.Implementation
                    .getBundledImageDescriptor(decoratorPath);
            return new DecorationOverlayIcon(baseImage, decoratorDescriptor, IDecoration.BOTTOM_LEFT);
        }

        private Image getEnhancedImage(final Image image, final Viewpoint viewpoint) {
            if (!ViewpointRegistry.getInstance().isFromPlugin(viewpoint) && image != null) {
                return SiriusEditPlugin.getPlugin()
                        .getImage(getOverlayedDescriptor(image, "icons/full/decorator/folder_close.gif")); //$NON-NLS-1$
            }
            return image;
        }

        @Override
        public Image getImage(final Object element) {
            Image image = null;

            switch (columnIndex) {
            case 0:
                if (element instanceof Viewpoint) {
                    final Viewpoint vp = (Viewpoint) element;
                    image = SiriusEditPlugin.getPlugin()
                            .getBundledImage("/icons/full/others/checkbox_inactive.gif"); //$NON-NLS-1$
                    if (findViewpoint(vp)) {
                        image = SiriusEditPlugin.getPlugin()
                                .getBundledImage("/icons/full/others/checkbox_active.gif"); //$NON-NLS-1$
                    }
                }
                break;
            case 1:
                if (element instanceof Viewpoint) {
                    final Viewpoint vp = (Viewpoint) element;
                    if (vp.getIcon() != null && vp.getIcon().length() > 0) {
                        final ImageDescriptor desc = SiriusEditPlugin.Implementation
                                .findImageDescriptor(vp.getIcon());
                        if (desc != null) {
                            image = SiriusEditPlugin.getPlugin().getImage(desc);
                            image = getEnhancedImage(image, vp);
                        }
                    }
                    if (image == null) {
                        image = SiriusEditPlugin.getPlugin()
                                .getImage(SiriusEditPlugin.getPlugin().getItemImageDescriptor(vp));
                        image = getEnhancedImage(image, vp);
                    }
                }
                break;
            case 2:
                break;
            default:
                break;
            }
            return image;
        }

        @Override
        public String getText(final Object element) {
            switch (columnIndex) {
            case 2:
                if (element instanceof Viewpoint) {
                    return new IdentifiedElementQuery((Viewpoint) element).getLabel();
                }
                break;
            default:
                break;
            }
            return null;
        }

        @Override
        public String getToolTipText(final Object element) {
            String toolTip = null;
            if (columnIndex == 2 && element instanceof Viewpoint) {
                Viewpoint viewpoint = (Viewpoint) element;
                final Resource resource = ((Viewpoint) element).eResource();
                if (resource != null) {
                    toolTip = resource.getURI().toString();
                }
                if (viewpoint.getEndUserDocumentation() != null
                        && viewpoint.getEndUserDocumentation().trim().length() > 0) {
                    if (toolTip != null) {
                        toolTip += "\n\n"; //$NON-NLS-1$
                    } else {
                        toolTip = ""; //$NON-NLS-1$
                    }
                    toolTip += viewpoint.getEndUserDocumentation();
                }
            }
            return toolTip;
        }

        @Override
        public Point getToolTipShift(final Object object) {
            return new Point(5, 5);
        }

        @Override
        public int getToolTipDisplayDelayTime(final Object object) {
            return 200;
        }

        @Override
        public void update(final ViewerCell cell) {
            columnIndex = cell.getColumnIndex();
            super.update(cell);
        }

        @Override
        public int getToolTipStyle(final Object object) {
            return SWT.SHADOW_OUT;
        }

    }

    /**
     * The content provider.
     *
     * @author mchauvin
     */
    private static final class ViewpointsTableContentProvider implements IStructuredContentProvider {
        @Override
        @SuppressWarnings("unchecked")
        public Object[] getElements(final Object inputElement) {
            if (inputElement instanceof Set<?>) {
                final Set<Viewpoint> viewpoints = (Set<Viewpoint>) inputElement;
                return viewpoints.toArray();
            }
            return Collections.EMPTY_LIST.toArray();
        }

        @Override
        public void dispose() {
            // nothing to do
        }

        @Override
        public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
            // nothing to do
        }
    }

    /**
     * An common interface which adds a set viewer method.
     *
     * @author mchauvin
     */
    private interface TableViewerAwareCellModifier extends ICellModifier {
        /**
         * Set the table viewer to update.
         *
         * @param viewer
         *            the viewer to update
         */
        void setViewer(final TableViewer viewer);
    }

    /**
     * An common abstract class for cell modifiers.
     *
     * @author mchauvin
     */
    private abstract static class AbstractViewpointsTableCellModifier implements TableViewerAwareCellModifier {

        protected TableViewer tableViewer;

        /** ll viewpoints and there selection state. */
        protected final Map<Viewpoint, Boolean> viewpoints;

        /**
         * Cosntructor.
         *
         * @param viewpoints
         *            All viewpoints and there selection state.
         */
        public AbstractViewpointsTableCellModifier(final Map<Viewpoint, Boolean> viewpoints) {
            this.viewpoints = viewpoints;
        }

        @Override
        public void setViewer(final TableViewer viewer) {
            this.tableViewer = viewer;
        }

        @Override
        public boolean canModify(final Object element, final String property) {

            if (property.equals(ViewpointSelection.COLUMNS[0])) {
                /* first column */
                return true;
            }
            return false;
        }

    }

    /**
     * The cell modifier which only modifies the input map.
     *
     * @author mchauvin
     */
    private static class ViewpointsTableLazyCellModifier extends AbstractViewpointsTableCellModifier {

        /**
         * Constructor.
         *
         * @param viewpoints
         *            All viewpoints and there selection state.
         */
        public ViewpointsTableLazyCellModifier(final Map<Viewpoint, Boolean> viewpoints) {
            super(viewpoints);
        }

        @Override
        public Object getValue(final Object element, final String property) {

            final Viewpoint viewpoint = (Viewpoint) element;
            Object result = null;

            if (property.equals(ViewpointSelection.COLUMNS[0])) {
                /* first column */

                result = Boolean.FALSE;
                for (final Map.Entry<Viewpoint, Boolean> entry : viewpoints.entrySet()) {
                    if (entry.getValue().booleanValue() && EqualityHelper.areEquals(viewpoint, entry.getKey())) {
                        result = Boolean.TRUE;
                        break;
                    }
                }
            } else if (property.equals(ViewpointSelection.COLUMNS[1])) {
                /* second column */
                // do nothing as there is only an image
            } else {
                /* third column */
                result = new IdentifiedElementQuery(viewpoint).getLabel();
            }
            return result;
        }

        @Override
        public void modify(final Object element, final String property, final Object value) {

            Object objElement;

            if (element instanceof Item) {
                objElement = ((Item) element).getData();
            } else {
                objElement = element;
            }

            if (property.equals(ViewpointSelection.COLUMNS[0])) {
                final Viewpoint vp = (Viewpoint) objElement;

                // Convert Object to Boolean without instanceof
                final Boolean result = Boolean.valueOf(Boolean.TRUE.equals(value));

                for (final Viewpoint viewpoint : viewpoints.keySet()) {
                    if (EqualityHelper.areEquals(viewpoint, vp)) {
                        viewpoints.put(viewpoint, result);
                        break;
                    }
                }

                /* update the label provider */
                this.tableViewer.update(vp, null);
            }
        }
    }
}