/*******************************************************************************
* Copyright (c) 2008 Conselleria de Infraestructuras y Transporte,
* Generalitat de la Comunitat Valenciana .
* 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: Francisco Javier Cano Muñoz (Prodevelop) - initial API implementation
*
******************************************************************************/
package org.eclipse.papyrus.uml.diagram.common.part;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
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.notify.Notification;
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.TransactionalEditingDomain;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
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.operation.IRunnableContext;
import org.eclipse.osgi.util.NLS;
import org.eclipse.papyrus.uml.diagram.common.Activator;
import org.eclipse.papyrus.uml.diagram.common.util.MDTUtil;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.part.FileEditorInput;
// TODO: Auto-generated Javadoc
/**
* Provides support to keep the <ResourceSet> unloaded when changing the <IEditorInput> or contents
* of the <Document>. Will be shared among several <IEditorPart>s using the same <EditingDomain> and
* the same <Resource>.
*
* @author <a href="mailto:fjcano@prodevelop.es">Francisco Javier Cano Muñoz</a>
*/
public class CachedResourcesDocumentProvider extends AbstractDocumentProvider implements IDiagramDocumentProvider {
// //
// XXX: keep resource in dispose
/** The unload on dispose. */
private boolean unloadOnDispose = true;
/**
* The editing domain identifier.
*/
private String editingDomainID = null;
/**
* Resource changes because of a save
*/
private boolean changingResourceBySave = true;
@Deprecated
public CachedResourcesDocumentProvider() {
editingDomainID = "";
return;
}
public CachedResourcesDocumentProvider(String editingDomainID) {
this.editingDomainID = editingDomainID;
}
/**
* Checks if is unload on dispose.
*
* @return true, if is unload on dispose
*/
// @unused
public boolean isUnloadOnDispose() {
return unloadOnDispose;
}
/**
* Sets the unload on dispose.
*
* @param unloadOnDispose
* the new unload on dispose
*/
public void setUnloadOnDispose(boolean unloadOnDispose) {
this.unloadOnDispose = unloadOnDispose;
}
synchronized public void setChangingResourceBySave(boolean changingResourceBySave) {
this.changingResourceBySave = changingResourceBySave;
}
public boolean isChangingResourceBySave() {
return changingResourceBySave;
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.gmf.runtime.diagram.ui.resources.editor.document.
* AbstractDocumentProvider#disposeElementInfo(java.lang.Object,
* org.eclipse.
* gmf.runtime.diagram.ui.resources.editor.document.AbstractDocumentProvider
* .ElementInfo)
*/
@Override
protected void disposeElementInfo(Object element, ElementInfo info) {
if(info instanceof CachedResourceSetInfo) {
CachedResourceSetInfo resourceSetInfo = (CachedResourceSetInfo)info;
resourceSetInfo.disposeButUnload();
}
super.disposeElementInfo(element, info);
}
/**
* Creates the editing domain.
*
* @param editorInput
* the editor input
*
* @return the transactional editing domain
*/
protected TransactionalEditingDomain createEditingDomain(IEditorInput editorInput) {
String id = getEditingDomainID();
String uri = null;
if(editorInput instanceof FileEditorInput) {
uri = ((FileEditorInput)editorInput).getPath().toString();
uri = MDTUtil.fullFilePathToResourceURI(uri).toString();
} else if(editorInput instanceof URIEditorInput) {
uri = ((URIEditorInput)editorInput).getURI().trimFragment().toString();
}
TransactionalEditingDomain editingDomain = EditingDomainRegistry.getInstance().get(id, uri);
return editingDomain;
}
/**
* Compute modification stamp.
*
* @param info
* the info
*
* @return the long
*/
protected long computeModificationStamp(CachedResourceSetInfo info) {
int result = 0;
for(Object element : info.getResourceSet().getResources()) {
Resource nextResource = (Resource)element;
IFile file = WorkspaceSynchronizer.getFile(nextResource);
if(file != null) {
if(file.getLocation() != null) {
result += file.getLocation().toFile().lastModified();
} else {
result += file.getModificationStamp();
}
}
}
return result;
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.gmf.runtime.diagram.ui.resources.editor.document.
* AbstractDocumentProvider#createEmptyDocument()
*/
@Override
protected IDocument createEmptyDocument() {
DiagramDocument document = new DiagramDocument();
document.setEditingDomain(createEditingDomain(null));
return document;
}
/**
* Creates the empty document.
*
* @param editorInput
* the editor input
*
* @return the i document
*/
protected IDocument createEmptyDocument(IEditorInput editorInput) {
DiagramDocument document = new DiagramDocument();
document.setEditingDomain(createEditingDomain(editorInput));
return document;
}
// //
// XXX:
/**
* The Class CachedResourceSetInfo.
*/
protected class CachedResourceSetInfo extends AbstractDocumentProvider.ElementInfo {
/** The my modification stamp. */
private long myModificationStamp = IResource.NULL_STAMP;
/** The my synchronizer. */
private WorkspaceSynchronizer mySynchronizer;
/** The my un synchronized resources. */
private final Collection myUnSynchronizedResources = new ArrayList();
/** The my document. */
private final IDiagramDocument myDocument;
/** The my editor input. */
private final IEditorInput myEditorInput;
/** The my update cache. */
private boolean myUpdateCache = true;
/** The my modifiable. */
private boolean myModifiable = false;
/** The my read only. */
private boolean myReadOnly = true;
/** The my resource set listener. */
private final ResourceSetModificationListener myResourceSetListener;
/**
* Instantiates a new cached resource set info.
*
* @param document
* the document
* @param editorInput
* the editor input
*/
public CachedResourceSetInfo(IDiagramDocument document, IEditorInput editorInput) {
super(document);
myDocument = document;
myEditorInput = editorInput;
startResourceListening();
myResourceSetListener = new ResourceSetModificationListener(this);
getResourceSet().eAdapters().add(myResourceSetListener);
}
/**
* Gets the modification stamp.
*
* @return the modification stamp
*/
// @unused
public long getModificationStamp() {
return myModificationStamp;
}
/**
* Sets the modification stamp.
*
* @param modificationStamp
* the modification stamp
*/
public void setModificationStamp(long modificationStamp) {
myModificationStamp = modificationStamp;
}
/**
* Gets the editing domain.
*
* @return the editing domain
*/
public TransactionalEditingDomain getEditingDomain() {
return myDocument.getEditingDomain();
}
/**
* Gets the resource set.
*
* @return the resource set
*/
public ResourceSet getResourceSet() {
return getEditingDomain().getResourceSet();
}
/**
* Gets the editor input.
*
* @return the editor input
*/
public IEditorInput getEditorInput() {
return myEditorInput;
}
/**
* Dispose.
*/
public void disposeButUnload() {
stopResourceListening();
getResourceSet().eAdapters().remove(myResourceSetListener);
}
/**
* Dispose.
*/
// @unused
public void dispose() {
stopResourceListening();
getResourceSet().eAdapters().remove(myResourceSetListener);
for(Object element : getResourceSet().getResources()) {
Resource resource = (Resource)element;
resource.unload();
}
}
/**
* Checks if is synchronized.
*
* @return true, if checks if is synchronized
*/
public boolean isSynchronized() {
return myUnSynchronizedResources.size() == 0;
}
/**
* Sets the un synchronized.
*
* @param resource
* the resource
*/
public void setUnSynchronized(Resource resource) {
myUnSynchronizedResources.add(resource);
}
/**
* Sets the synchronized.
*
* @param resource
* the resource
*/
public void setSynchronized(Resource resource) {
myUnSynchronizedResources.remove(resource);
}
/**
* Stop resource listening.
*/
public final void stopResourceListening() {
mySynchronizer.dispose();
mySynchronizer = null;
}
/**
* Start resource listening.
*/
public final void startResourceListening() {
mySynchronizer = new WorkspaceSynchronizer(getEditingDomain(), new SynchronizerDelegate());
}
/**
* Checks if is update cache.
*
* @return true, if checks if is update cache
*/
public boolean isUpdateCache() {
return myUpdateCache;
}
/**
* Sets the update cache.
*
* @param update
* the update
*/
public void setUpdateCache(boolean update) {
myUpdateCache = update;
}
/**
* Checks if is modifiable.
*
* @return true, if checks if is modifiable
*/
public boolean isModifiable() {
return myModifiable;
}
/**
* Sets the modifiable.
*
* @param modifiable
* the modifiable
*/
public void setModifiable(boolean modifiable) {
myModifiable = modifiable;
}
/**
* Checks if is read only.
*
* @return true, if checks if is read only
*/
public boolean isReadOnly() {
return myReadOnly;
}
/**
* Sets the read only.
*
* @param readOnly
* the read only
*/
public void setReadOnly(boolean readOnly) {
myReadOnly = readOnly;
}
/**
* Gets the loaded resources iterator.
*
* @return the loaded resources iterator
*/
public Iterator getLoadedResourcesIterator() {
return new ArrayList(getResourceSet().getResources()).iterator();
}
/**
* The Class SynchronizerDelegate.
*/
private class SynchronizerDelegate implements WorkspaceSynchronizer.Delegate {
/**
* Dispose.
*/
public void dispose() {
}
/**
* Handle resource changed.
*
* @param resource
* the resource
*
* @return true, if handle resource changed
*/
public boolean handleResourceChanged(final Resource resource) {
synchronized(CachedResourceSetInfo.this) {
// fjcano : if we are changing the resource in an internal
// save, we need not mark it as unsynchronized or reload the
// resource.
if(CachedResourcesDocumentProvider.this.isChangingResourceBySave()) {
return true;
}
// fjcano : if we get here the resource was modified
// externally.
if(CachedResourceSetInfo.this.fCanBeSaved) {
CachedResourceSetInfo.this.setUnSynchronized(resource);
return true;
}
}
Display.getDefault().asyncExec(new Runnable() {
public void run() {
handleElementChanged(CachedResourceSetInfo.this, resource, null);
}
});
return true;
}
/**
* Handle resource deleted.
*
* @param resource
* the resource
*
* @return true, if handle resource deleted
*/
public boolean handleResourceDeleted(Resource resource) {
synchronized(CachedResourceSetInfo.this) {
if(CachedResourceSetInfo.this.fCanBeSaved) {
CachedResourceSetInfo.this.setUnSynchronized(resource);
return true;
}
}
Display.getDefault().asyncExec(new Runnable() {
public void run() {
fireElementDeleted(CachedResourceSetInfo.this.getEditorInput());
}
});
return true;
}
/**
* Handle resource moved.
*
* @param resource
* the resource
* @param newURI
* the new uri
*
* @return true, if handle resource moved
*/
public boolean handleResourceMoved(Resource resource, final URI newURI) {
synchronized(CachedResourceSetInfo.this) {
if(CachedResourceSetInfo.this.fCanBeSaved) {
CachedResourceSetInfo.this.setUnSynchronized(resource);
return true;
}
}
if(myDocument.getDiagram().eResource() == resource) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
handleElementMoved(CachedResourceSetInfo.this.getEditorInput(), newURI);
}
});
} else {
handleResourceDeleted(resource);
}
return true;
}
}
}
/**
* The listener interface for receiving resourceSetModification events. The
* class that is interested in processing a resourceSetModification event
* implements this interface, and the object created with that class is
* registered with a component using the component's <code>addResourceSetModificationListener<code> method. When
* the resourceSetModification event occurs, that object's appropriate
* method is invoked.
*
* @see ResourceSetModificationEvent
*/
private class ResourceSetModificationListener extends EContentAdapter {
/** The my modified filter. */
private final NotificationFilter myModifiedFilter;
/** The my info. */
private final CachedResourceSetInfo myInfo;
/**
* The Constructor.
*
* @param info
* the info
*/
public ResourceSetModificationListener(CachedResourceSetInfo info) {
myInfo = info;
myModifiedFilter = NotificationFilter.createEventTypeFilter(Notification.SET).or(NotificationFilter.createEventTypeFilter(Notification.UNSET)).and(NotificationFilter.createFeatureFilter(Resource.class, Resource.RESOURCE__IS_MODIFIED));
}
/**
* Notify changed.
*
* @param notification
* the notification
*/
@Override
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 it = myInfo.getResourceSet().getResources().iterator(); 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));
}
}
}
}
}
}
}
// // General and common DocumentProvider code for GMF diagrams ////
@Override
protected ElementInfo createElementInfo(Object element) throws CoreException {
if(false == element instanceof FileEditorInput && false == element instanceof URIEditorInput) {
throw new CoreException(new Status(IStatus.ERROR, Activator.ID, 0, NLS.bind("Messages.SqlmodelDocumentProvider_IncorrectInputError", new Object[]{ element, "org.eclipse.ui.part.FileEditorInput", "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ //$NON-NLS-2$
null));
}
IEditorInput editorInput = (IEditorInput)element;
IDiagramDocument document = (IDiagramDocument)createDocument(editorInput);
CachedResourceSetInfo info = new CachedResourceSetInfo(document, editorInput);
info.setModificationStamp(computeModificationStamp(info));
info.fStatus = null;
return info;
}
@Override
protected IDocument createDocument(Object element) throws CoreException {
if(false == element instanceof FileEditorInput && false == element instanceof URIEditorInput) {
throw new CoreException(new Status(IStatus.ERROR, Activator.ID, 0, NLS.bind("Messages.SqlmodelDocumentProvider_IncorrectInputError", new Object[]{ element, "org.eclipse.ui.part.FileEditorInput", "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ //$NON-NLS-2$
null));
}
IDocument document = createEmptyDocument((IEditorInput)element);
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.
*/
protected void setupDocument(Object element, IDocument document) {
// for subclasses
}
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());
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(rootElement);
return;
}
} else {
for(Object rootElement : resource.getContents()) {
if(rootElement instanceof Diagram) {
document.setContent(rootElement);
return;
}
}
}
throw new RuntimeException("Messages.SqlmodelDocumentProvider_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, Activator.ID, 0, msg != null ? msg : "Messages.SqlmodelDocumentProvider_DiagramLoadingError", e));
}
throw thrownExcp;
}
} else {
throw new CoreException(new Status(IStatus.ERROR, Activator.ID, 0, NLS.bind("Messages.SqlmodelDocumentProvider_IncorrectInputError", new Object[]{ element, "org.eclipse.ui.part.FileEditorInput", "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ //$NON-NLS-2$
null));
}
}
@Override
public long getModificationStamp(Object element) {
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
return computeModificationStamp(info);
}
return super.getModificationStamp(element);
}
@Override
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);
}
public CachedResourceSetInfo getResourceSetInfo(Object editorInput) {
return (CachedResourceSetInfo)super.getElementInfo(editorInput);
}
@Override
protected void doValidateState(Object element, Object computationContext) throws CoreException {
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
Collection files2Validate = new ArrayList();
for(Iterator it = info.getLoadedResourcesIterator(); it.hasNext();) {
Resource nextResource = (Resource)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);
}
@Override
public boolean isReadOnly(Object element) {
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
if(info.isUpdateCache()) {
try {
updateCache(element);
} catch (CoreException ex) {
Activator.getDefault().logError("Messages.SqlmodelDocumentProvider_isModifiable", ex);
}
}
return info.isReadOnly();
}
return super.isReadOnly(element);
}
@Override
public boolean isModifiable(Object element) {
if(!isStateValidated(element)) {
if(element instanceof FileEditorInput || element instanceof URIEditorInput) {
return true;
}
}
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
if(info.isUpdateCache()) {
try {
updateCache(element);
} catch (CoreException ex) {
Activator.getDefault().logError("Messages.SqlmodelDocumentProvider_isModifiable", ex);
}
}
return info.isModifiable();
}
return super.isModifiable(element);
}
protected void updateCache(Object element) throws CoreException {
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
for(Iterator it = info.getLoadedResourcesIterator(); it.hasNext();) {
Resource nextResource = (Resource)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;
}
}
@Override
protected void doUpdateStateCache(Object element) throws CoreException {
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
info.setUpdateCache(true);
}
super.doUpdateStateCache(element);
}
@Override
public boolean isSynchronized(Object element) {
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
return info.isSynchronized();
}
return super.isSynchronized(element);
}
@Override
protected ISchedulingRule getResetRule(Object element) {
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
Collection rules = new ArrayList();
for(Iterator it = info.getLoadedResourcesIterator(); it.hasNext();) {
Resource nextResource = (Resource)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;
}
@Override
protected ISchedulingRule getSaveRule(Object element) {
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
Collection rules = new ArrayList();
for(Iterator it = info.getLoadedResourcesIterator(); it.hasNext();) {
Resource nextResource = (Resource)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;
}
@Override
protected ISchedulingRule getSynchronizeRule(Object element) {
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
Collection rules = new ArrayList();
for(Iterator it = info.getLoadedResourcesIterator(); it.hasNext();) {
Resource nextResource = (Resource)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;
}
@Override
protected ISchedulingRule getValidateStateRule(Object element) {
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
Collection files = new ArrayList();
for(Iterator it = info.getLoadedResourcesIterator(); it.hasNext();) {
Resource nextResource = (Resource)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;
}
private ISchedulingRule computeSchedulingRule(IResource toCreateOrModify) {
if(toCreateOrModify.exists()) {
return ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(toCreateOrModify);
}
IResource parent = toCreateOrModify;
do {
toCreateOrModify = parent;
parent = toCreateOrModify.getParent();
} while(parent != null && !parent.exists());
return ResourcesPlugin.getWorkspace().getRuleFactory().createRule(toCreateOrModify);
}
@Override
protected void doSynchronize(Object element, IProgressMonitor monitor) throws CoreException {
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
for(Iterator it = info.getLoadedResourcesIterator(); it.hasNext();) {
Resource nextResource = (Resource)it.next();
handleElementChanged(info, nextResource, monitor);
}
return;
}
super.doSynchronize(element, monitor);
}
@Override
protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException {
try {
// fjcano : we are modifying the resource by an internal save.
setChangingResourceBySave(true);
CachedResourceSetInfo info = getResourceSetInfo(element);
if(info != null) {
if(!overwrite && !info.isSynchronized()) {
throw new CoreException(new Status(IStatus.ERROR, Activator.ID, IResourceStatus.OUT_OF_SYNC_LOCAL, "Messages.SqlmodelDocumentProvider_UnsynchronizedFileSaveError", null));
}
info.stopResourceListening();
fireElementStateChanging(element);
try {
monitor.beginTask("Messages.SqlmodelDocumentProvider_SaveDiagramTask", info.getResourceSet().getResources().size() + 1); // "Saving diagram"
for(Iterator it = info.getLoadedResourcesIterator(); it.hasNext();) {
Resource nextResource = (Resource)it.next();
monitor.setTaskName(NLS.bind("Messages.SqlmodelDocumentProvider_SaveNextResourceTask", nextResource.getURI()));
if(nextResource.isLoaded() && !info.getEditingDomain().isReadOnly(nextResource)) {
try {
nextResource.save(MDTUtil.getSaveOptions());
} catch (IOException e) {
fireElementStateChangeFailed(element);
throw new CoreException(new Status(IStatus.ERROR, Activator.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 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, Activator.ID, 0, NLS.bind("Messages.SqlmodelDocumentProvider_IncorrectInputError", new Object[]{ element, "org.eclipse.ui.part.FileEditorInput", "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ //$NON-NLS-2$
null));
}
if(false == document instanceof IDiagramDocument) {
fireElementStateChangeFailed(element);
throw new CoreException(new Status(IStatus.ERROR, Activator.ID, 0, "Incorrect document used: " + document + " instead of org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDiagramDocument", null)); //$NON-NLS-1$ //$NON-NLS-2$
}
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.SqlmodelDocumentProvider_SaveAsOperation", diagramCopy.getName()), affectedFiles) {
@Override
protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
newResource.getContents().add(diagramCopy);
return CommandResult.newOKCommandResult();
}
}.execute(monitor, null);
newResource.save(MDTUtil.getSaveOptions());
} catch (ExecutionException e) {
fireElementStateChangeFailed(element);
throw new CoreException(new Status(IStatus.ERROR, Activator.ID, 0, e.getLocalizedMessage(), null));
} catch (IOException e) {
fireElementStateChangeFailed(element);
throw new CoreException(new Status(IStatus.ERROR, Activator.ID, 0, e.getLocalizedMessage(), null));
}
newResource.unload();
}
} finally {
// fjcano : the internal modification ended.
setChangingResourceBySave(false);
}
}
protected void handleElementChanged(CachedResourceSetInfo info, Resource changedResource, IProgressMonitor monitor) {
if(isChangingResourceBySave() == false) {
IFile file = WorkspaceSynchronizer.getFile(changedResource);
if(file != null) {
try {
file.refreshLocal(IResource.DEPTH_INFINITE, monitor);
} catch (CoreException ex) {
Activator.getDefault().logError("Messages.SqlmodelDocumentProvider_handleElementContentChanged", ex);
}
}
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());
}
}
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));
}
public IEditorInput createInputWithEditingDomain(IEditorInput editorInput, TransactionalEditingDomain domain) {
return editorInput;
}
public IDiagramDocument getDiagramDocument(Object element) {
IDocument doc = getDocument(element);
if(doc instanceof IDiagramDocument) {
return (IDiagramDocument)doc;
}
return null;
}
@Override
protected IRunnableContext getOperationRunner(IProgressMonitor monitor) {
return null;
}
protected String getEditingDomainID() {
return editingDomainID;
}
}