fr.lip6.move.coloane.core.ui.ColoaneEditor.java Source code

Java tutorial

Introduction

Here is the source code for fr.lip6.move.coloane.core.ui.ColoaneEditor.java

Source

/**
 * Copyright (c) 2006-2010 MoVe - Laboratoire d'Informatique de Paris 6 (LIP6).
 * 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:
 *   Jean-Baptiste VORON (LIP6) - Project Head / Initial contributor
 *   Clment DMOULINS (LIP6) - Project Manager
 *
 * Official contacts:
 *   coloane@lip6.fr
 *   http://coloane.lip6.fr
 */
package fr.lip6.move.coloane.core.ui;

import fr.lip6.move.coloane.core.copypast.CopyAction;
import fr.lip6.move.coloane.core.copypast.CutAction;
import fr.lip6.move.coloane.core.copypast.PasteAction;
import fr.lip6.move.coloane.core.exceptions.ColoaneException;
import fr.lip6.move.coloane.core.main.Coloane;
import fr.lip6.move.coloane.core.model.GraphEditorProperties;
import fr.lip6.move.coloane.core.model.GraphModel;
import fr.lip6.move.coloane.core.session.ISession;
import fr.lip6.move.coloane.core.session.SessionManager;
import fr.lip6.move.coloane.core.ui.actions.AlternateAction;
import fr.lip6.move.coloane.core.ui.actions.CurveAction;
import fr.lip6.move.coloane.core.ui.actions.NodeMoveAction;
import fr.lip6.move.coloane.core.ui.actions.RemoveInflexAction;
import fr.lip6.move.coloane.core.ui.actions.ResetAttributesLocationAction;
import fr.lip6.move.coloane.core.ui.checker.CheckerManager;
import fr.lip6.move.coloane.core.ui.checker.CommandStackListener;
import fr.lip6.move.coloane.core.ui.checker.MarkerManager;
import fr.lip6.move.coloane.core.ui.files.ModelLoader;
import fr.lip6.move.coloane.core.ui.files.ModelWriter;
import fr.lip6.move.coloane.core.ui.palette.PaletteFactory;
import fr.lip6.move.coloane.core.ui.palette.PaletteToolListener;
import fr.lip6.move.coloane.core.ui.rulers.EditorRuler;
import fr.lip6.move.coloane.core.ui.rulers.EditorRulerProvider;
import fr.lip6.move.coloane.core.ui.views.ModelLabelProvider;
import fr.lip6.move.coloane.interfaces.model.IGraph;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EventObject;
import java.util.List;
import java.util.logging.Logger;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.draw2d.ConnectionLayer;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.FreeformLayer;
import org.eclipse.draw2d.FreeformLayeredPane;
import org.eclipse.draw2d.LayeredPane;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.parts.ScrollableThumbnail;
import org.eclipse.draw2d.parts.Thumbnail;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.KeyHandler;
import org.eclipse.gef.KeyStroke;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.SnapToGeometry;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.dnd.TemplateTransferDragSourceListener;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.rulers.RulerProvider;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.actions.AlignmentAction;
import org.eclipse.gef.ui.actions.ToggleRulerVisibilityAction;
import org.eclipse.gef.ui.actions.ToggleSnapToGeometryAction;
import org.eclipse.gef.ui.actions.ZoomInAction;
import org.eclipse.gef.ui.actions.ZoomOutAction;
import org.eclipse.gef.ui.palette.FlyoutPaletteComposite.FlyoutPreferences;
import org.eclipse.gef.ui.palette.PaletteViewer;
import org.eclipse.gef.ui.palette.PaletteViewerProvider;
import org.eclipse.gef.ui.parts.ContentOutlinePage;
import org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette;
import org.eclipse.gef.ui.parts.GraphicalViewerKeyHandler;
import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer;
import org.eclipse.gef.ui.rulers.RulerComposite;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.viewers.DecoratingLabelProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.ide.FileStoreEditorInput;
import org.eclipse.ui.ide.IGotoMarker;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;

