Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2016-08-23 21:07:27 +0000
committerChristian W. Damus2016-08-23 21:07:27 +0000
commitae293862c718921e47a62e456d48f3c19cfbe78e (patch)
treefe95bc4745b4db378f7caecebf754c62454df2da /plugins/infra/emf
parent7e0c2b842c458bd621914b68da67ce97ee6fed21 (diff)
downloadorg.eclipse.papyrus-ae293862c718921e47a62e456d48f3c19cfbe78e.tar.gz
org.eclipse.papyrus-ae293862c718921e47a62e456d48f3c19cfbe78e.tar.xz
org.eclipse.papyrus-ae293862c718921e47a62e456d48f3c19cfbe78e.zip
Bug 497865: [Control Mode] UI for dependent controlled units
https://bugs.eclipse.org/bugs/show_bug.cgi?id=497865 Add an option to the standard control (create fragment) dialog for option to create sub-model unit (independently openable) or not (in which case it's a 'shard'). Add an approver interface to the participant protocols for validation of control/uncontrol requests and also to determine whether an object supports the sub-model unit form of controlled resource. Use this to let the UML participant disable the sub-model unit option for non-packages. Add a label decorator for controlled unit resources in the Project Explorer, with different presentation for 'shards' as for sub-model units that are independently openable. Add a context menu on model elements to toggle their independent sub-model status when they are currently controlled units. This is supported by another optional participant protocol for changing sub-unit mode so that for UML we can add/remove redundant profile applications on packages as necessary. (cherry-picked from streams/2.0-maintenance) Change-Id: I08ac9cc64d70432851f8e7e815f352f4b00d50f2
Diffstat (limited to 'plugins/infra/emf')
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/AbstractCrossReferenceIndex.java141
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/CrossReferenceIndex.java174
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/CrossReferenceIndexHandler.java10
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/OnDemandCrossReferenceIndex.java8
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/ICrossReferenceIndex.java196
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/ShardResourceHelper.java19
6 files changed, 452 insertions, 96 deletions
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/AbstractCrossReferenceIndex.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/AbstractCrossReferenceIndex.java
index b1470389b6e..f755c220494 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/AbstractCrossReferenceIndex.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/AbstractCrossReferenceIndex.java
@@ -21,6 +21,7 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
@@ -51,14 +52,14 @@ public abstract class AbstractCrossReferenceIndex implements ICrossReferenceInde
final SetMultimap<URI, URI> outgoingReferences = HashMultimap.create();
final SetMultimap<URI, URI> incomingReferences = HashMultimap.create();
- final SetMultimap<URI, URI> resourceToShards = HashMultimap.create();
- final SetMultimap<URI, URI> shardToParents = HashMultimap.create();
+ final SetMultimap<URI, URI> resourceToSubunits = HashMultimap.create();
+ final SetMultimap<URI, URI> subunitToParents = HashMultimap.create();
// These are abstracted as URIs without extension
SetMultimap<URI, URI> aggregateOutgoingReferences;
SetMultimap<URI, URI> aggregateIncomingReferences;
- SetMultimap<URI, URI> aggregateResourceToShards;
- SetMultimap<URI, URI> aggregateShardToParents;
+ SetMultimap<URI, URI> aggregateResourceToSubunits;
+ SetMultimap<URI, URI> aggregateSubunitToParents;
final SetMultimap<URI, String> shards = HashMultimap.create();
/**
@@ -219,36 +220,53 @@ public abstract class AbstractCrossReferenceIndex implements ICrossReferenceInde
}
@Override
- public ListenableFuture<SetMultimap<URI, URI>> getShardsAsync() {
- return afterIndex(getShardsCallable());
+ public ListenableFuture<SetMultimap<URI, URI>> getSubunitsAsync() {
+ return afterIndex(getSubunitsCallable());
}
@Override
- public SetMultimap<URI, URI> getShards() throws CoreException {
- return sync(afterIndex(getShardsCallable()));
+ public SetMultimap<URI, URI> getSubunits() throws CoreException {
+ return sync(afterIndex(getSubunitsCallable()));
}
- Callable<SetMultimap<URI, URI>> getShardsCallable() {
- return sync(() -> ImmutableSetMultimap.copyOf(resourceToShards));
+ Callable<SetMultimap<URI, URI>> getSubunitsCallable() {
+ return sync(() -> ImmutableSetMultimap.copyOf(resourceToSubunits));
}
@Override
- public ListenableFuture<Set<URI>> getShardsAsync(URI resourceURI) {
- return afterIndex(getShardsCallable(resourceURI));
+ public ListenableFuture<Set<URI>> getSubunitsAsync(URI resourceURI) {
+ return getSubunitsAsync(resourceURI, true);
}
@Override
- public Set<URI> getShards(URI resourceURI) throws CoreException {
- return sync(afterIndex(getShardsCallable(resourceURI)));
+ public Set<URI> getSubunits(URI resourceURI) throws CoreException {
+ return getSubunits(resourceURI, true);
}
- Callable<Set<URI>> getShardsCallable(URI shardURI) {
+ @Override
+ public ListenableFuture<Set<URI>> getSubunitsAsync(URI resourceURI, boolean shardOnly) {
+ return afterIndex(getSubunitsCallable(resourceURI, shardOnly));
+ }
+
+ @Override
+ public Set<URI> getSubunits(URI resourceURI, boolean shardOnly) throws CoreException {
+ return sync(afterIndex(getSubunitsCallable(resourceURI, shardOnly)));
+ }
+
+ Callable<Set<URI>> getSubunitsCallable(URI shardURI, boolean shardOnly) {
return sync(() -> {
String ext = shardURI.fileExtension();
URI withoutExt = shardURI.trimFileExtension();
- Set<URI> result = getAggregateShards().get(withoutExt).stream()
- // Only those that actually are shards
- .filter(AbstractCrossReferenceIndex.this::isShard0)
+
+ Stream<URI> intermediateResult = getAggregateShards().get(withoutExt).stream();
+
+ if (shardOnly) {
+ // Only those that actually are shards
+ intermediateResult = intermediateResult
+ .filter(AbstractCrossReferenceIndex.this::isShard0);
+ }
+
+ Set<URI> result = intermediateResult
.map(uri -> uri.appendFileExtension(ext))
.collect(Collectors.toSet());
@@ -260,16 +278,16 @@ public abstract class AbstractCrossReferenceIndex implements ICrossReferenceInde
SetMultimap<URI, URI> result;
synchronized (sync) {
- if (aggregateResourceToShards == null) {
+ if (aggregateResourceToSubunits == null) {
// Compute the aggregate now
- aggregateResourceToShards = HashMultimap.create();
- for (Map.Entry<URI, URI> next : resourceToShards.entries()) {
- aggregateResourceToShards.put(next.getKey().trimFileExtension(),
+ aggregateResourceToSubunits = HashMultimap.create();
+ for (Map.Entry<URI, URI> next : resourceToSubunits.entries()) {
+ aggregateResourceToSubunits.put(next.getKey().trimFileExtension(),
next.getValue().trimFileExtension());
}
}
- result = aggregateResourceToShards;
+ result = aggregateResourceToSubunits;
}
return result;
@@ -277,21 +295,32 @@ public abstract class AbstractCrossReferenceIndex implements ICrossReferenceInde
@Override
public ListenableFuture<Set<URI>> getParentsAsync(URI shardURI) {
- return afterIndex(getParentsCallable(shardURI));
+ return getParentsAsync(shardURI, true);
+ }
+
+ @Override
+ public ListenableFuture<Set<URI>> getParentsAsync(URI resourceURI, boolean shardOnly) {
+ return afterIndex(getParentsCallable(resourceURI, shardOnly));
}
@Override
public Set<URI> getParents(URI shardURI) throws CoreException {
- return sync(afterIndex(getParentsCallable(shardURI)));
+ return getParents(shardURI, true);
}
- Callable<Set<URI>> getParentsCallable(URI shardURI) {
+ @Override
+ public Set<URI> getParents(URI resourceURI, boolean shardOnly) throws CoreException {
+ return sync(afterIndex(getParentsCallable(resourceURI, shardOnly)));
+ }
+
+ Callable<Set<URI>> getParentsCallable(URI shardURI, boolean shardOnly) {
return sync(() -> {
Set<URI> result;
URI withoutExt = shardURI.trimFileExtension();
- // If it's not a shard, it has no parents, by definition
- if (!isShard0(withoutExt)) {
+ // If it's not a shard, it has no parents, by definition, unless we're also
+ // including sub-model units
+ if (shardOnly && !isShard0(withoutExt)) {
result = Collections.emptySet();
} else {
String ext = shardURI.fileExtension();
@@ -309,16 +338,16 @@ public abstract class AbstractCrossReferenceIndex implements ICrossReferenceInde
SetMultimap<URI, URI> result;
synchronized (sync) {
- if (aggregateShardToParents == null) {
+ if (aggregateSubunitToParents == null) {
// Compute the aggregate now
- aggregateShardToParents = HashMultimap.create();
- for (Map.Entry<URI, URI> next : shardToParents.entries()) {
- aggregateShardToParents.put(next.getKey().trimFileExtension(),
+ aggregateSubunitToParents = HashMultimap.create();
+ for (Map.Entry<URI, URI> next : subunitToParents.entries()) {
+ aggregateSubunitToParents.put(next.getKey().trimFileExtension(),
next.getValue().trimFileExtension());
}
}
- result = aggregateShardToParents;
+ result = aggregateSubunitToParents;
}
return result;
@@ -326,53 +355,69 @@ public abstract class AbstractCrossReferenceIndex implements ICrossReferenceInde
@Override
public ListenableFuture<Set<URI>> getRootsAsync(URI shardURI) {
- return afterIndex(getRootsCallable(shardURI));
+ return getRootsAsync(shardURI, true);
+ }
+
+ @Override
+ public ListenableFuture<Set<URI>> getRootsAsync(URI shardURI, boolean shardOnly) {
+ return afterIndex(getRootsCallable(shardURI, shardOnly));
}
@Override
public Set<URI> getRoots(URI shardURI) throws CoreException {
- return sync(afterIndex(getRootsCallable(shardURI)));
+ return getRoots(shardURI, true);
}
@Override
- public Set<URI> getRoots(URI shardURI, ICrossReferenceIndex alternate) throws CoreException {
+ public Set<URI> getRoots(URI shardURI, boolean shardOnly) throws CoreException {
+ return sync(afterIndex(getRootsCallable(shardURI, shardOnly)));
+ }
+
+ @Override
+ public Set<URI> getRoots(URI subunitURI, ICrossReferenceIndex alternate) throws CoreException {
+ return getRoots(subunitURI, true, alternate);
+ }
+
+ @Override
+ public Set<URI> getRoots(URI subunitURI, boolean shardOnly, ICrossReferenceIndex alternate) throws CoreException {
if (alternate == this) {
throw new IllegalArgumentException("self alternate"); //$NON-NLS-1$
}
Callable<Set<URI>> elseCallable = (alternate == null)
? null
- : () -> alternate.getRoots(shardURI);
+ : () -> alternate.getRoots(subunitURI, shardOnly);
- return ifAvailable(getRootsCallable(shardURI), elseCallable);
+ return ifAvailable(getRootsCallable(subunitURI, shardOnly), elseCallable);
}
- Callable<Set<URI>> getRootsCallable(URI shardURI) {
+ Callable<Set<URI>> getRootsCallable(URI subunitURI, boolean shardOnly) {
return sync(() -> {
Set<URI> result;
- URI withoutExt = shardURI.trimFileExtension();
+ URI withoutExt = subunitURI.trimFileExtension();
- // If it's not a shard, it has no roots, by definition
- if (!isShard0(withoutExt)) {
+ // If we need shards only and it's not a shard, it has no roots, by definition
+ if (shardOnly && !isShard0(withoutExt)) {
result = Collections.emptySet();
} else {
// TODO: Cache this?
ImmutableSet.Builder<URI> resultBuilder = ImmutableSet.builder();
- SetMultimap<URI, URI> shardToParents = getAggregateShardToParents();
+ SetMultimap<URI, URI> subunitToParents = getAggregateShardToParents();
// Breadth-first search of the parent graph
Queue<URI> queue = Lists.newLinkedList();
Set<URI> cycleDetect = Sets.newHashSet();
- String ext = shardURI.fileExtension();
+ String ext = subunitURI.fileExtension();
queue.add(withoutExt);
for (URI next = queue.poll(); next != null; next = queue.poll()) {
if (cycleDetect.add(next)) {
- if (shardToParents.containsKey(next)) {
- queue.addAll(shardToParents.get(next));
- } else {
- // It's a root
+ // Even if it looks like a shard but has no parents, it's a root
+ if ((!shardOnly || isShard0(next)) && subunitToParents.containsKey(next)) {
+ queue.addAll(subunitToParents.get(next));
+ } else if (!next.equals(withoutExt)) {
+ // It's a root (and not the original resource we were asked about)
resultBuilder.add(next.appendFileExtension(ext));
}
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/CrossReferenceIndex.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/CrossReferenceIndex.java
index df13d34186c..6730912a182 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/CrossReferenceIndex.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/CrossReferenceIndex.java
@@ -18,6 +18,9 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Set;
import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.xml.parsers.SAXParser;
@@ -32,6 +35,8 @@ import org.eclipse.papyrus.infra.emf.Activator;
import org.eclipse.papyrus.infra.emf.resource.index.IWorkspaceModelIndexProvider;
import org.eclipse.papyrus.infra.emf.resource.index.WorkspaceModelIndex;
import org.eclipse.papyrus.infra.emf.resource.index.WorkspaceModelIndex.PersistentIndexHandler;
+import org.eclipse.papyrus.infra.emf.resource.index.WorkspaceModelIndexAdapter;
+import org.eclipse.papyrus.infra.emf.resource.index.WorkspaceModelIndexEvent;
import org.xml.sax.helpers.DefaultHandler;
import com.google.common.util.concurrent.ListenableFuture;
@@ -43,6 +48,8 @@ public class CrossReferenceIndex extends AbstractCrossReferenceIndex {
private static final CrossReferenceIndex INSTANCE = new CrossReferenceIndex();
+ private final CopyOnWriteArrayList<Dispatcher> listeners = new CopyOnWriteArrayList<>();
+
private final WorkspaceModelIndex<CrossReferencedFile> index;
/**
@@ -56,9 +63,23 @@ public class CrossReferenceIndex extends AbstractCrossReferenceIndex {
"papyrusCrossRefs", //$NON-NLS-1$
"org.eclipse.emf.ecore.xmi", //$NON-NLS-1$
null, indexer(), MAX_INDEX_JOBS);
+ index.addListener(new WorkspaceModelIndexAdapter() {
+
+ @Override
+ public void indexCalculated(WorkspaceModelIndexEvent event) {
+ indexChanged();
+ }
+
+ @Override
+ public void indexRecalculated(WorkspaceModelIndexEvent event) {
+ indexChanged();
+ }
+ });
}
public void dispose() {
+ listeners.clear();
+
index.dispose();
}
@@ -66,6 +87,63 @@ public class CrossReferenceIndex extends AbstractCrossReferenceIndex {
return INSTANCE;
}
+ /**
+ * Registers a {@code handler} for updates to the index.
+ *
+ * @param handler
+ * invoked whenever the contents of the index change. No assumption
+ * must be made about the thread or kind of thread on which this call-back
+ * is invoked. If the thread context is important, use the
+ * {@link #onIndexChanged(Consumer, Executor)} API, instead
+ *
+ * @return a runnable that, when executed, will disconnect the {@code handler} so that
+ * it will no longer receive updates
+ *
+ * @see #onIndexChanged(Consumer, Executor)
+ */
+ public Runnable onIndexChanged(Consumer<? super CrossReferenceIndex> handler) {
+ return onIndexChanged(handler, null);
+ }
+
+ /**
+ * Registers a {@code handler} for updates to the index.
+ *
+ * @param handler
+ * invoked whenever the contents of the index change. No assumption
+ * must be made about the thread or kind of thread on which this call-back
+ * is invoked
+ * @param exec
+ * an executor on which to submit invocation of the {@code handler}, in case
+ * it needs to run on a specific thread. May be {@code null} to run in
+ * whatever thread processes index updates (about which, then, no assumptions
+ * may be made by the handler
+ *
+ * @return a runnable that, when executed, will disconnect the {@code handler} so that
+ * it will no longer receive updates
+ */
+ public Runnable onIndexChanged(Consumer<? super CrossReferenceIndex> handler, Executor exec) {
+ Runnable result;
+
+ if (handler != null) {
+ Dispatcher dispatcher = new Dispatcher(this, handler, exec);
+ if (listeners.add(dispatcher)) {
+ result = dispatcher::dispose;
+ } else {
+ result = Dispatcher::pass;
+ }
+ } else {
+ result = Dispatcher::pass;
+ }
+
+ return result;
+ }
+
+ private void indexChanged() {
+ if (!listeners.isEmpty()) {
+ listeners.forEach(Dispatcher::dispatch);
+ }
+ }
+
//
// Indexing
//
@@ -117,12 +195,12 @@ public class CrossReferenceIndex extends AbstractCrossReferenceIndex {
unindexResource(file);
// update the forward mapping
- resourceToShards.putAll(resourceURI, index.getShards());
+ resourceToSubunits.putAll(resourceURI, index.getShards());
outgoingReferences.putAll(resourceURI, index.getCrossReferences());
// and the reverse mapping
for (URI next : index.getShards()) {
- shardToParents.put(next, resourceURI);
+ subunitToParents.put(next, resourceURI);
}
for (URI next : index.getCrossReferences()) {
incomingReferences.put(next, resourceURI);
@@ -152,20 +230,20 @@ public class CrossReferenceIndex extends AbstractCrossReferenceIndex {
synchronized (sync) {
// purge the aggregates (for model-set "resource without URI")
- aggregateResourceToShards = null;
- aggregateShardToParents = null;
+ aggregateResourceToSubunits = null;
+ aggregateSubunitToParents = null;
aggregateOutgoingReferences = null;
aggregateIncomingReferences = null;
setShard(resourceURI, false);
// And remove all traces of this resource
- resourceToShards.removeAll(resourceURI);
+ resourceToSubunits.removeAll(resourceURI);
outgoingReferences.removeAll(resourceURI);
// the multimap's entry collection that underlies the key-set
// is modified as we go, so take a safe copy of the keys
- for (URI next : new ArrayList<>(shardToParents.keySet())) {
- shardToParents.remove(next, resourceURI);
+ for (URI next : new ArrayList<>(subunitToParents.keySet())) {
+ subunitToParents.remove(next, resourceURI);
}
for (URI next : new ArrayList<>(incomingReferences.keySet())) {
incomingReferences.remove(next, resourceURI);
@@ -211,7 +289,7 @@ public class CrossReferenceIndex extends AbstractCrossReferenceIndex {
this.isShard = handler.isShard();
this.crossReferences = handler.getCrossReferences();
- this.shards = handler.getShards();
+ this.shards = handler.getSubunits();
}
boolean isShard() {
@@ -246,4 +324,84 @@ public class CrossReferenceIndex extends AbstractCrossReferenceIndex {
return CrossReferenceIndex.INSTANCE.index;
}
}
+
+ private static final class Dispatcher {
+ private final CrossReferenceIndex owner;
+ private final Consumer<? super CrossReferenceIndex> handler;
+ private final Executor exec;
+
+ Dispatcher(CrossReferenceIndex owner,
+ Consumer<? super CrossReferenceIndex> handler,
+ Executor exec) {
+
+ super();
+
+ this.owner = owner;
+ this.handler = handler;
+ this.exec = exec;
+ }
+
+ static void pass() {
+ // Pass
+ }
+
+ public void dispose() {
+ owner.listeners.remove(this);
+ }
+
+ void dispatch() {
+ if (exec == null) {
+ handler.accept(owner);
+ } else {
+ exec.execute(() -> handler.accept(owner));
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((exec == null) ? 0 : exec.hashCode());
+ result = prime * result + ((handler == null) ? 0 : handler.hashCode());
+ result = prime * result + ((owner == null) ? 0 : owner.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Dispatcher other = (Dispatcher) obj;
+ if (exec == null) {
+ if (other.exec != null) {
+ return false;
+ }
+ } else if (!exec.equals(other.exec)) {
+ return false;
+ }
+ if (handler == null) {
+ if (other.handler != null) {
+ return false;
+ }
+ } else if (!handler.equals(other.handler)) {
+ return false;
+ }
+ if (owner == null) {
+ if (other.owner != null) {
+ return false;
+ }
+ } else if (!owner.equals(other.owner)) {
+ return false;
+ }
+ return true;
+ }
+
+ }
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/CrossReferenceIndexHandler.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/CrossReferenceIndexHandler.java
index 4b6dbe96778..fe2a824a803 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/CrossReferenceIndexHandler.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/CrossReferenceIndexHandler.java
@@ -44,7 +44,7 @@ public class CrossReferenceIndexHandler extends DefaultHandler {
private Set<String> crossReferences = Sets.newHashSet();
private XMIElement shard;
- private Set<String> shards = Sets.newHashSet();
+ private Set<String> subunits = Sets.newHashSet();
// The (optional) parent references in the annotation
private Set<String> parents = Sets.newHashSet();
@@ -93,8 +93,8 @@ public class CrossReferenceIndexHandler extends DefaultHandler {
return shard != null;
}
- public Set<String> getShards() {
- return shards;
+ public Set<String> getSubunits() {
+ return subunits;
}
public Set<String> getParents() {
@@ -145,8 +145,8 @@ public class CrossReferenceIndexHandler extends DefaultHandler {
// Don't index internal references
if (!xref.equals(fileURI)) {
if (element.isContainment()) {
- // Cross-resource containment is a shard relationship
- shards.add(xref.toString());
+ // Cross-resource containment is a sub-unit relationship
+ subunits.add(xref.toString());
} else if (isShard() && (element.parent == shard) && element.isRole(eAnnotationReferencesName)) {
// Handle shard parent resource reference. This is
// *not* a regular cross-resource reference
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/OnDemandCrossReferenceIndex.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/OnDemandCrossReferenceIndex.java
index 43090ea830a..9c7146bee09 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/OnDemandCrossReferenceIndex.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/internal/resource/OnDemandCrossReferenceIndex.java
@@ -108,7 +108,7 @@ public class OnDemandCrossReferenceIndex extends AbstractCrossReferenceIndex {
}
@Override
- Callable<SetMultimap<URI, URI>> getShardsCallable() {
+ Callable<SetMultimap<URI, URI>> getSubunitsCallable() {
// We don't parse on-the-fly for child shards; it requires scanning
// the whole resource
return () -> ImmutableSetMultimap.of();
@@ -153,7 +153,7 @@ public class OnDemandCrossReferenceIndex extends AbstractCrossReferenceIndex {
doIndex(next);
// And then, breadth-first, its parents that aren't already indexed
- shardToParents.get(next).stream()
+ subunitToParents.get(next).stream()
.filter(((Predicate<URI>) shards::containsKey).negate())
.forEach(toIndex::offer);
}
@@ -178,13 +178,13 @@ public class OnDemandCrossReferenceIndex extends AbstractCrossReferenceIndex {
}
// Clear the aggregate map because we now have updates to include
- aggregateShardToParents = null;
+ aggregateSubunitToParents = null;
setShard(resourceURI, handler.isShard());
Set<URI> parents = handler.getParents().stream()
.map(URI::createURI)
.collect(Collectors.toSet());
- shardToParents.putAll(resourceURI, parents);
+ subunitToParents.putAll(resourceURI, parents);
}
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/ICrossReferenceIndex.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/ICrossReferenceIndex.java
index 1e154444729..0f12edc3a3d 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/ICrossReferenceIndex.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/ICrossReferenceIndex.java
@@ -200,64 +200,117 @@ public interface ICrossReferenceIndex {
boolean isShard(URI resourceURI) throws CoreException;
/**
- * Asynchronously queries the mapping of URIs of resources to URIs of shards that are their immediate
- * children.
+ * Asynchronously queries the mapping of URIs of resources to URIs of sub-units
+ * that are their direct children.
*
- * @return a future result of the mapping of resource URIs to shard URIs
+ * @return a future result of the mapping of resource URIs to sub-unit URIs
*/
- ListenableFuture<SetMultimap<URI, URI>> getShardsAsync();
+ ListenableFuture<SetMultimap<URI, URI>> getSubunitsAsync();
/**
- * Queries the mapping of URIs of resources to URIs of shards that are their immediate
- * children.
+ * Queries the mapping of URIs of resources to URIs of controlled units that are
+ * their direct children.
*
- * @return the mapping of resource URIs to shard URIs
+ * @return the mapping of resource URIs to sub-unit URIs
*
* @throws CoreException
- * if the index either fails to compute the shards or if
+ * if the index either fails to compute the sub-units or if
* the calling thread is interrupted in waiting for the result
*/
- SetMultimap<URI, URI> getShards() throws CoreException;
+ SetMultimap<URI, URI> getSubunits() throws CoreException;
/**
- * Asynchronously queries the URIs of resources that are immediate shards of a
+ * Asynchronously queries the URIs of controlled units that are direct children of a
+ * given resource. Equivalent to calling {@link #getSUbunitsAsync(URI, boolean)}
+ * with a {@code true} argument.
+ *
+ * @param resourceURI
+ * the URI of a resource
+ * @return a future result of the URIs of sub-units that are its direct children
+ *
+ * @see #getSubunitsAsync(URI, boolean)
+ */
+ ListenableFuture<Set<URI>> getSubunitsAsync(URI resourceURI);
+
+ /**
+ * Asynchronously queries the URIs of controlled units that are direct children of a
* given resource.
*
* @param resourceURI
* the URI of a resource
- * @return a future result of the URIs of shards that are its immediate children
+ * @param shardOnly
+ * whether to consider only sub-units that are shards
+ * @return a future result of the URIs of sub-units that are its direct children
+ */
+ ListenableFuture<Set<URI>> getSubunitsAsync(URI resourceURI, boolean shardOnly);
+
+ /**
+ * Queries the URIs of controlled units that are direct children of a
+ * given resource. Equivalent to calling {@link #getSubunits(URI, boolean)}
+ * with a {@code true} argument.
+ *
+ * @param resourceURI
+ * the URI of a resource
+ * @return the URIs of sub-units that are its direct children
+ *
+ * @throws CoreException
+ * if the index either fails to compute the sub-units or if
+ * the calling thread is interrupted in waiting for the result
+ * @see #getSubunits(URI, boolean)
*/
- ListenableFuture<Set<URI>> getShardsAsync(URI resourceURI);
+ Set<URI> getSubunits(URI resourceURI) throws CoreException;
/**
- * Queries the URIs of resources that are immediate shards of a
+ * Queries the URIs of controlled units that are direct children of a
* given resource.
*
* @param resourceURI
* the URI of a resource
- * @return the URIs of shards that are its immediate children
+ * @param shardOnly
+ * whether to consider only sub-units that are shards
+ * @return the URIs of sub-units that are its direct children
*
* @throws CoreException
- * if the index either fails to compute the shards or if
+ * if the index either fails to compute the sub-units or if
* the calling thread is interrupted in waiting for the result
*/
- Set<URI> getShards(URI resourceURI) throws CoreException;
+ Set<URI> getSubunits(URI resourceURI, boolean shardOnly) throws CoreException;
/**
* Asynchronously queries URIs of resources that are immediate parents of a given
- * (potential) shard resource.
+ * (potential) shard resource. Equivalent to calling {@link #getParentsAsync(URI, boolean)}
+ * with a {@code true} argument.
*
* @param shardURI
* the URI of a potential shard resource. It needs not necessarily actually
* be a shard, in which case it trivially wouldn't have any parents
* @return the future result of the URIs of resources that are immediate parents of
* the shard
+ *
+ * @see #getParentsAsync(URI, boolean)
*/
ListenableFuture<Set<URI>> getParentsAsync(URI shardURI);
/**
+ * Asynchronously queries URIs of resources that are immediate parents of a given
+ * resource, whether it is a shard or a sub-model unit.
+ *
+ * @param resourceURI
+ * the URI of a potential shard or sub-model resource. It needs not necessarily
+ * actually be a shard or a sub-model, in which case it wouldn't have any parents
+ * @param shardOnly
+ * whether to consider only shards as validly having parents (useful for
+ * determining required resource dependencies)
+ *
+ * @return the future result of the URIs of resources that are immediate parents of
+ * the resource
+ */
+ ListenableFuture<Set<URI>> getParentsAsync(URI resourceURI, boolean shardOnly);
+
+ /**
* Queries URIs of resources that are immediate parents of a given
- * (potential) shard resource.
+ * (potential) shard resource. Equivalent to calling {@link #getParents(URI, boolean)}
+ * with a {@code true} argument.
*
* @param shardURI
* the URI of a potential shard resource. It needs not necessarily actually
@@ -268,23 +321,63 @@ public interface ICrossReferenceIndex {
* @throws CoreException
* if the index either fails to compute the parents or if
* the calling thread is interrupted in waiting for the result
+ *
+ * @see #getParents(URI, boolean)
*/
Set<URI> getParents(URI shardURI) throws CoreException;
/**
+ * Queries URIs of resources that are immediate parents of a given
+ * resource, whether it is a shard or a sub-model unit.
+ *
+ * @param resourceURI
+ * the URI of a potential shard or sub-model resource. It needs not necessarily
+ * actually be a shard or a sub-model, in which case it wouldn't have any parents
+ * @param shardOnly
+ * whether to consider only shards as validly having parents (useful for
+ * determining required resource dependencies)
+ * @return the URIs of resources that are immediate parents of
+ * the resource
+ *
+ * @throws CoreException
+ * if the index either fails to compute the parents or if
+ * the calling thread is interrupted in waiting for the result
+ */
+ Set<URI> getParents(URI resourceURI, boolean shardOnly) throws CoreException;
+
+ /**
* Asynchronously queries URIs of resources that are roots (ultimate parents) of a given
- * (potential) shard resource.
+ * (potential) shard resource. Equivalent to calling {@link #getRootsAsync(URI, boolean)}
+ * with a {@code true} argument.
*
* @param shardURI
* the URI of a potential shard resource. It needs not necessarily actually
* be a shard, in which case it trivially wouldn't have any parents
* @return the future result of the URIs of resources that are roots of its parent graph
+ *
+ * @see #getRootsAsync(URI, boolean)
*/
ListenableFuture<Set<URI>> getRootsAsync(URI shardURI);
/**
+ * Asynchronously queries URIs of resources that are roots (ultimate parents) of a given
+ * resource.
+ *
+ * @param resourceURI
+ * the URI of a potential sub-unit resource. It needs not necessarily actually
+ * be a sub-unit, in which case it wouldn't have any parents and, therefore,
+ * no roots
+ * @param shardOnly
+ * whether to consider only shards as validly having roots (useful for
+ * determining required resource dependencies)
+ * @return the future result of the URIs of resources that are roots of its parent graph
+ */
+ ListenableFuture<Set<URI>> getRootsAsync(URI resourceURI, boolean shardOnly);
+
+ /**
* Queries URIs of resources that are roots (ultimate parents) of a given
- * (potential) shard resource.
+ * (potential) shard resource. Equivalent to calling {@link #getRoots(URI, boolean)}
+ * with a {@code true} argument.
*
* @param shardURI
* the URI of a potential shard resource. It needs not necessarily actually
@@ -294,17 +387,20 @@ public interface ICrossReferenceIndex {
* @throws CoreException
* if the index either fails to compute the roots or if
* the calling thread is interrupted in waiting for the result
+ * @see #getRoots(URI, boolean)
*/
Set<URI> getRoots(URI shardURI) throws CoreException;
/**
- * Attempts to queries URIs of resources that are roots (ultimate parents) of a given
- * (potential) shard resource. If the receiver is not ready to provide a complete
+ * Attempts to query URIs of resources that are roots (ultimate parents) of a given
+ * (potential) sub-unit resource. If the receiver is not ready to provide a complete
* and/or correct result, then fall back to an {@code alternate}, if any.
+ * Equivalent to calling {@link #getRoots(URI, boolean, ICrossReferenceIndex)} with
+ * a {@code true} value for the {@code shardOnly} parameter.
*
- * @param shardURI
- * the URI of a potential shard resource. It needs not necessarily actually
- * be a shard, in which case it trivially wouldn't have any parents
+ * @param subunitURI
+ * the URI of a potential sub-unit resource. It needs not necessarily actually
+ * be a sub-unit, in which case it trivially wouldn't have any parents
* @param alternate
* a fall-back index from which to get the roots if I am not ready
* to provide them, or {@code null} if not required
@@ -317,6 +413,54 @@ public interface ICrossReferenceIndex {
* if the index is not available and the {@code alternate} fails
* @throws IllegalArgumentException
* if the {@code alternate} is myself (attempted recursion)
+ *
+ * @see #getRoots(URI, boolean, ICrossReferenceIndex)
*/
- Set<URI> getRoots(URI shardURI, ICrossReferenceIndex alternate) throws CoreException;
+ Set<URI> getRoots(URI subunitURI, ICrossReferenceIndex alternate) throws CoreException;
+
+ /**
+ * Queries URIs of resources that are roots (ultimate parents) of a given
+ * resource.
+ *
+ * @param resourceURI
+ * the URI of a potential sub-unit resource. It needs not necessarily actually
+ * be a sub-unit, in which case it trivially wouldn't have any parents and,
+ * therefore, no roots
+ * @param shardOnly
+ * whether to consider only shards as validly having roots (useful for
+ * determining required resource dependencies)
+ * @return the URIs of resources that are roots of its parent graph
+ *
+ * @throws CoreException
+ * if the index either fails to compute the roots or if
+ * the calling thread is interrupted in waiting for the result
+ */
+ Set<URI> getRoots(URI resourceURI, boolean shardOnly) throws CoreException;
+
+ /**
+ * Attempts to query URIs of resources that are roots (ultimate parents) of a given
+ * (potential) sub-unit resource. If the receiver is not ready to provide a complete
+ * and/or correct result, then fall back to an {@code alternate}, if any.
+ *
+ * @param subunitURI
+ * the URI of a potential sub-unit resource. It needs not necessarily actually
+ * be a sub-unit, in which case it trivially wouldn't have any parents
+ * @param shardOnly
+ * whether to consider only shards as validly having roots (useful for
+ * determining required resource dependencies)
+ * @param alternate
+ * a fall-back index from which to get the roots if I am not ready
+ * to provide them, or {@code null} if not required
+ * @return the URIs of resources that are roots of its parent graph, or {@code null}
+ * if the receiver cannot provide a result and there is no {@code alternate}.
+ * Note that {@code null} is only returned in this failure case; any successful
+ * result is at least an empty set
+ *
+ * @throws CoreException
+ * if the index is not available and the {@code alternate} fails
+ * @throws IllegalArgumentException
+ * if the {@code alternate} is myself (attempted recursion)
+ */
+ Set<URI> getRoots(URI subunitURI, boolean shardOnly, ICrossReferenceIndex alternate) throws CoreException;
+
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/ShardResourceHelper.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/ShardResourceHelper.java
index 29c004eb5c6..ad172b55d5e 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/ShardResourceHelper.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/ShardResourceHelper.java
@@ -213,6 +213,11 @@ public class ShardResourceHelper implements AutoCloseable {
resource.getContents(),
annotation);
}
+
+ result = new CommandWrapper(
+ "Toggle Submodel",
+ "Toggle the ability to open the resource as an independent sub-model unit",
+ result);
} else {
// Create the annotation
EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation();
@@ -252,7 +257,11 @@ public class ShardResourceHelper implements AutoCloseable {
// Ensure attachment of the adapter on first execution and record the
// annotation, if not already closed
- result = new CommandWrapper(result) {
+ result = new CommandWrapper(
+ "Toggle Submodel",
+ "Toggle the ability to open the resource as an independent sub-model unit",
+ result) {
+
@Override
public void execute() {
super.execute();
@@ -347,9 +356,7 @@ public class ShardResourceHelper implements AutoCloseable {
}
}
- if (result != null) {
- attachAnnotationAdapter(annotationOwner);
- }
+ attachAnnotationAdapter(annotationOwner);
}
return result;
@@ -412,7 +419,9 @@ public class ShardResourceHelper implements AutoCloseable {
if (annotationAdapter != null) {
Adapter adapter = annotationAdapter;
annotationAdapter = null;
- adapter.getTarget().eAdapters().remove(adapter);
+ if (adapter.getTarget() != null) {
+ adapter.getTarget().eAdapters().remove(adapter);
+ }
}
}
}

Back to the top