org.eclipse.sapphire.ui.swt.gef.SapphireDiagramEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.sapphire.ui.swt.gef.SapphireDiagramEditor.java

Source

/******************************************************************************
 * Copyright (c) 2015 Oracle and Liferay
 * 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:
 *    Ling Hao - initial implementation and ongoing maintenance
 *    Shenxue Zhou - Customized grid layer, grid state save and restore; DND fixes.
 *    Shenxue Zhou - [365019] SapphireDiagramEditor does not work on non-workspace files 
 *    Gregory Amerson - [374022] SapphireGraphicalEditor init with SapphireEditor
 *    Konstantin Komissarchik - [376245] Revert action in StructuredTextEditor does not revert diagram nodes and connections in SapphireDiagramEditor
 *    Gregory Amerson - [346172] Support zoom, print and save as image actions in the diagram editor
 *    Konstantin Komissarchik - [346172] Support zoom, print and save as image actions in the diagram editor
 *    Konstantin Komissarchik - [381794] Cleanup needed in presentation code for diagram context menu
 *    Konstantin Komissarchik - [382449] Support EL in EditorPageDef.PageHeaderText
 ******************************************************************************/

package org.eclipse.sapphire.ui.swt.gef;

import static org.eclipse.sapphire.ui.forms.swt.SwtUtil.toImageDescriptor;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.KeyHandler;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.SnapToGeometry;
import org.eclipse.gef.SnapToGrid;
import org.eclipse.gef.dnd.TemplateTransferDragSourceListener;
import org.eclipse.gef.editparts.GridLayer;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.palette.PaletteRoot;
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.GraphicalEditorWithFlyoutPalette;
import org.eclipse.gef.ui.parts.GraphicalViewerKeyHandler;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.TransferDropTargetListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.sapphire.Element;
import org.eclipse.sapphire.Event;
import org.eclipse.sapphire.ImageData;
import org.eclipse.sapphire.Listener;
import org.eclipse.sapphire.LoggingService;
import org.eclipse.sapphire.Sapphire;
import org.eclipse.sapphire.modeling.CapitalizationType;
import org.eclipse.sapphire.modeling.localization.LabelTransformer;
import org.eclipse.sapphire.ui.Bounds;
import org.eclipse.sapphire.ui.ISapphireEditorActionContributor;
import org.eclipse.sapphire.ui.ISapphirePart;
import org.eclipse.sapphire.ui.SapphireActionGroup;
import org.eclipse.sapphire.ui.SapphireActionSystem;
import org.eclipse.sapphire.ui.SapphireEditor;
import org.eclipse.sapphire.ui.SapphireEditorPagePart.PageHeaderImageEvent;
import org.eclipse.sapphire.ui.SapphireEditorPagePart.PageHeaderTextEvent;
import org.eclipse.sapphire.ui.SapphireEditorPagePart.SelectionChangedEvent;
import org.eclipse.sapphire.ui.SapphireHelpContext;
import org.eclipse.sapphire.ui.SapphirePart;
import org.eclipse.sapphire.ui.def.DefinitionLoader;
import org.eclipse.sapphire.ui.def.EditorPageDef;
import org.eclipse.sapphire.ui.diagram.ConnectionService;
import org.eclipse.sapphire.ui.diagram.DiagramConnectionPart;
import org.eclipse.sapphire.ui.diagram.def.DiagramEditorPageDef;
import org.eclipse.sapphire.ui.diagram.editor.DiagramDirectEditPartEvent;
import org.eclipse.sapphire.ui.diagram.editor.DiagramNodePart;
import org.eclipse.sapphire.ui.diagram.editor.DiagramPageEvent;
import org.eclipse.sapphire.ui.diagram.editor.SapphireDiagramEditorPagePart;
import org.eclipse.sapphire.ui.diagram.editor.SapphireDiagramEditorPagePart.AutoLayoutEvent;
import org.eclipse.sapphire.ui.diagram.editor.SapphireDiagramEditorPagePart.ZoomLevelEvent;
import org.eclipse.sapphire.ui.diagram.editor.ShapePart;
import org.eclipse.sapphire.ui.diagram.layout.DiagramLayoutPersistenceService;
import org.eclipse.sapphire.ui.forms.swt.ActionBridge;
import org.eclipse.sapphire.ui.forms.swt.ActionSystemPartBridge;
import org.eclipse.sapphire.ui.forms.swt.EditorPagePresentation;
import org.eclipse.sapphire.ui.forms.swt.HelpSystem;
import org.eclipse.sapphire.ui.forms.swt.SapphireActionPresentationManager;
import org.eclipse.sapphire.ui.forms.swt.SapphireToolBarManagerActionPresentation;
import org.eclipse.sapphire.ui.swt.gef.contextbuttons.ContextButtonManager;
import org.eclipse.sapphire.ui.swt.gef.dnd.ObjectsTransferDropTargetListener;
import org.eclipse.sapphire.ui.swt.gef.dnd.SapphireTemplateTransferDropTargetListener;
import org.eclipse.sapphire.ui.swt.gef.internal.DiagramEditorContextMenuProvider;
import org.eclipse.sapphire.ui.swt.gef.layout.HorizontalGraphLayout;
import org.eclipse.sapphire.ui.swt.gef.layout.VerticalGraphLayout;
import org.eclipse.sapphire.ui.swt.gef.model.DiagramConnectionModel;
import org.eclipse.sapphire.ui.swt.gef.model.DiagramModel;
import org.eclipse.sapphire.ui.swt.gef.model.DiagramModelBase;
import org.eclipse.sapphire.ui.swt.gef.model.DiagramNodeModel;
import org.eclipse.sapphire.ui.swt.gef.model.DiagramResourceCache;
import org.eclipse.sapphire.ui.swt.gef.model.ShapeModel;
import org.eclipse.sapphire.ui.swt.gef.model.ShapeModelUtil;
import org.eclipse.sapphire.ui.swt.gef.palette.DefaultFlyoutPalettePreferences;
import org.eclipse.sapphire.ui.swt.gef.parts.DiagramConnectionEditPart;
import org.eclipse.sapphire.ui.swt.gef.parts.DiagramNodeEditPart;
import org.eclipse.sapphire.ui.swt.gef.parts.SapphireDiagramEditorEditPartFactory;
import org.eclipse.sapphire.ui.swt.gef.presentation.DiagramPagePresentation;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.HelpEvent;
import org.eclipse.swt.events.HelpListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.forms.FormColors;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.widgets.ILayoutExtension;
import org.eclipse.ui.forms.widgets.SizeCache;
import org.eclipse.ui.internal.forms.widgets.FormHeading;
import org.eclipse.ui.internal.forms.widgets.FormUtil;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;