/**
 * This class describes a <b>model editor</b>
 */
public class ColoaneEditor extends GraphicalEditorWithFlyoutPalette
        implements ITabbedPropertySheetPageContributor, IGotoMarker {

    /**
     * Deals with the model outline
     */
    class OutlinePage extends ContentOutlinePage implements IAdaptable {
        private PageBook pageBook;
        private Canvas overview;
        private Thumbnail thumbnail;
        private DisposeListener disposeListener;

        /**
         * @param viewer viewer
         */
        public OutlinePage(EditPartViewer viewer) {
            super(viewer);
        }

        /** {@inheritDoc} */
        @Override
        public void init(IPageSite pageSite) {
            super.init(pageSite);
            ActionRegistry registry = getActionRegistry();
            IActionBars bars = pageSite.getActionBars();

            String id = ActionFactory.UNDO.getId();
            bars.setGlobalActionHandler(id, registry.getAction(id));

            id = ActionFactory.REDO.getId();
            bars.setGlobalActionHandler(id, registry.getAction(id));

            id = ActionFactory.DELETE.getId();
            bars.setGlobalActionHandler(id, registry.getAction(id));

            bars.updateActionBars();
        }

        /** {@inheritDoc} */
        @Override
        public void createControl(Composite parent) {
            pageBook = new PageBook(parent, SWT.NONE);
            overview = new Canvas(pageBook, SWT.NONE);
            pageBook.showPage(overview);
            showPage();
        }

        /** {@inheritDoc} */
        @Override
        public void dispose() {
            unhookOutlineViewer();
            if (thumbnail != null) {
                thumbnail.deactivate();
                thumbnail = null;
            }
            super.dispose();
            ColoaneEditor.this.outlinePage = null;
            outlinePage = null;
        }

        /** {@inheritDoc} */
        @Override
        @SuppressWarnings("rawtypes")
        public Object getAdapter(Class type) {
            if (type == ZoomManager.class) {
                return getGraphicalViewer().getProperty(ZoomManager.class.toString());
            }
            return null;
        }

        /** {@inheritDoc} */
        @Override
        public Control getControl() {
            return pageBook;
        }

        /**
         * Initialisation de l'overview
         */
        protected void initializeOverview() {
            LightweightSystem lws = new LightweightSystem(overview);
            RootEditPart rep = getGraphicalViewer().getRootEditPart();
            if (rep instanceof ScalableFreeformRootEditPart) {
                ScalableFreeformRootEditPart root = (ScalableFreeformRootEditPart) rep;
                thumbnail = new ScrollableThumbnail((Viewport) root.getFigure());
                thumbnail.setBorder(new MarginBorder(3));
                thumbnail.setSource(root.getLayer(LayerConstants.PRINTABLE_LAYERS));
                lws.setContents(thumbnail);
                disposeListener = new DisposeListener() {
                    @Override
                    public void widgetDisposed(DisposeEvent e) {
                        if (thumbnail != null) {
                            thumbnail.deactivate();
                            thumbnail = null;
                        }
                    }
                };
                getEditor().addDisposeListener(disposeListener);
            }
        }

        /**
         * @param contents modle de l'diteur
         */
        public void setContents(Object contents) {
            getViewer().setContents(contents);
        }

        /**
         * Affichage de l'overview
         */
        protected void showPage() {
            if (thumbnail == null) {
                initializeOverview();
            }
            pageBook.showPage(overview);
            thumbnail.setVisible(true);
        }

        /** TODO */
        protected void unhookOutlineViewer() {
            getSelectionSynchronizer().removeViewer(getViewer());
            if (disposeListener != null && getEditor() != null && !getEditor().isDisposed()) {
                getEditor().removeDisposeListener(disposeListener);
            }
        }
    }

    private static final String CONTRIBUTOR_ID = "fr.lip6.move.coloane.properties.contributor"; //$NON-NLS-1$
    private static final Logger LOGGER = Logger.getLogger("fr.lip6.move.coloane.core"); //$NON-NLS-1$
    private static final int MAXIMUM_FILE_SIZE = 2 * 1024 * 1024;

    /**
     * Focus listener.<br>
     * This listener is used to detect editor switches.<br>
     * In case of switch, it triggers some menus updates and recompute views dedicated to active editor.
     */
    private static TabListener listener = null;

    /** The check stack manager */
    private CommandStackListener checkStackManager;

    /** Outline page */
    private OutlinePage outlinePage;

    /** The current graph */
    private IGraph graph;

    /** The tools palette */
    private PaletteRoot paletteRoot;
    private RulerComposite rulerComposite;
    private final ILabelProvider labelProvider;
    private final ModelLabelProvider modelLabelProvider;

    /** Constructor */
    public ColoaneEditor() {
        modelLabelProvider = new ModelLabelProvider();
        labelProvider = new DecoratingLabelProvider(modelLabelProvider,
                PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator());
    }

    /** {@inheritDoc} */
    @Override
    protected final void initializeGraphicalViewer() {
        super.initializeGraphicalViewer();
        GraphicalViewer viewer = getGraphicalViewer();

        LOGGER.fine("Set the editor contents"); //$NON-NLS-1$
        viewer.setContents(getGraph()); // Set the contents !

        // Add the command stack event listener for listening to new added Command.
        checkStackManager = new CommandStackListener();
        this.getCommandStack().addCommandStackEventListener(checkStackManager);
    }

    /** {@inheritDoc} */
    @Override
    public final void dispose() {
        if (this.graph != null) {
            // Remove the stack listener dedicated to markers (problem view)
            this.getCommandStack().removeCommandStackEventListener(checkStackManager);
            // Remove all markers associated to the model that will be closed
            //         IResource resource = (IResource) getEditorInput().getAdapter(IResource.class);
            //         if (resource != null) {
            //            MarkerManager.deleteMarkers(resource);
            //         }
        }
        labelProvider.dispose();
        modelLabelProvider.dispose();
        super.dispose();
    }

    /** {@inheritDoc} */
    @Override
    protected final void configureGraphicalViewer() {
        List<String> zoomContributions;

        super.configureGraphicalViewer();
        ScrollingGraphicalViewer viewer = (ScrollingGraphicalViewer) getGraphicalViewer();

        // Define the rootEditPart :
        //   * Arcs are above the other elements
        //   * An image is placed on the background
        ScalableFreeformRootEditPart rootEditPart = new ScalableFreeformRootEditPart() {

            /** {@inheritDoc} */
            @Override
            protected LayeredPane createPrintableLayers() {
                FreeformLayeredPane layeredPane = new FreeformLayeredPane();
                layeredPane.add(new ConnectionLayer(), CONNECTION_LAYER);
                layeredPane.add(new FreeformLayer(), PRIMARY_LAYER);
                return layeredPane;
            }
        };

        viewer.setEditPartFactory(new PartFactory());
        viewer.setRootEditPart(rootEditPart);
        viewer.setKeyHandler(new GraphicalViewerKeyHandler(viewer));

        ContextMenuProvider cmProvider = new ColoaneContextMenuProvider(viewer, getActionRegistry());

        getSite().setSelectionProvider(viewer);

        // add default menu items (such "run as", "debug as" ...)
        // getSite().registerContextMenu(cmProvider, viewer);
        viewer.setContextMenu(cmProvider);

        // Zoom
        ZoomManager manager = rootEditPart.getZoomManager();
        getActionRegistry().registerAction(new ZoomInAction(manager));
        getActionRegistry().registerAction(new ZoomOutAction(manager));

        // Rulers
        IAction showRulers = new ToggleRulerVisibilityAction(getGraphicalViewer());
        getActionRegistry().registerAction(showRulers);

        // SnapToGeometry
        IAction snapAction = new ToggleSnapToGeometryAction(getGraphicalViewer());
        getActionRegistry().registerAction(snapAction);

        // Available zoom scales.
        // Here, 1 = 100%
        double[] zoomLevels = new double[] { 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 10.0, 20.0 };
        manager.setZoomLevels(zoomLevels);

        // Some usefull zoom scales
        zoomContributions = new ArrayList<String>();
        zoomContributions.add(ZoomManager.FIT_ALL);
        zoomContributions.add(ZoomManager.FIT_HEIGHT);
        zoomContributions.add(ZoomManager.FIT_WIDTH);
        manager.setZoomLevelContributions(zoomContributions);

        // Shortcuts (move selected nodes)
        KeyHandler keyHandler = new KeyHandler();
        keyHandler.put(KeyStroke.getPressed(SWT.ARROW_UP, 0), getActionRegistry().getAction(NodeMoveAction.UP));
        keyHandler.put(KeyStroke.getPressed(SWT.ARROW_DOWN, 0), getActionRegistry().getAction(NodeMoveAction.DOWN));
        keyHandler.put(KeyStroke.getPressed(SWT.ARROW_LEFT, 0), getActionRegistry().getAction(NodeMoveAction.LEFT));
        keyHandler.put(KeyStroke.getPressed(SWT.ARROW_RIGHT, 0),
                getActionRegistry().getAction(NodeMoveAction.RIGHT));
        viewer.setKeyHandler(keyHandler);

        this.loadProperties();
    }

    /**
     * Set editor properties (for this graph)
     */
    protected final void loadProperties() {
        GraphEditorProperties editorProperties = ((GraphModel) getGraph()).getEditorProperties();

        // Vertical ruler properties
        EditorRuler ruler = editorProperties.getRuler(PositionConstants.WEST);
        RulerProvider provider = null;
        if (ruler != null) {
            provider = new EditorRulerProvider(ruler);
        }
        getGraphicalViewer().setProperty(RulerProvider.PROPERTY_VERTICAL_RULER, provider);

        // Horizontal ruler properties
        ruler = editorProperties.getRuler(PositionConstants.NORTH);
        provider = null;
        if (ruler != null) {
            provider = new EditorRulerProvider(ruler);
        }
        getGraphicalViewer().setProperty(RulerProvider.PROPERTY_HORIZONTAL_RULER, provider);

        // General properties
        getGraphicalViewer().setProperty(RulerProvider.PROPERTY_RULER_VISIBILITY,
                editorProperties.getRulersVisibility());
        getGraphicalViewer().setProperty(SnapToGeometry.PROPERTY_SNAP_ENABLED, editorProperties.getSnapState());
    }

    /**
     * Save editor properties
     */
    protected final void saveProperties() {
        ((GraphModel) getGraph()).getEditorProperties().setRulersVisibility(
                ((Boolean) getGraphicalViewer().getProperty(RulerProvider.PROPERTY_RULER_VISIBILITY))
                        .booleanValue());
        ((GraphModel) getGraph()).getEditorProperties().setSnapState(
                ((Boolean) getGraphicalViewer().getProperty(SnapToGeometry.PROPERTY_SNAP_ENABLED)).booleanValue());
    }

    /**
     * @return The graph associated with this editor
     */
    public final IGraph getGraph() {
        if (graph == null) {
            throw new IllegalStateException("Graph has not be loaded"); //$NON-NLS-1$
        }
        return graph;
    }

    /**
     * @return The path of the current graph displayed by this editor
     */
    public final IPath getCurrentPath() {
        IFile file = ((IFileEditorInput) getEditorInput()).getFile();
        String projectName = file.getProject().getName();
        IPath path = new Path(projectName);
        return path.append(file.getProjectRelativePath());
    }

    /**
     * Put a particular GEF command on the editor stack
     * @param command The command that will be executed
     */
    public final void executeCommand(Command command) {
        super.getCommandStack().execute(command);
    }

    /**
     * Close the editor.
     */
    private void closeEditor() {
        setEditDomain(new DefaultEditDomain(this));
        Display.getDefault().asyncExec(new Runnable() {
            @Override
            public void run() {
                getSite().getPage().closeEditor(ColoaneEditor.this, false);
            }
        });
    }

    /**
     * The resource listener that updates file name, editor icon...
     */
    protected class ResourceListener implements IResourceChangeListener {
        @Override
        public final void resourceChanged(IResourceChangeEvent event) {
            if ((event.getType() & IResourceChangeEvent.POST_CHANGE) == IResourceChangeEvent.POST_CHANGE) {
                IFile previousFile = ((IFileEditorInput) ColoaneEditor.super.getEditorInput()).getFile();
                if (event.getDelta().findMember(previousFile.getFullPath()) != null) {
                    if (event.getDelta() != null && event.getDelta().getKind() == IResourceDelta.CHANGED) {
                        for (IResourceDelta c : Arrays.asList(event.getDelta().getAffectedChildren())) {
                            for (IResourceDelta d : Arrays.asList(c.getAffectedChildren())) {
                                if ((d.getKind() & IResourceDelta.ADDED) == IResourceDelta.ADDED) {
                                    final IFile file = (IFile) d.getResource();
                                    Display.getDefault().asyncExec(new Runnable() {
                                        @Override
                                        public void run() {
                                            ColoaneEditor.super.setInput(new FileEditorInput(file));
                                            ColoaneEditor.super.setPartName(file.getName());
                                            ColoaneEditor.super.setTitleImage(labelProvider.getImage(file));
                                        }
                                    });
                                    return;
                                }
                            }
                        }
                        if (event.getDelta().findMember(previousFile.getFullPath())
                                .getKind() == IResourceDelta.REMOVED) {
                            LOGGER.info("The editor on \"" + previousFile.getFullPath() //$NON-NLS-1$
                                    + "\" will be closed because the resource has been deleted."); //$NON-NLS-1$
                            Display.getDefault().asyncExec(new Runnable() {
                                @Override
                                public void run() {
                                    ColoaneEditor.this.getSite().getPage().closeEditor(ColoaneEditor.this, false);
                                }
                            });
                        }
                    }
                }
            }
        }
    }

    /**
     * Open a dialog to check that the user really wants to open a big file.
     * @param input The editor input
     * @return true if the user wants to open the editor
     */
    private boolean askOpen(final IEditorInput input) {
        // Ask if the model should be opened if the file is big:
        long fileSize = 0;
        if (input instanceof IFileEditorInput) {
            final IFile file = ((IFileEditorInput) input).getFile();
            fileSize = file.getRawLocation().toFile().length();
        } else if (input instanceof FileStoreEditorInput) {
            try {
                URL url = ((FileStoreEditorInput) input).getURI().toURL();
                fileSize = new File(url.getFile()).length();
            } catch (MalformedURLException e) {
            }
        }
        Shell shell = null;
        for (Shell s : Arrays.asList(Display.getCurrent().getShells())) {
            if (s.isEnabled()) {
                shell = s;
            }
        }
        if ((shell != null) && (fileSize > MAXIMUM_FILE_SIZE)) {
            boolean continueEditor = MessageDialog.openQuestion(shell, "Open a huge model?", //$NON-NLS-1$
                    "This model is stored in a file of size " + (fileSize / 1024 / 1024) //$NON-NLS-1$
                            + "Mbytes. Coloane is very likely to hang. Note that you can still send the model to Alligator services, even if it it closed. Are you sure that you want to open the model?"); //$NON-NLS-1$
            if (!continueEditor) {
                closeEditor();
                return false;
            }
        }
        return true;
    }

    /**
     * Remove file extension
     * @param filename The file name
     * @return filename without extension
     */
    private String nameOfFilename(String filename) {
        return filename.substring(0, filename.lastIndexOf('.'));
    }

    /**
     * Set editor contents.<br>
     * Contents are read from a file (previously created by the creation wizard).
     * @param input All information about the model
     */
    @Override
    protected final void setInput(final IEditorInput input) {
        super.setInput(input);
        if (!askOpen(input)) {
            return;
        }
        String name = ""; //$NON-NLS-1$
        if (input instanceof IFileEditorInput) {
            final IFile file = ((IFileEditorInput) input).getFile();
            name = nameOfFilename(file.getName());
        } else if (input instanceof FileStoreEditorInput) {
            name = nameOfFilename(input.getName());
        }
        // Fetch the XML file and set the name of the editor
        if (input instanceof IFileEditorInput) {
            final IFile file = ((IFileEditorInput) input).getFile();
            file.getWorkspace().addResourceChangeListener(new ResourceListener());
            this.graph = ModelLoader.loadGraphFromXML(file);
            setTitleImage(labelProvider.getImage(file));
            setPartName(name);
        } else if (input instanceof FileStoreEditorInput) {
            final File file = new File(((FileStoreEditorInput) input).getURI());
            this.graph = ModelLoader.loadGraphFromXML(((FileStoreEditorInput) input).getURI());
            setTitleImage(labelProvider.getImage(file));
            setPartName("..." + name); //$NON-NLS-1$
        }
        // If the loading fails... Display a message and quit
        if (this.graph == null) {
            closeEditor();
            return;
        }
        // Build a new session
        try {
            ISession session = SessionManager.getInstance().createSession(this.graph);
            setPartProperty("session.id", session.getSessionId()); //$NON-NLS-1$
            IResource resource = ResourcesPlugin.getWorkspace().getRoot()
                    .findMember(new Path(session.getSessionId()));
            if (resource != null) {
                CheckerManager.getInstance().checkAll(session.getChecker(), resource, this.graph);
            }
        } catch (ColoaneException ce) {
            LOGGER.warning("Cannot create a session for this model"); //$NON-NLS-1$
            LOGGER.warning(ce.getLogMessage());
            Coloane.showErrorMsg("Cannot create the session : " + ce.getMessage()); //$NON-NLS-1$
        }
        // Set the editor.
        // This operation cannot be performed earlier since the model formalism is not knew.
        // This information is needed to determine the palette to associate with the editor.
        // Do not move this instruction !
        setEditDomain(new DefaultEditDomain(this));
        // If the outline page has been built, display the graph inside
        if (outlinePage != null) {
            outlinePage.setContents(getGraph());
        }
    }

    /** {@inheritDoc} */
    @Override
    public final void doSave(IProgressMonitor monitor) {
        // Save editor properties
        this.saveProperties();

        // Fetch the (real) file and produce the XML representation of the current graph
        IFile file = ((IFileEditorInput) getEditorInput()).getFile();
        String xmlString = ModelWriter.translateToXML(graph);

        try {
            // Produce an input stream and write it to the file
            InputStream inputStream = new ByteArrayInputStream(xmlString.getBytes("UTF-8")); //$NON-NLS-1$
            file.setContents(inputStream, true, false, monitor);
            file.setCharset("UTF-8", monitor); //$NON-NLS-1$

            // As the model is now saved, we consider it as clean... (sync with its file)
            if (((GraphModel) graph).isDirty()) {
                ((GraphModel) graph).setDirtyState(false);
            }
        } catch (CoreException e) {
            LOGGER.warning("Error while writing the graph to the file " + file.getName()); //$NON-NLS-1$
        } catch (UnsupportedEncodingException e) {
            LOGGER.warning("Unsupported charset used by the graph..."); //$NON-NLS-1$
        }

        // Tells the command stack that the model has been saved
        getCommandStack().markSaveLocation();
    }

    /** {@inheritDoc} */
    @Override
    public final void doSaveAs() {
        // Save editor properties
        this.saveProperties();

        // Open a dialog box
        Shell shell = getSite().getWorkbenchWindow().getShell();
        SaveAsDialog dialog = new SaveAsDialog(shell);
        dialog.setOriginalFile(((IFileEditorInput) getEditorInput()).getFile());
        dialog.open();

        // Fetch the dialog box result
        IPath path = dialog.getResult();
        if (path != null) {
            // Try to save the editor's contents under a different file name
            final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);

            try {
                new ProgressMonitorDialog(shell).run(false, false, new WorkspaceModifyOperation() {
                    @Override
                    public void execute(final IProgressMonitor monitor) {
                        // Write the graph to its XML representation
                        String xmlString = ModelWriter.translateToXML(graph);
                        InputStream inputS = new ByteArrayInputStream(xmlString.getBytes());
                        try {
                            // If the file already exists, we replace its contents
                            if (file.exists()) {
                                file.setContents(inputS, true, false, monitor);
                                // Otherwise, we create the new file
                            } else {
                                file.create(inputS, true, monitor);
                            }
                        } catch (CoreException ce) {
                            LOGGER.warning("Error while writing the graph to the file " + file.getName()); //$NON-NLS-1$
                            ce.printStackTrace();
                        }
                    }
                });

                // Those lines are triggering a strange behavior.
                // setInput(new FileEditorInput(file));
                // getCommandStack().markSaveLocation();
                firePropertyChange(PROP_TITLE);

            } catch (InterruptedException ie) {
                // Should not happen, since the monitor dialog cannot be canceled
                ie.printStackTrace();
            } catch (InvocationTargetException ite) {
                ite.printStackTrace();
            }
        }
    }

    /** {@inheritDoc} */
    @Override
    public final void createPartControl(Composite parent) {

        // ytm, Jan 2015 : Performance Patch : DO NOT DARE TO DO THIS, who cares if icons of currently unopened editors is out of date ?
        // It is forbidden to have an operation when opening an editor whose complexity is proportional to number of currently opened editors (usually > 100 in my eclipse instances...)
        /**
        // Walk through all existing editors to show their icons:
        for (IEditorReference editor: Arrays.asList(this.getSite().getPage().getEditorReferences())) {
           editor.getEditor(true);
        }
        */
        if (listener == null) {
            LOGGER.config("Set the focus listener"); //$NON-NLS-1$
            listener = new TabListener();
            getSite().getPage().addPartListener(listener);
        }
        super.createPartControl(parent);
    }

    /** {@inheritDoc} */
    @Override
    public final boolean isSaveAsAllowed() {
        return true;
    }

    /** {@inheritDoc} */
    @Override
    public final void commandStackChanged(final EventObject event) {
        super.commandStackChanged(event);
        Display.getDefault().asyncExec(new Runnable() {
            @Override
            public void run() {
                firePropertyChange(IEditorPart.PROP_DIRTY);
            }
        });
    }

    /** {@inheritDoc} */
    @Override
    protected final PaletteViewerProvider createPaletteViewerProvider() {
        return new PaletteViewerProvider(getEditDomain()) {
            @Override
            protected void configurePaletteViewer(PaletteViewer viewer) {
                super.configurePaletteViewer(viewer);
                viewer.addDragSourceListener(new TemplateTransferDragSourceListener(viewer));
                viewer.addPaletteListener(new PaletteToolListener());
            }
        };
    }

    /** {@inheritDoc} */
    @Override
    protected final void createGraphicalViewer(Composite parent) {
        rulerComposite = new RulerComposite(parent, SWT.NONE);
        super.createGraphicalViewer(rulerComposite);
        rulerComposite.setGraphicalViewer((ScrollingGraphicalViewer) getGraphicalViewer());
    }

    /** {@inheritDoc} */
    @Override
    protected final Control getGraphicalControl() {
        return rulerComposite;
    }

    /** {@inheritDoc} */
    @SuppressWarnings("rawtypes")
    @Override
    public final Object getAdapter(Class type) {
        if (type == IContentOutlinePage.class) {
            outlinePage = new OutlinePage(getGraphicalViewer());
            return outlinePage;

            // Zoom Manager
        } else if (type == ZoomManager.class) {
            return ((ScalableFreeformRootEditPart) getGraphicalViewer().getRootEditPart()).getZoomManager();

            // Properties Page
        } else if (type == IPropertySheetPage.class) {
            return new TabbedPropertySheetPage(this);
        }

        return super.getAdapter(type);
    }

    /**
     * @return The editor
     */
    protected final FigureCanvas getEditor() {
        return (FigureCanvas) getGraphicalViewer().getControl();
    }

    /**
     * Build the tools palette
     * @return The palette
     */
    @Override
    protected final PaletteRoot getPaletteRoot() {
        // Should never be null
        if (graph == null) {
            LOGGER.warning("Cannot build the palette. The associated graph is null"); //$NON-NLS-1$
            return null;
        }

        // Build the entire palette
        paletteRoot = PaletteFactory.createPalette(graph.getFormalism());

        // If the building process has failed
        if (paletteRoot == null) {
            LOGGER.warning("Something went wring during the palette building process"); //$NON-NLS-1$
        }

        return paletteRoot;
    }

    /**
     * @return The palette preferences
     */
    @Override
    protected final FlyoutPreferences getPalettePreferences() {
        return PaletteFactory.createPalettePreferences();
    }

    /** {@inheritDoc} */
    @SuppressWarnings("unchecked")
    @Override
    protected final void createActions() {
        super.createActions();

        ActionRegistry registry = getActionRegistry();
        IAction action;

        // CUT
        action = new CutAction((IWorkbenchPart) this);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());

        // COPY
        action = new CopyAction((IWorkbenchPart) this);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());

        // PASTE
        action = new PasteAction((IWorkbenchPart) this);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());

        // MOVE ACTIONS
        action = new NodeMoveAction((IWorkbenchPart) this, NodeMoveAction.UP);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());
        action = new NodeMoveAction((IWorkbenchPart) this, NodeMoveAction.DOWN);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());
        action = new NodeMoveAction((IWorkbenchPart) this, NodeMoveAction.LEFT);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());
        action = new NodeMoveAction((IWorkbenchPart) this, NodeMoveAction.RIGHT);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());

        // CURVE
        action = new CurveAction((IWorkbenchPart) this);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());

        // ALTERNATE FIGURE
        action = new AlternateAction((IWorkbenchPart) this);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());

        // DELETE INFLEX POINT
        action = new RemoveInflexAction((IWorkbenchPart) this);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());

        // RESET ATTRIBUTES LOCATIONS
        action = new ResetAttributesLocationAction((IWorkbenchPart) this);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());

        // ALIGNMENT ACTIONS
        action = new AlignmentAction((IWorkbenchPart) this, PositionConstants.LEFT);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());
        action = new AlignmentAction((IWorkbenchPart) this, PositionConstants.RIGHT);
        registry.registerAction(action);
        getSelectionActions().add(((IAction) (action)).getId());
        action = new AlignmentAction((IWorkbenchPart) this, PositionConstants.TOP);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());
        action = new AlignmentAction((IWorkbenchPart) this, PositionConstants.BOTTOM);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());
        action = new AlignmentAction((IWorkbenchPart) this, PositionConstants.CENTER);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());
        action = new AlignmentAction((IWorkbenchPart) this, PositionConstants.MIDDLE);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());
    }

    /** {@inheritDoc} */
    @Override
    public final String getContributorId() {
        return CONTRIBUTOR_ID;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final void gotoMarker(IMarker marker) {
        MarkerManager.getInstance().doGotoMarker(marker);
    }

}