diff options
45 files changed, 2187 insertions, 560 deletions
diff --git a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/plugin.xml b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/plugin.xml index c3a91523985..4da738bd7f5 100644 --- a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/plugin.xml +++ b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/plugin.xml @@ -67,6 +67,9 @@ <readOnlyHandler class="org.eclipse.papyrus.cdo.core.resource.CDOReadOnlyHandler" priority="16"> + <affinity + axis="permission"> + </affinity> </readOnlyHandler> </extension> diff --git a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOReadOnlyHandler.java b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOReadOnlyHandler.java index 92498ce468f..08886591c1a 100644 --- a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOReadOnlyHandler.java +++ b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOReadOnlyHandler.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2013 CEA LIST. + * Copyright (c) 2013, 2014 CEA LIST and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,21 +8,26 @@ * * Contributors: * CEA LIST - Initial API and implementation + * Christian W. Damus (CEA) - bug 429826 + * *****************************************************************************/ package org.eclipse.papyrus.cdo.core.resource; +import java.util.Set; + import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.papyrus.cdo.internal.core.CDOUtils; -import org.eclipse.papyrus.infra.emf.readonly.AbstractReadOnlyHandler; +import org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler; +import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis; import com.google.common.base.Optional; /** - * This is the CDOReadOnlyHandler type. Enjoy. + * The CDO read handler is permission-based. */ public class CDOReadOnlyHandler extends AbstractReadOnlyHandler { @@ -30,10 +35,11 @@ public class CDOReadOnlyHandler extends AbstractReadOnlyHandler { super(editingDomain); } - public Optional<Boolean> anyReadOnly(URI[] uris) { + @Override + public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) { Optional<Boolean> result = Optional.absent(); - if((uris.length > 0) && CDOUtils.isCDOEditingDomain(getEditingDomain())) { + if(axes.contains(ReadOnlyAxis.PERMISSION) && (uris.length > 0) && CDOUtils.isCDOEditingDomain(getEditingDomain())) { for(int i = 0; !result.or(Boolean.FALSE) && (i < uris.length); i++) { // if it's a cdo:// URI, then I have a definitive answer if(CDOUtils.isCDOURI(uris[i])) { @@ -57,31 +63,31 @@ public class CDOReadOnlyHandler extends AbstractReadOnlyHandler { } @Override - public Optional<Boolean> isReadOnly(EObject eObject) { - + public Optional<Boolean> isReadOnly(Set<ReadOnlyAxis> axes, EObject eObject) { Optional<Boolean> result = Optional.absent(); - Resource resource = eObject.eResource(); - if((resource == null) || CDOUtils.isCDOURI(resource.getURI())) { - CDOObject cdo = CDOUtils.getCDOObject(eObject); - if(cdo != null) { - // I have a definitive answer for CDO objects - result = Optional.of(CDOUtils.isReadOnly(cdo)); + if(axes.contains(ReadOnlyAxis.PERMISSION)) { + Resource resource = eObject.eResource(); + if((resource == null) || CDOUtils.isCDOURI(resource.getURI())) { + CDOObject cdo = CDOUtils.getCDOObject(eObject); + if(cdo != null) { + // I have a definitive answer for CDO objects + result = Optional.of(CDOUtils.isReadOnly(cdo)); + } } } return result; } - public Optional<Boolean> makeWritable(URI[] uris) { - + @Override + public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) { // CDO requires the administrative UI to edit user permissions return Optional.absent(); } @Override - public Optional<Boolean> makeWritable(EObject eObject) { - + public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, EObject eObject) { // CDO requires the administrative UI to edit user permissions return Optional.absent(); } diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/AbstractReadOnlyHandler.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/AbstractReadOnlyHandler.java new file mode 100644 index 00000000000..097f6a5d9a9 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/AbstractReadOnlyHandler.java @@ -0,0 +1,185 @@ +/***************************************************************************** + * Copyright (c) 2013, 2014 Atos Origin, CEA, 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: + * Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation + * Christian W. Damus (CEA) - bug 323802 + * Christian W. Damus (CEA) - bug 429826 + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.core.resource; + +import static org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis.permissionAxes; + +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.edit.domain.EditingDomain; +import org.eclipse.papyrus.infra.core.Activator; +import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2; +import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis; + +import com.google.common.base.Optional; + +public abstract class AbstractReadOnlyHandler implements IReadOnlyHandler2 { + + private EditingDomain editingDomain; + + private CopyOnWriteArrayList<IReadOnlyListener> listeners = new CopyOnWriteArrayList<IReadOnlyListener>(); + + public AbstractReadOnlyHandler(EditingDomain editingDomain) { + this.editingDomain = editingDomain; + } + + public static IReadOnlyHandler2 adapt(IReadOnlyHandler handler, EditingDomain domain) { + return new Adapter(handler, domain); + } + + public EditingDomain getEditingDomain() { + return editingDomain; + } + + @Deprecated + public Optional<Boolean> anyReadOnly(URI[] uris) { + return anyReadOnly(permissionAxes(), uris); + } + + @Deprecated + public Optional<Boolean> isReadOnly(EObject eObject) { + return isReadOnly(permissionAxes(), eObject); + } + + public Optional<Boolean> isReadOnly(Set<ReadOnlyAxis> axes, EObject eObject) { + Resource res = eObject.eResource(); + if (res != null && res.getURI() != null) { + return anyReadOnly(axes, new URI[] {res.getURI()}); + } + return Optional.absent(); + } + + @Deprecated + public Optional<Boolean> makeWritable(URI[] uris) { + return makeWritable(permissionAxes(), uris); + } + + @Deprecated + public Optional<Boolean> makeWritable(EObject eObject) { + return makeWritable(permissionAxes(), eObject); + } + + public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, EObject eObject) { + Resource res = eObject.eResource(); + if (res != null && res.getURI() != null) { + return makeWritable(axes, new URI[] {res.getURI()}); + } + return Optional.absent(); + } + + /** + * By default, we do not handle writability of these resources. + */ + public Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, URI[] uris) { + return Optional.absent(); + } + + public Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, EObject object) { + Resource res = object.eResource(); + if((res != null) && (res.getURI() != null)) { + return canMakeWritable(axes, new URI[]{ res.getURI() }); + } + return Optional.absent(); + } + + @Override + public void addReadOnlyListener(IReadOnlyListener listener) { + listeners.addIfAbsent(listener); + } + + @Override + public void removeReadOnlyListener(IReadOnlyListener listener) { + listeners.remove(listener); + } + + protected void fireReadOnlyStateChanged(ReadOnlyAxis axis, URI resourceURI, boolean readOnly) { + if(!listeners.isEmpty()) { + ReadOnlyEvent event = new ReadOnlyEvent(this, axis, resourceURI, readOnly); + for(IReadOnlyListener next : listeners) { + try { + next.readOnlyStateChanged(event); + } catch (Exception e) { + Activator.log.error("Uncaught exception in read-only state change listener.", e); //$NON-NLS-1$ + } + } + } + } + + protected void fireReadOnlyStateChanged(ReadOnlyAxis axis, EObject object, boolean readOnly) { + if(!listeners.isEmpty()) { + ReadOnlyEvent event = new ReadOnlyEvent(this, axis, object, readOnly); + for(IReadOnlyListener next : listeners) { + try { + next.readOnlyStateChanged(event); + } catch (Exception e) { + Activator.log.error("Uncaught exception in read-only state change listener.", e); //$NON-NLS-1$ + } + } + } + } + + // + // Nested types + // + + private static class Adapter extends AbstractReadOnlyHandler { + private final IReadOnlyHandler delegate; + + Adapter(IReadOnlyHandler handler, EditingDomain editingDomain) { + super(editingDomain); + + this.delegate = handler; + } + + public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) { + // these handlers implicitly only deal with permission-based read-only-ness + return !axes.contains(ReadOnlyAxis.PERMISSION) ? Optional.<Boolean> absent() : delegate.anyReadOnly(uris); + } + + @Override + public Optional<Boolean> isReadOnly(Set<ReadOnlyAxis> axes, EObject eObject) { + return !axes.contains(ReadOnlyAxis.PERMISSION) ? Optional.<Boolean> absent() : delegate.isReadOnly(eObject); + } + + public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) { + // these handlers implicitly only deal with permission-based read-only-ness + Optional<Boolean> result = !axes.contains(ReadOnlyAxis.PERMISSION) ? Optional.<Boolean> absent() : delegate.makeWritable(uris); + + if (result.or(false)) { + for (URI next : uris) { + fireReadOnlyStateChanged(ReadOnlyAxis.PERMISSION, next, true); + } + } + + return result; + } + + @Override + public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, EObject eObject) { + Optional<Boolean> result = !axes.contains(ReadOnlyAxis.PERMISSION) ? Optional.<Boolean> absent() : delegate.makeWritable(eObject); + + if (result.or(false)) { + fireReadOnlyStateChanged(ReadOnlyAxis.PERMISSION, eObject, true); + } + + return result; + } + } +} diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/IReadOnlyHandler.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/IReadOnlyHandler.java index 5443ae7e690..8c69dd47aa2 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/IReadOnlyHandler.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/IReadOnlyHandler.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011, 2013 Atos Origin, CEA, and others.
+ * Copyright (c) 2011, 2014 Atos Origin, CEA, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,7 +9,7 @@ *
* Contributors:
* Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
- * Christian W. Damus (CEA)
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.infra.core.resource;
@@ -20,6 +20,14 @@ import org.eclipse.emf.edit.domain.EditingDomain; import com.google.common.base.Optional;
+/**
+ * A pluggable handler determining whether a resource is "read only" (not writable). Implementations
+ * of this interface, if they do not implement {@link IReadOnlyHandler2}, implicitly determine
+ * read-only-ness according to the {@linkplain ReadOnlyAxis#PERMISSION permission axis}.
+ *
+ * @see IReadOnlyHandler2
+ * @see ReadOnlyAxis#PERMISSION
+ */
public interface IReadOnlyHandler {
/**
@@ -28,8 +36,6 @@ public interface IReadOnlyHandler { *
* @param uris
* the URIs about which read-only-ness is to be determined
- * @param editingDomain
- * the domain in the context of which editing is being done
*
* @return {@link Optional#absent() absent} if I do not know whether any of
* the URIs is read-only or a {@link Optional#isPresent() present}
@@ -45,8 +51,6 @@ public interface IReadOnlyHandler { * @param uris
* the URIs of resources to make writable (not all are
* necessarily read-only)
- * @param editingDomain
- * the domain in the context of which editing is being done
*
* @return {@link Optional#absent() absent} if I do not know how to make
* these resources writable and the next provider should be given a
@@ -63,8 +67,6 @@ public interface IReadOnlyHandler { *
* @param eObject
* an element in some model resource
- * @param editingDomain
- * the contextual editing domain
*
* @return {@link Optional#absent() absent} if I do not know whether the
* {@code eObject} is read-only or a {@link Optional#isPresent()
@@ -79,8 +81,6 @@ public interface IReadOnlyHandler { * @param eObject
* a {@linkplain #isReadOnly(EObject, EditingDomain) read-only}
* element in some model resource
- * @param editingDomain
- * the domain in the context of which editing is being done
*
* @return {@link Optional#absent() absent} if I do not know how to make
* this object writable and the next provider should be given a
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/IReadOnlyHandler2.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/IReadOnlyHandler2.java index 8c266376d1c..143eed81a37 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/IReadOnlyHandler2.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/IReadOnlyHandler2.java @@ -12,34 +12,148 @@ */ package org.eclipse.papyrus.infra.core.resource; +import java.util.Set; + import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.edit.domain.EditingDomain; import com.google.common.base.Optional; /** - * An optional extension interface for {@linkplain IReadOnlyHandler read-only handlers} that support making files writable. + * An optional extension interface for {@linkplain IReadOnlyHandler read-only handlers} that support making files writable + * and pertain to other concerns than simply {@linkplain ReadOnlyAxis#PERMISSION permissions}. + * + * @see ReadOnlyAxis */ public interface IReadOnlyHandler2 extends IReadOnlyHandler { /** - * Queries whether I can make the resources indicated by the given URIs writable. + * A shortcut for {@link #anyReadOnly(Set, URI[])} with a singleton set + * of {@linkplain ReadOnlyAxis#PERMISSION}. + * + * @deprecated Use {@linkplain #anyReadOnly(Set, URI[])}, instead. + */ + Optional<Boolean> anyReadOnly(URI[] uris); + + /** + * A shortcut for {@link #makeWritable(Set, URI[])} with a singleton set + * of {@linkplain ReadOnlyAxis#PERMISSION}. + * + * @deprecated Use {@linkplain #makeWritable(Set, URI[])}, instead. + */ + Optional<Boolean> makeWritable(URI[] uris); + + /** + * A shortcut for {@link #isReadOnly(Set, EObject)} with a singleton set + * of {@linkplain ReadOnlyAxis#PERMISSION}. + * + * @deprecated Use {@linkplain #isReadOnly(Set, EObject)}, instead. + */ + Optional<Boolean> isReadOnly(EObject eObject); + + /** + * A shortcut for {@link #makeWritable(Set, EObject)} with a singleton set + * of {@linkplain ReadOnlyAxis#PERMISSION}. + * + * @deprecated Use {@linkplain #makeWritable(Set, EObject)}, instead. + */ + Optional<Boolean> makeWritable(EObject eObject); + + /** + * Queries whether any of the resources identified by the given URIs is + * read-only in any of the given {@code axes} of concern. + * + * @param axes + * the set of axes on which to query read-only state + * @param uris + * the URIs about which read-only-ness is to be determined + * + * @return {@link Optional#absent() absent} if I do not know whether any of + * the URIs is read-only or a {@link Optional#isPresent() present} + * boolean indicating whether any definitively is or they all + * definitively are not read-only + */ + Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris); + + /** + * Attempt to ensure that the resources identified by the given URIs are + * writable in any of the given {@code axes} of concern. + * + * @param axes + * the set of axes on which to query read-only state + * @param uris + * the URIs of resources to make writable (not all are + * necessarily read-only) + * + * @return {@link Optional#absent() absent} if I do not know how to make + * these resources writable and the next provider should be given a + * chance, or a {@link Optional#isPresent() present} boolean + * indicating that I made the resources writable ({@code true}) or + * they cannot be made writable ({@code false}) + */ + Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris); + + /** + * Queries whether an {@code eObject} is individually read-only in a given + * editing domain, if it is in a resource that supports object-level + * read/write permissions in any of the given {@code axes} of concern. + * + * @param axes + * the set of axes on which to query read-only state + * @param eObject + * an element in some model resource + * + * @return {@link Optional#absent() absent} if I do not know whether the + * {@code eObject} is read-only or a {@link Optional#isPresent() + * present} boolean indicating whether it definitively is or is not + * read-only + */ + Optional<Boolean> isReadOnly(Set<ReadOnlyAxis> axes, EObject eObject); + + /** + * Attempt to ensure that the given {@code eObject} is writable in any of the given {@code axes} of concern. + * + * @param axes + * the set of axes on which to query read-only state + * @param eObject + * a {@linkplain #isReadOnly(EObject, EditingDomain) read-only} + * element in some model resource + * + * @return {@link Optional#absent() absent} if I do not know how to make + * this object writable and the next provider should be given a + * chance, or a {@link Optional#isPresent() present} boolean + * indicating that I made it writable ({@code true}) or it cannot be + * made writable ({@code false}) + */ + Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, EObject eObject); + + /** + * Queries whether I can make the resources indicated by the given URIs writable in any of the given {@code axes} of concern. * + * @param axes + * the set of axes on which to query read-only state * @param uris * indicate a set of resources (presumed read-only) * @return a {@linkplain Optional#isPresent() present} boolean indicating either that I can make the resources writable or that I handle these * kinds of resources and they cannot be made writable; an {@linkplain Optional#absent() absent} value, otherwise */ - Optional<Boolean> canMakeWritable(URI[] uris); + Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, URI[] uris); /** - * Queries whether I can make the given {@code object} writable. + * Queries whether I can make the given {@code object} writable in any of the given {@code axes} of concern. * + * @param axes + * the set of axes on which to query read-only state * @param object * a model element (presumed read-only) * @return a {@linkplain Optional#isPresent() present} boolean indicating either that I can make the {@code object writable or that I handle its * kind of resources and it cannot be made writable; an {@linkplain Optional#absent() absent} value, otherwise */ - Optional<Boolean> canMakeWritable(EObject object); + Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, EObject object); + + void addReadOnlyListener(IReadOnlyListener listener); + + void removeReadOnlyListener(IReadOnlyListener listener); } diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/IReadOnlyListener.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/IReadOnlyListener.java new file mode 100644 index 00000000000..ae90c14aab7 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/IReadOnlyListener.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2014 CEA 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: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.core.resource; + +import java.util.EventListener; + + +/** + * This is the IReadOnlyListener type. Enjoy. + */ +public interface IReadOnlyListener extends EventListener { + + public void readOnlyStateChanged(ReadOnlyEvent event); +} diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ModelSet.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ModelSet.java index 96f02ae8f5d..ac45d457169 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ModelSet.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ModelSet.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2008, 2013 CEA LIST and others. + * Copyright (c) 2008, 2014 CEA LIST and others. * * * All rights reserved. This program and the accompanying materials @@ -14,6 +14,7 @@ * Christian W. Damus (CEA) - Support read-only state at object level (CDO) * Christian W. Damus (CEA) - Refactoring of Create Model Wizard (CDO) * Christian W. Damus (CEA LIST) - Controlled resources in CDO repositories + * Christian W. Damus (CEA) - bug 429826 * *****************************************************************************/ package org.eclipse.papyrus.infra.core.resource; @@ -108,7 +109,7 @@ public class ModelSet extends ResourceSetImpl { protected Adapter modificationTrackingAdapter; - protected IReadOnlyHandler roHandler; + protected IReadOnlyHandler2 roHandler; /** * URI pointing to resource on which back end should be deleted on save @@ -678,12 +679,13 @@ public class ModelSet extends ResourceSetImpl { Collection<IModel> modelList = models.values(); monitor.beginTask("Saving resources", modelList.size()); - if(isTrackingModification() && getReadOnlyHandler() != null) { + IReadOnlyHandler2 roHandler = getReadOnlyHandler(); + if(isTrackingModification() && (roHandler != null)) { Set<URI> roUris = new HashSet<URI>(); for(IModel model : modelList) { Set<URI> uris = model.getModifiedURIs(); for(URI u : uris) { - Optional<Boolean> res = getReadOnlyHandler().anyReadOnly(new URI[]{ u }); + Optional<Boolean> res = (roHandler.anyReadOnly(ReadOnlyAxis.permissionAxes(), new URI[]{ u })); if(res.isPresent() && res.get()) { roUris.add(u); } @@ -691,14 +693,14 @@ public class ModelSet extends ResourceSetImpl { } for(URI u : getResourcesToDeleteOnSave()) { - Optional<Boolean> res = getReadOnlyHandler().anyReadOnly(new URI[]{ u }); + Optional<Boolean> res = roHandler.anyReadOnly(ReadOnlyAxis.permissionAxes(), new URI[]{ u }); if(res.isPresent() && res.get()) { roUris.add(u); } } if(!roUris.isEmpty()) { - Optional<Boolean> authorizeSave = getReadOnlyHandler().makeWritable(roUris.toArray(new URI[roUris.size()])); + Optional<Boolean> authorizeSave = roHandler.makeWritable(ReadOnlyAxis.permissionAxes(), roUris.toArray(new URI[roUris.size()])); if(authorizeSave.isPresent() && !authorizeSave.get()) { monitor.done(); @@ -938,12 +940,14 @@ public class ModelSet extends ResourceSetImpl { } } - public IReadOnlyHandler getReadOnlyHandler() { + public IReadOnlyHandler2 getReadOnlyHandler() { if(roHandler == null) { EditingDomain editingDomain = getTransactionalEditingDomain(); Object handler = PlatformHelper.getAdapter(editingDomain, IReadOnlyHandler.class); - if(handler instanceof IReadOnlyHandler) { - roHandler = (IReadOnlyHandler)handler; + if(handler instanceof IReadOnlyHandler2) { + roHandler = (IReadOnlyHandler2)handler; + } else if(handler instanceof IReadOnlyHandler) { + roHandler = AbstractReadOnlyHandler.adapt((IReadOnlyHandler)handler, editingDomain); } } return roHandler; diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ReadOnlyAxis.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ReadOnlyAxis.java new file mode 100644 index 00000000000..bde0a900c44 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ReadOnlyAxis.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014 CEA 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: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.core.resource; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.Set; + +import com.google.common.collect.Sets; + + +/** + * The "read-only-ness" of resources can be partitioned according to a number of othogonal concerns, or <em>axes</em>. + * Being orthogonal, these concerns are independent, although any particular resource may be considered as read-only + * according to more than one of these simultaneously (or one or none at all). + */ +public enum ReadOnlyAxis { + /** + * The most basic and obvious axis is the permission, or access control, concern. This typically maps to + * permissions in the storage layer (file system, database, network, etc.). + */ + PERMISSION, + + /** + * Some resources may be considered as read-only for discretionary reasons: there is no obstacle of {@linkplain #PERMISSION permissions}, but + * merely that the user is discouraged from making modifications + * to such a resource or its contents as a matter of policy. + */ + DISCRETION; + + private static final Set<ReadOnlyAxis> ANY_AXIS = Sets.immutableEnumSet(EnumSet.allOf(ReadOnlyAxis.class)); + + private static final Set<ReadOnlyAxis> PERMISSION_AXES = Collections.singleton(PERMISSION); + + private static final Set<ReadOnlyAxis> DISCRETION_AXES = Collections.singleton(DISCRETION); + + /** + * Efficiently obtains me as a singleton set. + * + * @return a singleton set containing me only + */ + public Set<ReadOnlyAxis> singleton() { + switch(this) { + case PERMISSION: + return PERMISSION_AXES; + case DISCRETION: + return DISCRETION_AXES; + default: + throw new IllegalStateException("Impossible enumeration value: " + this); //$NON-NLS-1$ + } + } + + /** + * The set of axes for queries pertaining to any axis. That is to say, the complete set of all axes. + */ + public static Set<ReadOnlyAxis> anyAxis() { + return ANY_AXIS; + } + + /** + * The set of axes for queries pertaining to permission. That is to say, the singleton containing {@link #PERMISSION}. + */ + public static Set<ReadOnlyAxis> permissionAxes() { + return PERMISSION_AXES; + } + + /** + * The set of axes for queries pertaining to discretion. That is to say, the singleton containing {@link #DISCRETION}. + */ + public static Set<ReadOnlyAxis> discretionAxes() { + return DISCRETION_AXES; + } +} diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ReadOnlyEvent.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ReadOnlyEvent.java new file mode 100644 index 00000000000..8235b7b357e --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ReadOnlyEvent.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014 CEA 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: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.core.resource; + +import java.util.EventObject; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; + + +/** + * This is the ReadOnlyEvent type. Enjoy. + */ +public class ReadOnlyEvent extends EventObject { + + public static final int RESOURCE_READ_ONLY_STATE_CHANGED = 0; + + public static final int OBJECT_READ_ONLY_STATE_CHANGED = 1; + + private static final long serialVersionUID = 1L; + + private final int eventType; + + private final ReadOnlyAxis axis; + + private final URI resourceURI; + + private final EObject object; + + private final boolean readOnly; + + private ReadOnlyEvent(IReadOnlyHandler2 source, int eventType, ReadOnlyAxis axis, URI resourceURI, EObject object, boolean readOnly) { + super(source); + + this.eventType = eventType; + this.axis = axis; + this.resourceURI = resourceURI; + this.object = object; + this.readOnly = readOnly; + } + + public ReadOnlyEvent(IReadOnlyHandler2 source, ReadOnlyAxis axis, URI resourceURI, boolean readOnly) { + this(source, RESOURCE_READ_ONLY_STATE_CHANGED, axis, resourceURI, null, readOnly); + } + + public ReadOnlyEvent(IReadOnlyHandler2 source, ReadOnlyAxis axis, EObject object, boolean readOnly) { + this(source, RESOURCE_READ_ONLY_STATE_CHANGED, axis, null, object, readOnly); + } + + public IReadOnlyHandler2 getHandler() { + return (IReadOnlyHandler2)getSource(); + } + + public int getEventType() { + return eventType; + } + + public ReadOnlyAxis getAxis() { + return axis; + } + + public URI getResourceURI() { + return resourceURI; + } + + public EObject getObject() { + return object; + } + + public boolean isReadOnly() { + return readOnly; + } +} diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/TransactionHelper.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/TransactionHelper.java index 060c29865d2..a697a09ee26 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/TransactionHelper.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/TransactionHelper.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2014 CEA LIST.
+ * Copyright (c) 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,9 +8,21 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 429826
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.core.utils;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.emf.transaction.Transaction;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
/**
* This helper can be used to run (safe) transactions outside the CommandStack
@@ -22,4 +34,161 @@ public class TransactionHelper extends org.eclipse.papyrus.infra.core.sasheditor //Refactoring needed. The sasheditor contentprovider should have dependencies to infra.EMF...
+ public static final String TRANSACTION_OPTION_READ_ONLY_AXIS = "papyrus.read_only_axis"; //$NON-NLS-1$
+
+ public static final String TRANSACTION_OPTION_INTERACTIVE = "papyrus.interactive"; //$NON-NLS-1$
+
+ /**
+ * Merges the read-only {@code axis} option into an existing map of {@code options}.
+ *
+ * @param options
+ * an existing (non-{@code null}) options map
+ * @param axis
+ * the axis option to merge
+ * @return the augmented {@code options}
+ */
+ public static Map<String, Object> mergeReadOnlyAxisOption(Map<String, Object> options, ReadOnlyAxis axis) {
+ return mergeReadOnlyAxisOption(options, Collections.singleton(axis));
+ }
+
+ /**
+ * Merges the read-only {@code axes} option into an existing map of {@code options}.
+ *
+ * @param options
+ * an existing (non-{@code null}) options map
+ * @param axes
+ * the axes option to merge
+ * @return the augmented {@code options}
+ */
+ public static Map<String, Object> mergeReadOnlyAxisOption(Map<String, Object> options, Set<ReadOnlyAxis> axes) {
+ options.put(TRANSACTION_OPTION_READ_ONLY_AXIS, axes);
+ return options;
+ }
+
+ /**
+ * Adds the read-only {@code axis} option to a transaction's {@code options}.
+ *
+ * @param options
+ * an options map, which may be {@code null} or immutable
+ * @param axis
+ * the axis option to add
+ * @return a new map based on the {@code options} and including the {@code axis}
+ */
+ public static Map<String, Object> addReadOnlyAxisOption(Map<String, ?> options, ReadOnlyAxis axis) {
+ return addReadOnlyAxisOption(options, Collections.singleton(axis));
+ }
+
+ /**
+ * Adds the read-only {@code axes} option to a transaction's {@code options}.
+ *
+ * @param options
+ * an options map, which may be {@code null} or immutable
+ * @param axes
+ * the axes option to add
+ * @return a new map based on the {@code options} and including the {@code axes}
+ */
+ public static Map<String, Object> addReadOnlyAxisOption(Map<String, ?> options, Set<ReadOnlyAxis> axes) {
+ Map<String, Object> result = (options == null) ? Maps.<String, Object> newHashMap() : Maps.newHashMap(options);
+ result.put(TRANSACTION_OPTION_READ_ONLY_AXIS, axes);
+ return result;
+ }
+
+ /**
+ * Creates a new mutable transaction options map with a read-only {@code axis}.
+ *
+ * @param axis
+ * the axis option
+ * @return a new mutable map including the {@code axis}
+ */
+ public static Map<String, Object> readOnlyAxisOption(ReadOnlyAxis axis) {
+ return readOnlyAxisOption(Collections.singleton(axis));
+ }
+
+ /**
+ * Creates a new mutable transaction options map with a read-only {@code axes}.
+ *
+ * @param axes
+ * the axes option
+ * @return a new mutable map including the {@code axes}
+ */
+ public static Map<String, Object> readOnlyAxisOption(Set<ReadOnlyAxis> axes) {
+ return addReadOnlyAxisOption(null, axes);
+ }
+
+ /**
+ * Queries the read-only axes to be enforced by a {@code transaction}.
+ *
+ * @param transaction
+ * a transaction
+ * @return its read-only axes, which are {@linkplain ReadOnlyAxis#anyAxis() all of them} by default if the option is absent
+ */
+ @SuppressWarnings("unchecked")
+ public static Set<ReadOnlyAxis> getReadOnlyAxisOption(Transaction transaction) {
+ Set<ReadOnlyAxis> result;
+
+ Object value = transaction.getOptions().get(TRANSACTION_OPTION_READ_ONLY_AXIS);
+ if(value instanceof Set<?>) {
+ result = (Set<ReadOnlyAxis>)value;
+ } else if(value instanceof Iterable<?>) {
+ result = Sets.immutableEnumSet((Iterable<ReadOnlyAxis>)value);
+ } else {
+ result = ReadOnlyAxis.anyAxis();
+ }
+
+ return result;
+ }
+
+ /**
+ * Merges the {@code interactive} transaction option into an existing map of {@code options}.
+ *
+ * @param options
+ * an existing (non-{@code null}) options map
+ * @param interactive
+ * whether the transaction is in an user-interactive context
+ * @return the augmented {@code options}
+ */
+ public static Map<String, Object> mergeInteractiveOption(Map<String, Object> options, boolean interactive) {
+ options.put(TRANSACTION_OPTION_INTERACTIVE, interactive);
+ return options;
+ }
+
+ /**
+ * Adds the {@code interactive} option option to a transaction's {@code options}.
+ *
+ * @param options
+ * an options map, which may be {@code null} or immutable
+ * @param interactive
+ * whether the transaction is in an user-interactive context
+ * @return a new map based on the {@code options} and including the {@code interactive} option
+ */
+ public static Map<String, Object> addInteractiveOption(Map<String, ?> options, boolean interactive) {
+ Map<String, Object> result = (options == null) ? Maps.<String, Object> newHashMap() : Maps.newHashMap(options);
+ result.put(TRANSACTION_OPTION_INTERACTIVE, interactive);
+ return result;
+ }
+
+ /**
+ * Creates a new mutable transaction options map with an {@code interactive} option.
+ *
+ * @param interactive
+ * whether the transaction is in an user-interactive context
+ * @return a new mutable map including the {@code interactive} option
+ */
+ public static Map<String, Object> interactiveOption(boolean interactive) {
+ return addInteractiveOption(null, interactive);
+ }
+
+ /**
+ * Queries whether a {@code transaction} is running in a user-interactive context. In practice, this means that it would be appropriate to
+ * prompt the user to make resources/objects writable if necessary.
+ *
+ * @param transaction
+ * a transaction
+ * @return {@code false} if the {@code transaction} has the {@linkplain #TRANSACTION_OPTION_INTERACTIVE interactive option} set {@code false};
+ * {@code true}, otherwise (including the default case of no option set)
+ */
+ public static boolean isInteractive(Transaction transaction) {
+ Object value = transaction.getOptions().get(TRANSACTION_OPTION_INTERACTIVE);
+ return (value instanceof Boolean) ? (Boolean)value : true;
+ }
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/plugin.xml b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/plugin.xml index ea9f90089b1..6232c1f3e44 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/plugin.xml +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/plugin.xml @@ -8,20 +8,33 @@ class="org.eclipse.papyrus.infra.emf.readonly.ReferencedModelReadOnlyHandler"
id="org.eclipse.papyrus.infra.emf.readonly.ReferencedModelReadOnlyHandler"
priority="15">
+ <affinity
+ axis="discretion">
+ </affinity>
</readOnlyHandler>
<readOnlyHandler
class="org.eclipse.papyrus.infra.emf.readonly.FSReadOnlyHandler"
id="org.eclipse.papyrus.infra.emf.readonly.FSReadOnlyHandler"
priority="10">
+ <affinity
+ axis="permission">
+ </affinity>
</readOnlyHandler>
<readOnlyHandler
class="org.eclipse.papyrus.infra.emf.readonly.EMFReadOnlyHandler"
id="org.eclipse.papyrus.infra.emf.readonly.EMFReadOnlyHandler"
priority="5">
+ <affinity
+ axis="permission">
+ </affinity>
</readOnlyHandler>
<readOnlyHandler
class="org.eclipse.papyrus.infra.emf.readonly.SashModelReadOnlyHandler"
- priority="20"></readOnlyHandler>
+ priority="20">
+ <affinity
+ axis="discretion">
+ </affinity>
+ </readOnlyHandler>
</extension>
<extension
point="org.eclipse.ui.handlers">
@@ -133,6 +146,9 @@ <adapter
type="org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler">
</adapter>
+ <adapter
+ type="org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2">
+ </adapter>
</factory>
</extension>
<!-- commented for Papyrus M4 build -->
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/schema/readOnlyHandler.exsd b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/schema/readOnlyHandler.exsd index f6e1fa72735..cc704afdf94 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/schema/readOnlyHandler.exsd +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/schema/readOnlyHandler.exsd @@ -1,116 +1,144 @@ -<?xml version='1.0' encoding='UTF-8'?>
-<!-- Schema file written by PDE -->
-<schema targetNamespace="org.eclipse.papyrus.infra.emf.readonly" xmlns="http://www.w3.org/2001/XMLSchema">
-<annotation>
- <appinfo>
- <meta.schema plugin="org.eclipse.papyrus.infra.emf.readonly" id="readOnly" name="readOnly"/>
- </appinfo>
- <documentation>
- [Enter description of this extension point.]
- </documentation>
- </annotation>
-
- <element name="extension">
- <annotation>
- <appinfo>
- <meta.element />
- </appinfo>
- </annotation>
- <complexType>
- <sequence>
- <element ref="readOnlyHandler" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="point" type="string" use="required">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- <attribute name="id" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- <attribute name="name" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- <appinfo>
- <meta.attribute translatable="true"/>
- </appinfo>
- </annotation>
- </attribute>
- </complexType>
- </element>
-
- <element name="readOnlyHandler">
- <complexType>
- <attribute name="class" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- <appinfo>
- <meta.attribute kind="java" basedOn=":org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler"/>
- </appinfo>
- </annotation>
- </attribute>
- <attribute name="priority" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- <attribute name="id" type="string">
- <annotation>
- <documentation>
- optional id that can be used if this read only handler can be overriden.
- </documentation>
- </annotation>
- </attribute>
- </complexType>
- </element>
-
- <annotation>
- <appinfo>
- <meta.section type="since"/>
- </appinfo>
- <documentation>
- [Enter the first release in which this extension point appears.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="examples"/>
- </appinfo>
- <documentation>
- [Enter extension point usage example here.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="apiinfo"/>
- </appinfo>
- <documentation>
- [Enter API information here.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="implementation"/>
- </appinfo>
- <documentation>
- [Enter information about supplied implementation of this extension point.]
- </documentation>
- </annotation>
-
-
-</schema>
+<?xml version='1.0' encoding='UTF-8'?> +<!-- Schema file written by PDE --> +<schema targetNamespace="org.eclipse.papyrus.infra.emf.readonly" xmlns="http://www.w3.org/2001/XMLSchema"> +<annotation> + <appinfo> + <meta.schema plugin="org.eclipse.papyrus.infra.emf.readonly" id="readOnly" name="readOnly"/> + </appinfo> + <documentation> + [Enter description of this extension point.] + </documentation> + </annotation> + + <element name="extension"> + <annotation> + <appinfo> + <meta.element /> + </appinfo> + </annotation> + <complexType> + <sequence> + <element ref="readOnlyHandler" minOccurs="0" maxOccurs="unbounded"/> + </sequence> + <attribute name="point" type="string" use="required"> + <annotation> + <documentation> + + </documentation> + </annotation> + </attribute> + <attribute name="id" type="string"> + <annotation> + <documentation> + + </documentation> + </annotation> + </attribute> + <attribute name="name" type="string"> + <annotation> + <documentation> + + </documentation> + <appinfo> + <meta.attribute translatable="true"/> + </appinfo> + </annotation> + </attribute> + </complexType> + </element> + + <element name="readOnlyHandler"> + <complexType> + <sequence> + <element ref="affinity" minOccurs="0" maxOccurs="unbounded"/> + </sequence> + <attribute name="class" type="string"> + <annotation> + <documentation> + + </documentation> + <appinfo> + <meta.attribute kind="java" basedOn=":org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler"/> + </appinfo> + </annotation> + </attribute> + <attribute name="priority" type="string"> + <annotation> + <documentation> + + </documentation> + </annotation> + </attribute> + <attribute name="id" type="string"> + <annotation> + <documentation> + optional id that can be used if this read only handler can be overriden. + </documentation> + </annotation> + </attribute> + </complexType> + </element> + + <element name="affinity"> + <annotation> + <documentation> + Declaration of a handler's affinity with a particular read-only axis. + </documentation> + </annotation> + <complexType> + <attribute name="axis" use="required"> + <annotation> + <documentation> + The read-only axis (as enumerated in the <tt>ReadOnlyAxis</tt> type) to which handler is applicable. + </documentation> + </annotation> + <simpleType> + <restriction base="string"> + <enumeration value="discretion"> + </enumeration> + <enumeration value="permission"> + </enumeration> + </restriction> + </simpleType> + </attribute> + </complexType> + </element> + + <annotation> + <appinfo> + <meta.section type="since"/> + </appinfo> + <documentation> + [Enter the first release in which this extension point appears.] + </documentation> + </annotation> + + <annotation> + <appinfo> + <meta.section type="examples"/> + </appinfo> + <documentation> + [Enter extension point usage example here.] + </documentation> + </annotation> + + <annotation> + <appinfo> + <meta.section type="apiinfo"/> + </appinfo> + <documentation> + [Enter API information here.] + </documentation> + </annotation> + + <annotation> + <appinfo> + <meta.section type="implementation"/> + </appinfo> + <documentation> + [Enter information about supplied implementation of this extension point.] + </documentation> + </annotation> + + +</schema> diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/AbstractReadOnlyHandler.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/AbstractReadOnlyHandler.java index e378e43c022..95bccb2e856 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/AbstractReadOnlyHandler.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/AbstractReadOnlyHandler.java @@ -10,58 +10,20 @@ * Contributors:
* Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
* Christian W. Damus (CEA) - bug 323802
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.domain.EditingDomain;
-import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
-import com.google.common.base.Optional;
-
-public abstract class AbstractReadOnlyHandler implements IReadOnlyHandler2 {
-
- private EditingDomain editingDomain;
+/**
+ * @deprecated Use the {@link org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler} class, instead.
+ */
+@Deprecated
+public abstract class AbstractReadOnlyHandler extends org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler {
public AbstractReadOnlyHandler(EditingDomain editingDomain) {
- this.editingDomain = editingDomain;
- }
-
- public EditingDomain getEditingDomain() {
- return editingDomain;
- }
-
- public Optional<Boolean> isReadOnly(EObject eObject) {
- Resource res = eObject.eResource();
- if (res != null && res.getURI() != null) {
- return anyReadOnly(new URI[] {res.getURI()});
- }
- return Optional.absent();
- }
-
- public Optional<Boolean> makeWritable(EObject eObject) {
- Resource res = eObject.eResource();
- if (res != null && res.getURI() != null) {
- return makeWritable(new URI[] {res.getURI()});
- }
- return Optional.absent();
- }
-
- /**
- * By default, we do not handle writability of these resources.
- */
- public Optional<Boolean> canMakeWritable(URI[] uris) {
- return Optional.absent();
- }
-
- public Optional<Boolean> canMakeWritable(EObject object) {
- Resource res = object.eResource();
- if((res != null) && (res.getURI() != null)) {
- return canMakeWritable(new URI[]{ res.getURI() });
- }
- return Optional.absent();
+ super(editingDomain);
}
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/EMFReadOnlyHandler.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/EMFReadOnlyHandler.java index c30bbe21ba6..dd3fd1226ca 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/EMFReadOnlyHandler.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/EMFReadOnlyHandler.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,32 +8,42 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 429826
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
+import java.util.Set;
+
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import com.google.common.base.Optional;
-
+/**
+ * The EMF read-only handler is permission-based.
+ */
public class EMFReadOnlyHandler extends AbstractReadOnlyHandler {
public EMFReadOnlyHandler(EditingDomain editingDomain) {
super(editingDomain);
}
- public Optional<Boolean> anyReadOnly(URI[] uris) {
- for(URI uri : uris) {
- if(!uri.isPlatformResource()) {
- return Optional.of(Boolean.TRUE);
+ public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
+ if(axes.contains(ReadOnlyAxis.PERMISSION)) {
+ for(URI uri : uris) {
+ if(!(uri.isPlatformResource() || uri.isFile())) {
+ return Optional.of(Boolean.TRUE);
+ }
}
}
-
+
return Optional.absent();
}
- public Optional<Boolean> makeWritable(URI[] uris) {
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
return Optional.absent(); //We cannot change the read-only status
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/FSReadOnlyHandler.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/FSReadOnlyHandler.java index f035f201423..5df8b04d757 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/FSReadOnlyHandler.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/FSReadOnlyHandler.java @@ -10,12 +10,15 @@ * Contributors:
* Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
* Christian W. Damus (CEA) - bug 323802
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
-import java.util.ArrayList;
-import java.util.Collection;
+import java.io.File;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.core.resources.IFile;
@@ -26,71 +29,95 @@ import org.eclipse.core.runtime.Path; import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.swt.widgets.Display;
import com.google.common.base.Optional;
+/**
+ * The filesystem read-only handler is permission-based.
+ */
public class FSReadOnlyHandler extends AbstractReadOnlyHandler {
public FSReadOnlyHandler(EditingDomain editingDomain) {
super(editingDomain);
}
- public Optional<Boolean> anyReadOnly(URI[] uris) {
- for(URI uri : uris) {
-
- IFile file = getFile(uri);
- if(file != null && file.isReadOnly()) {
- return Optional.of(Boolean.TRUE);
+ public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
+ if(axes.contains(ReadOnlyAxis.PERMISSION)) {
+ for(URI uri : uris) {
+ IFile ifile = getIFile(uri);
+ if(ifile != null) {
+ if(ifile.isReadOnly()) {
+ return Optional.of(Boolean.TRUE);
+ }
+ } else {
+ File file = getFile(uri);
+ if((file != null) && file.exists() && !file.canWrite()) {
+ return Optional.of(Boolean.TRUE);
+ }
+ }
}
}
return Optional.absent();
}
- private static IFile getFile(URI uri) {
+ private static IFile getIFile(URI uri) {
if(uri.isPlatform()) {
return ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(uri.toPlatformString(true)));
}
return null;
}
- public Optional<Boolean> makeWritable(final URI[] uris) {
+ private static File getFile(URI uri) {
+ if(uri.isFile()) {
+ return new File(uri.toFileString());
+ }
+ return null;
+ }
+
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, final URI[] uris) {
+ if(!axes.contains(ReadOnlyAxis.PERMISSION)) {
+ return Optional.absent();
+ }
+
final AtomicBoolean doEnableWrite = new AtomicBoolean();
-
+
// We can't make a file writable if it already is (there are read-only handlers that treat files that
// are filesystem-writable as read-only for other reasons)
- Collection<IFile> readOnlyFiles = new ArrayList<IFile>(uris.length);
+ final Map<IFile, URI> readOnlyFiles = new LinkedHashMap<IFile, URI>();
for(int i = 0; i < uris.length; i++) {
- IFile file = getFile(uris[i]);
+ IFile file = getIFile(uris[i]);
if((file != null) && file.isReadOnly()) {
- readOnlyFiles.add(file);
+ readOnlyFiles.put(file, uris[i]);
}
}
-
- if (!readOnlyFiles.isEmpty()) {
+
+ if(!readOnlyFiles.isEmpty()) {
Display.getCurrent().syncExec(new Runnable() {
-
+
public void run() {
String message = "Do you want to remove read only flag on those files ?\n\n";
- for(URI uri : uris) {
- IFile file = getFile(uri);
- if(file != null && file.isReadOnly()) {
- message += file.getName() + "\n";
- }
+ for(IFile file : readOnlyFiles.keySet()) {
+ message += file.getName() + "\n";
}
doEnableWrite.set(MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), "Enable Write", message));
}
});
}
-
+
if(doEnableWrite.get()) {
Boolean ok = true;
- for(IFile file : readOnlyFiles) {
+ for(Map.Entry<IFile, URI> next : readOnlyFiles.entrySet()) {
try {
+ IFile file = next.getKey();
ResourceAttributes att = file.getResourceAttributes();
att.setReadOnly(false);
file.setResourceAttributes(att);
+
+ fireReadOnlyStateChanged(ReadOnlyAxis.PERMISSION, next.getValue(), true);
} catch (CoreException e) {
ok = false;
}
@@ -105,15 +132,17 @@ public class FSReadOnlyHandler extends AbstractReadOnlyHandler { * I can make workspace resources writable.
*/
@Override
- public Optional<Boolean> canMakeWritable(URI[] uris) {
+ public Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
Optional<Boolean> result = Optional.absent();
- for(int i = 0; (!result.isPresent() || result.get()) && (i < uris.length); i++) {
- if(uris[i].isPlatformResource()) {
- result = Optional.of(true);
- } else if(uris[i].isFile()) {
- // We don't make non-workspace (external but local) files writable
- result = Optional.of(false);
+ if(axes.contains(ReadOnlyAxis.PERMISSION)) {
+ for(int i = 0; (!result.isPresent() || result.get()) && (i < uris.length); i++) {
+ if(uris[i].isPlatformResource()) {
+ result = Optional.of(true);
+ } else if(uris[i].isFile()) {
+ // We don't make non-workspace (external but local) files writable
+ result = Optional.of(false);
+ }
}
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java index 0d178b8c6be..ebbacd5b4be 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java @@ -11,10 +11,13 @@ * Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
* Christian W. Damus (CEA) - Support object-level read/write controls (CDO)
* Christian W. Damus (CEA) - bug 323802
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
+import static org.eclipse.papyrus.infra.core.utils.TransactionHelper.isInteractive;
+
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -30,17 +33,17 @@ 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.EcoreUtil;
import org.eclipse.emf.transaction.NotificationFilter;
import org.eclipse.emf.transaction.Transaction;
import org.eclipse.emf.transaction.TransactionalCommandStack;
import org.eclipse.emf.transaction.impl.InternalTransaction;
import org.eclipse.emf.transaction.impl.TransactionChangeRecorder;
import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl;
-import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler;
import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
import org.eclipse.papyrus.infra.core.resource.IRollbackStatus;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.infra.core.resource.RollbackStatus;
+import org.eclipse.papyrus.infra.core.utils.TransactionHelper;
import org.eclipse.papyrus.infra.onefile.model.IPapyrusFile;
import org.eclipse.papyrus.infra.onefile.model.PapyrusModelHelper;
import org.eclipse.papyrus.infra.onefile.utils.OneFileUtils;
@@ -54,14 +57,11 @@ public class PapyrusROTransactionalEditingDomain extends TransactionalEditingDom @Override
public boolean isReadOnly(Resource resource) {
- if(resource != null && resource.getURI() != null) {
- return ReadOnlyManager.getReadOnlyHandler(this).anyReadOnly(new URI[]{ resource.getURI() }).get();
- }
- return false;
+ return isReadOnly(ReadOnlyAxis.anyAxis(), resource);
}
public boolean isReadOnly(EObject eObject) {
- return ReadOnlyManager.getReadOnlyHandler(this).isReadOnly(eObject).get();
+ return isReadOnly(ReadOnlyAxis.anyAxis(), eObject);
}
@Override
@@ -98,6 +98,7 @@ public class PapyrusROTransactionalEditingDomain extends TransactionalEditingDom && !Boolean.TRUE.equals(tx.getOptions().get(Transaction.OPTION_UNPROTECTED)) //
&& !willRollBack(tx)) {
+ final Set<ReadOnlyAxis> axes = TransactionHelper.getReadOnlyAxisOption(tx);
boolean readOnly;
// Check for Resource first because CDO resources *are* EObjects
@@ -107,10 +108,12 @@ public class PapyrusROTransactionalEditingDomain extends TransactionalEditingDom // We must be able to modify read-only resources in order to load them
return;
}
- readOnly = isReadOnly(resource) && !makeWritable(resource);
+ // If it's not an interactive transaction, don't try to make the resource writable because that would prompt the user
+ readOnly = isReadOnly(axes, resource) && !(isInteractive(tx) && makeWritable(axes, resource));
} else if(object instanceof EObject) {
EObject eObject = (EObject)object;
- readOnly = isReadOnly(eObject) && !makeWritable(eObject);
+ // If it's not an interactive transaction, don't try to make the object writable because that would prompt the user
+ readOnly = isReadOnly(axes, eObject) && !(isInteractive(tx) && makeWritable(axes, eObject));
} else {
// If it's not an EMF-managed object, we don't care
readOnly = false;
@@ -123,41 +126,43 @@ public class PapyrusROTransactionalEditingDomain extends TransactionalEditingDom }
}
}
-
+
private boolean willRollBack(Transaction tx) {
IStatus status = tx.getStatus();
return (status != null) && (status.getSeverity() >= IStatus.ERROR);
}
- protected boolean makeWritable(Resource resource) {
+ protected boolean isReadOnly(Set<ReadOnlyAxis> axes, Resource resource) {
+ if((resource != null) && (resource.getURI() != null)) {
+ return ReadOnlyManager.getReadOnlyHandler(this).anyReadOnly(axes, new URI[]{ resource.getURI() }).get();
+ }
+ return false;
+ }
+
+ protected boolean isReadOnly(Set<ReadOnlyAxis> axes, EObject eObject) {
+ return ReadOnlyManager.getReadOnlyHandler(this).isReadOnly(axes, eObject).get();
+ }
+
+ protected boolean makeWritable(Set<ReadOnlyAxis> axes, Resource resource) {
URI[] uris = getCompositeModelURIs(resource.getURI());
- IReadOnlyHandler handler = ReadOnlyManager.getReadOnlyHandler(this);
+ IReadOnlyHandler2 handler = ReadOnlyManager.getReadOnlyHandler(this);
- if(handler instanceof IReadOnlyHandler2) {
- if(!((IReadOnlyHandler2)handler).canMakeWritable(uris).or(false)) {
- return false;
- }
+ if(!handler.canMakeWritable(axes, uris).or(false)) {
+ return false;
}
- return handler.makeWritable(uris).get();
+ return handler.makeWritable(axes, uris).get();
}
- protected boolean makeWritable(EObject object) {
+ protected boolean makeWritable(Set<ReadOnlyAxis> axes, EObject object) {
boolean result;
- URI uri = EcoreUtil.getURI(object);
+ IReadOnlyHandler2 handler = ReadOnlyManager.getReadOnlyHandler(this);
- // If it's a workspace resource, we don't have to worry about object-level read-only state
- if(uri.isPlatformResource()) {
- result = makeWritable(object.eResource());
+ if(!handler.canMakeWritable(axes, object).or(false)) {
+ result = false;
} else {
- IReadOnlyHandler handler = ReadOnlyManager.getReadOnlyHandler(this);
-
- if((handler instanceof IReadOnlyHandler2) && !((IReadOnlyHandler2)handler).canMakeWritable(object).or(false)) {
- result = false;
- } else {
- result = handler.makeWritable(object).get();
- }
+ result = handler.makeWritable(axes, object).get();
}
return result;
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyAdapterFactory.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyAdapterFactory.java index 621235a1af2..5444e6fd48f 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyAdapterFactory.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyAdapterFactory.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2012 Atos Origin.
+ * Copyright (c) 2012, 2014 Atos Origin, CEA, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,6 +9,7 @@ *
* Contributors:
* Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
@@ -16,12 +17,13 @@ package org.eclipse.papyrus.infra.emf.readonly; import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
@SuppressWarnings("rawtypes")
public class ReadOnlyAdapterFactory implements IAdapterFactory {
public Object getAdapter(Object adaptableObject, Class adapterType) {
- if(IReadOnlyHandler.class == adapterType && adaptableObject instanceof EditingDomain) {
+ if(((IReadOnlyHandler.class == adapterType) || (IReadOnlyHandler2.class == adapterType)) && (adaptableObject instanceof EditingDomain)) {
return ReadOnlyManager.getReadOnlyHandler((EditingDomain) adaptableObject);
}
return null;
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManager.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManager.java index f09bd0e39df..9e849a4120a 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManager.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManager.java @@ -11,30 +11,42 @@ * Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
* Christian W. Damus (CEA) - support non-IFile resources and object-level permissions (CDO)
* Christian W. Damus (CEA) - bug 323802
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
+import static org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis.permissionAxes;
+
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.EnumMap;
+import java.util.EnumSet;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.papyrus.infra.core.Activator;
+import org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler;
import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler;
import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyListener;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyEvent;
import com.google.common.base.Optional;
-@SuppressWarnings("deprecation")
public class ReadOnlyManager implements IReadOnlyHandler2 {
//Using a WeakHashMap leads to a Memory Leak, because only the Key is weak.
@@ -42,10 +54,14 @@ public class ReadOnlyManager implements IReadOnlyHandler2 { //which prevents garbage collection of the EditingDomain
//Workaround: when the (Papyrus) editing domain is disposed, it removes itself from this map
//This won't work for non-papyrus editing domains, which are still leaked (But we do not use non-papyrus editing domains which this ReadOnlyManager)
- protected static Map<EditingDomain, IReadOnlyHandler> roHandlers = new HashMap<EditingDomain, IReadOnlyHandler>();
+ protected static Map<EditingDomain, IReadOnlyHandler2> roHandlers = new HashMap<EditingDomain, IReadOnlyHandler2>();
- public static IReadOnlyHandler getReadOnlyHandler(EditingDomain editingDomain) {
- IReadOnlyHandler roHandler = roHandlers.get(editingDomain);
+ private final CopyOnWriteArrayList<IReadOnlyListener> listeners = new CopyOnWriteArrayList<IReadOnlyListener>();
+
+ private IReadOnlyListener forwardingListener;
+
+ public static IReadOnlyHandler2 getReadOnlyHandler(EditingDomain editingDomain) {
+ IReadOnlyHandler2 roHandler = roHandlers.get(editingDomain);
if(roHandler == null) {
roHandler = new ReadOnlyManager(editingDomain);
roHandlers.put(editingDomain, roHandler);
@@ -58,6 +74,8 @@ public class ReadOnlyManager implements IReadOnlyHandler2 { public Class<?> handlerClass;
public int priority;
+
+ public Set<ReadOnlyAxis> axes;
public int compareTo(HandlerPriorityPair o) {
if(o.priority > priority) {
@@ -70,7 +88,7 @@ public class ReadOnlyManager implements IReadOnlyHandler2 { }
}
- protected static final Class<?>[] orderedHandlerClassesArray;
+ protected static final Map<Class<?>, Set<ReadOnlyAxis>> orderedHandlerClasses;
static {
IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.papyrus.infra.emf.readonly", "readOnlyHandler");
@@ -86,6 +104,18 @@ public class ReadOnlyManager implements IReadOnlyHandler2 { handlerPriorityPair.handlerClass = Platform.getBundle(elem.getContributor().getName()).loadClass(className);
handlerPriorityPair.priority = Integer.parseInt(elem.getAttribute("priority"));
+
+ IConfigurationElement[] affinities = elem.getChildren("affinity");
+ if ((affinities == null) || (affinities.length == 0)) {
+ // implicit affinity is with any axis
+ handlerPriorityPair.axes = ReadOnlyAxis.anyAxis();
+ } else {
+ handlerPriorityPair.axes = EnumSet.noneOf(ReadOnlyAxis.class);
+ for (IConfigurationElement next : affinities) {
+ handlerPriorityPair.axes.add(ReadOnlyAxis.valueOf(next.getAttribute("axis").toUpperCase()));
+ }
+ }
+
String id = elem.getAttribute("id");
if(id != null) {
//if any then the handler could be overrided by another registration
@@ -113,15 +143,16 @@ public class ReadOnlyManager implements IReadOnlyHandler2 { Collections.sort(handlerPriorityPairs);
- orderedHandlerClassesArray = new Class<?>[handlerPriorityPairs.size()];
+ orderedHandlerClasses = new LinkedHashMap<Class<?>, Set<ReadOnlyAxis>>();
- for(int i = 0; i < orderedHandlerClassesArray.length; i++) {
- orderedHandlerClassesArray[i] = handlerPriorityPairs.get(i).handlerClass;
+ for(HandlerPriorityPair next : handlerPriorityPairs) {
+ orderedHandlerClasses.put(next.handlerClass, next.axes);
}
}
- protected static IReadOnlyHandler create(final Class<?> handlerClass, EditingDomain editingDomain) {
+ @SuppressWarnings("deprecation")
+ protected static IReadOnlyHandler2 create(final Class<?> handlerClass, EditingDomain editingDomain) {
boolean isEditingDomainConstructor = true;
Constructor<?> constructor = null;
try {
@@ -131,14 +162,20 @@ public class ReadOnlyManager implements IReadOnlyHandler2 { constructor = handlerClass.getConstructor();
}
- if(IReadOnlyHandler.class.isAssignableFrom(constructor.getDeclaringClass())) {
+ if(IReadOnlyHandler2.class.isAssignableFrom(constructor.getDeclaringClass())) {
+ if(isEditingDomainConstructor) {
+ return (IReadOnlyHandler2)constructor.newInstance(editingDomain);
+ } else {
+ return (IReadOnlyHandler2)constructor.newInstance();
+ }
+ } else if(IReadOnlyHandler.class.isAssignableFrom(constructor.getDeclaringClass())) {
if(isEditingDomainConstructor) {
- return (IReadOnlyHandler)constructor.newInstance(editingDomain);
+ return AbstractReadOnlyHandler.adapt((IReadOnlyHandler)constructor.newInstance(editingDomain), editingDomain);
} else {
- return (IReadOnlyHandler)constructor.newInstance();
+ return AbstractReadOnlyHandler.adapt((IReadOnlyHandler)constructor.newInstance(), editingDomain);
}
} else if(org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler.class.isAssignableFrom(constructor.getDeclaringClass())) {
- return new HandlerAdapter((org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler)constructor.newInstance(), editingDomain);
+ return new OldStyleHandlerAdapter((org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler)constructor.newInstance(), editingDomain);
}
} catch (Exception e) {
}
@@ -146,142 +183,320 @@ public class ReadOnlyManager implements IReadOnlyHandler2 { return null;
}
- protected IReadOnlyHandler[] orderedHandlersArray;
+ protected Map<ReadOnlyAxis, IReadOnlyHandler2[]> orderedHandlersByAxis;
public ReadOnlyManager(EditingDomain editingDomain) {
- ArrayList<IReadOnlyHandler> handlers = new ArrayList<IReadOnlyHandler>();
- for(Class<?> roClass : orderedHandlerClassesArray) {
- IReadOnlyHandler h = create(roClass, editingDomain);
+ Map<ReadOnlyAxis, List<IReadOnlyHandler2>> handlers = new EnumMap<ReadOnlyAxis, List<IReadOnlyHandler2>>(ReadOnlyAxis.class);
+ for(Map.Entry<Class<?>, Set<ReadOnlyAxis>> roClass : orderedHandlerClasses.entrySet()) {
+ IReadOnlyHandler2 h = create(roClass.getKey(), editingDomain);
if(h != null) {
- handlers.add(h);
+ h.addReadOnlyListener(getForwardingListener());
+
+ for (ReadOnlyAxis axis : roClass.getValue()) {
+ List<IReadOnlyHandler2> list = handlers.get(axis);
+ if (list == null) {
+ list = new ArrayList<IReadOnlyHandler2>();
+ handlers.put(axis, list);
+ }
+ list.add(h);
+ }
+ }
+ }
+
+ // Iterate the enumeration to make sure all axes are represented (even if only by an empty array)
+ orderedHandlersByAxis = new EnumMap<ReadOnlyAxis, IReadOnlyHandler2[]>(ReadOnlyAxis.class);
+ for(ReadOnlyAxis axis : ReadOnlyAxis.values()) {
+ List<IReadOnlyHandler2> list = handlers.get(axis);
+ if(list == null) {
+ orderedHandlersByAxis.put(axis, new IReadOnlyHandler2[0]);
+ } else {
+ orderedHandlersByAxis.put(axis, list.toArray(new IReadOnlyHandler2[list.size()]));
}
}
- orderedHandlersArray = handlers.toArray(new IReadOnlyHandler[handlers.size()]);
}
- public Optional<Boolean> anyReadOnly(URI[] uris) {
+ public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
Optional<Boolean> result = Optional.absent();
- for(int i = 0; (i < orderedHandlersArray.length) && !result.isPresent(); i++) {
- result = orderedHandlersArray[i].anyReadOnly(uris);
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for(int i = 0; (i < all.length) && !result.or(Boolean.FALSE); i++) {
+ if(axes.contains(all[i])) {
+ result = anyReadOnly(all[i], uris);
+ }
}
return result.isPresent() ? result : Optional.of(Boolean.FALSE);
}
- public Optional<Boolean> isReadOnly(EObject eObject) {
+ private Optional<Boolean> anyReadOnly(ReadOnlyAxis axis, URI[] uris) {
+ Set<ReadOnlyAxis> axes = axis.singleton();
Optional<Boolean> result = Optional.absent();
- for(int i = 0; (i < orderedHandlersArray.length) && !result.isPresent(); i++) {
- result = orderedHandlersArray[i].isReadOnly(eObject);
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for(int i = 0; (i < orderedHandlers.length) && !result.isPresent(); i++) {
+ result = orderedHandlers[i].anyReadOnly(axes, uris);
}
return result.isPresent() ? result : Optional.of(Boolean.FALSE);
}
- public Optional<Boolean> makeWritable(URI[] uris) {
+ public Optional<Boolean> isReadOnly(Set<ReadOnlyAxis> axes, EObject eObject) {
+ Optional<Boolean> result = Optional.absent();
+
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for(int i = 0; (i < all.length) && !result.or(Boolean.FALSE); i++) {
+ if(axes.contains(all[i])) {
+ result = isReadOnly(all[i], eObject);
+ }
+ }
+
+ return result.isPresent() ? result : Optional.of(Boolean.FALSE);
+ }
+
+ private Optional<Boolean> isReadOnly(ReadOnlyAxis axis, EObject eObject) {
+ Set<ReadOnlyAxis> axes = axis.singleton();
+ Optional<Boolean> result = Optional.absent();
+
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for(int i = 0; (i < orderedHandlers.length) && !result.isPresent(); i++) {
+ result = orderedHandlers[i].isReadOnly(axes, eObject);
+ }
+
+ return result.isPresent() ? result : Optional.of(Boolean.FALSE);
+ }
+
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
+ Boolean finalResult = true;
+
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for(int i = 0; (i < all.length) && finalResult; i++) {
+ if(axes.contains(all[i])) {
+ finalResult = makeWritable(all[i], uris);
+ }
+ }
+
+ return Optional.of(finalResult);
+ }
+
+ private Boolean makeWritable(ReadOnlyAxis axis, URI[] uris) {
+ Set<ReadOnlyAxis> axes = axis.singleton();
Boolean finalResult = true;
- for(int i = 0; (i < orderedHandlersArray.length); i++) {
- Optional<Boolean> isRO = orderedHandlersArray[i].anyReadOnly(uris);
- if(isRO.isPresent() && isRO.get()) {
- Optional<Boolean> result = orderedHandlersArray[i].makeWritable(uris);
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for(int i = 0; (i < orderedHandlers.length); i++) {
+ Optional<Boolean> isRO = orderedHandlers[i].anyReadOnly(axes, uris);
+ if(isRO.or(Boolean.FALSE)) {
+ Optional<Boolean> result = orderedHandlers[i].makeWritable(axes, uris);
// makeWritable should provide an answer since anyReadOnly returned a positive value.
// If no answer consider it a failure
- if(!result.isPresent() || !result.get()) {
+ if(!result.or(Boolean.FALSE)) {
finalResult = false;
break;
}
}
}
+ return finalResult;
+ }
+
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, EObject eObject) {
+ Boolean finalResult = true;
+
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for(int i = 0; (i < all.length) && finalResult; i++) {
+ if(axes.contains(all[i])) {
+ finalResult = makeWritable(all[i], eObject);
+ }
+ }
+
return Optional.of(finalResult);
}
- public Optional<Boolean> makeWritable(EObject eObject) {
+ private Boolean makeWritable(ReadOnlyAxis axis, EObject eObject) {
+ Set<ReadOnlyAxis> axes = axis.singleton();
Boolean finalResult = true;
- for(int i = 0; (i < orderedHandlersArray.length); i++) {
- Optional<Boolean> isRO = orderedHandlersArray[i].isReadOnly(eObject);
- if(isRO.isPresent() && isRO.get()) {
- Optional<Boolean> result = orderedHandlersArray[i].makeWritable(eObject);
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for(int i = 0; (i < orderedHandlers.length); i++) {
+ Optional<Boolean> isRO = orderedHandlers[i].isReadOnly(axes, eObject);
+ if(isRO.or(Boolean.FALSE)) {
+ Optional<Boolean> result = orderedHandlers[i].makeWritable(axes, eObject);
// makeWritable should provide an answer since anyReadOnly returned a positive value
- // if no answer consider it fails
- if(result.isPresent() && !result.get()) {
+ // if no answer consider it a failure
+ if(!result.or(Boolean.FALSE)) {
finalResult = false;
+ break;
}
}
}
- return Optional.of(finalResult);
+ return finalResult;
}
-
- public Optional<Boolean> canMakeWritable(URI[] uris) {
+
+ public Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
Boolean result = false;
- for(int i = 0; (i < orderedHandlersArray.length); i++) {
- if(orderedHandlersArray[i] instanceof IReadOnlyHandler2) {
- IReadOnlyHandler2 h2 = (IReadOnlyHandler2)orderedHandlersArray[i];
- if (h2.anyReadOnly(uris).or(false)) {
- // Only ask a handler about making writable what it considers to be read-only
- Optional<Boolean> canMakeWritable = h2.canMakeWritable(uris);
- if(canMakeWritable.isPresent()) {
- result = canMakeWritable.get();
- break;
- }
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for(int i = 0; (i < all.length) && !result; i++) {
+ if(axes.contains(all[i])) {
+ result = canMakeWritable(all[i], uris);
+ }
+ }
+
+ return Optional.of(result);
+ }
+
+ private Boolean canMakeWritable(ReadOnlyAxis axis, URI[] uris) {
+ Set<ReadOnlyAxis> axes = axis.singleton();
+ Boolean result = false;
+
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for(int i = 0; (i < orderedHandlers.length); i++) {
+ if(orderedHandlers[i].anyReadOnly(axes, uris).or(false)) {
+ // Only ask a handler about making writable what it considers to be read-only
+ Optional<Boolean> canMakeWritable = orderedHandlers[i].canMakeWritable(axes, uris);
+ if(canMakeWritable.isPresent()) {
+ result = canMakeWritable.get();
+ break;
}
}
}
+ return result;
+ }
+
+ public Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, EObject object) {
+ Boolean result = false;
+
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for(int i = 0; (i < all.length) && !result; i++) {
+ if(axes.contains(all[i])) {
+ result = canMakeWritable(all[i], object);
+ }
+ }
+
return Optional.of(result);
}
-
- public Optional<Boolean> canMakeWritable(EObject object) {
+
+ private Boolean canMakeWritable(ReadOnlyAxis axis, EObject object) {
+ Set<ReadOnlyAxis> axes = axis.singleton();
Boolean result = false;
- for(int i = 0; (i < orderedHandlersArray.length); i++) {
- if(orderedHandlersArray[i] instanceof IReadOnlyHandler2) {
- IReadOnlyHandler2 h2 = (IReadOnlyHandler2)orderedHandlersArray[i];
- if (h2.isReadOnly(object).or(false)) {
- // Only ask a handler about making writable what it considers to be read-only
- Optional<Boolean> canMakeWritable = h2.canMakeWritable(object);
- if(canMakeWritable.isPresent()) {
- result = canMakeWritable.get();
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for(int i = 0; (i < orderedHandlers.length); i++) {
+ if(orderedHandlers[i].isReadOnly(axes, object).or(false)) {
+ // Only ask a handler about making writable what it considers to be read-only
+ Optional<Boolean> canMakeWritable = orderedHandlers[i].canMakeWritable(axes, object);
+ if(canMakeWritable.isPresent()) {
+ result = canMakeWritable.get();
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public void addReadOnlyListener(IReadOnlyListener listener) {
+ listeners.addIfAbsent(listener);
+ }
+
+ public void removeReadOnlyListener(IReadOnlyListener listener) {
+ listeners.remove(listener);
+ }
+
+ private IReadOnlyListener getForwardingListener() {
+ if(forwardingListener == null) {
+ forwardingListener = new IReadOnlyListener() {
+
+ public void readOnlyStateChanged(ReadOnlyEvent event) {
+ ReadOnlyEvent myEvent;
+
+ switch(event.getEventType()) {
+ case ReadOnlyEvent.OBJECT_READ_ONLY_STATE_CHANGED:
+ myEvent = new ReadOnlyEvent(ReadOnlyManager.this, event.getAxis(), event.getObject(), event.isReadOnly());
+ break;
+ default:
+ myEvent = new ReadOnlyEvent(ReadOnlyManager.this, event.getAxis(), event.getResourceURI(), event.isReadOnly());
break;
}
+
+ notifyReadOnlyStateChanged(myEvent);
}
- }
+ };
}
- return Optional.of(result);
+ return forwardingListener;
}
+
+ protected void notifyReadOnlyStateChanged(ReadOnlyEvent event) {
+ if(!listeners.isEmpty()) {
+ for(IReadOnlyListener next : listeners) {
+ try {
+ next.readOnlyStateChanged(event);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in read-only state change listener.", e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ //
+ // Deprecated API
+ //
+
+ @Deprecated
+ public Optional<Boolean> anyReadOnly(URI[] uris) {
+ return anyReadOnly(permissionAxes(), uris);
+ }
+
+ @Deprecated
+ public Optional<Boolean> isReadOnly(EObject eObject) {
+ return isReadOnly(permissionAxes(), eObject);
+ }
+
+ @Deprecated
+ public Optional<Boolean> makeWritable(URI[] uris) {
+ return makeWritable(permissionAxes(), uris);
+ }
+
+ @Deprecated
+ public Optional<Boolean> makeWritable(EObject eObject) {
+ return makeWritable(permissionAxes(), eObject);
+ }
+
+ //
+ // Legacy adapters
+ //
- private static final class HandlerAdapter extends AbstractReadOnlyHandler {
+ @SuppressWarnings("deprecation")
+ private static final class OldStyleHandlerAdapter extends AbstractReadOnlyHandler {
private final org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler delegate;
- HandlerAdapter(org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler handler, EditingDomain editingDomain) {
+ OldStyleHandlerAdapter(org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler handler, EditingDomain editingDomain) {
super(editingDomain);
this.delegate = handler;
}
- public Optional<Boolean> anyReadOnly(URI[] uris) {
+ public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
// the old API contract is that handlers only return true if they
// know it to be true, because the manager takes the first positive
- // answer
- boolean delegateResult = delegate.isReadOnly(uris, getEditingDomain());
+ // answer. Moreover, they only dealt with permission-based read-only-ness
+ boolean delegateResult = axes.contains(ReadOnlyAxis.PERMISSION) && delegate.isReadOnly(uris, getEditingDomain());
return delegateResult ? Optional.of(Boolean.TRUE) : Optional.<Boolean> absent();
}
- public Optional<Boolean> makeWritable(URI[] uris) {
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
// the old API contract is that handlers only return false if they
// tried to but could not make the resources writable, because the
// manager takes the first negative answer (this is opposite to the
- // isReadOnly logic)
- boolean delegateResult = delegate.enableWrite(uris, getEditingDomain());
+ // isReadOnly logic). Moreover, they only dealt with permission-based
+ // read-only-ness
+ boolean delegateResult = axes.contains(ReadOnlyAxis.PERMISSION) && delegate.enableWrite(uris, getEditingDomain());
return delegateResult ? Optional.<Boolean> absent() : Optional.of(Boolean.FALSE);
}
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyOneFileApprover.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyOneFileApprover.java index 03a5388e717..67df44387de 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyOneFileApprover.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyOneFileApprover.java @@ -10,6 +10,7 @@ * Contributors:
* Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
* Christian W. Damus (CEA) - bug 323802
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
@@ -38,8 +39,9 @@ import org.eclipse.emf.workspace.EMFCommandOperation; import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.common.core.command.ICompositeCommand;
-import org.eclipse.gmf.runtime.common.core.internal.command.ICommandWithSettableResult;
import org.eclipse.papyrus.commands.wrappers.GMFtoEMFCommandWrapper;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.infra.onefile.model.IPapyrusFile;
import org.eclipse.papyrus.infra.onefile.model.PapyrusModelHelper;
import org.eclipse.papyrus.infra.onefile.utils.OneFileUtils;
@@ -98,8 +100,9 @@ public class ReadOnlyOneFileApprover implements IOperationApprover2 { EditingDomain editingDomain = getEditingDomain(operation);
URI[] filesToCheckForLockArray = filesToCheckForLock.toArray(new URI[filesToCheckForLock.size()]);
- if(ReadOnlyManager.getReadOnlyHandler(editingDomain).anyReadOnly(filesToCheckForLockArray).get()) {
- Optional<Boolean> ok = ReadOnlyManager.getReadOnlyHandler(editingDomain).makeWritable(filesToCheckForLockArray);
+ IReadOnlyHandler2 roHandler = ReadOnlyManager.getReadOnlyHandler(editingDomain);
+ if(roHandler.anyReadOnly(ReadOnlyAxis.anyAxis(), filesToCheckForLockArray).get()) {
+ Optional<Boolean> ok = roHandler.makeWritable(ReadOnlyAxis.anyAxis(), filesToCheckForLockArray);
if(!ok.get()) {
return Status.CANCEL_STATUS;
}
@@ -115,7 +118,7 @@ public class ReadOnlyOneFileApprover implements IOperationApprover2 { }
if (editingDomain == null && command instanceof ICompositeCommand) {
- Iterator it = ((ICompositeCommand)command).iterator();
+ Iterator<?> it = ((ICompositeCommand)command).iterator();
while (editingDomain == null && it.hasNext()) {
IUndoableOperation c = (IUndoableOperation)it.next();
editingDomain = getEditingDomain(c);
@@ -134,9 +137,10 @@ public class ReadOnlyOneFileApprover implements IOperationApprover2 { * IStatus of the CommandResult that will be set on the
* command
*/
+ @SuppressWarnings("restriction")
protected void setCommandResult(ICommand command, IStatus status) {
- if(command instanceof ICommandWithSettableResult) {
- ((ICommandWithSettableResult)command).internalSetResult(new CommandResult(status));
+ if(command instanceof org.eclipse.gmf.runtime.common.core.internal.command.ICommandWithSettableResult) {
+ ((org.eclipse.gmf.runtime.common.core.internal.command.ICommandWithSettableResult)command).internalSetResult(new CommandResult(status));
}
}
@@ -147,7 +151,9 @@ public class ReadOnlyOneFileApprover implements IOperationApprover2 { protected Set<IFile> getAffectedFiles(IUndoableOperation operation, Set<IFile> result) {
if(operation instanceof ICommand) {
- result = appendFiles(result, ((ICommand)operation).getAffectedFiles());
+ @SuppressWarnings("unchecked")
+ Collection<IFile> files = ((ICommand)operation).getAffectedFiles();
+ result = appendFiles(result, files);
} else if(operation instanceof GMFtoEMFCommandWrapper) {
result = getAffectedFiles(((GMFtoEMFCommandWrapper)operation).getGMFCommand(), result);
} else if(operation instanceof EMFCommandOperation) {
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyTester.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyTester.java index eaef7d7c325..8ffdca3198a 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyTester.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyTester.java @@ -11,6 +11,7 @@ * Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
* Christian W. Damus (CEA) - Support read-only state at object level (CDO)
* Christian W. Damus (CEA) - bug 323802
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
@@ -19,12 +20,12 @@ import java.util.Iterator; import org.eclipse.core.expressions.PropertyTester;
import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory;
+import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler;
import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.infra.emf.utils.BusinessModelResolver;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import com.google.common.base.Objects;
@@ -59,9 +60,9 @@ public class ReadOnlyTester extends PropertyTester { if(businessObject instanceof EObject) {
EObject eObject = (EObject)businessObject;
- Resource resource = eObject.eResource();
- if((resource != null) && (resource.getResourceSet() != null)) {
- return Objects.equal(ReadOnlyManager.getReadOnlyHandler(WorkspaceEditingDomainFactory.INSTANCE.getEditingDomain(resource.getResourceSet())).isReadOnly(eObject).get(), expectedValue);
+ EditingDomain domain = EMFHelper.resolveEditingDomain(eObject);
+ if(domain != null) {
+ return Objects.equal(ReadOnlyManager.getReadOnlyHandler(domain).isReadOnly(ReadOnlyAxis.anyAxis(), eObject).or(false), expectedValue);
}
}
}
@@ -75,11 +76,13 @@ public class ReadOnlyTester extends PropertyTester { if(businessObject instanceof EObject) {
EObject eObject = (EObject)businessObject;
- Resource resource = eObject.eResource();
- if((resource != null) && (resource.getResourceSet() != null)) {
- IReadOnlyHandler handler = ReadOnlyManager.getReadOnlyHandler(WorkspaceEditingDomainFactory.INSTANCE.getEditingDomain(resource.getResourceSet()));
- boolean isAlreadyOrCanMakeWritable = !handler.isReadOnly(eObject).or(false) //
- || ((handler instanceof IReadOnlyHandler2) && ((IReadOnlyHandler2)handler).canMakeWritable(eObject).or(false));
+ EditingDomain domain = EMFHelper.resolveEditingDomain(eObject);
+ if(domain != null) {
+ IReadOnlyHandler2 handler = ReadOnlyManager.getReadOnlyHandler(domain);
+
+ boolean isAlreadyOrCanMakeWritable = !handler.isReadOnly(ReadOnlyAxis.anyAxis(), eObject).or(false) //
+ || handler.canMakeWritable(ReadOnlyAxis.anyAxis(), eObject).or(false);
+
return Objects.equal(isAlreadyOrCanMakeWritable, expectedValue);
}
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReferencedModelReadOnlyHandler.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReferencedModelReadOnlyHandler.java index 6d909461712..8d55efe222f 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReferencedModelReadOnlyHandler.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReferencedModelReadOnlyHandler.java @@ -22,8 +22,10 @@ import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.URIConverter; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler; +import org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler; +import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2; import org.eclipse.papyrus.infra.core.resource.ModelSet; +import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis; import org.eclipse.papyrus.infra.emf.readonly.internal.messages.Messages; import org.eclipse.swt.widgets.Display; @@ -32,8 +34,8 @@ import com.google.common.base.Optional; /** - * A {@linkplain IReadOnlyHandler read-only handler} for objects in referenced models, which by default shouldn't be editable in the context of the - * model referencing them. + * A {@linkplain IReadOnlyHandler2 read-only handler} for objects in referenced models, which by default shouldn't be editable in the context of the + * model referencing them. This is a discretion-based handler. */ public class ReferencedModelReadOnlyHandler extends AbstractReadOnlyHandler { @@ -68,95 +70,102 @@ public class ReferencedModelReadOnlyHandler extends AbstractReadOnlyHandler { this.interactive = interactive; } - public Optional<Boolean> anyReadOnly(URI[] uris) { + public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) { Optional<Boolean> result = Optional.absent(); - final URIConverter converter = getEditingDomain().getResourceSet().getURIConverter(); - - for(int i = 0; i < uris.length; i++) { - // Clients may pass object URIs (including fragments), so trim to a resource URI because we operate on the resource level - URI next = uris[i].trimFragment(); + if(axes.contains(ReadOnlyAxis.DISCRETION)) { + final URIConverter converter = getEditingDomain().getResourceSet().getURIConverter(); - // If the resource doesn't exist, then it can't be opened in some other editor, so - // we needn't be concerned about editing it in the context of a referencing model - if(!readableReferencedModels.contains(next.trimFileExtension()) && isNotModelSetMainModel(next) && converter.exists(next, null)) { - result = Optional.of(true); - break; + for(int i = 0; i < uris.length; i++) { + // Clients may pass object URIs (including fragments), so trim to a resource URI because we operate on the resource level + URI next = uris[i].trimFragment(); + + // If the resource doesn't exist, then it can't be opened in some other editor, so + // we needn't be concerned about editing it in the context of a referencing model + if(!readableReferencedModels.contains(next.trimFileExtension()) && isNotModelSetMainModel(next) && converter.exists(next, null)) { + result = Optional.of(true); + break; + } } } - + return result; } @Override - public Optional<Boolean> canMakeWritable(URI[] uris) { + public Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, URI[] uris) { Optional<Boolean> result = Optional.absent(); - for(int i = 0; i < uris.length; i++) { - // Clients may pass object URIs (including fragments), so trim to a resource URI because we operate on the resource level - URI next = uris[i].trimFragment(); - - if(isNotModelSetMainModel(next)) { - result = Optional.of(true); - } else { - // If it's not something I handle, then bomb - result = Optional.of(false); - break; + if(axes.contains(ReadOnlyAxis.DISCRETION)) { + for(int i = 0; i < uris.length; i++) { + // Clients may pass object URIs (including fragments), so trim to a resource URI because we operate on the resource level + URI next = uris[i].trimFragment(); + + if(isNotModelSetMainModel(next)) { + result = Optional.of(true); + } else { + // If it's not something I handle, then bomb + result = Optional.of(false); + break; + } } } - + return result; } - public Optional<Boolean> makeWritable(URI[] uris) { + public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) { Optional<Boolean> result = Optional.absent(); - final List<URI> toMakeWritable = new ArrayList<URI>(uris.length); - - for(int i = 0; i < uris.length; i++) { - // Clients may pass object URIs (including fragments), so trim to a resource URI because we operate on the resource level - URI next = uris[i].trimFragment(); - - if(isNotModelSetMainModel(next)) { - toMakeWritable.add(next); + if(axes.contains(ReadOnlyAxis.DISCRETION)) { + final List<URI> toMakeWritable = new ArrayList<URI>(uris.length); + + for(int i = 0; i < uris.length; i++) { + // Clients may pass object URIs (including fragments), so trim to a resource URI because we operate on the resource level + URI next = uris[i].trimFragment(); + + if(isNotModelSetMainModel(next)) { + toMakeWritable.add(next); + } } - } - - if(!toMakeWritable.isEmpty()) { - final boolean[] enableWrite = { !isInteractive() }; - - if(isInteractive()) { - Display.getCurrent().syncExec(new Runnable() { - - public void run() { - StringBuilder message = new StringBuilder(Messages.ReferencedModelReadOnlyHandler_promptMsg); - for(URI uri : toMakeWritable) { - String path; - if(uri.isPlatformResource()) { - path = uri.toPlatformString(true); - } else if(uri.isFile()) { - path = uri.toFileString(); - } else { - path = uri.toString(); + + if(!toMakeWritable.isEmpty()) { + final boolean[] enableWrite = { !isInteractive() }; + + if(isInteractive()) { + Display.getCurrent().syncExec(new Runnable() { + + public void run() { + StringBuilder message = new StringBuilder(Messages.ReferencedModelReadOnlyHandler_promptMsg); + for(URI uri : toMakeWritable) { + String path; + if(uri.isPlatformResource()) { + path = uri.toPlatformString(true); + } else if(uri.isFile()) { + path = uri.toFileString(); + } else { + path = uri.toString(); + } + + message.append(path); + message.append("\n"); //$NON-NLS-1$ } - - message.append(path); - message.append("\n"); //$NON-NLS-1$ + enableWrite[0] = MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), Messages.ReferencedModelReadOnlyHandler_promptTitle, message.toString()); } - enableWrite[0] = MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), Messages.ReferencedModelReadOnlyHandler_promptTitle, message.toString()); + }); + } + + if(enableWrite[0]) { + for(URI next : toMakeWritable) { + readableReferencedModels.add(next.trimFileExtension()); + fireReadOnlyStateChanged(ReadOnlyAxis.DISCRETION, next, true); } - }); - } - - if(enableWrite[0]) { - for(URI next : toMakeWritable) { - readableReferencedModels.add(next.trimFileExtension()); } + + result = Optional.of(enableWrite[0]); } - - result = Optional.of(enableWrite[0]); } - + return result; } diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/SashModelReadOnlyHandler.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/SashModelReadOnlyHandler.java index bf0a1a1a086..260ec8e371a 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/SashModelReadOnlyHandler.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/SashModelReadOnlyHandler.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2014 CEA LIST.
+ * Copyright (c) 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,12 +8,18 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 429826
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
+import java.util.Set;
+
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.infra.core.resource.sasheditor.DiModel;
import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModel;
@@ -25,7 +31,9 @@ import com.google.common.base.Optional; * If the model is located in the user preferences space, it may be considered
* read-only by other read-only handlers, whereas it shouldn't.
*
- * Its priority should be greater than EMFReadOnlyHandler, FSReadOnlyHandler and
+ * Its priority should be greater than EMFReadOnlyHandler, FSReadOnlyHandler and ...
+ *
+ * This handler is discretion-based.
*
* @author Camille Letavernier
*
@@ -45,28 +53,26 @@ public class SashModelReadOnlyHandler extends AbstractReadOnlyHandler { /**
* {@inheritDoc}
*/
- public Optional<Boolean> anyReadOnly(URI[] uris) {
- if(modelSet == null) {
+ public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
+ if((modelSet == null) || !axes.contains(ReadOnlyAxis.DISCRETION)) {
return Optional.absent();
}
+ // Only answer false if all of the resources in question are ones that we know must be allowed to be written
+ int knownWritableCount = 0;
for(URI uri : uris) {
- if(SashModel.SASH_MODEL_FILE_EXTENSION.equals(uri.fileExtension())) {
- return Optional.of(false);
- }
-
- if(DiModel.DI_FILE_EXTENSION.equals(uri.fileExtension())) {
- return Optional.of(false);
+ if(SashModel.SASH_MODEL_FILE_EXTENSION.equals(uri.fileExtension()) || DiModel.DI_FILE_EXTENSION.equals(uri.fileExtension())) {
+ knownWritableCount++;
}
}
- return Optional.absent();
+ return (knownWritableCount == uris.length) ? Optional.of(false) : Optional.<Boolean> absent();
}
/**
* {@inheritDoc}
*/
- public Optional<Boolean> makeWritable(URI[] uris) {
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
return Optional.absent(); //If the file is read-only, it can probably made writable by other read-only handlers (e.g. FSReadOnlyHandler).
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/handlers/EnableWriteCommandHandler.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/handlers/EnableWriteCommandHandler.java index 8d6dd98630c..8f736f64fa6 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/handlers/EnableWriteCommandHandler.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/handlers/EnableWriteCommandHandler.java @@ -9,6 +9,7 @@ * Contributors:
* Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
* Christian W. Damus (CEA) - bug 323802
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly.handlers;
@@ -27,6 +28,7 @@ import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.infra.emf.readonly.ReadOnlyManager;
import org.eclipse.papyrus.infra.emf.utils.BusinessModelResolver;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
@@ -53,8 +55,7 @@ public class EnableWriteCommandHandler extends AbstractHandler { associatedUris[i] = URI.createPlatformResourceURI(associatedFiles[i].getFullPath().toString(), true);
}
- ReadOnlyManager.getReadOnlyHandler(WorkspaceEditingDomainFactory.INSTANCE.getEditingDomain(rs))
- .makeWritable(associatedUris);
+ ReadOnlyManager.getReadOnlyHandler(WorkspaceEditingDomainFactory.INSTANCE.getEditingDomain(rs)).makeWritable(ReadOnlyAxis.anyAxis(), associatedUris);
}
}
return null;
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFHelper.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFHelper.java index 3abfeb91979..e522cff9c02 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFHelper.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFHelper.java @@ -11,6 +11,7 @@ * Christian W. Damus (CEA) - filter out EObjects that are Resources (CDO)
* Christian W. Damus (CEA) - Support read-only state at object level (CDO)
* Christian W. Damus (CEA) - bug 323802
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.utils;
@@ -49,6 +50,7 @@ import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.facet.custom.ui.CustomizedContentProviderUtils;
import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler;
import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers;
import org.eclipse.papyrus.infra.emf.Activator;
@@ -431,33 +433,66 @@ public class EMFHelper { }
/**
- * Tests if an EObject is read only
+ * Tests if an EObject is read only on any {@linkplain ReadOnlyAxis axis}.
* Delegates to the EObject's editing domain if it can be found
*
* @param eObject
* @return
- * True if the EObject is read only
+ * True if the EObject is read only on any axis
+ * @see #isReadOnly(Set, EObject, EditingDomain)
*/
public static boolean isReadOnly(final EObject eObject) {
+ return isReadOnly(ReadOnlyAxis.anyAxis(), eObject);
+ }
+
+ /**
+ * Tests if an EObject is read only on any of the specified {@code axes}.
+ * Delegates to the EObject's editing domain if it can be found
+ *
+ * @param axes
+ * a set if orthogonal axes of read-only-ness to consider. May be empty, but that would not be especially useful
+ * @param eObject
+ * @return
+ * True if the EObject is read only on any of the given {@code axes}
+ */
+ public static boolean isReadOnly(Set<ReadOnlyAxis> axes, final EObject eObject) {
EditingDomain domain = resolveEditingDomain(eObject);
- return isReadOnly(eObject, domain);
+ return isReadOnly(axes, eObject, domain);
}
/**
- * Tests if an EObject is read only
+ * Tests if an EObject is read only on any {@linkplain ReadOnlyAxis axis}.
* Delegates to the given editing domain if it isn't null
*
* @param eObject
+ * @param domain
+ * @return
+ * True if the EObject is read only on any axis
+ */
+ public static boolean isReadOnly(final EObject eObject, final EditingDomain domain) {
+ return isReadOnly(ReadOnlyAxis.anyAxis(), eObject, domain);
+ }
+
+ /**
+ * Tests if an EObject is read only on any of the specified {@code axes}.
+ * Delegates to the given editing domain if it isn't null
+ *
+ * @param axes
+ * a set if orthogonal axes of read-only-ness to consider. May be empty, but that would not be especially useful
+ * @param eObject
*
* @param domain
* @return
* True if the EObject is read only
*/
- public static boolean isReadOnly(final EObject eObject, final EditingDomain domain) {
+ public static boolean isReadOnly(Set<ReadOnlyAxis> axes, final EObject eObject, final EditingDomain domain) {
if(domain != null) {
Object handler = PlatformHelper.getAdapter(domain, IReadOnlyHandler.class);
- if(handler instanceof IReadOnlyHandler) {
- return ((IReadOnlyHandler)handler).isReadOnly(eObject).get();
+ if(handler instanceof IReadOnlyHandler2) {
+ return ((IReadOnlyHandler2)handler).isReadOnly(axes, eObject).get();
+ }else if(handler instanceof IReadOnlyHandler) {
+ // these handlers only deal with permission-based read-only-ness
+ return axes.contains(ReadOnlyAxis.PERMISSION) && ((IReadOnlyHandler)handler).isReadOnly(eObject).get();
}
if(eObject.eResource() != null) {
@@ -468,23 +503,41 @@ public class EMFHelper { }
/**
- * Tests if the Resource is read only
+ * Tests if the Resource is read only on any {@linkplain ReadOnlyAxis axis}.
* Delegates to the given editing domain if it isn't null
*
* @param resource
* @param domain
* @return
- * True if the Resource is read only
+ * True if the Resource is read only on any axis
*/
public static boolean isReadOnly(final Resource resource, final EditingDomain domain) {
+ return isReadOnly(ReadOnlyAxis.anyAxis(), resource, domain);
+ }
+
+ /**
+ * Tests if the Resource is read only on any of the given {@code axes}.
+ * Delegates to the given editing domain if it isn't null
+ *
+ * @param axes
+ * a set if orthogonal axes of read-only-ness to consider. May be empty, but that would not be especially useful
+ * @param resource
+ * @param domain
+ * @return
+ * True if the Resource is read only on any of the given {@code axes}
+ */
+ public static boolean isReadOnly(Set<ReadOnlyAxis> axes, final Resource resource, final EditingDomain domain) {
if(resource == null) {
return false;
}
if(domain != null && resource.getURI() != null) {
Object handler = PlatformHelper.getAdapter(domain, IReadOnlyHandler.class);
- if(handler instanceof IReadOnlyHandler) {
- return ((IReadOnlyHandler)handler).anyReadOnly(new URI[]{ resource.getURI() }).get();
+ if(handler instanceof IReadOnlyHandler2) {
+ return ((IReadOnlyHandler2)handler).anyReadOnly(axes, new URI[]{ resource.getURI() }).get();
+ } else if(handler instanceof IReadOnlyHandler) {
+ // these handlers only deal with permission-based read-only-ness
+ return axes.contains(ReadOnlyAxis.PERMISSION) && ((IReadOnlyHandler)handler).anyReadOnly(new URI[]{ resource.getURI() }).get();
}
return domain.isReadOnly(resource);
}
@@ -514,10 +567,27 @@ public class EMFHelper { * whether the {@code eObject} could be made writable
*/
public static boolean canMakeWritable(final EObject eObject, final EditingDomain domain) {
+ return canMakeWritable(ReadOnlyAxis.anyAxis(), eObject, domain);
+ }
+
+ /**
+ * Tests if an object that is read only could possibly be made writable according to any of
+ * the specified {@code axes} of read-only-ness.
+ *
+ * @param axes
+ * a set if orthogonal axes of read-only-ness to consider. May be empty, but that would not be especially useful
+ * @param eObject
+ * an object that is assumed to be read-only
+ * @param domain
+ * the editing domain context of the {@link eObject}
+ * @return
+ * whether the {@code eObject} could be made writable
+ */
+ public static boolean canMakeWritable(Set<ReadOnlyAxis> axes, final EObject eObject, final EditingDomain domain) {
if(domain != null) {
Object handler = PlatformHelper.getAdapter(domain, IReadOnlyHandler.class);
if(handler instanceof IReadOnlyHandler2) {
- return ((IReadOnlyHandler2)handler).canMakeWritable(eObject).or(false);
+ return ((IReadOnlyHandler2)handler).canMakeWritable(axes, eObject).or(false);
}
}
return false;
@@ -535,10 +605,27 @@ public class EMFHelper { * whether the {@code resource} could be made writable
*/
public static boolean canMakeWritable(final Resource resource, final EditingDomain domain) {
+ return canMakeWritable(ReadOnlyAxis.anyAxis(), resource, domain);
+ }
+
+ /**
+ * Tests if a resource that is read only could possibly be made writable according to any of
+ * the specified {@code axes} of read-only-ness.
+ *
+ * @param axes
+ * a set if orthogonal axes of read-only-ness to consider. May be empty, but that would not be especially useful
+ * @param resource
+ * a resource that is assumed to be read-only
+ * @param domain
+ * the editing domain context of the {@link resource}
+ * @return
+ * whether the {@code resource} could be made writable
+ */
+ public static boolean canMakeWritable(Set<ReadOnlyAxis> axes, final Resource resource, final EditingDomain domain) {
if(domain != null) {
Object handler = PlatformHelper.getAdapter(domain, IReadOnlyHandler.class);
if(handler instanceof IReadOnlyHandler2) {
- return ((IReadOnlyHandler2)handler).canMakeWritable(new URI[] { resource.getURI() }).or(false);
+ return ((IReadOnlyHandler2)handler).canMakeWritable(axes, new URI[] { resource.getURI() }).or(false);
}
}
return false;
diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common/src/org/eclipse/papyrus/uml/diagram/common/handlers/DeleteFromModelCommandHandler.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common/src/org/eclipse/papyrus/uml/diagram/common/handlers/DeleteFromModelCommandHandler.java index 5fe91cae260..8c4aac11912 100644 --- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common/src/org/eclipse/papyrus/uml/diagram/common/handlers/DeleteFromModelCommandHandler.java +++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common/src/org/eclipse/papyrus/uml/diagram/common/handlers/DeleteFromModelCommandHandler.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2010 CEA LIST. + * Copyright (c) 2010, 2014 CEA LIST and others. * * * All rights reserved. This program and the accompanying materials @@ -9,6 +9,7 @@ * * Contributors: * Yann Tanguy (CEA LIST) yann.tanguy@cea.fr - Initial API and implementation + * Christian W. Damus (CEA) - bug 429826 * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.common.handlers; @@ -37,7 +38,8 @@ import org.eclipse.gmf.runtime.notation.View; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialogWithToggle; import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler; +import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2; +import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis; import org.eclipse.papyrus.infra.emf.readonly.ReadOnlyManager; import org.eclipse.papyrus.infra.emf.utils.EMFHelper; import org.eclipse.papyrus.infra.gmfdiag.common.helper.NotationHelper; @@ -94,7 +96,7 @@ public class DeleteFromModelCommandHandler extends GraphicalCommandHandler imple @Override protected boolean computeEnabled() { TransactionalEditingDomain editingDomain = getEditingDomain(); - IReadOnlyHandler readOnly = ReadOnlyManager.getReadOnlyHandler(editingDomain); + IReadOnlyHandler2 readOnly = ReadOnlyManager.getReadOnlyHandler(editingDomain); for(IGraphicalEditPart editPart : getSelectedElements()) { EObject semantic = EMFHelper.getEObject(editPart); @@ -117,7 +119,7 @@ public class DeleteFromModelCommandHandler extends GraphicalCommandHandler imple uris.add(EcoreUtil.getURI(graphical)); } - Optional<Boolean> result = readOnly.anyReadOnly(uris.toArray(new URI[uris.size()])); + Optional<Boolean> result = readOnly.anyReadOnly(ReadOnlyAxis.anyAxis(), uris.toArray(new URI[uris.size()])); if(result.isPresent() && result.get()) { return false; } diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/plugin.xml b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/plugin.xml index 69fb1520f38..29bd6891f6f 100644 --- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/plugin.xml +++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/plugin.xml @@ -48,6 +48,9 @@ class="org.eclipse.papyrus.uml.controlmode.profile.ControlledElementReadOnlyHandler"
id="org.eclipse.papyrus.uml.controlmode.profile.ControlledElementReadOnlyHandler"
priority="50">
+ <affinity
+ axis="discretion">
+ </affinity>
</readOnlyHandler>
</extension>
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/ControlledElementReadOnlyHandler.java b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/ControlledElementReadOnlyHandler.java index 78020d006ce..cbd577fa771 100644 --- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/ControlledElementReadOnlyHandler.java +++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/ControlledElementReadOnlyHandler.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2013 Atos.
+ * Copyright (c) 2013, 2014 Atos, CEA, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,16 +9,20 @@ *
* Contributors:
* Arthur Daussy (Atos) arthur.daussy@atos.net - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.uml.controlmode.profile;
+import java.util.Set;
+
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.edit.domain.EditingDomain;
-import org.eclipse.papyrus.infra.emf.readonly.AbstractReadOnlyHandler;
+import org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.infra.widgets.toolbox.notification.builders.NotificationBuilder;
import org.eclipse.papyrus.uml.tools.model.UmlModel;
import org.eclipse.uml2.uml.Element;
@@ -30,7 +34,7 @@ import com.google.common.base.Optional; /**
* Read only handler that will prevent model fragment to be modified it the root element is not a package
* This restriction is because of the UML2 implementation which delete stereotype applications if the current model can not find the corresponding profile
- * application
+ * application. This handler is discretion-based.
*
* @author adaussy
*
@@ -41,8 +45,8 @@ public class ControlledElementReadOnlyHandler extends AbstractReadOnlyHandler { super(editingDomain);
}
- public Optional<Boolean> anyReadOnly(URI[] uris) {
- if(getEditingDomain() == null) {
+ public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
+ if((getEditingDomain() == null) || !axes.contains(ReadOnlyAxis.DISCRETION)) {
return Optional.absent();
}
ResourceSet resourceSet = getEditingDomain().getResourceSet();
@@ -65,7 +69,7 @@ public class ControlledElementReadOnlyHandler extends AbstractReadOnlyHandler { return Optional.absent();
}
- public Optional<Boolean> makeWritable(URI[] uris) {
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
//Never authorize write
NotificationBuilder.createErrorPopup("This model fragment can not be modified independently from the rest of the model").run();
return Optional.absent();
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/SwitchProfileDialog.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/SwitchProfileDialog.java index a172fb66fa7..b19b4395a4c 100644 --- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/SwitchProfileDialog.java +++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/SwitchProfileDialog.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 429826
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.modelrepair.ui;
@@ -47,8 +49,9 @@ import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.window.Window;
-import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.emf.readonly.ReadOnlyManager;
import org.eclipse.papyrus.infra.emf.resource.DependencyManagementHelper;
@@ -306,9 +309,9 @@ public class SwitchProfileDialog extends SelectionDialog { }
});
- IReadOnlyHandler handler = ReadOnlyManager.getReadOnlyHandler(editingDomain);
+ IReadOnlyHandler2 handler = ReadOnlyManager.getReadOnlyHandler(editingDomain);
for(Resource resource : modelSet.getResources()) {
- if(handler.anyReadOnly(new URI[]{ resource.getURI() }).get()) {
+ if(handler.anyReadOnly(ReadOnlyAxis.anyAxis(), new URI[]{ resource.getURI() }).get()) {
continue;
}
try {
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/providers/ResourceLabelProvider.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/providers/ResourceLabelProvider.java index 8d507133d95..45c7f978125 100644 --- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/providers/ResourceLabelProvider.java +++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/providers/ResourceLabelProvider.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 429826
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.modelrepair.ui.providers;
@@ -18,6 +20,7 @@ import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.infra.emf.readonly.ReadOnlyManager;
import org.eclipse.swt.graphics.Image;
@@ -75,13 +78,8 @@ public class ResourceLabelProvider extends ColumnLabelProvider { }
EditingDomain domain = TransactionalEditingDomain.Factory.INSTANCE.getEditingDomain(resourceSet);
- Optional<Boolean> readOnly = ReadOnlyManager.getReadOnlyHandler(domain).anyReadOnly(new URI[]{ uri });
- if(readOnly.isPresent()) {
- return readOnly.get() ? "true" : "false";
- } else {
- return "false";
- }
-
+ Optional<Boolean> readOnly = ReadOnlyManager.getReadOnlyHandler(domain).anyReadOnly(ReadOnlyAxis.anyAxis(), new URI[]{ uri });
+ return readOnly.or(false) ? "true" : "false";
}
public String getResourceText(Object element) {
diff --git a/plugins/uml/org.eclipse.papyrus.uml.profile/plugin.xml b/plugins/uml/org.eclipse.papyrus.uml.profile/plugin.xml index 38eaf4a5831..a9d6d447afd 100644 --- a/plugins/uml/org.eclipse.papyrus.uml.profile/plugin.xml +++ b/plugins/uml/org.eclipse.papyrus.uml.profile/plugin.xml @@ -115,6 +115,9 @@ class="org.eclipse.papyrus.uml.profile.readonly.AppliedProfileReadOnlyHandler"
id="org.eclipse.papyrus.uml.profile.readonly.AppliedProfileReadOnlyHandler"
priority="15">
+ <affinity
+ axis="discretion">
+ </affinity>
</readOnlyHandler>
</extension>
<extension
diff --git a/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/readonly/AppliedProfileReadOnlyHandler.java b/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/readonly/AppliedProfileReadOnlyHandler.java index 6c13310f271..1c7da5f5ca6 100644 --- a/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/readonly/AppliedProfileReadOnlyHandler.java +++ b/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/readonly/AppliedProfileReadOnlyHandler.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,28 +8,35 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 429826
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.profile.readonly;
+import java.util.Set;
+
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
-import org.eclipse.papyrus.infra.emf.readonly.AbstractReadOnlyHandler;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.uml.tools.model.UmlModel;
import org.eclipse.uml2.uml.Profile;
import com.google.common.base.Optional;
-
+/**
+ * Discretion-based read-only handler for applied profiles.
+ */
public class AppliedProfileReadOnlyHandler extends AbstractReadOnlyHandler {
public AppliedProfileReadOnlyHandler(EditingDomain editingDomain) {
super(editingDomain);
}
- public Optional<Boolean> anyReadOnly(URI[] uris) {
- if(getEditingDomain() != null) {
+ public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
+ if((getEditingDomain() != null) && axes.contains(ReadOnlyAxis.DISCRETION)) {
Resource mainUmlResource = null;
if(getEditingDomain().getResourceSet() instanceof ModelSet) {
UmlModel umlModel = (UmlModel)((ModelSet)getEditingDomain().getResourceSet()).getModel(UmlModel.MODEL_ID);
@@ -62,7 +69,7 @@ public class AppliedProfileReadOnlyHandler extends AbstractReadOnlyHandler { return false;
}
- public Optional<Boolean> makeWritable(URI[] uris) {
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
return Optional.absent(); //Applied profiles should remain read-only
}
diff --git a/plugins/views/modelexplorer/org.eclipse.papyrus.views.modelexplorer/src/org/eclipse/papyrus/views/modelexplorer/ModelExplorerView.java b/plugins/views/modelexplorer/org.eclipse.papyrus.views.modelexplorer/src/org/eclipse/papyrus/views/modelexplorer/ModelExplorerView.java index 99c1a9cfbb3..ba00ac932ac 100644 --- a/plugins/views/modelexplorer/org.eclipse.papyrus.views.modelexplorer/src/org/eclipse/papyrus/views/modelexplorer/ModelExplorerView.java +++ b/plugins/views/modelexplorer/org.eclipse.papyrus.views.modelexplorer/src/org/eclipse/papyrus/views/modelexplorer/ModelExplorerView.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010, 2013 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -10,6 +10,7 @@ * Contributors:
* Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
* Christian W. Damus (CEA) - post refreshes for transaction commit asynchronously (CDO)
+ * Christian W. Damus (CEA) - bug 429826
*
*****************************************************************************/
package org.eclipse.papyrus.views.modelexplorer;
@@ -54,7 +55,10 @@ import org.eclipse.jface.window.ToolTip; import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor;
import org.eclipse.papyrus.infra.core.lifecycleevents.IEditorInputChangedListener;
import org.eclipse.papyrus.infra.core.lifecycleevents.ISaveAndDirtyService;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyListener;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyEvent;
import org.eclipse.papyrus.infra.core.resource.additional.AdditionalResourcesModel;
import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageManager;
import org.eclipse.papyrus.infra.core.sasheditor.editor.IPage;
@@ -62,6 +66,7 @@ import org.eclipse.papyrus.infra.core.sasheditor.editor.IPageLifeCycleEventsList import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.utils.AdapterUtils;
import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
import org.eclipse.papyrus.infra.emf.providers.SemanticFromModelExplorer;
import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
@@ -726,6 +731,10 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti getCommonViewer().setInput(serviceRegistry);
}
editingDomain.addResourceSetListener(resourceSetListener);
+ IReadOnlyHandler2 readOnlyHandler = AdapterUtils.adapt(editingDomain, IReadOnlyHandler2.class, null);
+ if (readOnlyHandler != null) {
+ readOnlyHandler.addReadOnlyListener(createReadOnlyListener());
+ }
} catch (ServiceException e) {
// Can't get EditingDomain, skip
}
@@ -1068,4 +1077,30 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti //Nothing
}
+ private IReadOnlyListener createReadOnlyListener() {
+ return new IReadOnlyListener() {
+
+ public void readOnlyStateChanged(ReadOnlyEvent event) {
+ switch (event.getEventType()) {
+ case ReadOnlyEvent.RESOURCE_READ_ONLY_STATE_CHANGED:
+ if (!isRefreshing.get()) {
+ refresh();
+ }
+ break;
+ case ReadOnlyEvent.OBJECT_READ_ONLY_STATE_CHANGED:
+ CommonViewer viewer = getCommonViewer();
+ if ((viewer != null) && (viewer.getControl() != null) && !viewer.getControl().isDisposed()) {
+ viewer.refresh(event.getObject());
+ }
+ break;
+ default:
+ Activator.log.warn("Unsupported read-only event type: " + event.getEventType());
+ break;
+ }
+ if (!isRefreshing.get()) {
+ refresh();
+ }
+ }
+ };
+ }
}
diff --git a/tests/junit/extraplugins/cdo/org.eclipse.papyrus.cdo.core.tests/src/org/eclipse/papyrus/cdo/core/resource/tests/CDOAwareModelSetTest.java b/tests/junit/extraplugins/cdo/org.eclipse.papyrus.cdo.core.tests/src/org/eclipse/papyrus/cdo/core/resource/tests/CDOAwareModelSetTest.java index 5d69a8cb927..27a69ac726b 100644 --- a/tests/junit/extraplugins/cdo/org.eclipse.papyrus.cdo.core.tests/src/org/eclipse/papyrus/cdo/core/resource/tests/CDOAwareModelSetTest.java +++ b/tests/junit/extraplugins/cdo/org.eclipse.papyrus.cdo.core.tests/src/org/eclipse/papyrus/cdo/core/resource/tests/CDOAwareModelSetTest.java @@ -9,6 +9,7 @@ * Contributors: * CEA LIST - Initial API and implementation * Christian W. Damus (CEA) - bug 429242 + * Christian W. Damus (CEA) - bug 429826 * *****************************************************************************/ package org.eclipse.papyrus.cdo.core.resource.tests; @@ -38,6 +39,7 @@ import org.eclipse.papyrus.cdo.core.resource.PapyrusCDOResourceFactory; import org.eclipse.papyrus.cdo.core.tests.AbstractPapyrusCDOTest; import org.eclipse.papyrus.infra.core.Activator; import org.eclipse.papyrus.infra.core.resource.ModelSet; +import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis; import org.eclipse.papyrus.infra.core.services.ExtensionServicesRegistry; import org.eclipse.papyrus.infra.core.services.ServiceMultiException; import org.eclipse.papyrus.infra.core.services.ServiceNotFoundException; @@ -107,7 +109,7 @@ public class CDOAwareModelSetTest extends AbstractPapyrusCDOTest { CDOTransaction transaction = getTransaction(fixture); Resource resource = transaction.getOrCreateResource(getResourcePath(MODEL_FILENAME)); - assertThat(fixture.getReadOnlyHandler().anyReadOnly(new URI[]{ resource.getURI() }), is(Optional.of(false))); + assertThat(fixture.getReadOnlyHandler().anyReadOnly(ReadOnlyAxis.anyAxis(), new URI[]{ resource.getURI() }), is(Optional.of(false))); } @Test diff --git a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/Bug323802.uml b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/Bug323802.uml index cccdefe7e34..6c61fbbcb57 100644 --- a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/Bug323802.uml +++ b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/Bug323802.uml @@ -1,5 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <uml:Model xmi:version="20110701" xmlns:xmi="http://www.omg.org/spec/XMI/20110701" xmlns:uml="http://www.eclipse.org/uml2/4.0.0/UML" xmi:id="_-3u4cJW3EeOfoK3RwHm3pQ" name="bug323802"> + <packageImport xmi:id="_ycYPAKkTEeOizeYRjNFxJg"> + <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/> + </packageImport> <packagedElement xmi:type="uml:Class" xmi:id="_C3c2UJW4EeOfoK3RwHm3pQ" name="A" useCase="_0S-V8KYuEeO-ZNuEJamMWA"/> <packagedElement xmi:type="uml:UseCase" xmi:id="_0S-V8KYuEeO-ZNuEJamMWA" name="DoIt" subject="_C3c2UJW4EeOfoK3RwHm3pQ"/> </uml:Model> diff --git a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainTest.java b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainTest.java index 8cd46a7768c..808347fffcb 100644 --- a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainTest.java +++ b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainTest.java @@ -15,6 +15,7 @@ package org.eclipse.papyrus.infra.emf.readonly; import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; @@ -34,11 +35,17 @@ import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.RollbackException; +import org.eclipse.emf.transaction.TransactionalCommandStack; import org.eclipse.emf.workspace.AbstractEMFOperation; import org.eclipse.emf.workspace.IWorkspaceCommandStack; import org.eclipse.papyrus.infra.core.resource.IRollbackStatus; +import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis; import org.eclipse.papyrus.infra.core.resource.RollbackStatus; +import org.eclipse.papyrus.infra.core.utils.TransactionHelper; +import org.eclipse.papyrus.junit.utils.rules.ProjectFixture; import org.eclipse.uml2.common.util.UML2Util; import org.eclipse.uml2.uml.Classifier; import org.eclipse.uml2.uml.Model; @@ -48,6 +55,7 @@ import org.eclipse.uml2.uml.UseCase; import org.eclipse.uml2.uml.resource.UMLResource; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import com.google.common.collect.Iterables; @@ -58,6 +66,9 @@ import com.google.common.collect.Iterables; */ public class PapyrusROTransactionalEditingDomainTest { + @Rule + public final ProjectFixture project = new ProjectFixture(); + private PapyrusROTransactionalEditingDomain fixture; private Model model; @@ -161,6 +172,56 @@ public class PapyrusROTransactionalEditingDomainTest { assertThat(Iterables.filter(status[0].getCausalObjects(), Type.class), hasItem(string[0])); } + /** + * Test that transaction options can be used to influence the domain's read-only check. + */ + @Test + public void testReadOnlyAxisTransactionOption() throws Exception { + // Make our model read-only on the filesystem + project.setReadOnly(model.eResource()); + TransactionalCommandStack stack = (TransactionalCommandStack)fixture.getCommandStack(); + + RecordingCommand cmd = new RecordingCommand(fixture) { + + @Override + protected void doExecute() { + UseCase doIt = (UseCase)model.getOwnedType("DoIt"); + assertThat(doIt, notNullValue()); + + // try to delete from the read-only model + EcoreUtil.remove(doIt); + } + }; + + try { + stack.execute(cmd, TransactionHelper.interactiveOption(false)); + fail("Should have thrown RollbackException."); + } catch (RollbackException e) { + // Success + } + + // The command was rolled back, so it wasn't stacked + assertThat(fixture.getCommandStack().canUndo(), is(false)); + + // The change was rolled back + UseCase doIt = (UseCase)model.getOwnedType("DoIt"); + assertThat(doIt, notNullValue()); + assertThat(doIt.getSubjects().size(), is(1)); + assertThat(doIt.getSubjects().get(0).getName(), is("A")); + + // Now, try again with only the discretionary read-only-ness enforced + stack.execute(cmd, TransactionHelper.readOnlyAxisOption(ReadOnlyAxis.DISCRETION)); + + // The command was *not* rolled back, so it *was* stacked + assertThat(fixture.getCommandStack().canUndo(), is(true)); + + // The change was *not* rolled back + assertThat(doIt.eResource(), nullValue()); + assertThat(doIt.eContainer(), nullValue()); + doIt = (UseCase)model.getOwnedType("DoIt"); + assertThat(doIt, nullValue()); + } + // // Test framework // @@ -169,13 +230,14 @@ public class PapyrusROTransactionalEditingDomainTest { public void createFixture() throws Exception { fixture = (PapyrusROTransactionalEditingDomain)new PapyrusROTransactionalEditingDomainProvider().createTransactionalEditingDomain(new ResourceSetImpl()); - Resource res = fixture.getResourceSet().createResource(URI.createURI("platform:/resource/bogus/model.uml")); + Resource res = fixture.getResourceSet().createResource(project.getURI("model.uml")); InputStream input = PapyrusROTransactionalEditingDomainTest.class.getResourceAsStream("Bug323802.uml"); try { res.load(input, null); } finally { input.close(); } + res.save(null); model = (Model)res.getContents().get(0); } diff --git a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManagerTest.java b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManagerTest.java index 585d7e5309f..584282cb6a8 100644 --- a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManagerTest.java +++ b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManagerTest.java @@ -14,20 +14,12 @@ package org.eclipse.papyrus.infra.emf.readonly; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.fail; -import java.io.InputStream; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.ResourceAttributes; -import org.eclipse.core.runtime.CoreException; import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis; +import org.eclipse.papyrus.infra.emf.readonly.tests.PapyrusModelSetFixture; +import org.eclipse.papyrus.junit.utils.rules.JavaResource; import org.eclipse.papyrus.junit.utils.rules.ProjectFixture; -import org.eclipse.uml2.uml.Model; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -37,16 +29,15 @@ import org.junit.Test; /** * Test suite for the {@link ReadOnlyManager} class. */ +@JavaResource("Bug323802.uml") public class ReadOnlyManagerTest { @Rule - public final ProjectFixture project = new ProjectFixture(); - - private ReadOnlyManager fixture; + public final PapyrusModelSetFixture domain = new PapyrusModelSetFixture(); - private TransactionalEditingDomain domain; + private final ProjectFixture project = domain.getProject(); - private Model model; + private ReadOnlyManager fixture; public ReadOnlyManagerTest() { super(); @@ -54,78 +45,47 @@ public class ReadOnlyManagerTest { @Test public void testIsReadOnlyEObject() { - setReadOnly(project.getFile(model.eResource().getURI())); - assertThat(fixture.isReadOnly(model).or(false), is(true)); + project.setReadOnly(domain.getModelResource()); + assertThat(fixture.isReadOnly(ReadOnlyAxis.anyAxis(), domain.getModel()).or(false), is(true)); } @Test public void testCanMakeWritableEObject() { - setReadOnly(project.getFile(model.eResource().getURI())); - assertThat(fixture.canMakeWritable(model).or(false), is(true)); + project.setReadOnly(domain.getModelResource()); + assertThat(fixture.canMakeWritable(ReadOnlyAxis.anyAxis(), domain.getModel()).or(false), is(true)); } @Test public void testAnyReadOnlyURIs() { - URI uri = model.eResource().getURI(); - setReadOnly(project.getFile(uri)); - assertThat(fixture.anyReadOnly(new URI[]{ uri }).or(false), is(true)); + URI uri = domain.getModelResourceURI(); + project.setReadOnly(domain.getModelResource()); + assertThat(fixture.anyReadOnly(ReadOnlyAxis.anyAxis(), new URI[]{ uri }).or(false), is(true)); } @Test public void testCanMakeWritableURIs() { - URI uri = model.eResource().getURI(); - setReadOnly(project.getFile(uri)); - assertThat(fixture.canMakeWritable(new URI[]{ uri }).or(false), is(true)); + URI uri = domain.getModelResourceURI(); + project.setReadOnly(domain.getModelResource()); + assertThat(fixture.canMakeWritable(ReadOnlyAxis.anyAxis(), new URI[]{ uri }).or(false), is(true)); } + @Test + public void testSashModelReadOnlyIfPermissionReadOnly() { + URI sashModelURI = URI.createPlatformPluginURI("org.eclipse.papyrus.foo/models/bogus.di", true); + assertThat(fixture.anyReadOnly(ReadOnlyAxis.anyAxis(), new URI[]{ sashModelURI }).or(false), is(true)); + } + // // Test framework // @Before public void createFixture() throws Exception { - domain = (PapyrusROTransactionalEditingDomain)new PapyrusROTransactionalEditingDomainProvider().createTransactionalEditingDomain(new ResourceSetImpl()); - fixture = new ReadOnlyManager(domain); - - Resource res = domain.getResourceSet().createResource(project.getURI("model.uml")); - InputStream input = ReadOnlyManagerTest.class.getResourceAsStream("Bug323802.uml"); - try { - res.load(input, null); - } finally { - input.close(); - } - res.save(null); // Make sure it exists - model = (Model)res.getContents().get(0); + fixture = new ReadOnlyManager(domain.getEditingDomain()); } @After public void destroyFixture() { - ResourceSet rset = domain.getResourceSet(); - - model = null; - - domain.dispose(); - domain = null; fixture = null; - - for(Resource next : rset.getResources()) { - next.unload(); - next.eAdapters().clear(); - } - - rset.getResources().clear(); - rset.eAdapters().clear(); - } - - void setReadOnly(IFile file) { - ResourceAttributes attr = file.getResourceAttributes(); - attr.setReadOnly(true); - - try { - file.setResourceAttributes(attr); - } catch (CoreException e) { - e.getLocalizedMessage(); - fail("Failed to make workspace file read-only: " + e.getLocalizedMessage()); - } } } diff --git a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyTesterTest.java b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyTesterTest.java new file mode 100644 index 00000000000..7b1951eea28 --- /dev/null +++ b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyTesterTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2014 CEA 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: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.emf.readonly; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import org.eclipse.papyrus.infra.emf.readonly.tests.PapyrusROEditingDomainFixture; +import org.eclipse.papyrus.junit.utils.rules.JavaResource; +import org.eclipse.papyrus.junit.utils.rules.ProjectFixture; +import org.eclipse.uml2.uml.Type; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import com.google.common.collect.Iterators; + + +/** + * This is the ReadOnlyTesterTest type. Enjoy. + */ +@JavaResource("Bug323802.uml") +public class ReadOnlyTesterTest { + + @Rule + public final PapyrusROEditingDomainFixture domain = new PapyrusROEditingDomainFixture(); + + private final ProjectFixture project = domain.getProject(); + + private ReadOnlyTester fixture; + + @Test + public void testAsBoolean() { + assertThat(fixture.asBoolean(true), is(true)); + assertThat(fixture.asBoolean(false), is(false)); + assertThat(fixture.asBoolean("hello"), is(true)); + assertThat(fixture.asBoolean(null), is(true)); + } + + @Test + public void testIsReadOnly() { + assertThat(fixture.testIsReadOnly(Iterators.singletonIterator(domain.getModel()), false), is(true)); + + Type string = domain.getModel().getImportedPackages().get(0).getOwnedType("String"); + assertThat(fixture.testIsReadOnly(Iterators.singletonIterator(string), true), is(true)); + + project.setReadOnly(domain.getModelResource()); + assertThat(fixture.testIsReadOnly(Iterators.singletonIterator(domain.getModel()), true), is(true)); + } + + @Test + public void testCanMakeWritable() { + // If it's already writable, well, then it's trivially easy to make it writable + assertThat(fixture.canMakeWritable(Iterators.singletonIterator(domain.getModel()), true), is(true)); + + Type string = domain.getModel().getImportedPackages().get(0).getOwnedType("String"); + assertThat(fixture.canMakeWritable(Iterators.singletonIterator(string), true), is(false)); + + project.setReadOnly(domain.getModelResource()); + assertThat(fixture.canMakeWritable(Iterators.singletonIterator(domain.getModel()), true), is(true)); + } + + // + // Test framework + // + + @Before + public void createFixture() throws Exception { + fixture = new ReadOnlyTester(); + } + + @After + public void destroyFixture() { + fixture = null; + } + +} diff --git a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/ReferencedModelReadOnlyHandlerTest.java b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/ReferencedModelReadOnlyHandlerTest.java index 6f638990388..b8bd67a125b 100644 --- a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/ReferencedModelReadOnlyHandlerTest.java +++ b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/ReferencedModelReadOnlyHandlerTest.java @@ -12,6 +12,7 @@ */ package org.eclipse.papyrus.infra.emf.readonly; +import static org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis.discretionAxes; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; @@ -124,8 +125,8 @@ public class ReferencedModelReadOnlyHandlerTest { public void testCrossReferencedWorkspaceModelElementsMadeWritable() { Property ssn = person.getAttribute("ssn", null); assumeReadOnly(ssn.getType()); - assertThat(fixture.canMakeWritable(ssn.getType()).or(false), is(true)); - assertThat(fixture.makeWritable(ssn.getType()).or(false), is(true)); + assertThat(fixture.canMakeWritable(discretionAxes(), ssn.getType()).or(false), is(true)); + assertThat(fixture.makeWritable(discretionAxes(), ssn.getType()).or(false), is(true)); assertNotReadOnly(ssn.getType()); assertNotReadOnly(person.getAttribute("registered", null).getType()); } @@ -174,8 +175,8 @@ public class ReferencedModelReadOnlyHandlerTest { public void testObjectURIsWithFragment() { Property ssn = person.getAttribute("ssn", null); URI uri = EcoreUtil.getURI(ssn); - assertThat(fixture.anyReadOnly(new URI[]{ uri }).or(false), is(false)); - assertThat(fixture.canMakeWritable(new URI[]{ uri }).or(true), is(false)); + assertThat(fixture.anyReadOnly(discretionAxes(), new URI[]{ uri }).or(false), is(false)); + assertThat(fixture.canMakeWritable(discretionAxes(), new URI[]{ uri }).or(true), is(false)); } // @@ -310,17 +311,17 @@ public class ReferencedModelReadOnlyHandlerTest { } void assertReadOnly(EObject object) { - Optional<Boolean> status = fixture.isReadOnly(object); + Optional<Boolean> status = fixture.isReadOnly(discretionAxes(), object); assertThat("Not read-only", status.or(false), is(true)); } void assertNotReadOnly(EObject object) { - Optional<Boolean> status = fixture.isReadOnly(object); + Optional<Boolean> status = fixture.isReadOnly(discretionAxes(), object); assertThat("Should not be either read-only or definitely writable", status.isPresent(), is(false)); } void assumeReadOnly(EObject object) { - Optional<Boolean> status = fixture.isReadOnly(object); + Optional<Boolean> status = fixture.isReadOnly(discretionAxes(), object); assumeThat("Not read-only", status.or(false), is(true)); } diff --git a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/tests/AllTests.java b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/tests/AllTests.java index b7d564ad280..12d2f83dd10 100644 --- a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/tests/AllTests.java +++ b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/tests/AllTests.java @@ -14,6 +14,7 @@ package org.eclipse.papyrus.infra.emf.readonly.tests; import org.eclipse.papyrus.infra.emf.readonly.PapyrusROTransactionalEditingDomainTest; import org.eclipse.papyrus.infra.emf.readonly.ReadOnlyManagerTest; +import org.eclipse.papyrus.infra.emf.readonly.ReadOnlyTesterTest; import org.eclipse.papyrus.infra.emf.readonly.ReferencedModelReadOnlyHandlerTest; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -25,7 +26,7 @@ import org.junit.runners.Suite.SuiteClasses; */ @RunWith(Suite.class) @SuiteClasses({ -PapyrusROTransactionalEditingDomainTest.class, ReferencedModelReadOnlyHandlerTest.class, ReadOnlyManagerTest.class +PapyrusROTransactionalEditingDomainTest.class, ReferencedModelReadOnlyHandlerTest.class, ReadOnlyManagerTest.class, ReadOnlyTesterTest.class }) public class AllTests { diff --git a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/tests/PapyrusModelSetFixture.java b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/tests/PapyrusModelSetFixture.java new file mode 100644 index 00000000000..6f96df8d47e --- /dev/null +++ b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/tests/PapyrusModelSetFixture.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2014 CEA 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: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.emf.readonly.tests; + +import static org.junit.Assert.fail; + +import java.util.Collections; + +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.papyrus.infra.core.resource.EditingDomainServiceFactory; +import org.eclipse.papyrus.infra.core.resource.ModelSet; +import org.eclipse.papyrus.infra.core.services.ServiceDescriptor; +import org.eclipse.papyrus.infra.core.services.ServiceDescriptor.ServiceTypeKind; +import org.eclipse.papyrus.infra.core.services.ServiceStartKind; +import org.eclipse.papyrus.infra.core.services.ServicesRegistry; +import org.eclipse.papyrus.infra.emf.readonly.PapyrusROTransactionalEditingDomain; +import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceInitializerService; +import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceSet; +import org.eclipse.papyrus.junit.utils.rules.AbstractModelFixture; +import org.junit.runner.Description; + + +/** + * This is the PapyrusModelSetFixture type. Enjoy. + */ +public class PapyrusModelSetFixture extends AbstractModelFixture<PapyrusROTransactionalEditingDomain> { + + public PapyrusModelSetFixture() { + super(); + } + + protected PapyrusROTransactionalEditingDomain createEditingDomain() { + try { + ServicesRegistry services = createServiceRegistry(); + return (PapyrusROTransactionalEditingDomain)services.getService(ModelSet.class).getTransactionalEditingDomain(); + } catch (Exception e) { + e.printStackTrace(); + fail("Failed to initialize service registry and/or editing domain: " + e.getLocalizedMessage()); + return null; // unreachable + } + } + + @Override + protected void finished(Description description) { + ResourceSet rset = getEditingDomain().getResourceSet(); + + try { + ServicesRegistry services = ServiceUtilsForResourceSet.getInstance().getServiceRegistry(rset); + services.disposeRegistry(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + super.finished(description); + } + } + + protected ServicesRegistry createServiceRegistry() throws Exception { + ServicesRegistry result = new ServicesRegistry(); + result.add(ModelSet.class, 10, new ModelSet()); + result.add(ServiceUtilsForResourceInitializerService.class, 10, new ServiceUtilsForResourceInitializerService()); + + ServiceDescriptor desc = new ServiceDescriptor(TransactionalEditingDomain.class, EditingDomainServiceFactory.class.getName(), ServiceStartKind.STARTUP, 10, Collections.singletonList(ModelSet.class.getName())); + desc.setServiceTypeKind(ServiceTypeKind.serviceFactory); + desc.setClassBundleID(org.eclipse.papyrus.infra.core.Activator.PLUGIN_ID); + result.add(desc); + + result.startRegistry(); + + return result; + } +} diff --git a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/tests/PapyrusROEditingDomainFixture.java b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/tests/PapyrusROEditingDomainFixture.java new file mode 100644 index 00000000000..3f1db0e0338 --- /dev/null +++ b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly.tests/src/org/eclipse/papyrus/infra/emf/readonly/tests/PapyrusROEditingDomainFixture.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014 CEA 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: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.emf.readonly.tests; + +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.papyrus.infra.emf.readonly.PapyrusROTransactionalEditingDomain; +import org.eclipse.papyrus.infra.emf.readonly.PapyrusROTransactionalEditingDomainProvider; +import org.eclipse.papyrus.junit.utils.rules.AbstractModelFixture; + + +/** + * This is the PapyrusROEditingDomainFixture type. Enjoy. + */ +public class PapyrusROEditingDomainFixture extends AbstractModelFixture<PapyrusROTransactionalEditingDomain> { + + public PapyrusROEditingDomainFixture() { + super(); + } + + protected PapyrusROTransactionalEditingDomain createEditingDomain() { + return (PapyrusROTransactionalEditingDomain)new PapyrusROTransactionalEditingDomainProvider().createTransactionalEditingDomain(new ResourceSetImpl()); + } +} diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractModelFixture.java b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractModelFixture.java new file mode 100644 index 00000000000..25829351a1f --- /dev/null +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractModelFixture.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2014 CEA 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: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.junit.utils.rules; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; + +import java.io.InputStream; +import java.lang.reflect.Method; +import java.net.URL; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.edit.domain.EditingDomain; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.papyrus.junit.utils.rules.ProjectFixture; +import org.eclipse.uml2.uml.Model; +import org.junit.Rule; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + + +/** + * Abstract superclass for JUnit test fixture rules that provide: + * <ul> + * <li>an editing domain of some kind (subclasses must create it)</li> + * <li>a test project in the workspace, exposed via a nested {@link ProjectFixture} rule</li> + * <li>a test {@link Model} loaded from a resource in the plug-in and saved as <tt>model.uml</tt> in the test project. This model is specified using + * an annotation on the test, as described below</li> + * </ul> + * The test model template to load into the editing domain and project must be specified by one of the following annotations: + * <ul> + * <li>{@link JavaResource @JavaResource}: specifies the path to a resource to be loaded from the test class's classpath, using the + * {@link Class#getResource(String)} API</li> + * <li>{@link PluginResource @PluginResource}: specifies a path relative to the root of the OSGi bundle containing the test class, to be loaded via + * the {@link Bundle#getEntry(String)} API</li> + * </ul> + * The resource annotation may be specified either on the test method, in which case it applies to that test case, or on the test + * class, in which case it applies to all test methods in the class that do not have a resource annotation of their own (method + * annotations take precedence over the class annotation). + */ +public abstract class AbstractModelFixture<T extends EditingDomain> extends TestWatcher { + + private final ProjectFixture project = new ProjectFixture(); + + private T domain; + + private Model model; + + public AbstractModelFixture() { + super(); + } + + public Statement apply(Statement base, Description description) { + // Wrap myself in the project rule so that the project exists when I start + Statement result = super.apply(base, description); + result = project.apply(result, description); + return result; + } + + /** + * Obtains the nested project fixture rule. If stored in a field of the test class, it must not be annotated as a {@link Rule @Rule} because that + * would result in double initialization of the rule. + * + * @return the nested project fixture + */ + public ProjectFixture getProject() { + return project; + } + + public T getEditingDomain() { + return domain; + } + + /** + * Obtains the test model, which is resident in the <tt>model.uml</tt> file in the test project (as indicated by its + * {@linkplain #getModelResourceURI() URI}). + * + * @return the test model + */ + public Model getModel() { + return model; + } + + public Resource getModelResource() { + return getModel().eResource(); + } + + public URI getModelResourceURI() { + return getModelResource().getURI(); + } + + public URI getModelURI() { + return EcoreUtil.getURI(getModel()); + } + + protected abstract T createEditingDomain(); + + @Override + protected void starting(Description description) { + domain = createEditingDomain(); + + Resource res = domain.getResourceSet().createResource(project.getURI("model.uml")); + + try { + InputStream input = getResourceURL(description).openStream(); + try { + res.load(input, null); + } finally { + input.close(); + } + res.save(null); // Make sure it exists + } catch (Exception e) { + e.printStackTrace(); + fail("Failed to load test resource: " + e.getLocalizedMessage()); + } + + model = (Model)res.getContents().get(0); + } + + @Override + protected void finished(Description description) { + ResourceSet rset = domain.getResourceSet(); + + model = null; + + if(domain instanceof TransactionalEditingDomain) { + ((TransactionalEditingDomain)domain).dispose(); + } + domain = null; + + for(Resource next : rset.getResources()) { + next.unload(); + next.eAdapters().clear(); + } + + rset.getResources().clear(); + rset.eAdapters().clear(); + } + + protected URL getResourceURL(Description description) { + URL result = null; + + Class<?> testClass = description.getTestClass(); + + Method testMethod = null; + try { + testMethod = testClass.getDeclaredMethod(description.getMethodName()); + } catch (Exception e) { + e.printStackTrace(); + fail("Could not access test method via JUnit framework."); + } + + if(testMethod.isAnnotationPresent(JavaResource.class)) { + result = testClass.getResource(testMethod.getAnnotation(JavaResource.class).value()); + } else if(testMethod.isAnnotationPresent(PluginResource.class)) { + result = FrameworkUtil.getBundle(testClass).getEntry(testMethod.getAnnotation(PluginResource.class).value()); + } else { + // The class must have an annotation + if(testClass.isAnnotationPresent(JavaResource.class)) { + result = testClass.getResource(testClass.getAnnotation(JavaResource.class).value()); + } else if(testClass.isAnnotationPresent(PluginResource.class)) { + result = FrameworkUtil.getBundle(testClass).getEntry(testClass.getAnnotation(PluginResource.class).value()); + } + } + + assertThat("No JavaResource or PluginResource annotation found on test.", result, notNullValue()); + + return result; + } +} diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/JavaResource.java b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/JavaResource.java new file mode 100644 index 00000000000..d9aa6b14340 --- /dev/null +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/JavaResource.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 CEA 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: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.junit.utils.rules; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * Annotation indicating the classpath-relative path to a resource from which to load the test model of an {@link AbstractModelFixture}. + * + * @see AbstractModelFixture + * @see PluginResource + */ +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface JavaResource { + + String value(); +} diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PluginResource.java b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PluginResource.java new file mode 100644 index 00000000000..dc1e7e6eacd --- /dev/null +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PluginResource.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 CEA 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: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.junit.utils.rules; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * Annotation indicating the bundle-relative path to a resource from which to load the test model of an {@link AbstractModelFixture}. + * + * @see AbstractModelFixture + * @see JavaResource + */ +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface PluginResource { + + String value(); +} diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ProjectFixture.java b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ProjectFixture.java index f808abda246..1cdd9f45c72 100644 --- a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ProjectFixture.java +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ProjectFixture.java @@ -12,6 +12,10 @@ */ package org.eclipse.papyrus.junit.utils.rules; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; + import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; @@ -22,6 +26,8 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.workspace.util.WorkspaceSynchronizer; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; @@ -122,4 +128,37 @@ public class ProjectFixture implements TestRule { resource.setResourceAttributes(attr); } } + + public void setReadOnly(String projectRelativePath) { + setReadOnly(new Path(projectRelativePath)); + } + + public void setReadOnly(IPath projectRelativePath) { + setReadOnly(project.findMember(projectRelativePath)); + } + + public void setReadOnly(Resource resource) { + IFile file = WorkspaceSynchronizer.getFile(resource); + assertThat("Cannot set non-workspace resource read-only", file, notNullValue()); + setReadOnly(file); + } + + public void setReadOnly(IResource resource) { + setReadOnly(resource, true); + } + + public void setReadOnly(IResource resource, boolean readOnly) { + ResourceAttributes attr = resource.getResourceAttributes(); + + if(attr.isReadOnly() != readOnly) { + attr.setReadOnly(readOnly); + + try { + resource.setResourceAttributes(attr); + } catch (CoreException e) { + e.getLocalizedMessage(); + fail(String.format("Failed to make workspace resource %s: %s", readOnly ? "read-only" : "writable", e.getLocalizedMessage())); + } + } + } } |