ac.soton.multisim.diagram.part.MultisimDocumentProvider.java Source code

Java tutorial

Introduction

Here is the source code for ac.soton.multisim.diagram.part.MultisimDocumentProvider.java

Source

/*
 * Copyright (c) 2014 University of Southampton.
 * 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
 */
package ac.soton.multisim.diagram.part;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.MultiRule;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.ui.URIEditorInput;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EContentAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.transaction.NotificationFilter;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.diagram.core.DiagramEditingDomainFactory;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.AbstractDocumentProvider;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.DiagramDocument;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDiagramDocument;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDiagramDocumentProvider;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDocument;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.internal.EditorStatusCodes;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.internal.util.DiagramIOUtil;
import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
import org.eclipse.gmf.runtime.emf.core.resources.GMFResourceFactory;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.part.FileEditorInput;
import org.eventb.emf.core.AbstractExtension;
import org.eventb.emf.core.machine.Machine;

import ac.soton.multisim.Component;
import ac.soton.multisim.ComponentDiagram;
import ac.soton.multisim.EventBComponent;
import ac.soton.multisim.MultisimPackage;

/**
 * @generated
 */
public class MultisimDocumentProvider extends AbstractDocumentProvider implements IDiagramDocumentProvider {

    /**
     * @generated
     */
    protected ElementInfo createElementInfo(Object element) throws CoreException {
        if (false == element instanceof FileEditorInput && false == element instanceof URIEditorInput) {
            throw new CoreException(new Status(IStatus.ERROR, MultisimDiagramEditorPlugin.ID, 0,
                    NLS.bind(Messages.MultisimDocumentProvider_IncorrectInputError,
                            new Object[] { element, "org.eclipse.ui.part.FileEditorInput", //$NON-NLS-1$
                                    "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ 
                    null));
        }
        IEditorInput editorInput = (IEditorInput) element;
        IDiagramDocument document = (IDiagramDocument) createDocument(editorInput);

        ResourceSetInfo info = new ResourceSetInfo(document, editorInput);
        info.setModificationStamp(computeModificationStamp(info));
        info.fStatus = null;
        return info;
    }

    /**
     * @generated
     */
    protected IDocument createDocument(Object element) throws CoreException {
        if (false == element instanceof FileEditorInput && false == element instanceof URIEditorInput) {
            throw new CoreException(new Status(IStatus.ERROR, MultisimDiagramEditorPlugin.ID, 0,
                    NLS.bind(Messages.MultisimDocumentProvider_IncorrectInputError,
                            new Object[] { element, "org.eclipse.ui.part.FileEditorInput", //$NON-NLS-1$
                                    "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ 
                    null));
        }
        IDocument document = createEmptyDocument();
        setDocumentContent(document, (IEditorInput) element);
        setupDocument(element, document);
        return document;
    }

    /**
     * Sets up the given document as it would be provided for the given element. The
     * content of the document is not changed. This default implementation is empty.
     * Subclasses may reimplement.
     * 
     * @param element the blue-print element
     * @param document the document to set up
     * @generated
     */
    protected void setupDocument(Object element, IDocument document) {
        // for subclasses
    }

    /**
     * @generated
     */
    private long computeModificationStamp(ResourceSetInfo info) {
        int result = 0;
        for (Iterator<Resource> it = info.getLoadedResourcesIterator(); it.hasNext();) {
            Resource nextResource = it.next();
            IFile file = WorkspaceSynchronizer.getFile(nextResource);
            if (file != null) {
                if (file.getLocation() != null) {
                    result += file.getLocation().toFile().lastModified();
                } else {
                    result += file.getModificationStamp();
                }
            }
        }
        return result;
    }

    /**
     * @generated
     */
    protected IDocument createEmptyDocument() {
        DiagramDocument document = new DiagramDocument();
        document.setEditingDomain(createEditingDomain());
        return document;
    }

    /**
     * @generated
     */
    private TransactionalEditingDomain createEditingDomain() {
        TransactionalEditingDomain editingDomain = DiagramEditingDomainFactory.getInstance().createEditingDomain();
        editingDomain.setID("ac.soton.multisim.diagram.EditingDomain"); //$NON-NLS-1$
        final NotificationFilter diagramResourceModifiedFilter = NotificationFilter
                .createNotifierFilter(editingDomain.getResourceSet())
                .and(NotificationFilter.createEventTypeFilter(Notification.ADD)).and(NotificationFilter
                        .createFeatureFilter(ResourceSet.class, ResourceSet.RESOURCE_SET__RESOURCES));
        editingDomain.getResourceSet().eAdapters().add(new Adapter() {

            private Notifier myTarger;

            public Notifier getTarget() {
                return myTarger;
            }

            public boolean isAdapterForType(Object type) {
                return false;
            }

            public void notifyChanged(Notification notification) {
                if (diagramResourceModifiedFilter.matches(notification)) {
                    Object value = notification.getNewValue();
                    if (value instanceof Resource) {
                        ((Resource) value).setTrackingModification(true);
                    }
                }
            }

            public void setTarget(Notifier newTarget) {
                myTarger = newTarget;
            }

        });

        return editingDomain;
    }

    /**
     * @generated
     */
    protected void setDocumentContent(IDocument document, IEditorInput element) throws CoreException {
        IDiagramDocument diagramDocument = (IDiagramDocument) document;
        TransactionalEditingDomain domain = diagramDocument.getEditingDomain();
        if (element instanceof FileEditorInput) {
            IStorage storage = ((FileEditorInput) element).getStorage();
            Diagram diagram = DiagramIOUtil.load(domain, storage, true, getProgressMonitor());
            document.setContent(diagram);
        } else if (element instanceof URIEditorInput) {
            URI uri = ((URIEditorInput) element).getURI();
            Resource resource = null;
            try {
                resource = domain.getResourceSet().getResource(uri.trimFragment(), false);
                if (resource == null) {
                    resource = domain.getResourceSet().createResource(uri.trimFragment());
                }
                if (!resource.isLoaded()) {
                    try {
                        Map options = new HashMap(GMFResourceFactory.getDefaultLoadOptions());
                        // @see 171060 
                        // options.put(org.eclipse.emf.ecore.xmi.XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, Boolean.TRUE);
                        resource.load(options);
                    } catch (IOException e) {
                        resource.unload();
                        throw e;
                    }
                }
                if (uri.fragment() != null) {
                    EObject rootElement = resource.getEObject(uri.fragment());
                    if (rootElement instanceof Diagram) {
                        document.setContent((Diagram) rootElement);
                        return;
                    }
                } else {
                    for (Iterator it = resource.getContents().iterator(); it.hasNext();) {
                        Object rootElement = it.next();
                        if (rootElement instanceof Diagram) {
                            document.setContent((Diagram) rootElement);
                            return;
                        }
                    }
                }
                throw new RuntimeException(Messages.MultisimDocumentProvider_NoDiagramInResourceError);
            } catch (Exception e) {
                CoreException thrownExcp = null;
                if (e instanceof CoreException) {
                    thrownExcp = (CoreException) e;
                } else {
                    String msg = e.getLocalizedMessage();
                    thrownExcp = new CoreException(new Status(IStatus.ERROR, MultisimDiagramEditorPlugin.ID, 0,
                            msg != null ? msg : Messages.MultisimDocumentProvider_DiagramLoadingError, e));
                }
                throw thrownExcp;
            }
        } else {
            throw new CoreException(new Status(IStatus.ERROR, MultisimDiagramEditorPlugin.ID, 0,
                    NLS.bind(Messages.MultisimDocumentProvider_IncorrectInputError,
                            new Object[] { element, "org.eclipse.ui.part.FileEditorInput", //$NON-NLS-1$
                                    "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ 
                    null));
        }
    }

    /**
     * @generated
     */
    public long getModificationStamp(Object element) {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            return computeModificationStamp(info);
        }
        return super.getModificationStamp(element);
    }

    /**
     * @generated
     */
    public boolean isDeleted(Object element) {
        IDiagramDocument document = getDiagramDocument(element);
        if (document != null) {
            Resource diagramResource = document.getDiagram().eResource();
            if (diagramResource != null) {
                IFile file = WorkspaceSynchronizer.getFile(diagramResource);
                return file == null || file.getLocation() == null || !file.getLocation().toFile().exists();
            }
        }
        return super.isDeleted(element);
    }

    /**
     * @generated
     */
    public ResourceSetInfo getResourceSetInfo(Object editorInput) {
        return (ResourceSetInfo) super.getElementInfo(editorInput);
    }

    /**
     * @generated
     */
    protected void disposeElementInfo(Object element, ElementInfo info) {
        if (info instanceof ResourceSetInfo) {
            ResourceSetInfo resourceSetInfo = (ResourceSetInfo) info;
            resourceSetInfo.dispose();
        }
        super.disposeElementInfo(element, info);
    }

    /**
     * @generated
     */
    protected void doValidateState(Object element, Object computationContext) throws CoreException {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            LinkedList<IFile> files2Validate = new LinkedList<IFile>();
            for (Iterator<Resource> it = info.getLoadedResourcesIterator(); it.hasNext();) {
                Resource nextResource = it.next();
                IFile file = WorkspaceSynchronizer.getFile(nextResource);
                if (file != null && file.isReadOnly()) {
                    files2Validate.add(file);
                }
            }
            ResourcesPlugin.getWorkspace().validateEdit(
                    (IFile[]) files2Validate.toArray(new IFile[files2Validate.size()]), computationContext);
        }

        super.doValidateState(element, computationContext);
    }

    /**
     * @generated
     */
    public boolean isReadOnly(Object element) {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            if (info.isUpdateCache()) {
                try {
                    updateCache(element);
                } catch (CoreException ex) {
                    MultisimDiagramEditorPlugin.getInstance()
                            .logError(Messages.MultisimDocumentProvider_isModifiable, ex);
                    // Error message to log was initially taken from org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.internal.l10n.EditorMessages.StorageDocumentProvider_isModifiable
                }
            }
            return info.isReadOnly();
        }
        return super.isReadOnly(element);
    }

    /**
     * @generated
     */
    public boolean isModifiable(Object element) {
        if (!isStateValidated(element)) {
            if (element instanceof FileEditorInput || element instanceof URIEditorInput) {
                return true;
            }
        }
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            if (info.isUpdateCache()) {
                try {
                    updateCache(element);
                } catch (CoreException ex) {
                    MultisimDiagramEditorPlugin.getInstance()
                            .logError(Messages.MultisimDocumentProvider_isModifiable, ex);
                    // Error message to log was initially taken from org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.internal.l10n.EditorMessages.StorageDocumentProvider_isModifiable
                }
            }
            return info.isModifiable();
        }
        return super.isModifiable(element);
    }

    /**
     * @generated
     */
    protected void updateCache(Object element) throws CoreException {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            for (Iterator<Resource> it = info.getLoadedResourcesIterator(); it.hasNext();) {
                Resource nextResource = it.next();
                IFile file = WorkspaceSynchronizer.getFile(nextResource);
                if (file != null && file.isReadOnly()) {
                    info.setReadOnly(true);
                    info.setModifiable(false);
                    return;
                }
            }
            info.setReadOnly(false);
            info.setModifiable(true);
            return;
        }
    }

    /**
     * @generated
     */
    protected void doUpdateStateCache(Object element) throws CoreException {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            info.setUpdateCache(true);
        }
        super.doUpdateStateCache(element);
    }

