bilab.notebook.NotebookPageEditor.java Source code

Java tutorial

Introduction

Here is the source code for bilab.notebook.NotebookPageEditor.java

Source

/**
 * This document is a part of the source code and related artifacts for BiLab,
 * an open source interactive workbench for computational biologists.
 * 
 * http://computing.ornl.gov/
 * 
 * Copyright  2011 Oak Ridge National Laboratory
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package bilab.notebook;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.EventObject;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
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.dnd.TemplateTransferDragSourceListener;
import org.eclipse.gef.dnd.TemplateTransferDropTargetListener;
import org.eclipse.gef.editparts.ScalableRootEditPart;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.requests.CreationFactory;
import org.eclipse.gef.requests.SimpleFactory;
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.TreeViewer;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.util.TransferDropTargetListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;

import bilab.notebook.model.GraphicsDiagram;
import bilab.notebook.parts.GraphicsEditPartFactory;
import bilab.notebook.parts.GraphicsTreeEditPartFactory;

/**
 * A graphical editor with flyout palette that can edit .bln files. The binding
 * between the .shapes file extension and this editor is done in plugin.xml
 * 
 * @author Elias Volanakis
 */
public class NotebookPageEditor extends GraphicalEditorWithFlyoutPalette {

    /**
     * Creates an outline pagebook for this editor.
     */
    public class NotebookEditorOutlinePage extends ContentOutlinePage {
        /**
         * Pointer to the editor instance associated with this outline page.
         * Used for calling back on editor methods.
         */
        private final NotebookPageEditor editor;
        /** A pagebook can containt multiple pages (just one in our case). */
        private PageBook pagebook;

        /**
         * Create a new outline page for the shapes editor.
         * 
         * @param editor
         *            the editor associated with this outline page (non-null)
         * @param viewer
         *            a viewer (TreeViewer instance) used for this outline page
         * @throws IllegalArgumentException
         *             if editor is null
         */
        public NotebookEditorOutlinePage(final NotebookPageEditor editor, final EditPartViewer viewer) {
            super(viewer);
            if (editor == null) {
                throw new IllegalArgumentException();
            }
            this.editor = editor;
        }

