org.eclipse.bpmn2.modeler.ui.editor.BPMN2MultiPageEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.bpmn2.modeler.ui.editor.BPMN2MultiPageEditor.java

Source

/*******************************************************************************
 * Copyright (c) 2011, 2012 Red Hat, Inc.
 *  All rights reserved.
 * This program is 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:
 * Red Hat, Inc. - initial API and implementation
 *
 * @author Bob Brodt
 ******************************************************************************/

package org.eclipse.bpmn2.modeler.ui.editor;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.Transaction;
import org.eclipse.bpmn2.ReceiveTask;
import org.eclipse.bpmn2.di.BPMNDiagram;
import org.eclipse.bpmn2.modeler.core.utils.ModelUtil;
import org.eclipse.bpmn2.modeler.ui.Bpmn2DiagramEditorInput;
import org.eclipse.core.internal.resources.Container;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.command.CommandStack;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.graphiti.ui.editor.DiagramEditor;
import org.eclipse.graphiti.ui.editor.DiagramEditorInput;
import org.eclipse.graphiti.ui.internal.services.GraphitiUiInternal;
import org.eclipse.graphiti.ui.services.GraphitiUi;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabFolder2Listener;
import org.eclipse.swt.custom.CTabFolderEvent;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.ISaveablePart2;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.ide.IGotoMarker;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.part.MultiPageEditorSite;
import org.eclipse.ui.internal.WorkbenchMessages;

import de.tudarmstadt.dvs.ukuflow.hash.HashUtil;
import de.tudarmstadt.dvs.ukuflow.script.eventbasescript.expression.EEventBaseScript;
import de.tudarmstadt.dvs.ukuflow.tools.debugger.BpmnLog;

/**
 * This class implements a multi-page version of the BPMN2 Modeler (BPMN2Editor
 * class). To revert back to the original, single-page version simply change the
 * editor extension point in plugin.xml (see comments there).
 * 
 * This is still in the experimental phase and currently only supports a single
 * diagram per .bpmn file. An optional second page, which displays the XML
 * source, can be created from the context menu. The source view is not yet
 * synchronized to the design view and can only show the XML as of the last
 * "Save" i.e. the current state of the file on disk, not the in-memory model.
 * Design/Source view synchronization will be implemented in a future version,
 * but direct editing of the XML will not be supported - it will remain
 * "view only".
 * 
 * Future versions will support multiple diagrams per .bpmn file with the
 * ability to add and remove pages containing different diagram types. It should
 * be possible for the user to create a single file that contains a mix of
 * Process, Collaboration and Choreography diagrams. Whether or not these types
 * of files are actually deployable and/or executable is another story ;)
 */
public class BPMN2MultiPageEditor extends MultiPageEditorPart implements IGotoMarker {

    DesignEditor designEditor;
    SourceViewer sourceViewer;
    private CTabFolder tabFolder;
    private int defaultTabHeight;
    private List<BPMNDiagram> bpmnDiagrams = new ArrayList<BPMNDiagram>();
    // HIENADD: additional attributes:
    Map<EditorPart, Tupel> mapping = new HashMap<EditorPart, Tupel>();
    // providerID is the id for event viewer editor. so that Graphiti knows how
    // to open it.
    private final static String ProviderID = "ukuFlowEvent";
    private BpmnLog log = BpmnLog.getInstance(this.getClass().getSimpleName());

    // HIENDONE
    public BPMN2MultiPageEditor() {
        super();
    }

    @Override
    protected IEditorSite createSite(IEditorPart editor) {
        if (editor instanceof DesignEditor)
            return new DesignEditorSite(this, editor);
        return new MultiPageEditorSite(this, editor);
    }

    @Override
    public String getTitle() {
        if (designEditor != null)
            return designEditor.getTitle();
        return super.getTitle();
    }

    @Override
    public String getPartName() {
        if (designEditor != null)
            return designEditor.getPartName();
        return super.getPartName();
    }

