/**
* Copyright (c) 2002-2010 IBM Corporation and others.
* 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:
* IBM - Initial API and implementation
*/
package org.eclipse.emf.edit.domain;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CommandStack;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.command.UnexecutableCommand;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.AbstractTreeIterator;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.UniqueEList;
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.resource.URIConverter;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.edit.EMFEditPlugin;
import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.command.CopyToClipboardCommand;
import org.eclipse.emf.edit.command.CreateChildCommand;
import org.eclipse.emf.edit.command.CutToClipboardCommand;
import org.eclipse.emf.edit.command.DeleteCommand;
import org.eclipse.emf.edit.command.OverrideableCommand;
import org.eclipse.emf.edit.command.PasteFromClipboardCommand;
import org.eclipse.emf.edit.command.RemoveCommand;
import org.eclipse.emf.edit.command.ReplaceCommand;
import org.eclipse.emf.edit.provider.IEditingDomainItemProvider;
import org.eclipse.emf.edit.provider.IWrapperItemProvider;
import org.eclipse.emf.edit.provider.ItemProviderAdapter;
/**
* This class implements an editing domain by delegating to adapters that implement
* {@link org.eclipse.emf.edit.provider.IEditingDomainItemProvider}.
*/
public class AdapterFactoryEditingDomain implements EditingDomain
{
/**
* This class is an adapter than implements {@link IEditingDomainProvider}.
*/
public static class EditingDomainProvider extends AdapterImpl implements IEditingDomainProvider
{
/**
* Keeps track of the editing domain.
*/
protected EditingDomain editingDomain;
public EditingDomainProvider(EditingDomain editingDomain)
{
this.editingDomain = editingDomain;
}
public EditingDomain getEditingDomain()
{
return editingDomain;
}
@Override
public boolean isAdapterForType(Object type)
{
return type == IEditingDomainProvider.class;
}
}
/**
* Returns whether the object is, contains, or wraps something that likely represents
* a stale {@link Resource#unload() unloaded} {@link EObject#eIsProxy() object}.
* It's best to stop using unloaded objects entirely because they ought to be garbage collected
* and should be replaced by their {@link AdapterFactoryEditingDomain#resolve(Collection) resolved} result.
* @since 2.4
*/
static public boolean isStale(Object object)
{
if (object instanceof IWrapperItemProvider)
{
IWrapperItemProvider wrapper = (IWrapperItemProvider)object;
return isStale(wrapper.getValue()) || isStale(wrapper.getOwner());
}
else if (object instanceof Collection<?>)
{
for (Object item : (Collection<?>)object)
{
if (isStale(item))
{
return true;
}
}
return false;
}
else if (object instanceof Object[])
{
for (Object item : (Object[])object)
{
if (isStale(item))
{
return true;
}
}
return false;
}
else if (object instanceof EObject)
{
EObject eObject = (EObject)object;
return eObject.eIsProxy() && eObject.eAdapters().isEmpty();
}
else if (object instanceof FeatureMap.Entry)
{
return isStale(((FeatureMap.Entry)object).getValue());
}
else if (object == null)
{
return false;
}
else
{
return false;
}
}
/**
* This returns the editing domain of the given EMF object, or null, if it can't be determined.
* This is implemented by checking whether the {@link org.eclipse.emf.ecore.resource.ResourceSet} of the object
* implements {@link IEditingDomainProvider}
* and returns that result or null.
*
* <p>
* Just as for {@link #getEditingDomainFor(java.lang.Object) getEditingDomainFor(Object)},
* it is recommended that you always keep an editing domain instance available through some other means.
*/
static public EditingDomain getEditingDomainFor(EObject object)
{
if (object != null)
{
Resource resource = object.eResource();
if (resource != null)
{
IEditingDomainProvider editingDomainProvider =
(IEditingDomainProvider)EcoreUtil.getExistingAdapter(resource, IEditingDomainProvider.class);
if (editingDomainProvider != null)
{
return editingDomainProvider.getEditingDomain();
}
else
{
ResourceSet resourceSet = resource.getResourceSet();
if (resourceSet instanceof IEditingDomainProvider)
{
EditingDomain editingDomain = ((IEditingDomainProvider)resourceSet).getEditingDomain();
return editingDomain;
}
else if (resourceSet != null)
{
editingDomainProvider = (IEditingDomainProvider)EcoreUtil.getExistingAdapter(resourceSet, IEditingDomainProvider.class);
if (editingDomainProvider != null)
{
return editingDomainProvider.getEditingDomain();
}
}
}
}
}
return null;
}
/**
* This returns the editing domain for the given arbitrary object, or null, if it can't be determined.
* It is recommended that you always work directly with an EditingDomain instance whenever possible.
* This is implemented to checks if the object itself implements {@link org.eclipse.emf.edit.domain.IEditingDomainProvider}
* and returns that result.
* Otherwise it checks if it is valid to call
* {@link #getEditingDomainFor(org.eclipse.emf.ecore.EObject) getEditingDomainFor(EObject)}
* and returns that result or null.
*
* <p>
* It is recommended that you always keep an editing domain instance available through some other means;
* this should only be used to implement things such as a global popup action for some object;
* in such a cases such as that the editing domain returned here
* may well be one that belongs to some editor you know nothing about,
* which is what you want.
*/
static public EditingDomain getEditingDomainFor(Object object)
{
if (object instanceof IEditingDomainProvider)
{
EditingDomain editingDomain = ((IEditingDomainProvider)object).getEditingDomain();
return editingDomain;
}
else if (object instanceof EObject)
{
EditingDomain editingDomain = AdapterFactoryEditingDomain.getEditingDomainFor((EObject)object);
return editingDomain;
}
else if (object instanceof FeatureMap.Entry)
{
return getEditingDomainFor(((FeatureMap.Entry)object).getValue());
}
else if (object instanceof IWrapperItemProvider)
{
return getEditingDomainFor(((IWrapperItemProvider)object).getValue());
}
else
{
return null;
}
}
/**
* This is a convenient way to determine the adapter to which editing domain methods are delegated for a given object,
* by providing nothing more than the object itself.
* It is recommended that you always work directly with an EditingDomain instance whenever possible.
* If the object is an EMF object,
* this is implemented to call {@link #getEditingDomainFor(java.lang.Object) getEditingDomainFor(Object)}
* and to return the adapter returned from the domain's adapter factory.
* If the object itself is an IEditingDomainItemProvider, it returns the object.
* Otherwise, it returns null.
*/
static public IEditingDomainItemProvider getEditingDomainItemProviderFor(Object object)
{
if (object instanceof EObject)
{
EObject eObject = (EObject)object;
EditingDomain editingDomain = getEditingDomainFor(eObject);
if (editingDomain instanceof AdapterFactoryEditingDomain)
{
object = ((AdapterFactoryEditingDomain)editingDomain).getAdapterFactory().adapt(eObject, IEditingDomainItemProvider.class);
}
}
return
object instanceof IEditingDomainItemProvider ?
(IEditingDomainItemProvider)object :
object instanceof IWrapperItemProvider ?
getEditingDomainItemProviderFor(((IWrapperItemProvider)object).getValue()) :
object instanceof FeatureMap.Entry ?
getEditingDomainItemProviderFor(((FeatureMap.Entry)object).getValue()) :
null;
}
/**
* This is an implementation of a context that knows about this editing domain.
* It is used to help implement
* {@link #getEditingDomainFor(java.lang.Object) getEditingDomainFor(Object)}
* and {@link #getEditingDomainFor(org.eclipse.emf.ecore.EObject) getEditingDomainFor(EObject)}
* An instance of this is created if needed in the constructor.
*
*/
protected class AdapterFactoryEditingDomainResourceSet extends ResourceSetImpl implements IEditingDomainProvider
{
public AdapterFactoryEditingDomainResourceSet()
{
super();
// setResourceFactoryRegister(new ExtensibleContextResourceFactoryRegister());
//EATM setResourceFactoryRegister(new ContextResourceFactoryRegister());
}
public EditingDomain getEditingDomain()
{
return AdapterFactoryEditingDomain.this;
}
}
/**
* This is the adapter factory used to create the adapter to which calls are delegated.
*/
protected AdapterFactory adapterFactory;
/**
* This is the command stack that was passed into the constructor.
*/
protected CommandStack commandStack;
/**
* This is the resource set used to contain all created and loaded resources.
*/
protected ResourceSet resourceSet;
/**
* This is the current clipboard.
*/
protected Collection<Object> clipboard;
/**
* This controls whether or not copy command optimizations are safe in this domain.
*/
protected boolean optimizeCopy = true;
/**
* This controls whether the domain is read only.
*/
protected Map<Resource, Boolean> resourceToReadOnlyMap;
/**
* Create an instance from the adapter factory, and the specialized command stack.
*/
public AdapterFactoryEditingDomain(AdapterFactory adapterFactory, CommandStack commandStack)
{
this.adapterFactory = adapterFactory;
this.commandStack = commandStack;
this.resourceSet = new AdapterFactoryEditingDomainResourceSet();
}
/**
* Create an instance from the adapter factory, the specialized command stack, and the map used to maintain read only state.
*/
public AdapterFactoryEditingDomain(AdapterFactory adapterFactory, CommandStack commandStack, Map<Resource, Boolean> resourceToReadOnlyMap)
{
this.adapterFactory = adapterFactory;
this.commandStack = commandStack;
this.resourceSet = new AdapterFactoryEditingDomainResourceSet();
this.resourceToReadOnlyMap = resourceToReadOnlyMap;
}
/**
* Create an instance from the adapter factory, the specialized command stack, and the specialized resource set.
* If the resource set's context is null, one will be created here;
* otherwise, the existing context should implement {@link org.eclipse.emf.edit.domain.IEditingDomainProvider}.
*/
public AdapterFactoryEditingDomain(AdapterFactory adapterFactory, CommandStack commandStack, ResourceSet resourceSet)
{
this.adapterFactory = adapterFactory;
this.commandStack = commandStack;
this.resourceSet = resourceSet;
/*
if (resourceSet.getContext() == null)
{
Context context = new AdapterFactoryEditingDomainContext();
resourceSet.setContext(context);
}
*/
}
/**
* This returns the adapter factory used by this domain.
*/
public AdapterFactory getAdapterFactory()
{
return adapterFactory;
}
/**
* This sets the adapter factory after the domain is already created.
*/
public void setAdapterFactory(AdapterFactory adapterFactory)
{
this.adapterFactory = adapterFactory;
}
/**
* This is a convenience method to create a resource, you could use the resource set returned by {@link #getResourceSet} directly.
*/
public Resource createResource(String fileNameURI)
{
URI uri = URI.createURI(fileNameURI);
Resource resource = resourceSet.createResource(uri);
return resource;
}
/**
* This is a convenience method to load a resource, you could use the resource set returned by {@link #getResourceSet} directly.
*/
public Resource loadResource(String fileNameURI)
{
try
{
Resource resource = resourceSet.getResource(URI.createURI(fileNameURI), true);
return resource;
}
catch (Exception exception)
{
EMFEditPlugin.INSTANCE.log(exception);
}
return null;
}
/**
* This returns the resource set used to contain all created and loaded resources.
*/
public ResourceSet getResourceSet()
{
return resourceSet;
}
/**
* This delegates to
* {@link org.eclipse.emf.edit.provider.IEditingDomainItemProvider#createCommand IEditingDomainItemProvider.createCommand}.
*/
public Command createCommand(Class<? extends Command> commandClass, CommandParameter commandParameter)
{
// If the owner parameter is set, we delegate to the owner's adapter
//
Object owner = commandParameter.getOwner();
if (commandClass == CopyToClipboardCommand.class)
{
return new CopyToClipboardCommand(this, commandParameter.getCollection());
}
else if (commandClass == PasteFromClipboardCommand.class)
{
return new PasteFromClipboardCommand
(this, commandParameter.getOwner(), commandParameter.getFeature(), commandParameter.getIndex(), getOptimizeCopy());
}
else if (commandClass == CutToClipboardCommand.class)
{
return new CutToClipboardCommand
(this, RemoveCommand.create(this, commandParameter.getOwner(), commandParameter.getFeature(), commandParameter.getCollection()));
}
else if (commandClass == DeleteCommand.class)
{
return new DeleteCommand(this, commandParameter.getCollection());
}
else if (owner != null)
{
// If there is an adapter of the correct type...
//
IEditingDomainItemProvider editingDomainItemProvider =
(IEditingDomainItemProvider)
adapterFactory.adapt(owner, IEditingDomainItemProvider.class);
return
editingDomainItemProvider != null ?
editingDomainItemProvider.createCommand(owner, this, commandClass, commandParameter) :
new ItemProviderAdapter(null).createCommand(owner, this, commandClass, commandParameter);
}
else
{
// If command has no owner specified
//
if (commandClass == RemoveCommand.class)
{
// For RemoveCommand, we will find the owner by calling EditingDomain.getParent() on the object(s) being removed.
//
CompoundCommand removeCommand = new CompoundCommand(CompoundCommand.MERGE_COMMAND_ALL);
List<Object> objects = new ArrayList<Object>(commandParameter.getCollection());
while (!objects.isEmpty())
{
// We will iterate over the whole collection, removing some as we go.
//
ListIterator<Object> remainingObjects = objects.listIterator();
// Take the first object, and remove it.
//
Object object = remainingObjects.next();
remainingObjects.remove();
// Determine the object's parent.
//
Object parent = getParent(object);
if (parent != null)
{
// Now we want to find all the other objects with this same parent.
// So we can collection siblings together and give the parent control over their removal.
//
List<Object> siblings = new ArrayList<Object>();
siblings.add(object);
while (remainingObjects.hasNext())
{
// Get the next object and check if it has the same parent.
//
Object otherObject = remainingObjects.next();
Object otherParent = getParent(otherObject);
if (otherParent == parent)
{
// Remove the object and add it as a sibling.
//
remainingObjects.remove();
siblings.add(otherObject);
}
}
// We will now create a command with this implied parent
//
removeCommand.append(createCommand(RemoveCommand.class, new CommandParameter(parent, null, siblings)));
}
else if (object != null)
{
// The parent is null, which implies a top-level removal, so create a self-removing command.
//
removeCommand.append(createCommand(RemoveCommand.class, new CommandParameter(object, null, Collections.singleton(object))));
}
}
return removeCommand.unwrap();
}
else if (commandClass == ReplaceCommand.class)
{
Object obj = commandParameter.getValue();
Object parent = (obj == null) ? null : getParent(obj);
if (parent == null) parent = obj;
return createCommand(ReplaceCommand.class, new CommandParameter(parent, null, obj, commandParameter.getCollection()));
}
else if (commandClass == CreateChildCommand.class)
{
// For CreateChildCommand, we will find the owner by calling EditingDomain.getParent() on the first selected object
Collection<?> sel = commandParameter.getCollection();
Object parent = sel == null ? null : getParent(sel.iterator().next());
if (parent == null)
{
return UnexecutableCommand.INSTANCE;
}
return createCommand(CreateChildCommand.class, new CommandParameter(parent, commandParameter.getFeature(), commandParameter.getValue(), commandParameter.getCollection(), commandParameter.getIndex()));
}
}
/*
try
{
Constructor<? extends Command> constructor = commandClass.getConstructor(EditingDomain.class, CommandParameter.class);
Command command = constructor.newInstance(new Object [] { this, commandParameter });
return command;
}
catch (IllegalAccessException exception)
{
// Ignore.
}
catch (InstantiationException exception)
{
// Ignore.
}
catch (NoSuchMethodException exception)
{
// Ignore.
}
catch (InvocationTargetException exception)
{
// Ignore.
}
*/
return UnexecutableCommand.INSTANCE;
}
/**
* This just returns null, since this is an optional feature that we don't support here.
*/
public Command createOverrideCommand(OverrideableCommand command)
{
return null;
}
/**
* This returns the command stack provided in the constructor.
*/
public CommandStack getCommandStack()
{
return commandStack;
}
/**
* This delegates to
* {@link org.eclipse.emf.edit.provider.IEditingDomainItemProvider#getChildren IEditingDomainItemProvider.getChildren}.
*/
public Collection<?> getChildren(Object object)
{
// If there is an adapter of the correct type...
//
IEditingDomainItemProvider editingDomainItemProvider =
(IEditingDomainItemProvider)
adapterFactory.adapt(object, IEditingDomainItemProvider.class);
return
editingDomainItemProvider != null ?
editingDomainItemProvider.getChildren(object) :
Collections.emptyList();
}
/**
* This delegates to
* {@link org.eclipse.emf.edit.provider.IEditingDomainItemProvider#getParent IEditingDomainItemProvider.getParent}.
*/
public Object getParent(Object object)
{
// If there is an adapter of the correct type...
//
IEditingDomainItemProvider editingDomainItemProvider =
(IEditingDomainItemProvider)
adapterFactory.adapt(object, IEditingDomainItemProvider.class);
return
editingDomainItemProvider != null ?
editingDomainItemProvider.getParent(object) :
null;
}
public Object getRoot(Object object)
{
Object result = object;
for (Object parent = getParent(object); parent != null; parent = getParent(parent))
{
result = parent;
}
return result;
}
/**
* Each {@link #isStale(Object)} in the list is unwrapped,
* {@link EcoreUtil#resolve(EObject, ResourceSet) resolved},
* and rewrapped before it's added to the result;
* Other objects are passed through unchecked.
* @since 2.4
*/
public List<?> resolve(Collection<?> objects)
{
List<Object> result = new UniqueEList<Object>();
for (Object object : objects)
{
if (isStale(object))
{
Object unwrappedObject = unwrap(object);
if (unwrappedObject instanceof EObject)
{
EObject resolvedEObject = EcoreUtil.resolve((EObject)unwrappedObject, resourceSet);
if (resolvedEObject != unwrappedObject)
{
result.add(object instanceof IWrapperItemProvider ? getWrapper(resolvedEObject) : resolvedEObject);
}
}
}
else
{
result.add(object);
}
}
return result;
}
public Object getWrapper(Object object)
{
return getWrapper(object, this);
}
/**
* Determine a wrapper associated with the given object in the given editing domain.
* @param object the object for which to determine a wrapper.
* @param domain the domain in which to find the wrapper.
* @return a wrapper or the object itself.
* @since 2.5
*/
public static Object getWrapper(Object object, EditingDomain domain)
{
if (object != null)
{
for (Iterator<?> i = domain.treeIterator(domain.getRoot(object)); i.hasNext(); )
{
Object element = i.next();
Object elementValue = element;
while (elementValue instanceof IWrapperItemProvider)
{
elementValue = ((IWrapperItemProvider)elementValue).getValue();
}
if (elementValue == object)
{
return element;
}
else if (elementValue instanceof FeatureMap.Entry)
{
Object entryValue = ((FeatureMap.Entry)elementValue).getValue();
if (entryValue == object)
{
return element;
}
}
}
}
return object;
}
public static Object unwrap(Object object)
{
while (object instanceof IWrapperItemProvider)
{
object = ((IWrapperItemProvider)object).getValue();
}
if (object instanceof FeatureMap.Entry)
{
object = ((FeatureMap.Entry)object).getValue();
}
return object;
}
/**
* This delegates to
* {@link org.eclipse.emf.edit.provider.IEditingDomainItemProvider#getNewChildDescriptors IEditingDomainItemProvider.getNewChildDescriptors}.
*/
public Collection<?> getNewChildDescriptors(Object object, Object sibling)
{
// If no object is specified, but an existing sibling is, the object is
// its parent.
//
if (object == null)
{
object = getParent(sibling);
}
// If there is an adapter of the correct type...
//
IEditingDomainItemProvider editingDomainItemProvider =
(IEditingDomainItemProvider)
adapterFactory.adapt(object, IEditingDomainItemProvider.class);
return
editingDomainItemProvider != null ?
editingDomainItemProvider.getNewChildDescriptors(object, this, sibling) :
Collections.emptyList();
}
/**
* This returns the clipboard of the editing domain.
*/
public Collection<Object> getClipboard()
{
return clipboard;
}
/**
* This sets the clipboard of the editing domain.
*/
public void setClipboard(Collection<Object> clipboard)
{
this.clipboard = clipboard;
}
/**
* This returns whether or not copy command optimizations are safe in this domain.
*/
public boolean getOptimizeCopy()
{
return optimizeCopy;
}
/**
* This sets whether or not copy command optimizations are safe in this domain.
*/
public void setOptimizeCopy(boolean optimizeCopy)
{
this.optimizeCopy = optimizeCopy;
}
/**
* Returns the map of resource to a Boolean value indicating whether the resource is read only.
*/
public Map<Resource, Boolean> getResourceToReadOnlyMap()
{
return resourceToReadOnlyMap;
}
/**
* Set the map of resource to a Boolean value indicating whether the resource is read only.
*/
public void setResourceToReadOnlyMap(Map<Resource, Boolean> resourceToReadOnlyMap)
{
this.resourceToReadOnlyMap = resourceToReadOnlyMap;
}
/**
* This returns whether the resource is read only.
*/
public boolean isReadOnly(Resource resource)
{
if (resourceToReadOnlyMap == null)
{
return false;
}
else
{
Boolean result = resourceToReadOnlyMap.get(resource);
if (result == null && resource != null)
{
Map<?, ?> options = Collections.singletonMap(URIConverter.OPTION_REQUESTED_ATTRIBUTES, Collections.singleton(URIConverter.ATTRIBUTE_READ_ONLY));
Map<String, ?> attributes = (resource.getResourceSet() == null ? resourceSet : resource.getResourceSet()).getURIConverter().getAttributes(resource.getURI(), options);
result = Boolean.TRUE.equals(attributes.get(URIConverter.ATTRIBUTE_READ_ONLY));
resourceToReadOnlyMap.put(resource, result);
}
return Boolean.TRUE.equals(result);
}
}
/**
* Returns whether to expect that the resource corresponding to the given URI form will be read only.
* @deprecated this method is no longer called by {@link #isReadOnly(Resource)}
*/
@Deprecated
protected boolean isReadOnlyURI(URI uri)
{
if (uri.isArchive())
{
return isReadOnlyURI(URI.createURI(uri.authority()));
}
return !uri.isPlatformResource() && (uri.isRelative() || !uri.isFile());
}
/**
* This implements an tree iterator that iterates over an object, it's domain children, their domain children, and so on.
*/
public static class DomainTreeIterator<E> extends AbstractTreeIterator<E>
{
private static final long serialVersionUID = 1L;
/**
* This is the domain that defines the tree structured.
*/
protected EditingDomain domain;
/**
* This constructs tree iterator that iterates over an object, it's domain children, their domain children, and so on.
*/
public DomainTreeIterator(EditingDomain domain, E object)
{
super(object);
this.domain = domain;
}
/**
* This constructs tree iterator that iterates over an object (but only if includeRoot is true),
* it's domain children, their domain children, and so on.
*/
public DomainTreeIterator(EditingDomain domain, Object object, boolean includeRoot)
{
super(object, includeRoot);
this.domain = domain;
}
@SuppressWarnings("unchecked")
@Override
protected Iterator<E> getChildren(Object o)
{
return (Iterator<E>)domain.getChildren(o).iterator();
}
}
/**
* This returns a tree iterator that will yield the object, the children of the object, their children, and so on.
*/
public TreeIterator<?> treeIterator(Object object)
{
return new DomainTreeIterator<Object>(this, object);
}
/**
* This returns a path list from the root object to the given object in the tree.
*/
public List<?> getTreePath(Object object)
{
LinkedList<Object> result = new LinkedList<Object>();
result.addFirst(object);
while ((object = getParent(object)) != null)
{
result.addFirst(object);
}
return result;
}
/**
* This returns whether or not the domain allows the given object to be moved to
* a different resource from its container.
* In this implementation, an EObject is controllable if it has a container,
* it is contained via a feature that allows proxy resolution, and neither it
* nor its container is in a read-only resource.
*/
public boolean isControllable(Object object)
{
if (!(object instanceof EObject)) return false;
EObject eObject = (EObject)object;
EObject container = eObject.eContainer();
return container != null && eObject.eContainmentFeature().isResolveProxies() &&
!isReadOnly(eObject.eResource()) && !isReadOnly(container.eResource());
}
/**
* This returns whether or not an object has been moved to a different resource from
* its container. It is a simple convenience method that compares the two resource
* of the two objects.
*/
public static boolean isControlled(Object object)
{
if (!(object instanceof EObject)) return false;
EObject eObject = (EObject)object;
EObject container = eObject.eContainer();
Resource resource = eObject.eResource();
return resource != null && container != null && resource != container.eResource();
}
}