/**
 * @author <a href="mailto:ling.hao@oracle.com">Ling Hao</a>
 * @author <a href="mailto:shenxue.zhou@oracle.com">Shenxue Zhou</a>
 * @author <a href="mailto:gregory.amerson@liferay.com">Gregory Amerson</a>
 * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
 */

public class SapphireDiagramEditor extends GraphicalEditorWithFlyoutPalette
        implements ISapphireEditorActionContributor, EditorPagePresentation {
    private final SapphireEditor editor;
    private Element element;
    private DefinitionLoader.Reference<EditorPageDef> definition;
    private SapphireDiagramEditorPagePart part;

    private DiagramLayoutPersistenceService layoutPersistenceService;
    private ConnectionService connectionService;
    private PaletteRoot root;
    private DiagramPagePresentation diagramPresentation;
    private DiagramModel diagramModel;
    private Listener layoutPersistenceServiceListener;
    private List<ISapphirePart> selectedParts = new ArrayList<ISapphirePart>();
    private List<GraphicalEditPart> selectedEditParts = null;
    private boolean editorIsDirty = false;

    private Point mouseLocation;
    private DiagramConfigurationManager configManager;
    private GraphicalViewerKeyHandler graphicalViewerKeyHandler;
    private SapphireDiagramKeyHandler diagramKeyHandler;
    private ContextButtonManager contextButtonManager = null;
    private boolean directEditingActive = false;

    // Diagram header, borrowed from org.eclipse.ui.forms.widgets.Form class
    private FormHeading header;
    private Composite body;
    private SizeCache bodyCache = new SizeCache();
    private SizeCache headCache = new SizeCache();
    private FormColors formColors;
    private Listener diagramEditorPagePartListener;

    private Map<String, ActionBridge> globalActions;

    private SapphireDiagramOutline diagramOutline;

    private boolean isSelectionFromPagePart = false;

    public SapphireDiagramEditor(final SapphireEditor editor, final Element element,
            final DefinitionLoader.Reference<EditorPageDef> definition) {
        if (editor == null) {
            throw new IllegalArgumentException();
        }

        if (element == null) {
            throw new IllegalArgumentException();
        }

        if (definition == null) {
            throw new IllegalArgumentException();
        }

        this.editor = editor;
        this.element = element;
        this.definition = definition;

        this.part = new SapphireDiagramEditorPagePart();
        this.part.init(editor, this.element, this.definition.resolve(), Collections.<String, String>emptyMap());
        this.part.initialize();

        final String partName = this.definition.resolve().getPageName().localized(CapitalizationType.TITLE_STYLE,
                false);
        setPartName(partName);

        // Initialize connection service
        this.connectionService = SapphireDiagramEditorFactory.getConnectionService(this.part);
        // Initialize layout persistence service
        this.layoutPersistenceService = SapphireDiagramEditorFactory.getLayoutPersistenceService(this.part);

        this.configManager = new DiagramConfigurationManager(this);

        setEditDomain(new DefaultEditDomain(this));

        this.part.attach(new Listener() {
            @Override
            public void handle(final Event event) {
                if (event instanceof SelectionChangedEvent) {
                    isSelectionFromPagePart = true;
                    selectParts(part.getSelections());
                    isSelectionFromPagePart = false;
                } else if (event instanceof DiagramPageEvent) {
                    handleDiagramPageEvent((DiagramPageEvent) event);
                } else if (event instanceof DiagramDirectEditPartEvent) {
                    selectAndDirectEditPart(((DiagramDirectEditPartEvent) event).part());
                }
            }
        });

        this.layoutPersistenceServiceListener = new Listener() {
            @Override
            public void handle(final Event event) {
                if (event instanceof DiagramLayoutPersistenceService.DirtyStateEvent) {
                    final DiagramLayoutPersistenceService.DirtyStateEvent evt = (DiagramLayoutPersistenceService.DirtyStateEvent) event;

                    if (evt.after() == true) {
                        markEditorDirty();
                    } else {
                        markEditorClean();
                    }
                }
            }
        };

        this.layoutPersistenceService.attach(this.layoutPersistenceServiceListener);

        this.diagramEditorPagePartListener = new Listener() {
            @Override
            public void handle(final Event event) {
                if (event instanceof PageHeaderTextEvent) {
                    refreshPageHeaderText();
                } else if (event instanceof PageHeaderImageEvent) {
                    refreshPageHeaderImage();
                } else if (event instanceof ZoomLevelEvent) {
                    refreshZoomLevel();
                } else if (event instanceof AutoLayoutEvent) {
                    autoLayout(((AutoLayoutEvent) event).horizontal());
                }
            }
        };

        this.part.attach(this.diagramEditorPagePartListener);
    }

    private void handleDiagramPageEvent(DiagramPageEvent event) {
        switch (event.getDiagramPageEventType()) {
        case GridStateChange:
            getGraphicalViewer().setProperty(SnapToGrid.PROPERTY_GRID_VISIBLE, part.isGridVisible());
            getGraphicalViewer().setProperty(SnapToGrid.PROPERTY_GRID_ENABLED, part.isGridVisible());
            getGraphicalViewer().setProperty(SnapToGrid.PROPERTY_GRID_SPACING,
                    new Dimension(part.getGridUnit(), part.getVerticalGridUnit()));
            markEditorDirty();
            break;
        case GuideStateChange:
            getGraphicalViewer().setProperty(SnapToGeometry.PROPERTY_SNAP_ENABLED,
                    Boolean.valueOf(part.isShowGuides()));
            markEditorDirty();
            break;
        case DiagramChange:
            refreshPalette();
            break;
        case DiagramSave:
            // Noop
            break;
        case SelectAll:
            selectAll();
            break;
        case SelectAllNodes:
            selectAllNodes();
            break;
        default:
            break;
        }
    }

    public DiagramEditorPageDef getDiagramEditorPageDef() {
        return (DiagramEditorPageDef) this.definition.resolve();
    }

    public final SapphireEditor getEditor() {
        return this.editor;
    }

    public SapphireDiagramEditorPagePart getPart() {
        return this.part;
    }

    public final Element getModelElement() {
        return this.part.getModelElement();
    }

    public DiagramLayoutPersistenceService getLayoutPersistenceService() {
        return this.layoutPersistenceService;
    }

    public ConnectionService getConnectionService() {
        return this.connectionService;
    }

    @Override
    public boolean isDirty() {
        return this.editorIsDirty;
    }

    protected void markEditorDirty() {
        this.editorIsDirty = true;
        firePropertyChange(IWorkbenchPartConstants.PROP_DIRTY);
    }

    protected void markEditorClean() {
        this.editorIsDirty = false;
        firePropertyChange(IWorkbenchPartConstants.PROP_DIRTY);
    }

    @Override
    public DefaultEditDomain getEditDomain() {
        return super.getEditDomain();
    }

    @Override
    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
        // If not the active editor, ignore selection changed.
        boolean editorIsActive = getSite().getPage().isPartVisible(this);
        if (!editorIsActive) {
            // Check if we are a page of the active multipage editor
            IEditorPart activeEditor = getSite().getPage().getActiveEditor();
            if (activeEditor != null) {
                // Check if the top level editor if it is active
                editorIsActive = getSite().getPage().isPartVisible(activeEditor);
                if (activeEditor instanceof FormEditor) {
                    if (!(this.equals(((FormEditor) activeEditor).getActiveEditor()))) {
                        editorIsActive = false;
                    }
                }
            }
        }
        if (editorIsActive) {
            // Bug 339360 - MultiPage Editor's selectionProvider does not notify PropertySheet (edit) 
            // bypass the selection provider
            if (selection instanceof StructuredSelection) {
                StructuredSelection structuredSelection = (StructuredSelection) selection;
                List<ISapphirePart> partList = new ArrayList<ISapphirePart>();
                List<GraphicalEditPart> editPartList = new ArrayList<GraphicalEditPart>();
                for (Iterator<?> iterator = structuredSelection.iterator(); iterator.hasNext();) {
                    Object object = iterator.next();
                    EditPart editPart = null;
                    if (object instanceof EditPart) {
                        editPart = (EditPart) object;
                    } else if (object instanceof IAdaptable) {
                        editPart = (EditPart) ((IAdaptable) object).getAdapter(EditPart.class);
                    }
                    if (editPart != null && editPart.getModel() instanceof DiagramModelBase) {
                        SapphirePart sp = ((DiagramModelBase) editPart.getModel()).getSapphirePart();
                        partList.add(sp);
                        editPartList.add((GraphicalEditPart) editPart);
                    }
                }
                // If the properties sheet has multiple tabs, switching tabs would trigger selection changed
                // event. But the selection would be empty. So we don't want to update the properties sheet or
                // the key handler in this case.
                if (!partList.isEmpty()) {
                    this.selectedParts = partList;
                    this.selectedEditParts = editPartList;
                    if (!this.isSelectionFromPagePart) {
                        getPart().setSelections(partList, false);
                    }
                    updateKeyHandler();

                    //               // [Bug 380728] Floating toolbar appears on a node when multiple nodes are selected
                    //               if (partList.size() > 1 || !(partList.get(0) instanceof DiagramNodePart))
                    //               {
                    //                  this.contextButtonManager.hideContextButtonsInstantly();
                    //               }
                    this.contextButtonManager.refresh();
                }
            }
        }
    }

    private void initActions() {
        this.globalActions = new HashMap<String, ActionBridge>();

        final ActionBridge selectAllBridge = new ActionBridge(this.diagramPresentation,
                this.part.getAction("Sapphire.Diagram.SelectAll"));
        this.globalActions.put(ActionFactory.SELECT_ALL.getId(), selectAllBridge);

        final ActionBridge deleteBridge = new ActionBridge(this.diagramPresentation,
                this.part.getAction("Sapphire.Delete"));
        this.globalActions.put(ActionFactory.DELETE.getId(), deleteBridge);

        final ActionBridge printBridge = new ActionBridge(this.diagramPresentation,
                this.part.getAction("Sapphire.Diagram.Print"));
        this.globalActions.put(ActionFactory.PRINT.getId(), printBridge);
    }

    private void updateKeyHandler() {
        if (this.diagramKeyHandler != null) {
            this.diagramKeyHandler.dispose();
            this.diagramKeyHandler = null;
        }
        List<ISapphirePart> selectedParts = this.getSelectedParts();
        this.diagramKeyHandler = new SapphireDiagramKeyHandler(this, selectedParts);
        if (this.graphicalViewerKeyHandler == null) {
            graphicalViewerKeyHandler = new GraphicalViewerKeyHandler(getGraphicalViewer());
        }
        KeyHandler parentKeyHandler = graphicalViewerKeyHandler.setParent(this.diagramKeyHandler);
        getGraphicalViewer().setKeyHandler(parentKeyHandler);
    }

    private void refreshPalette() {
        PaletteRoot pr = getPaletteRoot();
        if (pr instanceof SapphirePaletteRoot) {
            SapphirePaletteRoot spr = (SapphirePaletteRoot) pr;
            spr.updatePaletteEntries();
        }
    }

    @Override
    protected PaletteRoot getPaletteRoot() {
        if (root == null)
            root = new SapphirePaletteRoot(part);
        return root;
    }

    @Override
    public void doSave(IProgressMonitor monitor) {
        try {
            this.part.saveDiagram();
            markEditorClean();
        } catch (Exception e) {
            Sapphire.service(LoggingService.class).log(e);
        }
    }

    @Override
    protected void initializeGraphicalViewer() {
        super.initializeGraphicalViewer();

        GraphicalViewer viewer = getGraphicalViewer();

        viewer.getControl().addMouseMoveListener(new MouseMoveListener() {
            public void mouseMove(MouseEvent e) {
                setMouseLocation(e.x, e.y);
            }
        });

        // set the contents of this editor
        viewer.setContents(diagramModel);

        // listen for dropped parts
        viewer.addDropTargetListener(new SapphireTemplateTransferDropTargetListener(this));
        viewer.addDropTargetListener((TransferDropTargetListener) new ObjectsTransferDropTargetListener(viewer));
        postInit();
    }

    private void postInit() {
        // refresh node bounds
        for (DiagramNodeModel node : this.diagramModel.getNodes()) {
            node.handleMoveNode();
        }

        //initRenderingContext();
        initActions();
        configureDiagramHeading();

        // If the layout file doesn't exist or no layout is written to the layout file, apply auto layout
        if (hasNoExistingLayout()) {
            getGraphicalViewer().flush();
            getPart().autoLayout(true);
            markEditorClean();
        }

    }

    private void autoLayout(boolean horizontal) {
        if (horizontal) {
            new HorizontalGraphLayout().layout(this, true);
        } else {
            new VerticalGraphLayout().layout(this, true);
        }
    }

    private boolean hasNoExistingLayout() {
        if (this.layoutPersistenceService == null) {
            return true;
        }
        List<DiagramNodeModel> nodes = this.diagramModel.getNodes();
        for (DiagramNodeModel node : nodes) {
            DiagramNodePart nodePart = node.getModelPart();
            Bounds bounds = nodePart.getNodeBounds();
            if (bounds.getX() == -1 || bounds.getY() == -1) {
                return true;
            }
        }

        return false;
    }

    public DiagramPagePresentation getDiagramPresentation() {
        return this.diagramPresentation;
    }

    public DiagramModel getDiagramModel() {
        return this.diagramModel;
    }

    public DiagramResourceCache getResourceCache() {
        return this.diagramPresentation.getResourceCache();
    }

    public DiagramConfigurationManager getConfigurationManager() {
        return this.configManager;
    }

    public ContextButtonManager getContextButtonManager() {
        return contextButtonManager;
    }

    @Override
    public void createPartControl(Composite parent) {
        final Composite main = new Composite(parent, SWT.NONE);
        main.setLayout(new FormLayout());
        this.header = new FormHeading(main, SWT.NULL);
        this.formColors = new FormColors(parent.getDisplay());

        super.createPartControl(main);
        this.body = getGraphicalControl().getParent();
    }

    @Override
    protected void configureGraphicalViewer() {
        super.configureGraphicalViewer();
        GraphicalViewer viewer = getGraphicalViewer();
        this.diagramPresentation = new DiagramPagePresentation(this.part, this.configManager,
                viewer.getControl().getShell());
        this.diagramModel = new DiagramModel(this.diagramPresentation);

        viewer.setEditPartFactory(new SapphireDiagramEditorEditPartFactory(getConfigurationManager()));

        viewer.setRootEditPart(new ScalableFreeformRootEditPart() {
            @Override
            protected GridLayer createGridLayer() {
                return new SapphireDiagramGridLayer(diagramModel);
            }
        });

        // configure the context menu provider
        ContextMenuProvider cmProvider = new DiagramEditorContextMenuProvider(this);
        viewer.setContextMenu(cmProvider);

        // Configure grid and guide properties
        boolean isGridVisibleInViewer = false;
        if (viewer.getProperty(SnapToGrid.PROPERTY_GRID_VISIBLE) != null) {
            isGridVisibleInViewer = (Boolean) viewer.getProperty(SnapToGrid.PROPERTY_GRID_VISIBLE);
        }
        if (this.part.isGridVisible() != isGridVisibleInViewer) {
            viewer.setProperty(SnapToGrid.PROPERTY_GRID_VISIBLE, this.part.isGridVisible());
            viewer.setProperty(SnapToGrid.PROPERTY_GRID_ENABLED, this.part.isGridVisible());
            viewer.setProperty(SnapToGrid.PROPERTY_GRID_SPACING,
                    new Dimension(this.part.getGridUnit(), this.part.getVerticalGridUnit()));
        }

        boolean isShowGuidesInViewer = false;
        if (viewer.getProperty(SnapToGeometry.PROPERTY_SNAP_ENABLED) != null) {
            isShowGuidesInViewer = (Boolean) viewer.getProperty(SnapToGeometry.PROPERTY_SNAP_ENABLED);
        }
        if (this.part.isShowGuides() != isShowGuidesInViewer) {
            viewer.setProperty(SnapToGeometry.PROPERTY_SNAP_ENABLED, this.part.isShowGuides());
        }

        // Support context help

        this.getGraphicalControl().addHelpListener(new HelpListener() {
            public void helpRequested(HelpEvent event) {
                if (getSelectedParts() != null && getSelectedParts().size() == 1) {
                    ISapphirePart part = getSelectedParts().get(0);
                    final SapphireHelpContext context = new SapphireHelpContext(part.getLocalModelElement(), null);
                    if (context.getText() != null
                            || (context.getRelatedTopics() != null && context.getRelatedTopics().length > 0)) {
                        // determine a location in the upper right corner of the widget
                        org.eclipse.swt.graphics.Point point = HelpSystem
                                .computePopUpLocation(event.widget.getDisplay());
                        // display the help
                        PlatformUI.getWorkbench().getHelpSystem().displayContext(context, point.x, point.y);
                    }
                }
            }
        });

        // context button manager
        contextButtonManager = new ContextButtonManager(this);

        final int zoomLevel = getPart().state().getZoomLevel().content();
        final double zoom = (double) zoomLevel / 100;

        getZoomManager().setZoom(zoom);
    }

    @Override
    protected PaletteViewerProvider createPaletteViewerProvider() {
        return new PaletteViewerProvider(getEditDomain()) {
            @Override
            protected void configurePaletteViewer(PaletteViewer viewer) {
                super.configurePaletteViewer(viewer);
                viewer.addDragSourceListener(new TemplateTransferDragSourceListener(viewer));
            }

            @Override
            public PaletteViewer createPaletteViewer(Composite parent) {
                PaletteViewer pViewer = new SapphirePaletteViewer();
                pViewer.createControl(parent);
                configurePaletteViewer(pViewer);
                hookPaletteViewer(pViewer);
                return pViewer;
            }

        };
    }

    @Override
    protected FlyoutPreferences getPalettePreferences() {
        return new DefaultFlyoutPalettePreferences(getPart().state());
    }

    public IAction getAction(String actionId) {
        if (actionId.equals(ActionFactory.SELECT_ALL.getId())) {
            return this.globalActions.get(ActionFactory.SELECT_ALL.getId());
        } else if (actionId.equals(ActionFactory.DELETE.getId())) {
            return this.globalActions.get(ActionFactory.DELETE.getId());
        } else if (actionId.equals(ActionFactory.PRINT.getId())) {
            return this.globalActions.get(ActionFactory.PRINT.getId());
        }

        return getActionRegistry().getAction(actionId);
    }

    @Override
    @SuppressWarnings("rawtypes")

    public Object getAdapter(Class type) {
        if (type == IContentOutlinePage.class) {
            return getDiagramOutline();
        }
        return super.getAdapter(type);
    }

    @Override
    public GraphicalViewer getGraphicalViewer() {
        return super.getGraphicalViewer();
    }

    public List<ISapphirePart> getSelectedParts() {
        return this.selectedParts;
    }

    public List<GraphicalEditPart> getSelectedEditParts() {
        return this.selectedEditParts;
    }

    public GraphicalEditPart getGraphicalEditPart(ISapphirePart sapphirePart) {
        if (sapphirePart instanceof DiagramNodePart || sapphirePart instanceof ShapePart
                || sapphirePart instanceof DiagramConnectionPart) {
            GraphicalViewer viewer = this.getGraphicalViewer();

            Object editpartObj = null;
            DiagramNodePart nodePart = null;
            DiagramConnectionPart connPart = null;
            if (sapphirePart instanceof DiagramNodePart) {
                nodePart = (DiagramNodePart) sapphirePart;
                DiagramNodeModel nodeModel = this.getDiagramModel().getDiagramNodeModel(nodePart);
                editpartObj = viewer.getEditPartRegistry().get(nodeModel);
            } else if (sapphirePart instanceof ShapePart) {
                nodePart = sapphirePart.nearest(DiagramNodePart.class);
                DiagramNodeModel nodeModel = this.getDiagramModel().getDiagramNodeModel(nodePart);
                ShapeModel shapeModel = ShapeModelUtil.getChildShapeModel(nodeModel.getShapeModel(),
                        (ShapePart) sapphirePart);
                editpartObj = viewer.getEditPartRegistry().get(shapeModel);
            } else if (sapphirePart instanceof DiagramConnectionPart) {
                connPart = (DiagramConnectionPart) sapphirePart;
                DiagramConnectionModel connModel = this.getDiagramModel().getDiagramConnectionModel(connPart);
                editpartObj = viewer.getEditPartRegistry().get(connModel);
            }
            return (GraphicalEditPart) editpartObj;
        }
        return null;
    }

    public void selectAndDirectEditPart(final ISapphirePart part) {
        if (part instanceof DiagramNodePart || part instanceof ShapePart || part instanceof DiagramConnectionPart) {
            GraphicalViewer viewer = getGraphicalViewer();
            // Bug 370869 - DND from the tool palette would show an invalid cursor before placing the new node 
            // in direct edit mode. TODO why?
            //viewer.getControl().forceFocus();

            GraphicalEditPart editpart = getGraphicalEditPart(part);
            ISapphirePart parentPart = part.parent();
            while ((editpart == null || !editpart.isSelectable()) && parentPart != null) {
                editpart = getGraphicalEditPart(parentPart);
                parentPart = parentPart.parent();
            }
            if (editpart != null) {
                // Force a layout first.
                viewer.flush();
                viewer.select(editpart);
                viewer.reveal(editpart);
                if (part instanceof DiagramNodePart) {
                    getDiagramModel().handleDirectEditing((DiagramNodePart) part);
                } else if (part instanceof ShapePart) {
                    getDiagramModel().handleDirectEditing((ShapePart) part);
                } else if (part instanceof DiagramConnectionPart) {
                    getDiagramModel().handleDirectEditing((DiagramConnectionPart) part);
                }

            }
        }
    }

    public void selectAll() {
        GraphicalViewer viewer = this.getGraphicalViewer();
        for (Object obj : viewer.getEditPartRegistry().values()) {
            if (obj instanceof DiagramConnectionEditPart || obj instanceof DiagramNodeEditPart) {
                viewer.appendSelection((EditPart) obj);
            }
        }
    }

    public void selectAllNodes() {
        GraphicalViewer viewer = this.getGraphicalViewer();
        viewer.deselectAll();
        for (Object obj : viewer.getEditPartRegistry().values()) {
            if (obj instanceof DiagramNodeEditPart) {
                viewer.appendSelection((DiagramNodeEditPart) obj);
            }
        }
    }

    public void selectParts(final List<ISapphirePart> selections) {
        boolean selectionChanged = false;
        if (this.selectedParts.size() != selections.size()) {
            selectionChanged = true;
        } else if (!this.selectedParts.containsAll(selections) || !selections.containsAll(this.selectedParts)) {
            selectionChanged = true;
        }
        if (selectionChanged) {
            GraphicalViewer viewer = this.getGraphicalViewer();

            if (selections.isEmpty()) {
                viewer.flush();
                viewer.deselectAll();
                return;
            }
            boolean first = true;
            for (ISapphirePart sapphirePart : selections) {
                Object editpartObj = getGraphicalEditPart(sapphirePart);
                if (editpartObj != null) {
                    if (first) {
                        viewer.flush();
                        viewer.select((EditPart) editpartObj);
                        first = false;
                    } else {
                        viewer.appendSelection((EditPart) editpartObj);
                    }
                    viewer.reveal((EditPart) editpartObj);
                }
            }
        }
    }

    public Point getMouseLocation() {
        if (mouseLocation == null) {
            mouseLocation = new Point();
        }
        return mouseLocation;
    }

    private void setMouseLocation(int x, int y) {
        getMouseLocation().setLocation(x, y);
        Point realLocation = calculateRealMouseLocation(getMouseLocation());
        this.part.setMouseLocation(realLocation.x, realLocation.y);
    }

    public FigureCanvas getFigureCanvas() {
        GraphicalViewer viewer = getGraphicalViewer();
        return (FigureCanvas) viewer.getControl();
    }

    public double getZoomLevel() {
        ZoomManager zoomManager = getZoomManager();
        if (zoomManager == null)
            return 1;

        /*
         * avoid long running calculations for large diagrams and zoom factors
         * below 5%
         */
        return Math.max(0.05D, zoomManager.getZoom());
    }

    /**
     * Calculates the location in dependence from scrollbars and zoom factor.
     * 
     * @param nativeLocation
     *            the native location
     * @return the point
     */
    public Point calculateRealMouseLocation(Point nativeLocation) {
        Point ret = new Point(nativeLocation);
        Point viewLocation;
        // view location depends on the current scroll bar position
        viewLocation = getFigureCanvas().getViewport().getViewLocation();

        ret.x += viewLocation.x;
        ret.y += viewLocation.y;

        final ZoomManager zoomManager = getZoomManager();

        if (zoomManager != null) {
            ret = ret.getScaled(1 / zoomManager.getZoom());
        }

        return ret;
    }

    @Override
    public void dispose() {
        super.dispose();

        diagramPresentation.dispose();

        if (layoutPersistenceService != null) {
            // FIXME: KOSTA: This is very questionable. Only service context should be disposing services.

            layoutPersistenceService.detach(this.layoutPersistenceServiceListener);
            layoutPersistenceService.dispose();
        }

        this.part.detach(this.diagramEditorPagePartListener);
        final Image image = this.header.getImage();
        if (image != null) {
            image.dispose();
        }

        for (ActionSystemPartBridge bridge : this.globalActions.values()) {
            bridge.dispose();
        }

        this.element = null;

        this.part.dispose();
        this.part = null;

        this.definition.dispose();
        this.definition = null;
    }

    public boolean isDirectEditingActive() {
        return directEditingActive;
    }

    public void setDirectEditingActive(boolean directEditingActive) {
        this.directEditingActive = directEditingActive;
        getContextButtonManager().hideContextButtonsInstantly();
    }

    private void configureDiagramHeading() {
        decorateHeading();

        final SapphireActionGroup actions = this.part.getActions(SapphireActionSystem.CONTEXT_DIAGRAM_HEADER);
        if (actions != null && !actions.isEmpty()) {
            final SapphireActionPresentationManager actionPresentationManager = new SapphireActionPresentationManager(
                    this.diagramPresentation, actions);
            final SapphireToolBarManagerActionPresentation actionPresentation = new SapphireToolBarManagerActionPresentation(
                    actionPresentationManager);
            actionPresentation.setToolBarManager(this.header.getToolBarManager());
            actionPresentation.render();
        }

        refreshPageHeaderText();
        refreshPageHeaderImage();
    }

    /**
     * Takes advantage of the gradients and other capabilities to decorate the
     * form heading using colors computed based on the current skin and
     * operating system.
     * 
     * @since 3.3
     */

    private void decorateHeading() {
        Color top = this.formColors.getColor(IFormColors.H_GRADIENT_END);
        Color bot = this.formColors.getColor(IFormColors.H_GRADIENT_START);
        this.header.setTextBackground(new Color[] { top, bot }, new int[] { 100 }, true);
        this.header.putColor(IFormColors.H_BOTTOM_KEYLINE1,
                this.formColors.getColor(IFormColors.H_BOTTOM_KEYLINE1));
        this.header.putColor(IFormColors.H_BOTTOM_KEYLINE2,
                this.formColors.getColor(IFormColors.H_BOTTOM_KEYLINE2));
        this.header.putColor(IFormColors.H_HOVER_LIGHT, this.formColors.getColor(IFormColors.H_HOVER_LIGHT));
        this.header.putColor(IFormColors.H_HOVER_FULL, this.formColors.getColor(IFormColors.H_HOVER_FULL));
        this.header.putColor(IFormColors.TB_TOGGLE, this.formColors.getColor(IFormColors.TB_TOGGLE));
        this.header.putColor(IFormColors.TB_TOGGLE_HOVER, this.formColors.getColor(IFormColors.TB_TOGGLE_HOVER));
        this.header.setSeparatorVisible(true);
        this.header.setFont(JFaceResources.getHeaderFont());
        this.header.setForeground(this.formColors.getColor(IFormColors.TITLE));
    }

    private void refreshPageHeaderText() {
        this.header.setText(
                LabelTransformer.transform(this.part.getPageHeaderText(), CapitalizationType.TITLE_STYLE, false));
        this.header.layout();
    }

    private void refreshPageHeaderImage() {
        final Image oldImage = this.header.getImage();

        if (oldImage != null) {
            oldImage.dispose();
        }

        final ImageData newImageData = this.part.getPageHeaderImage();

        if (newImageData == null) {
            this.header.setImage(null);
        } else {
            this.header.setImage(toImageDescriptor(newImageData).createImage());
        }
    }

    private void refreshZoomLevel() {
        final int zoomLevel = this.part.getZoomLevel();
        final double zoom = (double) zoomLevel / 100;

        getZoomManager().setZoom(zoom);
    }

    private ZoomManager getZoomManager() {
        return (ZoomManager) getGraphicalViewer().getProperty(ZoomManager.class.toString());
    }

    private SapphireDiagramOutline getDiagramOutline() {
        if (this.diagramOutline == null && getGraphicalViewer() != null) {
            RootEditPart rootEditPart = getGraphicalViewer().getRootEditPart();
            if (rootEditPart instanceof ScalableFreeformRootEditPart) {
                this.diagramOutline = new SapphireDiagramOutline((ScalableFreeformRootEditPart) rootEditPart);
            }
        }
        return this.diagramOutline;
    }

    // -----------------------------------------------------------------------------------------------
    // Inner classes
    //------------------------------------------------------------------------------------------------

    private class FormLayout extends Layout implements ILayoutExtension {
        public int computeMinimumWidth(Composite composite, boolean flushCache) {
            return computeSize(composite, 5, SWT.DEFAULT, flushCache).x;
        }

        public int computeMaximumWidth(Composite composite, boolean flushCache) {
            return computeSize(composite, SWT.DEFAULT, SWT.DEFAULT, flushCache).x;
        }

        public org.eclipse.swt.graphics.Point computeSize(Composite composite, int wHint, int hHint,
                boolean flushCache) {
            if (flushCache) {
                bodyCache.flush();
                headCache.flush();
            }
            bodyCache.setControl(body);
            headCache.setControl(header);

            int width = 0;
            int height = 0;

            org.eclipse.swt.graphics.Point hsize = headCache.computeSize(FormUtil.getWidthHint(wHint, header),
                    SWT.DEFAULT);
            width = Math.max(hsize.x, width);
            height = hsize.y;

            boolean ignoreBody = false;

            org.eclipse.swt.graphics.Point bsize;
            if (ignoreBody)
                bsize = new org.eclipse.swt.graphics.Point(0, 0);
            else
                bsize = bodyCache.computeSize(FormUtil.getWidthHint(wHint, body), SWT.DEFAULT);
            width = Math.max(bsize.x, width);
            height += bsize.y;
            return new org.eclipse.swt.graphics.Point(width, height);
        }

        protected void layout(Composite composite, boolean flushCache) {
            if (flushCache) {
                bodyCache.flush();
                headCache.flush();
            }
            bodyCache.setControl(body);
            headCache.setControl(header);
            Rectangle carea = composite.getClientArea();

            org.eclipse.swt.graphics.Point hsize = headCache.computeSize(carea.width, SWT.DEFAULT);
            headCache.setBounds(0, 0, carea.width, hsize.y);
            bodyCache.setBounds(0, hsize.y, carea.width, carea.height - hsize.y);
        }
    }

}