        /*
         * (non-Javadoc)
         * 
         * @see
         * org.eclipse.ui.part.IPage#createControl(org.eclipse.swt.widgets.Composite
         * )
         */
        @Override
        public void createControl(final Composite parent) {
            pagebook = new PageBook(parent, SWT.NONE);

            // create outline viewer page
            final Control outline = getViewer().createControl(pagebook);
            // configure outline viewer
            getViewer().setEditDomain(editor.getEditDomain());
            getViewer().setEditPartFactory(new GraphicsTreeEditPartFactory());
            getViewer().setKeyHandler(editor.getCommonKeyHandler());
            // configure & add context menu to viewer
            final ContextMenuProvider cmProvider = new NotebookPageEditorContextMenuProvider(getViewer(),
                    editor.getActionRegistry());
            getViewer().setContextMenu(cmProvider);
            getSite().registerContextMenu("org.eclipse.gef.examples.shapes.outline.contextmenu", cmProvider,
                    getSite().getSelectionProvider());
            // hook outline viewer
            editor.getSelectionSynchronizer().addViewer(getViewer());
            // initialize outline viewer with model
            getViewer().setContents(editor.getModel());
            // show outline viewer
            pagebook.showPage(outline);
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.ui.part.IPage#dispose()
         */
        @Override
        public void dispose() {
            // unhook outline viewer
            editor.getSelectionSynchronizer().removeViewer(getViewer());
            // dispose
            super.dispose();
            editor.disposeOutlinePage();
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.ui.part.IPage#getControl()
         */
        @Override
        public Control getControl() {
            return pagebook;
        }
    } // inner class

    /** This is the root of the editor's model. */
    private GraphicsDiagram diagram = new GraphicsDiagram();
    /** OutlinePage instance for this editor. */
    private IContentOutlinePage outlinePage;
    /** Palette component, holding the tools and shapes. */
    private PaletteRoot palette;
    /** Cache save-request status. */
    private boolean saveAlreadyRequested;

    /**
     * KeyHandler with common bindings for both the Outline View and the Editor.
     */
    private KeyHandler sharedKeyHandler;

    /** Create a new ShapesEditor instance. This is called by the Workspace. */
    public NotebookPageEditor() {
        setEditDomain(new DefaultEditDomain(this));
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.gef.ui.parts.GraphicalEditor#commandStackChanged(java.util
     * .EventObject)
     */
    @Override
    public void commandStackChanged(final EventObject event) {
        super.commandStackChanged(event);
        if (isDirty() && !saveAlreadyRequested) {
            saveAlreadyRequested = true;
            firePropertyChange(IEditorPart.PROP_DIRTY);
        } else {
            saveAlreadyRequested = false;
            firePropertyChange(IEditorPart.PROP_DIRTY);
        }
    }

    /**
     * Configure the graphical viewer before it receives contents.
     * <p>
     * This is the place to choose an appropriate RootEditPart and
     * EditPartFactory for your editor. The RootEditPart determines the behavior
     * of the editor's "work-area". For example, GEF includes zoomable and
     * scrollable root edit parts. The EditPartFactory maps model elements to
     * edit parts (controllers).
     * </p>
     * 
     * @see org.eclipse.gef.ui.parts.GraphicalEditor#configureGraphicalViewer()
     */
    @Override
    protected void configureGraphicalViewer() {
        super.configureGraphicalViewer();

        final GraphicalViewer viewer = getGraphicalViewer();
        viewer.setRootEditPart(new ScalableRootEditPart());
        viewer.setEditPartFactory(new GraphicsEditPartFactory());
        viewer.setKeyHandler(new GraphicalViewerKeyHandler(viewer).setParent(getCommonKeyHandler()));

        // configure the context menu provider
        final ContextMenuProvider cmProvider = new NotebookPageEditorContextMenuProvider(viewer,
                getActionRegistry());
        viewer.setContextMenu(cmProvider);
        getSite().registerContextMenu(cmProvider, viewer);
    }

    private void createOutputStream(final OutputStream os) throws IOException {
        final ObjectOutputStream oos = new ObjectOutputStream(os);
        oos.writeObject(getModel());
        oos.close();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#
     * createPaletteViewerProvider()
     */
    @Override
    protected PaletteViewerProvider createPaletteViewerProvider() {
        return new PaletteViewerProvider(getEditDomain()) {
            @Override
            protected void configurePaletteViewer(final PaletteViewer viewer) {
                super.configurePaletteViewer(viewer);
                // create a drag source listener for this palette viewer
                // together with an appropriate transfer drop target listener,
                // this will enable
                // model element creation by dragging a
                // CombinatedTemplateCreationEntries
                // from the palette into the editor
                // @see ShapesEditor#createTransferDropTargetListener()
                viewer.addDragSourceListener(new TemplateTransferDragSourceListener(viewer));
            }
        };
    }

    /**
     * Create a transfer drop target listener. When using a
     * CombinedTemplateCreationEntry tool in the palette, this will enable model
     * element creation by dragging from the palette.
     * 
     * @see #createPaletteViewerProvider()
     */
    private TransferDropTargetListener createTransferDropTargetListener() {
        return new TemplateTransferDropTargetListener(getGraphicalViewer()) {
            @Override
            protected CreationFactory getFactory(final Object template) {
                return new SimpleFactory((Class) template);
            }
        };
    }

    /**
     * Forget the outline page for this editor. Note that this is called from
     * ShapesEditorOutlinePage#dispose, so the outline page is already disposed.
     * 
     * @see ShapesEditorOutlinePage#dispose()
     */
    private void disposeOutlinePage() {
        outlinePage = null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor
     * )
     */
    @Override
    public void doSave(final IProgressMonitor monitor) {

        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            createOutputStream(out);
            final IFile file = ((IFileEditorInput) getEditorInput()).getFile();
            file.setContents(new ByteArrayInputStream(out.toByteArray()), true, // keep
                    // saving,
                    // even
                    // if
                    // IFile
                    // is
                    // out
                    // of
                    // sync
                    // with
                    // the
                    // Workspace
                    false, // dont keep history
                    monitor); // progress monitor
            getCommandStack().markSaveLocation();
        } catch (final CoreException ce) {
            ce.printStackTrace();
        } catch (final IOException ioe) {
            ioe.printStackTrace();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.ISaveablePart#doSaveAs()
     */
    @Override
    public void doSaveAs() {
        // Show a SaveAs dialog
        final Shell shell = getSite().getWorkbenchWindow().getShell();
        final SaveAsDialog dialog = new SaveAsDialog(shell);
        dialog.setOriginalFile(((IFileEditorInput) getEditorInput()).getFile());
        dialog.open();

        final 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, // don't fork
                        false, // not cancelable
                        new WorkspaceModifyOperation() { // run this operation
                            @Override
                            public void execute(final IProgressMonitor monitor) {
                                try {
                                    final ByteArrayOutputStream out = new ByteArrayOutputStream();
                                    createOutputStream(out);
                                    file.create(new ByteArrayInputStream(out.toByteArray()), // contents
                                            true, // keep saving, even if IFile
                                            // is out of sync with the
                                            // Workspace
                                            monitor); // progress monitor
                                } catch (final CoreException ce) {
                                    ce.printStackTrace();
                                } catch (final IOException ioe) {
                                    ioe.printStackTrace();
                                }
                            }
                        });
                // set input to the new file
                setInput(new FileEditorInput(file));
                getCommandStack().markSaveLocation();
            } catch (final InterruptedException ie) {
                // should not happen, since the monitor dialog is not cancelable
                ie.printStackTrace();
            } catch (final InvocationTargetException ite) {
                ite.printStackTrace();
            }
        } // if
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#getAdapter(
     * java.lang.Class)
     */
    @Override
    public Object getAdapter(final Class type) {
        // returns the content outline page for this editor
        if (type == IContentOutlinePage.class) {
            if (outlinePage == null) {
                outlinePage = new NotebookEditorOutlinePage(this, new TreeViewer());
            }
            return outlinePage;
        }
        return super.getAdapter(type);
    }