    /**
     * @generated
     */
    public boolean isSynchronized(Object element) {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            return info.isSynchronized();
        }
        return super.isSynchronized(element);
    }

    /**
     * @generated
     */
    protected ISchedulingRule getResetRule(Object element) {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            LinkedList<ISchedulingRule> rules = new LinkedList<ISchedulingRule>();
            for (Iterator<Resource> it = info.getLoadedResourcesIterator(); it.hasNext();) {
                Resource nextResource = it.next();
                IFile file = WorkspaceSynchronizer.getFile(nextResource);
                if (file != null) {
                    rules.add(ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(file));
                }
            }
            return new MultiRule((ISchedulingRule[]) rules.toArray(new ISchedulingRule[rules.size()]));
        }
        return null;
    }

    /**
     * @generated
     */
    protected ISchedulingRule getSaveRule(Object element) {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            LinkedList<ISchedulingRule> rules = new LinkedList<ISchedulingRule>();
            for (Iterator<Resource> it = info.getLoadedResourcesIterator(); it.hasNext();) {
                Resource nextResource = it.next();
                IFile file = WorkspaceSynchronizer.getFile(nextResource);
                if (file != null) {
                    rules.add(computeSchedulingRule(file));
                }
            }
            return new MultiRule((ISchedulingRule[]) rules.toArray(new ISchedulingRule[rules.size()]));
        }
        return null;
    }

    /**
     * @generated
     */
    protected ISchedulingRule getSynchronizeRule(Object element) {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            LinkedList<ISchedulingRule> rules = new LinkedList<ISchedulingRule>();
            for (Iterator<Resource> it = info.getLoadedResourcesIterator(); it.hasNext();) {
                Resource nextResource = it.next();
                IFile file = WorkspaceSynchronizer.getFile(nextResource);
                if (file != null) {
                    rules.add(ResourcesPlugin.getWorkspace().getRuleFactory().refreshRule(file));
                }
            }
            return new MultiRule((ISchedulingRule[]) rules.toArray(new ISchedulingRule[rules.size()]));
        }
        return null;
    }

    /**
     * @generated
     */
    protected ISchedulingRule getValidateStateRule(Object element) {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            LinkedList<ISchedulingRule> files = new LinkedList<ISchedulingRule>();
            for (Iterator<Resource> it = info.getLoadedResourcesIterator(); it.hasNext();) {
                Resource nextResource = it.next();
                IFile file = WorkspaceSynchronizer.getFile(nextResource);
                if (file != null) {
                    files.add(file);
                }
            }
            return ResourcesPlugin.getWorkspace().getRuleFactory()
                    .validateEditRule((IFile[]) files.toArray(new IFile[files.size()]));
        }
        return null;
    }

    /**
     * @generated
     */
    private ISchedulingRule computeSchedulingRule(IResource toCreateOrModify) {
        if (toCreateOrModify.exists())
            return ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(toCreateOrModify);

        IResource parent = toCreateOrModify;
        do {
            /*
             * XXX This is a workaround for
             * https://bugs.eclipse.org/bugs/show_bug.cgi?id=67601
             * IResourceRuleFactory.createRule should iterate the hierarchy
             * itself.
             */
            toCreateOrModify = parent;
            parent = toCreateOrModify.getParent();
        } while (parent != null && !parent.exists());

        return ResourcesPlugin.getWorkspace().getRuleFactory().createRule(toCreateOrModify);
    }

    /**
     * @generated
     */
    protected void doSynchronize(Object element, IProgressMonitor monitor) throws CoreException {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            for (Iterator<Resource> it = info.getLoadedResourcesIterator(); it.hasNext();) {
                Resource nextResource = it.next();
                handleElementChanged(info, nextResource, monitor);
            }
            return;
        }
        super.doSynchronize(element, monitor);
    }

    /**
     * @generated NOT
     */
    protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite)
            throws CoreException {
        ResourceSetInfo info = getResourceSetInfo(element);
        if (info != null) {
            if (!overwrite && !info.isSynchronized()) {
                throw new CoreException(
                        new Status(IStatus.ERROR, MultisimDiagramEditorPlugin.ID, IResourceStatus.OUT_OF_SYNC_LOCAL,
                                Messages.MultisimDocumentProvider_UnsynchronizedFileSaveError, null));
            }
            info.stopResourceListening();
            fireElementStateChanging(element);
            try {
                monitor.beginTask(Messages.MultisimDocumentProvider_SaveDiagramTask,
                        info.getResourceSet().getResources().size() + 1); //"Saving diagram"
                //XXX save Event-B component
                saveEventB(document);
                for (Iterator<Resource> it = info.getLoadedResourcesIterator(); it.hasNext();) {
                    Resource nextResource = it.next();
                    monitor.setTaskName(NLS.bind(Messages.MultisimDocumentProvider_SaveNextResourceTask,
                            nextResource.getURI()));
                    if (nextResource.isLoaded() && !info.getEditingDomain().isReadOnly(nextResource)) {
                        try {
                            nextResource.save(MultisimDiagramEditorUtil.getSaveOptions());
                        } catch (IOException e) {
                            fireElementStateChangeFailed(element);
                            throw new CoreException(new Status(IStatus.ERROR, MultisimDiagramEditorPlugin.ID,
                                    EditorStatusCodes.RESOURCE_FAILURE, e.getLocalizedMessage(), null));
                        }
                    }
                    monitor.worked(1);
                }
                monitor.done();
                info.setModificationStamp(computeModificationStamp(info));
            } catch (RuntimeException x) {
                fireElementStateChangeFailed(element);
                throw x;
            } finally {
                info.startResourceListening();
            }
        } else {
            URI newResoruceURI;
            List<IFile> affectedFiles = null;
            if (element instanceof FileEditorInput) {
                IFile newFile = ((FileEditorInput) element).getFile();
                affectedFiles = Collections.singletonList(newFile);
                newResoruceURI = URI.createPlatformResourceURI(newFile.getFullPath().toString(), true);
            } else if (element instanceof URIEditorInput) {
                newResoruceURI = ((URIEditorInput) element).getURI();
            } else {
                fireElementStateChangeFailed(element);
                throw new CoreException(new Status(IStatus.ERROR, MultisimDiagramEditorPlugin.ID, 0,
                        NLS.bind(Messages.MultisimDocumentProvider_IncorrectInputError,
                                new Object[] { element, "org.eclipse.ui.part.FileEditorInput", //$NON-NLS-1$
                                        "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ 
                        null));
            }
            if (false == document instanceof IDiagramDocument) {
                fireElementStateChangeFailed(element);
                throw new CoreException(new Status(IStatus.ERROR, MultisimDiagramEditorPlugin.ID, 0,
                        "Incorrect document used: " + document //$NON-NLS-1$
                                + " instead of org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDiagramDocument", //$NON-NLS-1$
                        null));
            }
            IDiagramDocument diagramDocument = (IDiagramDocument) document;
            final Resource newResource = diagramDocument.getEditingDomain().getResourceSet()
                    .createResource(newResoruceURI);
            final Diagram diagramCopy = (Diagram) EcoreUtil.copy(diagramDocument.getDiagram());
            try {
                new AbstractTransactionalCommand(diagramDocument.getEditingDomain(),
                        NLS.bind(Messages.MultisimDocumentProvider_SaveAsOperation, diagramCopy.getName()),
                        affectedFiles) {
                    protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info)
                            throws ExecutionException {
                        newResource.getContents().add(diagramCopy);
                        return CommandResult.newOKCommandResult();
                    }
                }.execute(monitor, null);
                newResource.save(MultisimDiagramEditorUtil.getSaveOptions());
            } catch (ExecutionException e) {
                fireElementStateChangeFailed(element);
                throw new CoreException(new Status(IStatus.ERROR, MultisimDiagramEditorPlugin.ID, 0,
                        e.getLocalizedMessage(), null));
            } catch (IOException e) {
                fireElementStateChangeFailed(element);
                throw new CoreException(new Status(IStatus.ERROR, MultisimDiagramEditorPlugin.ID, 0,
                        e.getLocalizedMessage(), null));
            }
            newResource.unload();
        }
    }

    /**
     * @generated
     */
    protected void handleElementChanged(ResourceSetInfo info, Resource changedResource, IProgressMonitor monitor) {
        IFile file = WorkspaceSynchronizer.getFile(changedResource);
        if (file != null) {
            try {
                file.refreshLocal(IResource.DEPTH_INFINITE, monitor);
            } catch (CoreException ex) {
                MultisimDiagramEditorPlugin.getInstance()
                        .logError(Messages.MultisimDocumentProvider_handleElementContentChanged, ex);
                // Error message to log was initially taken from org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.internal.l10n.EditorMessages.FileDocumentProvider_handleElementContentChanged
            }
        }
        changedResource.unload();

        fireElementContentAboutToBeReplaced(info.getEditorInput());
        removeUnchangedElementListeners(info.getEditorInput(), info);
        info.fStatus = null;
        try {
            setDocumentContent(info.fDocument, info.getEditorInput());
        } catch (CoreException e) {
            info.fStatus = e.getStatus();
        }
        if (!info.fCanBeSaved) {
            info.setModificationStamp(computeModificationStamp(info));
        }
        addUnchangedElementListeners(info.getEditorInput(), info);
        fireElementContentReplaced(info.getEditorInput());
    }

    /**
     * @generated
     */
    protected void handleElementMoved(IEditorInput input, URI uri) {
        if (input instanceof FileEditorInput) {
            IFile newFile = ResourcesPlugin.getWorkspace().getRoot()
                    .getFile(new Path(URI.decode(uri.path())).removeFirstSegments(1));
            fireElementMoved(input, newFile == null ? null : new FileEditorInput(newFile));
            return;
        }
        // TODO: append suffix to the URI! (use diagram as a parameter)
        fireElementMoved(input, new URIEditorInput(uri));
    }

    /**
     * @generated
     */
    public IEditorInput createInputWithEditingDomain(IEditorInput editorInput, TransactionalEditingDomain domain) {
        return editorInput;
    }

    /**
     * @generated
     */
    public IDiagramDocument getDiagramDocument(Object element) {
        IDocument doc = getDocument(element);
        if (doc instanceof IDiagramDocument) {
            return (IDiagramDocument) doc;
        }
        return null;
    }

    /**
     * @generated
     */
    protected IRunnableContext getOperationRunner(IProgressMonitor monitor) {
        return null;
    }

    /**
     * @generated
     */
    protected class ResourceSetInfo extends ElementInfo {

        /**
         * @generated
         */
        private long myModificationStamp = IResource.NULL_STAMP;

        /**
         * @generated
         */
        private WorkspaceSynchronizer mySynchronizer;

        /**
         * @generated
         */
        private LinkedList<Resource> myUnSynchronizedResources = new LinkedList<Resource>();

        /**
         * @generated
         */
        private IDiagramDocument myDocument;

        /**
         * @generated
         */
        private IEditorInput myEditorInput;

        /**
         * @generated
         */
        private boolean myUpdateCache = true;

        /**
         * @generated
         */
        private boolean myModifiable = false;

        /**
         * @generated
         */
        private boolean myReadOnly = true;

        /**
         * @generated
         */
        private ResourceSetModificationListener myResourceSetListener;

        /**
         * @generated
         */
        public ResourceSetInfo(IDiagramDocument document, IEditorInput editorInput) {
            super(document);
            myDocument = document;
            myEditorInput = editorInput;
            startResourceListening();
            myResourceSetListener = new ResourceSetModificationListener(this);
            getResourceSet().eAdapters().add(myResourceSetListener);
        }

        /**
         * @generated
         */
        public long getModificationStamp() {
            return myModificationStamp;
        }

        /**
         * @generated
         */
        public void setModificationStamp(long modificationStamp) {
            myModificationStamp = modificationStamp;
        }

        /**
         * @generated
         */
        public TransactionalEditingDomain getEditingDomain() {
            return myDocument.getEditingDomain();
        }

        /**
         * @generated
         */
        public ResourceSet getResourceSet() {
            return getEditingDomain().getResourceSet();
        }

        /**
         * @generated
         */
        public Iterator<Resource> getLoadedResourcesIterator() {
            return new ArrayList<Resource>(getResourceSet().getResources()).iterator();
        }

        /**
         * @generated
         */
        public IEditorInput getEditorInput() {
            return myEditorInput;
        }

        /**
         * @generated
         */
        public void dispose() {
            stopResourceListening();
            getResourceSet().eAdapters().remove(myResourceSetListener);
            for (Iterator<Resource> it = getLoadedResourcesIterator(); it.hasNext();) {
                Resource resource = it.next();
                resource.unload();
            }
            getEditingDomain().dispose();
        }

        /**
         * @generated
         */
        public boolean isSynchronized() {
            return myUnSynchronizedResources.size() == 0;
        }

        /**
         * @generated
         */
        public void setUnSynchronized(Resource resource) {
            myUnSynchronizedResources.add(resource);
        }

        /**
         * @generated
         */
        public void setSynchronized(Resource resource) {
            myUnSynchronizedResources.remove(resource);
        }

        /**
         * @generated
         */
        public final void stopResourceListening() {
            mySynchronizer.dispose();
            mySynchronizer = null;
        }

        /**
         * @generated
         */
        public final void startResourceListening() {
            mySynchronizer = new WorkspaceSynchronizer(getEditingDomain(), new SynchronizerDelegate());
        }

        /**
         * @generated
         */
        public boolean isUpdateCache() {
            return myUpdateCache;
        }

        /**
         * @generated
         */
        public void setUpdateCache(boolean update) {
            myUpdateCache = update;
        }

        /**
         * @generated
         */
        public boolean isModifiable() {
            return myModifiable;
        }

        /**
         * @generated
         */
        public void setModifiable(boolean modifiable) {
            myModifiable = modifiable;
        }

        /**
         * @generated
         */
        public boolean isReadOnly() {
            return myReadOnly;
        }

        /**
         * @generated
         */
        public void setReadOnly(boolean readOnly) {
            myReadOnly = readOnly;
        }

        /**
         * @generated
         */
        private class SynchronizerDelegate implements WorkspaceSynchronizer.Delegate {

            /**
             * @generated
             */
            public void dispose() {
            }

            /**
             * @generated
             */
            public boolean handleResourceChanged(final Resource resource) {
                synchronized (ResourceSetInfo.this) {
                    if (ResourceSetInfo.this.fCanBeSaved) {
                        ResourceSetInfo.this.setUnSynchronized(resource);
                        return true;
                    }
                }
                Display.getDefault().asyncExec(new Runnable() {
                    public void run() {
                        handleElementChanged(ResourceSetInfo.this, resource, null);
                    }
                });
                return true;
            }

            /**
             * @generated
             */
            public boolean handleResourceDeleted(Resource resource) {
                synchronized (ResourceSetInfo.this) {
                    if (ResourceSetInfo.this.fCanBeSaved) {
                        ResourceSetInfo.this.setUnSynchronized(resource);
                        return true;
                    }
                }
                Display.getDefault().asyncExec(new Runnable() {
                    public void run() {
                        fireElementDeleted(ResourceSetInfo.this.getEditorInput());
                    }
                });
                return true;
            }

            /**
             * @generated
             */
            public boolean handleResourceMoved(Resource resource, final URI newURI) {
                synchronized (ResourceSetInfo.this) {
                    if (ResourceSetInfo.this.fCanBeSaved) {
                        ResourceSetInfo.this.setUnSynchronized(resource);
                        return true;
                    }
                }
                if (myDocument.getDiagram().eResource() == resource) {
                    Display.getDefault().asyncExec(new Runnable() {
                        public void run() {
                            handleElementMoved(ResourceSetInfo.this.getEditorInput(), newURI);
                        }
                    });
                } else {
                    handleResourceDeleted(resource);
                }
                return true;
            }

        }

    }

    /**
     * @generated
     */
    private class ResourceSetModificationListener extends EContentAdapter {

        /**
         * @generated
         */
        private NotificationFilter myModifiedFilter;

        /**
         * @generated
         */
        private ResourceSetInfo myInfo;

        /**
         * @generated
         */
        public ResourceSetModificationListener(ResourceSetInfo info) {
            myInfo = info;
            myModifiedFilter = NotificationFilter.createEventTypeFilter(Notification.SET)
                    .or(NotificationFilter.createEventTypeFilter(Notification.UNSET))
                    .and(NotificationFilter.createFeatureFilter(Resource.class, Resource.RESOURCE__IS_MODIFIED));
        }

        /**
         * @generated
         */
        public void notifyChanged(Notification notification) {
            if (notification.getNotifier() instanceof ResourceSet) {
                super.notifyChanged(notification);
            }
            if (!notification.isTouch() && myModifiedFilter.matches(notification)) {
                if (notification.getNotifier() instanceof Resource) {
                    Resource resource = (Resource) notification.getNotifier();
                    if (resource.isLoaded()) {
                        boolean modified = false;
                        for (Iterator /*<org.eclipse.emf.ecore.resource.Resource>*/it = myInfo
                                .getLoadedResourcesIterator(); it.hasNext() && !modified;) {
                            Resource nextResource = (Resource) it.next();
                            if (nextResource.isLoaded()) {
                                modified = nextResource.isModified();
                            }
                        }
                        boolean dirtyStateChanged = false;
                        synchronized (myInfo) {
                            if (modified != myInfo.fCanBeSaved) {
                                myInfo.fCanBeSaved = modified;
                                dirtyStateChanged = true;
                            }
                            if (!resource.isModified()) {
                                myInfo.setSynchronized(resource);
                            }
                        }
                        if (dirtyStateChanged) {
                            fireElementDirtyStateChanged(myInfo.getEditorInput(), modified);

                            if (!modified) {
                                myInfo.setModificationStamp(computeModificationStamp(myInfo));
                            }
                        }
                    }
                }
            }
        }

    }

    /**
     * Persists EventB component.
     * Stores EventBComponent as an extension in a machine.
     * 
     * @param document
     * @custom
     */
    private void saveEventB(IDocument document) {
        ComponentDiagram diagram = (ComponentDiagram) ((IDiagramDocument) document).getDiagram().getElement();
        final TransactionalEditingDomain domain = ((IDiagramDocument) document).getEditingDomain();
        CompoundCommand compoundCmd = new CompoundCommand();

        for (final Component comp : diagram.getComponents()) {
            if (comp instanceof EventBComponent && ((EventBComponent) comp).getMachine() != null) {

                // adds command to extend Event-B machine with component config
                // NOTE: replaces existing extension of the same id
                compoundCmd.append(new RecordingCommand(domain) {
                    @Override
                    protected void doExecute() {
                        EventBComponent compCopy = (EventBComponent) EcoreUtil.copy(comp);
                        try {
                            Resource resource = domain.getResourceSet().getResource(compCopy.getMachine().getURI(),
                                    true);

                            if (resource != null && resource.isLoaded()) {
                                Machine machine = (Machine) resource.getContents().get(0);
                                if (machine == null)
                                    return;

                                // remove any existing extensions of the same id (EventB component)
                                Iterator<AbstractExtension> it = machine.getExtensions().iterator();
                                while (it.hasNext()) {
                                    if (MultisimPackage.EXTENSION_ID.equals(it.next().getExtensionId())) {
                                        it.remove();
                                    }
                                }
                                //                        compCopy.setReference(ComponentsPackage.COMPONENTS_EXTENSION_ID
                                //                              + "." + EcoreUtil.generateUUID());
                                machine.getExtensions().add(compCopy);
                                resource.save(Collections.EMPTY_MAP);
                            }
                        } catch (IOException e) {
                            MessageDialog.openError(Display.getDefault().getActiveShell(), "Event-B Component",
                                    "Failed to save component '" + comp.getName() + "' to its machine.");
                        }
                    }
                });
            }
        }
        domain.getCommandStack().execute(compoundCmd);
    }

}