    /**
     * Method declared on IEditorPart.
     * 
     * @param marker
     *            Marker to look for
     */
    @Override
    public void gotoMarker(IMarker marker) {
        if (getActivePage() < 0) {
            setActivePage(0);
        }
        IDE.gotoMarker(getEditor(getActivePage()), marker);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.MultiPageEditorPart#createPages()
     */
    @Override
    protected void createPages() {
        tabFolder = (CTabFolder) getContainer();
        tabFolder.addCTabFolder2Listener(new CTabFolder2Listener() {

            @Override
            public void close(CTabFolderEvent event) {
                // System.out.println("Convert phase should be here");

                if (event.item.getData() == sourceViewer)
                    removeSourceViewer();
                else if (event.item.getData() instanceof DiagramEditor) {
                    // TODO: checking modification:
                    String MESSAGE = "Resource has been modified. Save changes?";
                    int choice = -1;
                    DiagramEditor editor = (DiagramEditor) event.item.getData();
                    if (editor.isDirty()) {
                        // ASK FOR SAVE:
                        Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
                        String[] buttons = new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL,
                                IDialogConstants.CANCEL_LABEL };
                        MessageDialog d = new MessageDialog(shell, WorkbenchMessages.Save_Resource, null, MESSAGE,
                                MessageDialog.QUESTION, buttons, 0) {
                            protected int getShellStyle() {
                                return super.getShellStyle() | SWT.SHEET;
                            }
                        };
                        choice = d.open();
                        switch (choice) {
                        case ISaveablePart2.YES: // yes                     
                            editor.doSave(new NullProgressMonitor());
                            break;
                        case ISaveablePart2.NO: // no
                            System.out.println("no");
                            break;
                        default:
                        case ISaveablePart2.CANCEL: // cancel
                            System.out.println("cancel");
                            event.doit = false;
                            return;
                        }
                    }
                    removeEventViewer(editor);
                }
            }

            @Override
            public void minimize(CTabFolderEvent event) {
            }

            @Override
            public void maximize(CTabFolderEvent event) {
            }

            @Override
            public void restore(CTabFolderEvent event) {
            }

            @Override
            public void showList(CTabFolderEvent event) {
            }

        });
        tabFolder.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                int pageIndex = tabFolder.getSelectionIndex();
                if (pageIndex >= 0 && pageIndex < bpmnDiagrams.size() && designEditor != null) {
                    BPMNDiagram bpmnDiagram = bpmnDiagrams.get(pageIndex);
                    designEditor.selectBpmnDiagram(bpmnDiagram);
                }
            }
        });

        // defer editor layout until all pages have been created
        tabFolder.setLayoutDeferred(true);

        createDesignEditor();

        Display.getDefault().asyncExec(new Runnable() {
            public void run() {
                setActivePage(0);
                designEditor.selectBpmnDiagram(bpmnDiagrams.get(0));
                tabFolder.setLayoutDeferred(false);
                tabFolder.setTabPosition(SWT.TOP);
                updateTabs();
            }
        });
    }

    protected void createDesignEditor() {
        if (designEditor == null) {
            designEditor = new DesignEditor(this, this);

            try {
                int pageIndex = tabFolder.getItemCount();
                if (sourceViewer != null)
                    --pageIndex;
                addPage(pageIndex, designEditor, BPMN2MultiPageEditor.this.getEditorInput());
                defaultTabHeight = tabFolder.getTabHeight();
                setPageText(pageIndex, ModelUtil.getDiagramTypeName(designEditor.getBpmnDiagram()));

                defaultTabHeight = tabFolder.getTabHeight();

                updateTabs();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public DesignEditor getDesignEditor() {
        return designEditor;
    }

    protected void addDesignPage(final BPMNDiagram bpmnDiagram) {
        createDesignEditor();
        Display.getDefault().asyncExec(new Runnable() {
            public void run() {
                try {

                    int pageIndex = tabFolder.getItemCount();
                    if (sourceViewer != null)
                        --pageIndex;
                    Bpmn2DiagramEditorInput input = (Bpmn2DiagramEditorInput) designEditor.getEditorInput();
                    input.setBpmnDiagram(bpmnDiagram);
                    addPage(pageIndex, designEditor, input);
                    CTabItem oldItem = tabFolder.getItem(pageIndex - 1);
                    CTabItem newItem = tabFolder.getItem(pageIndex);
                    newItem.setControl(oldItem.getControl());
                    setPageText(pageIndex, bpmnDiagram.getName());

                    setActivePage(pageIndex);
                    updateTabs();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public void showDesignPage(final BPMNDiagram bpmnDiagram) {
        final int pageIndex = bpmnDiagrams.indexOf(bpmnDiagram);
        if (pageIndex >= 0) {
            if (getDesignEditor().getBpmnDiagram() != bpmnDiagram) {
                setActivePage(pageIndex);
            }
        } else {
            designEditor.showDesignPage(bpmnDiagram);
        }
    }

    protected void removeDesignPage(final BPMNDiagram bpmnDiagram) {
        final int pageIndex = bpmnDiagrams.indexOf(bpmnDiagram);
        if (pageIndex > 0) {
            // go back to "Design" page - the only page that can't be removed
            Display.getCurrent().asyncExec(new Runnable() {
                @Override
                public void run() {
                    setActivePage(0);

                    IEditorPart editor = getEditor(pageIndex);
                    if (editor instanceof DesignEditor) {
                        ((DesignEditor) editor).deleteBpmnDiagram(bpmnDiagram);
                    }

                    // need to manage this ourselves so that the CTabFolder
                    // doesn't
                    // dispose our editor site (a child of the CTabItem.control)
                    tabFolder.getItem(pageIndex).setControl(null);

                    removePage(pageIndex);

                    tabFolder.getSelection().getControl().setVisible(true);
                }
            });
        }
    }

    public int getDesignPageCount() {
        int count = getPageCount();
        if (sourceViewer != null)
            --count;
        return count;
    }

    protected void createSourceViewer() {
        if (sourceViewer == null) {
            sourceViewer = new SourceViewer(this);

            try {
                int pageIndex = tabFolder.getItemCount();
                FileEditorInput input = new FileEditorInput(designEditor.getModelFile());
                addPage(pageIndex, sourceViewer, input);
                tabFolder.getItem(pageIndex).setShowClose(true);

                setPageText(pageIndex, "Source");
                setActivePage(pageIndex);

                updateTabs();
            } catch (Exception e) {
                e.printStackTrace();
                if (sourceViewer != null)
                    sourceViewer.dispose();
            }
        }
    }

    public SourceViewer getSourceViewer() {
        return sourceViewer;
    }

    public void removeSourceViewer() {
        // there will only be one source page and it will always be the last
        // page in the tab folder
        if (sourceViewer != null) {
            for (EditorPart ed : mapping.keySet()) {
                if (ed.equals(sourceViewer)) {
                    removePage(mapping.get(ed).index);
                    mapping.remove(ed);
                    sourceViewer = null;
                    break;
                }

            }
        }
    }

    public void addPage(int pageIndex, IEditorPart editor, IEditorInput input) throws PartInitException {
        super.addPage(pageIndex, editor, input);
        if (editor instanceof DesignEditor) {
            bpmnDiagrams.add(pageIndex, ((DesignEditor) editor).getBpmnDiagram());
        }
        String id = null;
        if (editor instanceof EventViewer) {
            id = ((EventViewer) editor).id;
        }
        mapping.put((EditorPart) editor, new Tupel(pageIndex, id));
    }

    @Override
    public void removePage(int pageIndex) {
        Object page = tabFolder.getItem(pageIndex).getData();
        super.removePage(pageIndex);
        updateTabs();
        if (page instanceof DesignEditor) {
            bpmnDiagrams.remove(pageIndex);
        }
    }

    @Override
    protected void pageChange(int newPageIndex) {
        super.pageChange(newPageIndex);

        IEditorPart editor = getEditor(newPageIndex);
        if (editor instanceof DesignEditor) {
            BPMNDiagram bpmnDiagram = bpmnDiagrams.get(newPageIndex);
            ((DesignEditor) editor).pageChange(bpmnDiagram);
            // Diagram diagram = DIUtils.findDiagram(designEditor, bpmnDiagram);
            // if (diagram != null)
            // designEditor.selectPictogramElements(new PictogramElement[]
            // {(PictogramElement)diagram});
        }
    }

    public int getPageCount() {
        return tabFolder.getItemCount();
    }

    public CTabItem getTabItem(int pageIndex) {
        return tabFolder.getItem(pageIndex);
    }

    public BPMNDiagram getBpmnDiagram(int i) {
        if (i >= 0 && i < bpmnDiagrams.size()) {
            return bpmnDiagrams.get(i);
        }
        return null;
    }

    private void updateTabs() {
        if (!tabFolder.getLayoutDeferred()) {
            if (tabFolder.getItemCount() == 1) {
                tabFolder.setTabHeight(0);
            } else
                tabFolder.setTabHeight(defaultTabHeight);
        }
        tabFolder.layout();
    }

    public CTabFolder getTabFolder() {
        return tabFolder;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.
     * IProgressMonitor)
     */
    @Override
    public void doSave(IProgressMonitor monitor) {
        IEditorPart editor = getActiveEditor();
        if (editor instanceof DesignEditor) {
            for (EditorPart ep : mapping.keySet()) {
                ep.doSave(monitor);
            }
            designEditor.doSave(monitor);
        } else {
            System.out.println("converting & saving event diagram ...");
            editor.doSave(monitor);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.EditorPart#doSaveAs()
     */
    @Override
    public void doSaveAs() {
        IEditorPart activeEditor = getActiveEditor();
        activeEditor.doSaveAs();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
     */
    @Override
    public boolean isSaveAsAllowed() {

        /*
         * Depending upon the active page in multipage editor, call the
         * saveAsAllowed. It helps to see whether a particular editor allows
         * 'save as' feature
         */
        IEditorPart activeEditor = getActiveEditor();
        if (activeEditor != null)
            return activeEditor.isSaveAsAllowed();
        return false;
    }

    @Override
    public void dispose() {
        designEditor.dispose();
        for (EditorPart editor : mapping.keySet()) {
            if (editor != null && !(editor instanceof DesignEditor))
                editor.dispose();
        }
    }

    @Override
    public IEditorPart getActiveEditor() {
        return super.getActiveEditor();
    }

    public void createEventViewer(ReceiveTask task, String nid, String text, EEventBaseScript ebs) {
        boolean recreateDiagram = false;
        EventViewer eventView = null;
        for (EditorPart ed : mapping.keySet()) {
            if (ed instanceof EventViewer) {
                if (((EventViewer) ed).id.equals(nid)) {
                    setActivePage(((EventViewer) ed).index);
                    return;
                }
            }
        }
        try {
            int pageIndex = tabFolder.getItemCount();
            IContainer folder = designEditor.getModelFile().getParent();

            IFile target = null;
            try {
                if (folder instanceof Container) {
                    target = ((Container) folder).getFile(nid + ".evb");
                    target = ResourcesPlugin.getWorkspace().getRoot()
                            .getFile(folder.getFullPath().addTrailingSeparator().append(nid + ".evb"));
                } else
                    log.error("cannot get file '" + nid + ".evb' from folder " + folder);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (target.exists()) {
                log.debug("target exists -> check matching and openfile?");
                String lastFileHash = task.getFileHash();
                String lastScriptHash = task.getScriptHash();
                if (task.getEventScript() == null || lastFileHash == null || lastScriptHash == null) {
                    recreateDiagram = true;
                } else {
                    String fileHash = HashUtil.getHash(target.getContents());
                    String scriptHash = HashUtil.getHash(task.getEventScript());
                    if (!fileHash.equals(lastFileHash) || !scriptHash.equals(lastScriptHash)) {
                        // TODO inform user that target file will be overrided!!!
                        Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
                        String[] buttons = new String[] { IDialogConstants.YES_LABEL,
                                //IDialogConstants.NO_LABEL,
                                IDialogConstants.CANCEL_LABEL };
                        @SuppressWarnings("restriction")
                        MessageDialog d = new MessageDialog(shell, "Override exist file?", null,
                                ".evb file and the script are inconsistent. Do you want to override .evb file?",
                                MessageDialog.QUESTION, buttons, 0) {
                            protected int getShellStyle() {
                                return super.getShellStyle() | SWT.SHEET;
                            }
                        };
                        int choice = d.open();
                        switch (choice) {
                        case ISaveablePart2.YES: // yes                     
                            //editor.doSave(new NullProgressMonitor());
                            break;
                        case ISaveablePart2.NO: // no
                            System.out.println("no");
                            return;
                        default:
                        case ISaveablePart2.CANCEL: // cancel
                            System.out.println("cancel");
                            //event.doit = false;
                            return;
                        }
                        recreateDiagram = true;
                    }
                }
            } else
                recreateDiagram = true;

            if (recreateDiagram) {
                recreateDiagram = true;
                log.debug("create file " + nid + ".evb and try to open it");
                // create & convert!
                final Diagram diagram = Graphiti.getPeCreateService().createDiagram(ProviderID, nid + ".evb", true);
                URI uri = URI.createPlatformResourceURI(target.getFullPath().toString(), true);
                // FileService
                @SuppressWarnings("restriction")
                final TransactionalEditingDomain editingDomain = GraphitiUiInternal.getEmfService()
                        .createResourceSetAndEditingDomain();
                final ResourceSet resourceSet = editingDomain.getResourceSet();
                final Resource resource = resourceSet.createResource(uri);
                final CommandStack cmdStack = editingDomain.getCommandStack();
                cmdStack.execute(new RecordingCommand(editingDomain) {

                    @Override
                    protected void doExecute() {
                        resource.setTrackingModification(true);
                        resource.getContents().add(diagram);

                    }
                });
                save(editingDomain, Collections.<Resource, Map<?, ?>>emptyMap());
                editingDomain.dispose();
            }
            // FileEditorInput input = new FileEditorInput();
            String id = GraphitiUi.getExtensionManager().getDiagramTypeProviderId(ProviderID);
            DiagramEditorInput input = new DiagramEditorInput(
                    // This is, folks, it works :D
                    //URI.createFileURI(target.getLocation().toOSString()),
                    //URI.createFileURI(target.getFullPath().toOSString()),
                    URI.createPlatformResourceURI(target.getFullPath().toString(), true), id);

            eventView = new EventViewer(task, nid, pageIndex, recreateDiagram, ebs);//TODO
            addPage(pageIndex, eventView, input);
            tabFolder.getItem(pageIndex).setShowClose(true);

            setPageText(pageIndex, nid);
            setActivePage(pageIndex);

            updateTabs();
        } catch (Exception e) {
            e.printStackTrace();
            if (eventView != null)
                eventView.dispose();
        }
    }

    private static void save(TransactionalEditingDomain editingDomain, Map<Resource, Map<?, ?>> options) {
        saveInWorkspaceRunnable(editingDomain, options);
    }

    private static void saveInWorkspaceRunnable(final TransactionalEditingDomain editingDomain,
            final Map<Resource, Map<?, ?>> options) {

        final Map<URI, Throwable> failedSaves = new HashMap<URI, Throwable>();
        final IWorkspaceRunnable wsRunnable = new IWorkspaceRunnable() {
            @Override
            public void run(final IProgressMonitor monitor) throws CoreException {

                final Runnable runnable = new Runnable() {

                    @Override
                    public void run() {
                        Transaction parentTx;
                        if (editingDomain != null && (parentTx = ((TransactionalEditingDomainImpl) editingDomain)
                                .getActiveTransaction()) != null) {
                            do {
                                if (!parentTx.isReadOnly()) {
                                    throw new IllegalStateException(
                                            "FileService.save() called from within a command (likely produces a deadlock)"); //$NON-NLS-1$
                                }
                            } while ((parentTx = ((TransactionalEditingDomainImpl) editingDomain)
                                    .getActiveTransaction().getParent()) != null);
                        }

                        final EList<Resource> resources = editingDomain.getResourceSet().getResources();
                        // Copy list to an array to prevent
                        // ConcurrentModificationExceptions
                        // during the saving of the dirty resources
                        Resource[] resourcesArray = new Resource[resources.size()];
                        resourcesArray = resources.toArray(resourcesArray);
                        final Set<Resource> savedResources = new HashSet<Resource>();
                        for (int i = 0; i < resourcesArray.length; i++) {
                            // In case resource modification tracking is
                            // switched on, we can check if a resource
                            // has been modified, so that we only need to same
                            // really changed resources; otherwise
                            // we need to save all resources in the set
                            final Resource resource = resourcesArray[i];
                            if (resource.isModified()) {
                                try {
                                    resource.save(options.get(resource));
                                    savedResources.add(resource);
                                } catch (final Throwable t) {
                                    failedSaves.put(resource.getURI(), t);
                                }
                            }
                        }
                    }
                };

                try {
                    editingDomain.runExclusive(runnable);
                } catch (final InterruptedException e) {
                    throw new RuntimeException(e);
                }
                editingDomain.getCommandStack().flush();
            }
        };
        try {
            ResourcesPlugin.getWorkspace().run(wsRunnable, null);
            if (!failedSaves.isEmpty()) {
                throw new WrappedException(createMessage(failedSaves), new RuntimeException());
            }
        } catch (final CoreException e) {
            final Throwable cause = e.getStatus().getException();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            }
            throw new RuntimeException(e);
        }
    }

    private static String createMessage(Map<URI, Throwable> failedSaves) {
        final StringBuilder buf = new StringBuilder("The following resources could not be saved:");
        for (final Entry<URI, Throwable> entry : failedSaves.entrySet()) {
            buf.append("\nURI: ").append(entry.getKey().toString()).append(", cause: \n")
                    .append(getExceptionAsString(entry.getValue()));
        }
        return buf.toString();
    }

    private static String getExceptionAsString(Throwable t) {
        final StringWriter stringWriter = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(stringWriter);
        t.printStackTrace(printWriter);
        final String result = stringWriter.toString();
        try {
            stringWriter.close();
        } catch (final IOException e) {
            // $JL-EXC$ ignore
        }
        printWriter.close();
        return result;
    }

    private void removeEventViewer(DiagramEditor view) {
        // there will only be one source page and it will always be the last
        // page in the tab folder
        for (EditorPart ed : mapping.keySet()) {
            if (ed.equals(view)) {
                int removeIndex = mapping.get(ed).index;
                System.out.println("remove page with id " + removeIndex);
                removePage(mapping.get(ed).index);
                mapping.remove(ed);
                view = null;
                for (EditorPart ed1 : mapping.keySet()) {
                    // update indices
                    if (mapping.get(ed1).index > removeIndex)
                        mapping.get(ed1).index -= 1;
                }
                break;
            }

        }
    }

    class Tupel {
        public int index;
        public String id;

        public Tupel(int index, String id) {
            this.index = index;
            this.id = id;
        }
    }
}