    /**
     * Returns the KeyHandler with common bindings for both the Outline and
     * Graphical Views. For example, delete is a common action.
     */
    KeyHandler getCommonKeyHandler() {
        if (sharedKeyHandler == null) {
            sharedKeyHandler = new KeyHandler();

            // Add key and action pairs to sharedKeyHandler
            sharedKeyHandler.put(KeyStroke.getPressed(SWT.DEL, 127, 0),
                    getActionRegistry().getAction(ActionFactory.DELETE.getId()));
        }
        return sharedKeyHandler;
    }

    private GraphicsDiagram getModel() {
        return diagram;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#
     * getPalettePreferences()
     */
    @Override
    protected FlyoutPreferences getPalettePreferences() {
        return NotebookPageEditorPaletteFactory.createPalettePreferences();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#getPaletteRoot
     * ()
     */
    @Override
    protected PaletteRoot getPaletteRoot() {
        if (palette == null) {
            palette = NotebookPageEditorPaletteFactory.createPalette();
        }
        return palette;
    }

    private void handleLoadException(final Exception e) {
        bilab.Notify.userError(this,
                "Unable to load the specified file as a Notebook.  Creating empty document instead.");
        diagram = new GraphicsDiagram();
    }

    /**
     * Set up the editor's inital content (after creation).
     * 
     * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#initializeGraphicalViewer()
     */
    @Override
    protected void initializeGraphicalViewer() {
        super.initializeGraphicalViewer();
        final GraphicalViewer graphicalViewer = getGraphicalViewer();
        graphicalViewer.setContents(getModel()); // set the contents of this
                                                 // editor
                                                 // listen for dropped parts
        graphicalViewer.addDropTargetListener(createTransferDropTargetListener());
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.ISaveablePart#isDirty()
     */
    @Override
    public boolean isDirty() {
        return getCommandStack().isDirty();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
     */
    @Override
    public boolean isSaveAsAllowed() {
        return true;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.EditorPart#setInput(org.eclipse.ui.IEditorInput)
     */
    @Override
    protected void setInput(final IEditorInput input) {
        super.setInput(input);
        try {
            final IFile file = ((IFileEditorInput) input).getFile();
            final ObjectInputStream in = new ObjectInputStream(file.getContents());
            diagram = (GraphicsDiagram) in.readObject();
            in.close();
            setPartName(file.getName());
        } catch (final IOException e) {
            handleLoadException(e);
        } catch (final CoreException e) {
            handleLoadException(e);
        } catch (final ClassNotFoundException e) {
            handleLoadException(e);
        } catch (final Exception e) {
            handleLoadException(e);
        }
    }
}