Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2016-08-23 17:07:27 -0400
committerChristian W. Damus2016-08-23 17:07:27 -0400
commitae293862c718921e47a62e456d48f3c19cfbe78e (patch)
treefe95bc4745b4db378f7caecebf754c62454df2da /plugins
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')
-rw-r--r--plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/controlMode.mediawiki39
-rw-r--r--plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ControlAction.pngbin20669 -> 78105 bytes
-rw-r--r--plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ControlDialog.pngbin15203 -> 31434 bytes
-rw-r--r--plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/Decorations.pngbin0 -> 97131 bytes
-rw-r--r--plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ToggleSubmodelAction.pngbin0 -> 89416 bytes
-rw-r--r--plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/UncontrolAction.pngbin21812 -> 85197 bytes
-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
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/META-INF/MANIFEST.MF5
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/build.properties13
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco.pngbin0 -> 1283 bytes
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco.pxmbin0 -> 146911 bytes
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco@2x.pngbin0 -> 1330 bytes
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco.pngbin0 -> 1276 bytes
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco.pxmbin0 -> 146911 bytes
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco@2x.pngbin0 -> 1330 bytes
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/plugin.properties40
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/plugin.xml79
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/schema/participant.exsd253
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModeManager.java171
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModePlugin.java22
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModeRequestParameters.java25
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/IControlModeManager.java96
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/commands/BasicControlCommand.java13
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/handler/ControlCommandHandler.java26
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/handler/UncontrolCommandHandler.java19
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/handler/SubmodelState.java119
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/handler/ToggleSubmodelHandler.java108
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/ui/ControlledUnitLabelDecorator.java184
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/messages/messages.properties15
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IControlCommandApprover.java57
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IShardModeCommandParticipant.java72
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ui/CreateModelFragmentDialog.java161
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ui/IControlModeFragmentDialogProvider.java75
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/.classpath14
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/.settings/org.eclipse.jdt.core.prefs6
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/META-INF/MANIFEST.MF6
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/pom.xml2
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/UMLProfileControlParticipant.java75
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveStereotypeApplicationToControlResource.java8
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/ProfileApplicationHelper.java10
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/SafeDialogOpenerDuringValidation.java12
46 files changed, 1959 insertions, 314 deletions
diff --git a/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/controlMode.mediawiki b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/controlMode.mediawiki
index cca9840a0ac..6598fad7c1f 100644
--- a/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/controlMode.mediawiki
+++ b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/controlMode.mediawiki
@@ -10,22 +10,53 @@ This is specially helpful working in collaborative environments, since the Team
==Create a submodel==
To create a submodel:
#Right click on the element which you wish to move to a different resource (a Package in the common case)
-#Select ''Create Submodel''[[Image:images/ControlAction.png]]
+#Select ''Create Submodel''<br/>[[Image:images/ControlAction.png]]
#The following dialog appears.<br/>[[Image:images/ControlDialog.png]]
#Select the desired location for the new resource
#Click ''OK''.
+'''Important:''' The selected element has not been moved just yet. The model editor will be dirty i.e. there will be an asterisk next to its name in the tab. In order to complete the submodel creation, you need to '''save''' your model.
+The new resource is created in the chosen location with the chosen file name, whilst a green decorator is shown in the Model Explorer view of the parent model to indicate this element is in a submodel.
-'''Important:''' The selected element has not been moved just yet. The model editor will be dirty i.e. there will be an asterisk next to its name in the tab. In order to complete the submodel creation, you need to '''save''' your model.
+Note that, for a package, the dialog shows an option to have it be openable and editable in its own editor, independently of the package containing it (and the one containing that, etc.).
+This can be convenient, but it does mean that the package has to redundantly apply all of the
+profile applications applied to the packages containing it, so that stereotypes can properly be
+manipulated in the editor. This can result in inconsistencies if a profile definition changes
+over time and not all applications in all packages are kept up-to-date consistently with
+stereotype migrations. This option is available only for packages, because only they can have
+profile applications. For other kinds of elements, this option is disabled and the resources
+created for them will always open in the context of the containing model.
+
+When this option is not selected, then the resulting submodel cannot be opened separately.
+Attempting to open it, usually by double-clicking it in the Project Explorer, will instead
+open the top-most independent submodel (or the root model package). Or, if that is already
+open, just activate its editor. This ensures that the nesting package context, and especially
+its profile applications, is always available to properly manage stereotypes.
+
+==Toggle the Independent Submodel Support==
+
+Once a package has been stored in a submodel resource, the support for editing it independently
+can be added and removed at any time:
+#Right-click on the submodel package in the Model Explorer.
+#If the package is independently editable, the ''Independent Submodel'' menu item will have a check mark. Otherwise, it will not.
+#Click the ''Independent Submodel'' menu item to change whether the package can be edited independently or not.
+[[Image:images/ToggleSubmodelAction.png]]
+
+'''Important:''' These changes will only take permanent effect on the next '''save''' action. Until then, the resource on disk is not changed and so what happens when it is opened in an editor will not change.
+
+In the Project Explorer view, the submodel resource is indicated by a filled blue
+note-paper decoration or a hollow blue decoration in the case that it is not an independently
+openable submodel.
+
+[[Image:images/Decorations.png|400px]]
-The new resource is created in the chosen location with the chosen file name, whilst a green decorator is shown in the model explorer view of the parent model to indicate this element is in a submodel.
==Reintegrate a submodel into the main model==
To reintegrate a submodel into the main model:
#Open the parent model
-#Right click on the submodel element in the model explorer (recognizable with the green decorator).
+#Right click on the submodel element in the Model Explorer (recognizable with the green decorator).
#Select ''Reintegrate Submodel''
[[Image:images/UncontrolAction.png]]
diff --git a/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ControlAction.png b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ControlAction.png
index e367d368785..d2ae4b42e11 100644
--- a/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ControlAction.png
+++ b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ControlAction.png
Binary files differ
diff --git a/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ControlDialog.png b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ControlDialog.png
index 6070123c5f1..73cb67e17db 100644
--- a/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ControlDialog.png
+++ b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ControlDialog.png
Binary files differ
diff --git a/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/Decorations.png b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/Decorations.png
new file mode 100644
index 00000000000..ace910b1d35
--- /dev/null
+++ b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/Decorations.png
Binary files differ
diff --git a/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ToggleSubmodelAction.png b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ToggleSubmodelAction.png
new file mode 100644
index 00000000000..67127c4f343
--- /dev/null
+++ b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/ToggleSubmodelAction.png
Binary files differ
diff --git a/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/UncontrolAction.png b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/UncontrolAction.png
index 9a8573519e3..5b525e97731 100644
--- a/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/UncontrolAction.png
+++ b/plugins/doc/org.eclipse.papyrus.infra.services.controlmode.doc/resource/images/UncontrolAction.png
Binary files differ
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);
+ }
}
}
}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/META-INF/MANIFEST.MF b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/META-INF/MANIFEST.MF
index 03a66ee9175..baca073f4d7 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/META-INF/MANIFEST.MF
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/META-INF/MANIFEST.MF
@@ -2,6 +2,8 @@ Manifest-Version: 1.0
Export-Package: org.eclipse.papyrus.infra.services.controlmode,
org.eclipse.papyrus.infra.services.controlmode.commands,
org.eclipse.papyrus.infra.services.controlmode.handler,
+ org.eclipse.papyrus.infra.services.controlmode.internal.handler;x-internal:=true,
+ org.eclipse.papyrus.infra.services.controlmode.internal.ui;x-internal:=true,
org.eclipse.papyrus.infra.services.controlmode.participants,
org.eclipse.papyrus.infra.services.controlmode.ui,
org.eclipse.papyrus.infra.services.controlmode.util;uses:="org.eclipse.emf.ecore"
@@ -15,7 +17,8 @@ Require-Bundle: org.eclipse.emf.edit.ui;bundle-version="[2.12.0,3.0.0)";visibili
org.eclipse.papyrus.infra.services.edit;bundle-version="[2.0.0,3.0.0)",
org.eclipse.papyrus.infra.core.sashwindows.di;bundle-version="[1.2.0,2.0.0)";visibility:=reexport,
org.eclipse.papyrus.infra.ui;bundle-version="[1.2.0,2.0.0)",
- org.eclipse.papyrus.infra.types.core;bundle-version="[3.0.0,4.0.0)"
+ org.eclipse.papyrus.infra.types.core;bundle-version="[3.0.0,4.0.0)",
+ org.eclipse.papyrus.infra.onefile;bundle-version="[2.0.0,3.0.0)"
Bundle-Vendor: %providerName
Bundle-ActivationPolicy: lazy
Bundle-Version: 1.4.0.qualifier
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/build.properties b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/build.properties
index 85f999f60cd..71872030c97 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/build.properties
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/build.properties
@@ -1,5 +1,15 @@
#
-#Mon Sep 12 09:29:37 CEST 2011
+# Copyright (c) 2009, 2016 Atos Origin, Christian W. Damus, 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:
+# Atos Origin - Initial API and implementation
+# Christian W. Damus - bug 497865
+#
bin.includes = META-INF/,\
.,\
plugin.xml,\
@@ -8,6 +18,7 @@ bin.includes = META-INF/,\
about.html,\
icons/,\
model/
+bin.excludes = icons/**/*.pxm
output..=bin/
src.includes = about.html
source..=src/
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco.png b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco.png
new file mode 100644
index 00000000000..f218590a367
--- /dev/null
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco.png
Binary files differ
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco.pxm b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco.pxm
new file mode 100644
index 00000000000..f650eb05258
--- /dev/null
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco.pxm
Binary files differ
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco@2x.png b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco@2x.png
new file mode 100644
index 00000000000..6f554582eb2
--- /dev/null
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/shard_deco@2x.png
Binary files differ
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco.png b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco.png
new file mode 100644
index 00000000000..7589ba96994
--- /dev/null
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco.png
Binary files differ
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco.pxm b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco.pxm
new file mode 100644
index 00000000000..a10adfda411
--- /dev/null
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco.pxm
Binary files differ
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco@2x.png b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco@2x.png
new file mode 100644
index 00000000000..8715e4e0f3d
--- /dev/null
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/icons/full/ovr16/submodel_deco@2x.png
Binary files differ
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/plugin.properties b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/plugin.properties
index db95d842854..7ccda077a6d 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/plugin.properties
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/plugin.properties
@@ -1,12 +1,32 @@
-#/*****************************************************************************
-# * Copyright (c) 2009 Atos Origin.
-# *
-# *
-# * 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
-# *
-# *****************************************************************************/
+#
+# Copyright (c) 2009, 2016 Atos Origin, Christian W. Damus, 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:
+# Atos Origin - Initial API and implementation
+# Christian W. Damus - bug 497865
+#
pluginName=Papyrus Control Mode
providerName=Eclipse Modeling Project
+
+cmd.control.desc = Move this submodel into its own resource (file)
+cmd.control.name = Create submodel unit
+cmd.control.showDlg.name = Show control mode dialog
+cmd.control.resource.name = Resource Location
+cmd.uncontrol.desc = Reintegrate this submodel into the resource (file) of the parent model
+cmd.uncontrol.name = Reintegrate submodel unit into parent model
+cmd.control.label = Create Submodel
+cmd.control.tip = Move this submodel into its own resource (file)
+cmd.uncontrol.label = Reintegrate Submodel
+cmd.uncontrol.tip = Reintegrate this submodel into the resource (file) of the parent model
+cmd.submodel.desc = Change whether the controlled unit is an independent sub-model unit
+cmd.submodel.name = Toggle Submodel Unit
+cmd.submodel.label = Independent Submodel
+cmd.submodel.tip = Change whether the controlled unit is an independent sub-model unit
+decorator.controlmode.label = Controlled Units
+decorator.controlmode.desc = Decorates controlled unit resources in the Project Explorer.
+extpt.participant.name = Control-mode Participants
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/plugin.xml b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/plugin.xml
index f1264b55313..78725c65d9a 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/plugin.xml
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/plugin.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
- <extension-point id="org.eclipse.papyrus.infra.services.controlmode.participant" name="participant" schema="schema/participant.exsd"/>
+ <extension-point id="org.eclipse.papyrus.infra.services.controlmode.participant" name="%extpt.participant.name" schema="schema/participant.exsd"/>
<extension
point="org.eclipse.core.expressions.propertyTesters">
<propertyTester
@@ -43,12 +43,12 @@
point="org.eclipse.ui.commands">
<command
defaultHandler="org.eclipse.papyrus.infra.services.controlmode.handler.ControlCommandHandler"
- description="Move this submodel into its own resource (file)"
+ description="%cmd.control.desc"
id="org.eclipse.papyrus.infra.services.controlmode.createsubmodel"
- name="Create submodel unit">
+ name="%cmd.control.name">
<commandParameter
id="org.eclipse.papyrus.infra.services.controlmode.useDialogParameter"
- name="Show control mode dialog"
+ name="%cmd.control.showDlg.name"
optional="true">
<values
class="org.eclipse.papyrus.infra.services.controlmode.commands.ControlModeCommandParameterValues">
@@ -56,7 +56,7 @@
</commandParameter>
<commandParameter
id="org.eclipse.papyrus.infra.services.controlmode.resourceLocation"
- name="Resource Location"
+ name="%cmd.control.resource.name"
optional="true">
<values
class="org.eclipse.papyrus.infra.services.controlmode.commands.ResourceLocationParameterValues">
@@ -65,9 +65,19 @@
</command>
<command
defaultHandler="org.eclipse.papyrus.infra.services.controlmode.handler.UncontrolCommandHandler"
- description="Reintegrate this submodel into the resource (file) of the parent model"
+ description="%cmd.uncontrol.desc"
id="org.eclipse.papyrus.infra.services.controlmode.reintegratesubmodel"
- name="Reintegrate submodel unit into parent model">
+ name="%cmd.uncontrol.name">
+ </command>
+ <command
+ defaultHandler="org.eclipse.papyrus.infra.services.controlmode.internal.handler.ToggleSubmodelHandler"
+ description="%cmd.submodel.desc"
+ id="org.eclipse.papyrus.infra.services.controlmode.toggleSubmodelStyle"
+ name="%cmd.submodel.name">
+ <state
+ id="org.eclipse.ui.commands.toggleState"
+ class="org.eclipse.papyrus.infra.services.controlmode.internal.handler.SubmodelState">
+ </state>
</command>
</extension>
<extension
@@ -78,9 +88,9 @@
<command
commandId="org.eclipse.papyrus.infra.services.controlmode.createsubmodel"
icon="icons/CreateSubModel_16.png"
- label="Create Submodel"
+ label="%cmd.control.label"
style="push"
- tooltip="Move this submodel into its own resource (file)">
+ tooltip="%cmd.control.tip">
<visibleWhen
checkEnabled="false">
<with
@@ -96,9 +106,33 @@
<command
commandId="org.eclipse.papyrus.infra.services.controlmode.reintegratesubmodel"
icon="icons/ReintegrateSubModel_16.png"
- label="Reintegrate Submodel"
+ label="%cmd.uncontrol.label"
style="push"
- tooltip="Reintegrate this submodel into the resource (file) of the parent model">
+ tooltip="%cmd.uncontrol.tip">
+ <visibleWhen
+ checkEnabled="false">
+ <with
+ variable="selection">
+ <and>
+ <test
+ forcePluginActivation="true"
+ property="org.eclipse.papyrus.infra.services.controlmode.isFragmentModel"
+ value="true">
+ </test>
+ <test
+ forcePluginActivation="true"
+ property="org.eclipse.papyrus.infra.services.controlmode.isParentLoaded"
+ value="true">
+ </test>
+ </and>
+ </with>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.papyrus.infra.services.controlmode.toggleSubmodelStyle"
+ label="%cmd.submodel.label"
+ style="toggle"
+ tooltip="%cmd.submodel.tip">
<visibleWhen
checkEnabled="false">
<with
@@ -127,4 +161,27 @@
path="model/controlmode.elementtypesconfigurations">
</elementTypeSet>
</extension>
+ <extension
+ point="org.eclipse.ui.decorators">
+ <decorator
+ class="org.eclipse.papyrus.infra.services.controlmode.internal.ui.ControlledUnitLabelDecorator"
+ id="org.eclipse.papyrus.infra.services.controlmode.ui.ControlledUnit"
+ label="%decorator.controlmode.label"
+ lightweight="true"
+ state="true">
+ <description>
+ %decorator.controlmode.desc
+ </description>
+ <enablement>
+ <or>
+ <objectClass
+ name="org.eclipse.core.resources.IFile">
+ </objectClass>
+ <objectClass
+ name="org.eclipse.papyrus.infra.onefile.model.IPapyrusFile">
+ </objectClass>
+ </or>
+ </enablement>
+ </decorator>
+ </extension>
</plugin>
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/schema/participant.exsd b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/schema/participant.exsd
index 58c31156260..ad0fe87029c 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/schema/participant.exsd
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/schema/participant.exsd
@@ -1,125 +1,128 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<!-- Schema file written by PDE -->
-<schema targetNamespace="org.eclipse.papyrus.infra.services.controlmode" xmlns="http://www.w3.org/2001/XMLSchema">
-<annotation>
- <appinfo>
- <meta.schema plugin="org.eclipse.papyrus.infra.services.controlmode" id="participant" name="Control Mode Participant"/>
- </appinfo>
- <documentation>
- This extension point is used to register participant to compute the control command.
-WARNING : The attribute ID is not being used for now
- </documentation>
- </annotation>
-
- <element name="extension">
- <annotation>
- <appinfo>
- <meta.element />
- </appinfo>
- </annotation>
- <complexType>
- <sequence>
- <element ref="participant" minOccurs="1" 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="participant">
- <annotation>
- <documentation>
- Participant to the control command. This participant should implements either IControlCommandParticipant or IUncontrolCommandParticipant or both
- </documentation>
- </annotation>
- <complexType>
- <attribute name="class" type="string" use="required">
- <annotation>
- <documentation>
- Class which implements the participant. This participant should implements either IControlCommandParticipant or IUncontrolCommandParticipant or both
- </documentation>
- <appinfo>
- <meta.attribute kind="java" basedOn=":org.eclipse.papyrus.infra.services.controlmode.participants.IControlModeParticipant"/>
- </appinfo>
- </annotation>
- </attribute>
- </complexType>
- </element>
-
- <annotation>
- <appinfo>
- <meta.section type="since"/>
- </appinfo>
- <documentation>
- 0.8.2
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="examples"/>
- </appinfo>
- <documentation>
- &lt;extension
- point=&quot;org.eclipse.papyrus.infra.services.controlmode.participant&quot;&gt;
- &lt;participant
- class=&quot;org.eclipse.papyrus.infra.services.controlmode.participants.NotationControlModeParticipant&quot;&gt;
- &lt;/participant&gt;
-&lt;/extension&gt;
- </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>
-
- <annotation>
- <appinfo>
- <meta.section type="copyright"/>
- </appinfo>
- <documentation>
- License
-
-The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available at http://www.eclipse.org/legal/epl-v10.html. For purposes of the EPL, &quot;Program&quot; will mean the Content.
-
-If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor&apos;s license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.
- </documentation>
- </annotation>
-
-</schema>
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.papyrus.infra.services.controlmode" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.papyrus.infra.services.controlmode" id="participant" name="Control Mode Participant"/>
+ </appinfo>
+ <documentation>
+ This extension point is used to register participant to compute the control command.
+WARNING : The attribute ID is not being used for now
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="participant" minOccurs="1" 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="participant">
+ <annotation>
+ <documentation>
+ Registration of a participant in the construction of control commands.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ Class that implements the participant. This participant should implements either IControlCommandParticipant or IUncontrolCommandParticipant or both.
+
+As of the 1.3 release, another participant interface may be
+implemented for validation of a control mode request: IControlCommandApprover.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.papyrus.infra.services.controlmode.participants.IControlModeParticipant"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 0.8.2
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ &lt;extension
+ point=&quot;org.eclipse.papyrus.infra.services.controlmode.participant&quot;&gt;
+ &lt;participant
+ class=&quot;org.eclipse.papyrus.infra.services.controlmode.participants.NotationControlModeParticipant&quot;&gt;
+ &lt;/participant&gt;
+&lt;/extension&gt;
+ </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>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2013, 2016 ATOS Origin, 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
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/epl-v10.html
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModeManager.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModeManager.java
index c24a70c8588..1fd54c7ffc4 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModeManager.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModeManager.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013 Atos.
+ * Copyright (c) 2013, 2016 Atos, Christian W. Damus, 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
@@ -7,19 +7,27 @@
*
* Contributors:
* Arthur Daussy <a href="mailto:arthur.daussy@atos.net"> - initial API and implementation
+ * Christian W. Damus - bug 497865
******************************************************************************/
package org.eclipse.papyrus.infra.services.controlmode;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
+import java.util.Objects;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.common.util.BasicDiagnostic;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.common.core.command.ICompositeCommand;
@@ -30,8 +38,10 @@ import org.eclipse.papyrus.infra.services.controlmode.commands.BasicUncontrolCom
import org.eclipse.papyrus.infra.services.controlmode.commands.CreateControlResource;
import org.eclipse.papyrus.infra.services.controlmode.commands.RemoveControlResourceCommand;
import org.eclipse.papyrus.infra.services.controlmode.messages.Messages;
+import org.eclipse.papyrus.infra.services.controlmode.participants.IControlCommandApprover;
import org.eclipse.papyrus.infra.services.controlmode.participants.IControlCommandParticipant;
import org.eclipse.papyrus.infra.services.controlmode.participants.IControlModeParticipant;
+import org.eclipse.papyrus.infra.services.controlmode.participants.IShardModeCommandParticipant;
import org.eclipse.papyrus.infra.services.controlmode.participants.IUncontrolCommandParticipant;
/**
@@ -66,6 +76,7 @@ public class ControlModeManager implements IControlModeManager {
*/
protected final class PartipantComparator implements Comparator<IControlModeParticipant> {
+ @Override
public int compare(IControlModeParticipant arg0, IControlModeParticipant arg1) {
int i = arg1.getPriority();
int j = arg0.getPriority();
@@ -95,21 +106,35 @@ public class ControlModeManager implements IControlModeManager {
protected static String PARTICPANT_ATTRIBUTE = "class"; //$NON-NLS-1$
/**
- * @return the unique instance of the manager
+ * Hold all the {@link IControlCommandParticipant}
*/
- public static IControlModeManager getInstance() {
- return SingletonHolder.INSTANCE;
- }
+ protected ArrayList<IControlCommandParticipant> controlCommandParticipants = new ArrayList<>();
/**
- * Hold all the {@link IControlCommandParticipant}
+ * Hold all the {@link IUncontrolCommandParticipant}
*/
- protected ArrayList<IControlCommandParticipant> controlCommandParticipants = new ArrayList<IControlCommandParticipant>();
+ protected ArrayList<IUncontrolCommandParticipant> uncontrolCommandParticipants = new ArrayList<>();
/**
- * Hold all the {@link IUncontrolCommandParticipant}
+ * Hold all the {@link IShardModeCommandParticipant}s.
+ *
+ * @since 1.3
*/
- protected ArrayList<IUncontrolCommandParticipant> uncontrolCommandParticipants = new ArrayList<IUncontrolCommandParticipant>();
+ protected List<IShardModeCommandParticipant> shardModeCommandParticipants = new ArrayList<>();
+
+ /**
+ * Hold all the {@link IControlCommandApprover}s.
+ *
+ * @since 1.3
+ */
+ protected List<IControlCommandApprover> controlCommandApprovers = new ArrayList<>();
+
+ /**
+ * @return the unique instance of the manager
+ */
+ public static IControlModeManager getInstance() {
+ return SingletonHolder.INSTANCE;
+ }
/**
*
@@ -118,6 +143,7 @@ public class ControlModeManager implements IControlModeManager {
initParticipants();
}
+ @Override
public ICommand getControlCommand(ControlModeRequest request) {
boolean isOK = verifCorrectCommand(request);
if (!isOK) {
@@ -169,7 +195,7 @@ public class ControlModeManager implements IControlModeManager {
*/
protected ICompositeCommand getPostCommand(ControlModeRequest request) {
boolean isControlRequest = request.isControlRequest();
- CompositeTransactionalCommand cc = new CompositeTransactionalCommand(request.getEditingDomain(), isControlRequest ? CONTROL_COMMAND_POST_COMMANDS : UNCONTROL_COMMAND_POST_COMMANDS);//////$NON-NLS-1$ //$NON-NLS-2$
+ CompositeTransactionalCommand cc = new CompositeTransactionalCommand(request.getEditingDomain(), isControlRequest ? CONTROL_COMMAND_POST_COMMANDS : UNCONTROL_COMMAND_POST_COMMANDS);////// $NON-NLS-1$ //$NON-NLS-2$
if (isControlRequest) {
getPostControlCommand(request, cc);
} else {
@@ -275,6 +301,7 @@ public class ControlModeManager implements IControlModeManager {
}
}
+ @Override
public ICommand getUncontrolCommand(ControlModeRequest request) {
boolean isOK = verifCorrectCommand(request);
if (!isOK) {
@@ -302,6 +329,122 @@ public class ControlModeManager implements IControlModeManager {
}
/**
+ * @since 1.3
+ */
+ protected List<IShardModeCommandParticipant> getShardModeCommandParticipants() {
+ return shardModeCommandParticipants;
+ }
+
+ /**
+ * @since 1.3
+ */
+ @Override
+ public ICommand getShardModeCommand(ControlModeRequest request) {
+ // This does validation of the request, too
+ ICommand baseCommand = IControlModeManager.super.getShardModeCommand(request);
+
+ // Include participants
+
+ ICommand result = new CompositeTransactionalCommand(request.getEditingDomain(), Messages.getString("ControlModeManager.changeControlModeCommand.label")); //$NON-NLS-1$
+ ICommand preCommand = getPreShardModeCommand(request);
+ if (preCommand != null) {
+ result = result.compose(preCommand);
+ }
+
+ result = result.compose(baseCommand);
+
+ ICommand postCommand = getPostShardModeCommand(request);
+ if (postCommand != null) {
+ result = result.compose(postCommand);
+ }
+
+ return result.reduce();
+ }
+
+ /**
+ * @since 1.3
+ */
+ protected ICommand getPreShardModeCommand(ControlModeRequest request) {
+ return getParticipantCommand(request,
+ getShardModeCommandParticipants(),
+ IShardModeCommandParticipant::providesShardModeCommand,
+ IShardModeCommandParticipant::getPreShardModeCommand);
+ }
+
+ /**
+ * @since 1.3
+ */
+ protected ICommand getPostShardModeCommand(ControlModeRequest request) {
+ return getParticipantCommand(request,
+ getShardModeCommandParticipants(),
+ IShardModeCommandParticipant::providesShardModeCommand,
+ IShardModeCommandParticipant::getPostShardModeCommand);
+ }
+
+ private <P extends IControlModeParticipant> ICommand getParticipantCommand(ControlModeRequest request,
+ Collection<? extends P> participants,
+ BiPredicate<? super P, ? super ControlModeRequest> filter,
+ BiFunction<? super P, ? super ControlModeRequest, ICommand> commandFunction) {
+
+ return participants.stream()
+ .filter(p -> filter.test(p, request))
+ .map(p -> commandFunction.apply(p, request))
+ .filter(Objects::nonNull)
+ .reduce(ICommand::compose)
+ .orElse(null);
+ }
+
+ /**
+ * @since 1.3
+ */
+ @Override
+ public Diagnostic approveRequest(ControlModeRequest request) {
+ Diagnostic result;
+
+ Collection<? extends IControlCommandApprover> approvers = getControlCommandApprovers();
+ if (approvers.isEmpty()) {
+ result = Diagnostic.OK_INSTANCE;
+ } else {
+ result = approvers.stream()
+ .map(a -> a.approveRequest(request))
+ .filter(Objects::nonNull)
+ .reduce(Diagnostic.OK_INSTANCE, this::merge);
+ }
+
+ return result;
+ }
+
+ private Diagnostic merge(Diagnostic a, Diagnostic b) {
+ return (a.getSeverity() == Diagnostic.OK)
+ ? b
+ : (b.getSeverity() == Diagnostic.OK)
+ ? a
+ : merge(new BasicDiagnostic(a.getSource(), a.getCode(), a.getMessage(), null), a, b);
+ }
+
+ private <D extends DiagnosticChain> D merge(D chain, Diagnostic a, Diagnostic b) {
+ chain.merge(a);
+ chain.merge(b);
+ return chain;
+ }
+
+ /**
+ * @since 1.3
+ */
+ @Override
+ public boolean canCreateSubmodel(EObject objectToControl) {
+ Collection<? extends IControlCommandApprover> approvers = getControlCommandApprovers();
+ return approvers.isEmpty() || approvers.stream().allMatch(a -> a.canCreateSubModel(objectToControl));
+ }
+
+ /**
+ * @since 1.3
+ */
+ protected List<IControlCommandApprover> getControlCommandApprovers() {
+ return controlCommandApprovers;
+ }
+
+ /**
* Init the manager with all particpants
*/
protected void initParticipants() {
@@ -315,6 +458,12 @@ public class ControlModeManager implements IControlModeManager {
if (particpant instanceof IUncontrolCommandParticipant) {
getUncontrolCommandParticipants().add((IUncontrolCommandParticipant) particpant);
}
+ if (particpant instanceof IShardModeCommandParticipant) {
+ getShardModeCommandParticipants().add((IShardModeCommandParticipant) particpant);
+ }
+ if (particpant instanceof IControlCommandApprover) {
+ getControlCommandApprovers().add((IControlCommandApprover) particpant);
+ }
} catch (CoreException exception) {
exception.printStackTrace();
}
@@ -322,5 +471,7 @@ public class ControlModeManager implements IControlModeManager {
PartipantComparator comparator = new PartipantComparator();
Collections.sort(uncontrolCommandParticipants, comparator);
Collections.sort(controlCommandParticipants, comparator);
+ Collections.sort(shardModeCommandParticipants, comparator);
+ Collections.sort(controlCommandApprovers, comparator);
}
}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModePlugin.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModePlugin.java
index 2e777ec45e9..7d797a13c17 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModePlugin.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModePlugin.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2010 Atos Origin.
+ * Copyright (c) 2010, 2016 Atos Origin, Christian W. Damus, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,10 +9,12 @@
*
* Contributors:
* Emilien Perico (Atos Origin) emilien.perico@atosorigin.com - Initial API and implementation
+ * Christian W. Damus - bug 497865
*
*****************************************************************************/
package org.eclipse.papyrus.infra.services.controlmode;
+import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.papyrus.infra.core.log.LogHelper;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
@@ -58,4 +60,22 @@ public class ControlModePlugin extends AbstractUIPlugin {
return plugin;
}
+ /**
+ * Gets an icon from this bundle.
+ *
+ * @param path
+ * the icon path. If it does not start with {@code "icons/"} then it
+ * is assumed to be relative to the icons directory
+ *
+ * @return the image descriptor for the icon
+ *
+ * @since 1.3
+ */
+ public ImageDescriptor getIcon(String path) {
+ if (!path.startsWith("icons/")) { //$NON-NLS-1$
+ path = "icons/" + path; //$NON-NLS-1$
+ }
+ return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path);
+ }
+
}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModeRequestParameters.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModeRequestParameters.java
index c7f619f750c..c792d281215 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModeRequestParameters.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ControlModeRequestParameters.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 Atos.
+ * Copyright (c) 2013, 2016 Atos, Christian W. Damus, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,6 +9,7 @@
*
* Contributors:
* Arthur Daussy (Atos) arthur.daussy@atos.net - Initial API and implementation
+ * Christian W. Damus - bug 497865
*
*****************************************************************************/
@@ -43,4 +44,26 @@ public interface ControlModeRequestParameters {
*/
public static String MOVED_OPENABLES = "org.eclipse.papyrus.infra.services.controlmode.ControlModeRequestParameters.MovedOpenables"; //$NON-NLS-1$
+ /**
+ * Key used to store the 'create a shard resource' option in the control request.
+ * The value is a boolean and its default is {@code false}.
+ *
+ * @since 1.3
+ */
+ public static String CREATE_SHARD = "org.eclipse.papyrus.infra.services.controlmode.ControlModeRequestParameters.CreateShard"; //$NON-NLS-1$
+
+ /**
+ * Queries whether a {@code request} is configured to create a 'shard' resource.
+ *
+ * @param request
+ * a control mode request
+ *
+ * @return whether the {@code request} is a control request with the shard option
+ *
+ * @since 1.3
+ * @see #CREATE_SHARD
+ */
+ public static boolean isCreateShard(ControlModeRequest request) {
+ return request.isControlRequest() && Boolean.TRUE.equals(request.getParameter(CREATE_SHARD));
+ }
}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/IControlModeManager.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/IControlModeManager.java
index 237d33b81e5..e8680b11ef0 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/IControlModeManager.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/IControlModeManager.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013 Atos.
+ * Copyright (c) 2013, 2016 Atos, Christian W. Damus, 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
@@ -7,10 +7,23 @@
*
* Contributors:
* Arthur Daussy <a href="mailto:arthur.daussy@atos.net"> - initial API and implementation
+ * Christian W. Damus - bug 497865
******************************************************************************/
package org.eclipse.papyrus.infra.services.controlmode;
+import static org.eclipse.papyrus.infra.services.controlmode.ControlModeRequestParameters.isCreateShard;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.papyrus.infra.emf.gmf.command.EMFtoGMFCommandWrapper;
+import org.eclipse.papyrus.infra.emf.resource.ShardResourceHelper;
+import org.eclipse.papyrus.infra.services.controlmode.participants.IControlCommandApprover;
/**
* A control manger is able to compute a command in order to control or uncontrol an element from a {@link ControlModeRequest}.
@@ -37,4 +50,85 @@ public interface IControlModeManager {
*/
public ICommand getUncontrolCommand(ControlModeRequest request);
+ /**
+ * Obtains a command to change only the 'shard' mode of an already
+ * controlled object.
+ *
+ * @param request
+ * a request, which must be a
+ * {@link ControlModeRequest#isControlRequest() control} request
+ * it simply changes the sub-unit structure between
+ * 'sub-model' and 'shard' unit type
+ *
+ * @return the command to change the 'shard' mode of an object
+ *
+ * @throws IllegalArgumentException
+ * if the {@code request} is of the wrong
+ * kind or does not correctly specify the new 'shard' mode
+ * to configure
+ *
+ * @since 1.3
+ */
+ public default ICommand getShardModeCommand(ControlModeRequest request) {
+ // We don't know how to include participants in this
+
+ if (!request.isControlRequest()) {
+ throw new IllegalArgumentException("not a control request"); //$NON-NLS-1$
+ }
+ if (request.getParameter(ControlModeRequestParameters.CREATE_SHARD) == null) {
+ throw new IllegalArgumentException("no shard mode parameter in request"); //$NON-NLS-1$
+ }
+ if (request.getTargetObject() == null) {
+ throw new IllegalArgumentException("no target object in request"); //$NON-NLS-1$
+ }
+
+ Command baseCommand;
+ EObject object = request.getTargetObject();
+
+ try (ShardResourceHelper helper = new ShardResourceHelper(object)) {
+ baseCommand = helper.getSetShardCommand(isCreateShard(request));
+ }
+
+ // Some components want to get affected files before executing, but the
+ // affected-objects list of an AddCommand is null until it is executed
+ // and this would cause an NPE in the inference of affected files
+ return new EMFtoGMFCommandWrapper(baseCommand) {
+ @SuppressWarnings("rawtypes")
+ @Override
+ public List getAffectedFiles() {
+ return Arrays.asList(WorkspaceSynchronizer.getFile(object.eResource()));
+ }
+ };
+ }
+
+ /**
+ * Queries whether the given {@code request} is approved for processing
+ * to construct a command. Any {@code false} result vetoes the request.
+ *
+ * @param request
+ * a proposed control or uncontrol request
+ *
+ * @return a diagnostic result according to the
+ * {@link IControlCommandApprover#approveRequest(ControlModeRequest)} protocol
+ *
+ * @since 1.3
+ */
+ public default Diagnostic approveRequest(ControlModeRequest request) {
+ return Diagnostic.OK_INSTANCE;
+ }
+
+ /**
+ * Queries whether the given object can be controlled as an independent sub-model unit.
+ *
+ * @param objectToControl
+ * an object to be controlled
+ *
+ * @return whether an independent sub-model unit is supported for the object,
+ * according to the {@link IControlCommandApprover#canCreateSubModel(EObject)} protocol
+ *
+ * @since 1.3
+ */
+ public default boolean canCreateSubmodel(EObject objectToControl) {
+ return true;
+ }
}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/commands/BasicControlCommand.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/commands/BasicControlCommand.java
index e1395fb9c69..880777688ff 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/commands/BasicControlCommand.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/commands/BasicControlCommand.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 Atos.
+ * Copyright (c) 2013, 2016 Atos, Christian W. Damus, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,6 +9,7 @@
*
* Contributors:
* Arthur Daussy (Atos) arthur.daussy@atos.net - Initial API and implementation
+ * Christian W. Damus - bug 497865
*
*****************************************************************************/
package org.eclipse.papyrus.infra.services.controlmode.commands;
@@ -24,7 +25,9 @@ import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
+import org.eclipse.papyrus.infra.emf.resource.ShardResourceHelper;
import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequestParameters;
import org.eclipse.papyrus.infra.services.controlmode.messages.Messages;
/**
@@ -67,6 +70,14 @@ public class BasicControlCommand extends AbstractControlCommand {
objectToControl.eResource().setModified(true);
}
resource.getContents().add(objectToControl);
+
+ // Should we create the unit as a 'shard' resource?
+ if (ControlModeRequestParameters.isCreateShard(getRequest())) {
+ try (ShardResourceHelper helper = new ShardResourceHelper(objectToControl)) {
+ helper.setShard(true);
+ }
+ }
+
return CommandResult.newOKCommandResult(resource);
}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/handler/ControlCommandHandler.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/handler/ControlCommandHandler.java
index 863ec49631a..3a9e5211b94 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/handler/ControlCommandHandler.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/handler/ControlCommandHandler.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013, 2014 Atos, CEA LIST, and others.
+ * Copyright (c) 2013, 2016 Atos, CEA LIST, Christian W. Damus, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -13,6 +13,7 @@
* Christian W. Damus (CEA) - bug 410346
* Juan Cadavid <juan.cadavid@cea.fr> - bug 399877
* Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Bug 436952
+ * Christian W. Damus - bug 497865
*
*****************************************************************************/
package org.eclipse.papyrus.infra.services.controlmode.handler;
@@ -25,6 +26,9 @@ import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.ParameterValuesException;
import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.emf.common.util.BasicDiagnostic;
+import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
@@ -37,7 +41,6 @@ import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
import org.eclipse.papyrus.infra.core.services.ServiceException;
-import org.eclipse.papyrus.infra.core.utils.AdapterUtils;
import org.eclipse.papyrus.infra.emf.gmf.command.GMFtoEMFCommandWrapper;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForEObject;
@@ -50,9 +53,11 @@ import org.eclipse.papyrus.infra.services.controlmode.commands.ResourceLocationP
import org.eclipse.papyrus.infra.services.controlmode.messages.Messages;
import org.eclipse.papyrus.infra.services.controlmode.ui.IControlModeFragmentDialogProvider;
import org.eclipse.papyrus.infra.services.controlmode.util.LabelHelper;
+import org.eclipse.papyrus.infra.tools.util.PlatformHelper;
import org.eclipse.papyrus.infra.widgets.toolbox.notification.builders.NotificationBuilder;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
/**
* Handler used to control an element
@@ -82,6 +87,7 @@ public class ControlCommandHandler extends AbstractHandler {
/** The Constant CONTROLMODE_USE_DIALOG_PARAMETER. */
public static final String CONTROLMODE_USE_DIALOG_PARAMETER = "org.eclipse.papyrus.infra.services.controlmode.useDialogParameter"; //$NON-NLS-1$
+ @Override
public Object execute(ExecutionEvent event) throws ExecutionException {
ISelection selection = HandlerUtil.getCurrentSelection(event);
@@ -95,12 +101,18 @@ public class ControlCommandHandler extends AbstractHandler {
TransactionalEditingDomain editingDomain = ServiceUtilsForEObject.getInstance().getTransactionalEditingDomain(eObjectToControl);
if (getShowDialogParameterValue(event)) {
IControlModeFragmentDialogProvider provider = getDialogProvider(eObjectToControl);
- Dialog dialog = provider.createDialog(Display.getCurrent().getActiveShell(), eObjectToControl.eResource(), getDefaultLabelResource(eObjectToControl));
+ Dialog dialog = provider.createDialog(Display.getCurrent().getActiveShell(), eObjectToControl, getDefaultLabelResource(eObjectToControl));
if (dialog.open() == Window.OK) {
- ControlModeRequest controlRequest = ControlModeRequest.createUIControlModelRequest(editingDomain, eObjectToControl, provider.getSelectedURI(dialog));
+ ControlModeRequest controlRequest = provider.getControlRequest(dialog, editingDomain, eObjectToControl);
IControlModeManager controlMng = ControlModeManager.getInstance();
- ICommand controlCommand = controlMng.getControlCommand(controlRequest);
- editingDomain.getCommandStack().execute(new GMFtoEMFCommandWrapper(controlCommand));
+ Diagnostic problems = controlMng.approveRequest(controlRequest);
+ if ((problems != null) && (problems.getSeverity() >= Diagnostic.ERROR)) {
+ IStatus status = BasicDiagnostic.toIStatus(problems);
+ StatusManager.getManager().handle(status, StatusManager.SHOW);
+ } else {
+ ICommand controlCommand = controlMng.getControlCommand(controlRequest);
+ editingDomain.getCommandStack().execute(new GMFtoEMFCommandWrapper(controlCommand));
+ }
}
} else {
URI resourceURI = getParameterisedURI(event);
@@ -177,7 +189,7 @@ public class ControlCommandHandler extends AbstractHandler {
IControlModeFragmentDialogProvider getDialogProvider(EObject context) {
try {
ModelSet modelSet = ServiceUtilsForEObject.getInstance().getModelSet(context);
- return AdapterUtils.adapt(modelSet, IControlModeFragmentDialogProvider.class, IControlModeFragmentDialogProvider.DEFAULT);
+ return PlatformHelper.getAdapter(modelSet, IControlModeFragmentDialogProvider.class, IControlModeFragmentDialogProvider.DEFAULT);
} catch (ServiceException e) {
// can't get the model set? Odd
ControlModePlugin.log.error(MODELSET_ERROR, e);
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/handler/UncontrolCommandHandler.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/handler/UncontrolCommandHandler.java
index 0031ed0712a..b27397ebe79 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/handler/UncontrolCommandHandler.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/handler/UncontrolCommandHandler.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 Atos.
+ * Copyright (c) 2013, 2016 Atos, Christian W. Damus, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -10,6 +10,7 @@
* Contributors:
* Arthur Daussy (Atos) arthur.daussy@atos.net - Initial API and implementation
* Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Bug 436952
+ * Christian W. Damus - bug 497865
*
*****************************************************************************/
package org.eclipse.papyrus.infra.services.controlmode.handler;
@@ -17,6 +18,9 @@ package org.eclipse.papyrus.infra.services.controlmode.handler;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.emf.common.util.BasicDiagnostic;
+import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
@@ -32,6 +36,7 @@ import org.eclipse.papyrus.infra.services.controlmode.messages.Messages;
import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForSelection;
import org.eclipse.papyrus.infra.widgets.toolbox.notification.builders.NotificationBuilder;
import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
/**
* Handler use to uncontrol an element
@@ -54,6 +59,7 @@ public class UncontrolCommandHandler extends AbstractHandler {
* @return
* @throws ExecutionException
*/
+ @Override
public Object execute(ExecutionEvent event) throws ExecutionException {
ISelection selection = HandlerUtil.getCurrentSelection(event);
@@ -68,8 +74,15 @@ public class UncontrolCommandHandler extends AbstractHandler {
EObject eObjectToControl = EMFHelper.getEObject(((IStructuredSelection) selection).getFirstElement());
ControlModeRequest controlRequest = ControlModeRequest.createUIUncontrolModelRequest(editingDomain, eObjectToControl);
IControlModeManager controlMng = ControlModeManager.getInstance();
- ICommand controlCommand = controlMng.getUncontrolCommand(controlRequest);
- editingDomain.getCommandStack().execute(new GMFtoEMFCommandWrapper(controlCommand));
+
+ Diagnostic problems = controlMng.approveRequest(controlRequest);
+ if ((problems != null) && (problems.getSeverity() >= Diagnostic.ERROR)) {
+ IStatus status = BasicDiagnostic.toIStatus(problems);
+ StatusManager.getManager().handle(status, StatusManager.SHOW);
+ } else {
+ ICommand controlCommand = controlMng.getUncontrolCommand(controlRequest);
+ editingDomain.getCommandStack().execute(new GMFtoEMFCommandWrapper(controlCommand));
+ }
} catch (ServiceException e) {
NotificationBuilder.createInfoPopup(NO_EDITING_DOMAIN_MESSAGE).run();
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/handler/SubmodelState.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/handler/SubmodelState.java
new file mode 100644
index 00000000000..24958a5435b
--- /dev/null
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/handler/SubmodelState.java
@@ -0,0 +1,119 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus 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 - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.services.controlmode.internal.handler;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.Objects;
+
+import org.eclipse.core.commands.State;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.papyrus.infra.emf.resource.ShardResourceHelper;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeManager;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * The current "sub-model" toggle state of an element.
+ *
+ * @see ToggleSubmodelHandler
+ */
+public class SubmodelState extends State implements ISelectionListener {
+
+ private ISelectionService selectionService = null;
+
+ private Reference<EObject> selectedElement;
+
+ /**
+ * Initializes me.
+ */
+ public SubmodelState() {
+ super();
+
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+
+ if (window != null) {
+ selectionService = window.getSelectionService();
+ if (selectionService != null) {
+ selectionService.addSelectionListener(this);
+ update(selectionService.getSelection());
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+ if (selectionService != null) {
+ selectionService.removeSelectionListener(this);
+ }
+
+ super.dispose();
+ }
+
+ @Override
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ update(selection);
+ }
+
+ private void update(ISelection selection) {
+ // Default state is not canonical
+ boolean state = false;
+
+ selectedElement = null;
+
+ if (selection instanceof IStructuredSelection) {
+ EObject element = ((List<?>) ((IStructuredSelection) selection).toList()).stream()
+ .map(EMFHelper::getEObject)
+ .filter(Objects::nonNull)
+ .findFirst().orElse(null);
+ if (element != null) {
+ selectedElement = new WeakReference<>(element);
+ state = ControlModeManager.getInstance().canCreateSubmodel(element);
+ }
+ }
+
+ // Fires notification if changed from previous state
+ setValue(state);
+ }
+
+ // I am a computed value, actually
+ @Override
+ public Object getValue() {
+ boolean result = false;
+
+ EObject element = (selectedElement == null) ? null : selectedElement.get();
+ if (element != null) {
+ result = isIndependentSubmodel(element);
+ }
+
+ return result;
+ }
+
+ static boolean isIndependentSubmodel(EObject object) {
+ boolean result = false;
+
+ try (ShardResourceHelper helper = new ShardResourceHelper(object)) {
+ result = !helper.isShard();
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/handler/ToggleSubmodelHandler.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/handler/ToggleSubmodelHandler.java
new file mode 100644
index 00000000000..eb193675058
--- /dev/null
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/handler/ToggleSubmodelHandler.java
@@ -0,0 +1,108 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus 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 - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.services.controlmode.internal.handler;
+
+import static org.eclipse.papyrus.infra.emf.gmf.command.ICommandWrapper.wrap;
+
+import java.util.List;
+import java.util.Objects;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.papyrus.infra.emf.resource.ShardResourceHelper;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeManager;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequestParameters;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Handler for the "toggle sub-model style" command. It is only enabled for
+ * objects that are capable of the independent sub-model semantics, according
+ * to registered control-mode participants.
+ */
+public class ToggleSubmodelHandler extends AbstractHandler {
+
+ /**
+ * Initializes me.
+ */
+ public ToggleSubmodelHandler() {
+ super();
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ EObject selection = getSelection(event.getApplicationContext());
+
+ if (selection != null) {
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(selection);
+ if (domain != null) {
+ // Note that the object is already controlled, so the 'new URI' is not so new
+ ControlModeRequest request = ControlModeRequest.createUIControlModelRequest(
+ domain, selection, selection.eResource().getURI());
+
+ // Toggle the state
+ try (ShardResourceHelper helper = new ShardResourceHelper(selection)) {
+ request.setParameter(ControlModeRequestParameters.CREATE_SHARD, !helper.isShard());
+ }
+
+ ICommand modelCommand = ControlModeManager.getInstance().getShardModeCommand(request);
+ if ((modelCommand != null) && modelCommand.canExecute()) {
+ domain.getCommandStack().execute(wrap(modelCommand, Command.class));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ EObject getSelection(Object evaluationContext) {
+ EObject result = null;
+
+ Object value = HandlerUtil.getVariable(evaluationContext, ISources.ACTIVE_CURRENT_SELECTION_NAME);
+ if (value instanceof ISelection) {
+ IStructuredSelection selection = (IStructuredSelection) value;
+ result = ((List<?>) selection.toList()).stream()
+ .map(EMFHelper::getEObject)
+ .filter(Objects::nonNull)
+ .findFirst()
+ .orElse(null);
+ }
+
+ return result;
+ }
+
+ @Override
+ public void setEnabled(Object evaluationContext) {
+ boolean enabled = false;
+
+ EObject selection = getSelection(evaluationContext);
+ if (selection != null) {
+ // If it shouldn't be sub-model-able but it actually is, then let
+ // it be converted to a shard unit
+ enabled = ControlModeManager.getInstance().canCreateSubmodel(selection)
+ || SubmodelState.isIndependentSubmodel(selection);
+ }
+
+ setBaseEnabled(enabled);
+ }
+}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/ui/ControlledUnitLabelDecorator.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/ui/ControlledUnitLabelDecorator.java
new file mode 100644
index 00000000000..e80bbe48a12
--- /dev/null
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/internal/ui/ControlledUnitLabelDecorator.java
@@ -0,0 +1,184 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus 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 - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.services.controlmode.internal.ui;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.BaseLabelProvider;
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.ILightweightLabelDecorator;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
+import org.eclipse.papyrus.infra.emf.internal.resource.CrossReferenceIndex;
+import org.eclipse.papyrus.infra.emf.resource.ICrossReferenceIndex;
+import org.eclipse.papyrus.infra.onefile.model.IPapyrusFile;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModePlugin;
+import org.eclipse.papyrus.infra.tools.util.CoreExecutors;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * A label decorator for controlled-unit resources in the Project Explorer.
+ */
+public class ControlledUnitLabelDecorator extends BaseLabelProvider implements ILightweightLabelDecorator {
+
+ private ICrossReferenceIndex index;
+ private Runnable unregisterHandler;
+
+ /**
+ * Initializes me.
+ */
+ public ControlledUnitLabelDecorator() {
+ super();
+
+ // A very coarse-grained label change event
+ index = CrossReferenceIndex.getInstance();
+ unregisterHandler = CrossReferenceIndex.getInstance().onIndexChanged(
+ __ -> fireLabelProviderChanged(new LabelProviderChangedEvent(this)),
+ CoreExecutors.getUIExecutorService());
+ }
+
+ @Override
+ public void dispose() {
+ try {
+ if (unregisterHandler != null) {
+ unregisterHandler.run();
+ unregisterHandler = null;
+ }
+ } finally {
+ super.dispose();
+ }
+ }
+
+ @Override
+ public void decorate(Object element, IDecoration decoration) {
+ if (element instanceof IFile) {
+ decorateFile((IFile) element, decoration);
+ } else if (element instanceof IPapyrusFile) {
+ decorateFile((IPapyrusFile) element, decoration);
+ }
+ }
+
+ private void decorateFile(IFile file, IDecoration decoration) {
+ ListenableFuture<SubunitKind> futureKind = getSubunitKind(file);
+ if (futureKind.isDone()) {
+ SubunitKind kind = Futures.getUnchecked(futureKind);
+ if (kind != SubunitKind.NONE) {
+ addOverlay(decoration, kind);
+ }
+ } else {
+ futureKind.addListener(postUpdate(file), CoreExecutors.getUIExecutorService());
+ }
+ }
+
+ private void decorateFile(IPapyrusFile file, IDecoration decoration) {
+ List<ListenableFuture<SubunitKind>> kindFutures = Lists.newArrayListWithExpectedSize(3);
+
+ for (IResource resource : file.getAssociatedResources()) {
+ if (resource.getType() == IResource.FILE) {
+ kindFutures.add(getSubunitKind((IFile) resource));
+ }
+ }
+
+ ListenableFuture<List<SubunitKind>> futureKinds = Futures.allAsList(kindFutures);
+ if (futureKinds.isDone()) {
+ SubunitKind kind = SubunitKind.max(Futures.getUnchecked(futureKinds));
+
+ if (kind != SubunitKind.NONE) {
+ addOverlay(decoration, kind);
+ }
+ } else {
+ futureKinds.addListener(postUpdate(file), CoreExecutors.getUIExecutorService());
+ }
+ }
+
+ private void addOverlay(IDecoration decoration, SubunitKind kind) {
+ decoration.addOverlay(kind.getIcon(), IDecoration.TOP_RIGHT); // $NON-NLS-1$
+ }
+
+ private ListenableFuture<SubunitKind> getSubunitKind(IFile file) {
+ URI uri = URI.createPlatformResourceURI(file.getFullPath().toPortableString(), true);
+
+ // If it has any parents, it is at least a sub-model unit
+ ListenableFuture<Set<URI>> parents = index.getParentsAsync(uri, false);
+ ListenableFuture<Boolean> isShard = index.isShardAsync(uri);
+
+ Function<Object, SubunitKind> kindFunction = __ -> {
+ SubunitKind result = SubunitKind.NONE;
+
+ // Both are guaranteed done now
+ if (!Futures.getUnchecked(parents).isEmpty()) {
+ // It is at least a sub-model unit
+ result = Futures.getUnchecked(isShard)
+ ? SubunitKind.SHARD
+ : SubunitKind.SUBMODEL;
+ }
+
+ return result;
+ };
+
+ @SuppressWarnings("unchecked")
+ ListenableFuture<?> combined = Futures.allAsList(parents, isShard);
+ return Futures.transform(combined, kindFunction);
+ }
+
+ private Runnable postUpdate(Object element) {
+ return new Runnable() {
+
+ @Override
+ public void run() {
+ fireLabelProviderChanged(new LabelProviderChangedEvent(ControlledUnitLabelDecorator.this, element));
+ }
+ };
+ }
+
+ //
+ // Nested types
+ //
+
+ private enum SubunitKind {
+ NONE, SUBMODEL, SHARD;
+
+ ImageDescriptor getIcon() {
+ ImageDescriptor result;
+
+ switch (this) {
+ case SHARD:
+ result = ControlModePlugin.getDefault().getIcon("full/ovr16/shard_deco.png"); //$NON-NLS-1$
+ break;
+ case SUBMODEL:
+ result = ControlModePlugin.getDefault().getIcon("full/ovr16/submodel_deco.png"); //$NON-NLS-1$
+ break;
+ default:
+ result = null;
+ break;
+ }
+
+ return result;
+ }
+
+ static SubunitKind max(Collection<SubunitKind> kinds) {
+ return kinds.isEmpty() ? NONE : Collections.max(kinds);
+ }
+ }
+}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/messages/messages.properties b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/messages/messages.properties
index 338a61ff9d2..71be1ed9c4e 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/messages/messages.properties
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/messages/messages.properties
@@ -1,3 +1,16 @@
+#
+# Copyright (c) 2014, 2016 CEA LIST, Christian W. Damus, 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:
+# Gabriel Pascual (ALL4TEC) - Initial API and implementation
+# Christian W. Damus - bug 497865
+#
+
AbstractControlResourceCommand.object.error=EObject not link to resource set
AbstractSatelliteResourceParticipant.command.title={0} Composite Command [ {1} ]
AbstractSatelliteResourceParticipant.control.post.label=Post Control
@@ -21,6 +34,7 @@ ControlCommandHandler.empty.selection.message=Nothing to control
ControlCommandHandler.modelset.error=Cannot obtain ModelSet for controlled object.
ControlCommandHandler.parameter.error=Parameter not defined for control mode command.
ControlCommandHandler.parameter.value.error=Parameter values exception in control mode command.
+ControlModeManager.changeControlModeCommand.label=Change Control Mode
ControlModeManager.control.command.parent.title=Control command [Composite parent]
ControlModeManager.post.commands.label=Control Command [ Post commands]
ControlModeManager.pre.commands.label=Control Command [ Pre commands]
@@ -31,6 +45,7 @@ CreateControlResource.command.title=Create a control resource
CreateControlResource.modelset.error=Unable to get model set
CreateControlResource.resource.error=Unable to create new resource to control
CreateModelFragmentDialog.dialog.title=Submodel Resource
+CreateModelFragmentDialog.submodel.checkbox=Create an independent submodel resource
LabelHelper.label.error=Error in getting correct label
OptionalMessageDialog.checkbox.label=Do not show this message again
RemoveControlResourceCommand.command.title=Uncontrol command
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IControlCommandApprover.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IControlCommandApprover.java
new file mode 100644
index 00000000000..2da187173ad
--- /dev/null
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IControlCommandApprover.java
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus 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 - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.services.controlmode.participants;
+
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
+
+/**
+ * An optional participant protocol for approval of {@link ControlModeRequest}s
+ * before an attempt is made to execute them.
+ *
+ * @since 1.3
+ */
+public interface IControlCommandApprover extends IControlModeParticipant {
+ /**
+ * Queries whether the given {@code request} is approved for processing
+ * to construct a command. Any {@linkplain Diagnostic#ERROR error} result
+ * vetoes the request.
+ *
+ * @param request
+ * a proposed control or uncontrol request
+ *
+ * @return a diagnostic indicating approval ({@link Diagnostic#OK}) or
+ * not (usually {@link Diagnostic#ERROR}). A {@link DiagnosticChain} may
+ * be returned to report multiple problems
+ */
+ default Diagnostic approveRequest(ControlModeRequest request) {
+ return Diagnostic.OK_INSTANCE;
+ }
+
+ /**
+ * Queries whether it should be permitted to create a sub-model resource
+ * (independently openable) for the given object. If any approver returns
+ * {@code false}, then creating a sub-model is vetoed.
+ *
+ * @param objectToControl
+ * an object to be controlled
+ *
+ * @return whether it may be created as a sub-model
+ */
+ default boolean canCreateSubModel(EObject objectToControl) {
+ return true;
+ }
+}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IShardModeCommandParticipant.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IShardModeCommandParticipant.java
new file mode 100644
index 00000000000..0b534706462
--- /dev/null
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IShardModeCommandParticipant.java
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus 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 - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.services.controlmode.participants;
+
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
+
+/**
+ * An optional participant protocol for contribution of ancillary changes
+ * when the 'shard' mode of a sub-unit resource is changed.
+ *
+ * @since 1.3
+ */
+public interface IShardModeCommandParticipant extends IControlModeParticipant {
+
+ /**
+ * Queries whether I participate in processing of the given {@code request}.
+ *
+ * @param request
+ * a request, which will always be a
+ * {@link ControlModeRequest#isControlRequest() control} request by
+ * by default because it simply changes the sub-unit structure between
+ * 'sub-model' and 'shard' unit type
+ *
+ * @return whether I should be asked for commands to participate in the
+ * shard conversion operation
+ */
+ boolean providesShardModeCommand(ControlModeRequest request);
+
+ /**
+ * Obtains a command to execute before the basic conversion of the
+ * 'shard' mode is performed.
+ *
+ * @param request
+ * a request, which will always be a
+ * {@link ControlModeRequest#isControlRequest() control} request by
+ * by default because it simply changes the sub-unit structure between
+ * 'sub-model' and 'shard' unit type
+ *
+ * @return a command, or {@code null} if none is needed
+ */
+ default ICommand getPreShardModeCommand(ControlModeRequest request) {
+ return null;
+ }
+
+ /**
+ * Obtains a command to execute after the basic conversion of the
+ * 'shard' mode is performed.
+ *
+ * @param request
+ * a request, which will always be a
+ * {@link ControlModeRequest#isControlRequest() control} request by
+ * by default because it simply changes the sub-unit structure between
+ * 'sub-model' and 'shard' unit type
+ *
+ * @return a command, or {@code null} if none is needed
+ */
+ default ICommand getPostShardModeCommand(ControlModeRequest request) {
+ return null;
+ }
+}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ui/CreateModelFragmentDialog.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ui/CreateModelFragmentDialog.java
index 626400d8e3d..7defb515031 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ui/CreateModelFragmentDialog.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ui/CreateModelFragmentDialog.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006 Anyware Technologies. All rights reserved. This program
+ * Copyright (c) 2006, 2016 Anyware Technologies. All rights reserved. This program, Christian W. Damus, and others
* 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
@@ -7,6 +7,7 @@
* Contributors:
* Jacques Lescot (Anyware Technologies) - Initial API and implementation
* Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Bug 436947
+ * Christian W. Damus - bug 497865
******************************************************************************/
package org.eclipse.papyrus.infra.services.controlmode.ui;
@@ -14,12 +15,23 @@ import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.ui.dialogs.ResourceDialog;
import org.eclipse.emf.common.ui.dialogs.WorkspaceResourceDialog;
+import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeManager;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModePlugin;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
import org.eclipse.papyrus.infra.services.controlmode.messages.Messages;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
@@ -33,15 +45,22 @@ import org.eclipse.swt.widgets.Shell;
*/
public class CreateModelFragmentDialog extends ResourceDialog {
+ static final String DIALOG_SETTINGS = "CreateModelFragmentDialog"; //$NON-NLS-1$
+ static final String SETTING_CREATE_SHARD = "createShard"; //$NON-NLS-1$
+
/** The Constant DIALOG_TITLE. */
private static final String DIALOG_TITLE = Messages.getString("CreateModelFragmentDialog.dialog.title"); //$NON-NLS-1$
private URI uri;
private Resource currentResource;
+ private EObject objectToControl;
private String defaultName;
+ private Button shardButton;
+ private boolean createShard;
+
/**
* The constructor
*
@@ -51,11 +70,20 @@ public class CreateModelFragmentDialog extends ResourceDialog {
* @param defaultName
*/
public CreateModelFragmentDialog(Shell parent, Resource theCurrentResource, String defaultName) {
- super(parent, DIALOG_TITLE, SWT.SAVE); //$NON-NLS-1$
+ super(parent, DIALOG_TITLE, SWT.SAVE);
this.currentResource = theCurrentResource;
this.defaultName = defaultName;
}
+ /**
+ * @since 1.3
+ */
+ public CreateModelFragmentDialog(Shell parent, EObject objectToControl, String defaultName) {
+ this(parent, objectToControl.eResource(), defaultName); // $NON-NLS-1$
+
+ this.objectToControl = objectToControl;
+ }
+
@Override
protected void prepareBrowseWorkspaceButton(Button browseWorkspaceButton) {
browseWorkspaceButton.addSelectionListener(new SelectionAdapter() {
@@ -84,6 +112,59 @@ public class CreateModelFragmentDialog extends ResourceDialog {
protected Control createContents(Composite parent) {
Control result = super.createContents(parent);
this.uriField.setText(computeDefaultURI());
+
+ // And the rest of the dialog initialization
+ loadDialogState();
+
+ // Is the sub-model unit option available?
+ if ((objectToControl != null) && !ControlModeManager.getInstance().canCreateSubmodel(objectToControl)) {
+ // We can only create a shard resource
+ shardButton.setSelection(false);
+ shardButton.setEnabled(false);
+ createShard = true;
+ }
+
+ // Initial validation
+ validateDialog();
+
+ return result;
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite result = (Composite) super.createDialogArea(parent);
+ Control[] superContents = result.getChildren();
+
+ // Note that the polarity of this button is the reverse of the option:
+ // it asks the user whether to create a *non-shard*
+ shardButton = new Button(result, SWT.CHECK);
+ {
+ FormData data = new FormData();
+ data.top = new FormAttachment(uriField, CONTROL_OFFSET);
+ data.left = new FormAttachment(0, CONTROL_OFFSET);
+ data.right = new FormAttachment(100, -CONTROL_OFFSET);
+ shardButton.setLayoutData(data);
+
+ // And re-attach the separator
+ Control separator = superContents[superContents.length - 1];
+ ((FormData) separator.getLayoutData()).top.control = shardButton;
+ }
+ shardButton.setText(Messages.getString("CreateModelFragmentDialog.submodel.checkbox")); //$NON-NLS-1$
+ shardButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ createShard = !shardButton.getSelection();
+
+ validateDialog();
+ }
+ });
+
+ uriField.addModifyListener(__ -> validateDialog());
+
+ // This is guaranteed by contract with subclasses to be the first child
+ Control buttonComposite = superContents[0];
+ result.setTabList(new Control[] { uriField, buttonComposite, shardButton });
+
return result;
}
@@ -99,6 +180,9 @@ public class CreateModelFragmentDialog extends ResourceDialog {
protected boolean processResources() {
URI uri = URI.createURI(getURIText());
this.uri = uri;
+
+ saveDialogState();
+
return true;
}
@@ -110,4 +194,77 @@ public class CreateModelFragmentDialog extends ResourceDialog {
public URI getURI() {
return uri;
}
+
+ /**
+ * Queries whether the user elected to create a 'shard' resource (by un-checking
+ * the 'create an independent sub-model resource' option).
+ *
+ * @return whether to create a shard resource
+ *
+ * @since 1.3
+ */
+ public boolean isCreateShard() {
+ return createShard;
+ }
+
+ private void loadDialogState() {
+ IDialogSettings settings = DialogSettings.getOrCreateSection(ControlModePlugin.getDefault().getDialogSettings(), DIALOG_SETTINGS);
+ loadDialogState(settings);
+ }
+
+ /**
+ * Initializes the dialog state from the given {@code settings}.
+ * Subclasses may extend (be sure to call {@code super}).
+ *
+ * @param settings
+ * the dialog settings to read from (never {@code null})
+ * @since 1.3
+ */
+ protected void loadDialogState(IDialogSettings settings) {
+ createShard = settings.getBoolean(SETTING_CREATE_SHARD);
+ shardButton.setSelection(!createShard);
+ }
+
+ private void saveDialogState() {
+ IDialogSettings settings = DialogSettings.getOrCreateSection(ControlModePlugin.getDefault().getDialogSettings(), DIALOG_SETTINGS);
+ saveDialogState(settings);
+ }
+
+ /**
+ * Stores the dialog state to the given {@code settings}.
+ * Subclasses may extend (be sure to call {@code super}).
+ *
+ * @param settings
+ * the dialog settings to write to (never {@code null})
+ * @since 1.3
+ */
+ protected void saveDialogState(IDialogSettings settings) {
+ // Only store this setting if it's a choice
+ if (shardButton.isEnabled()) {
+ settings.put(SETTING_CREATE_SHARD, createShard);
+ }
+ }
+
+ /**
+ * @since 1.3
+ */
+ protected boolean validateDialog() {
+ URI uri = getURIs().stream().findAny().orElse(null);
+ boolean result = uri != null;
+
+ // Can only create requests for validation if we have an object and a URI
+ if ((objectToControl != null) && (uri != null)) {
+ ControlModeRequest request = ControlModeRequest.createUIControlModelRequest(
+ TransactionUtil.getEditingDomain(objectToControl),
+ objectToControl,
+ uri);
+
+ Diagnostic diagnostic = ControlModeManager.getInstance().approveRequest(request);
+ result = diagnostic.getSeverity() < Diagnostic.ERROR;
+ }
+
+ getButton(IDialogConstants.OK_ID).setEnabled(result);
+
+ return result;
+ }
}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ui/IControlModeFragmentDialogProvider.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ui/IControlModeFragmentDialogProvider.java
index e32965619a1..54c36d77363 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ui/IControlModeFragmentDialogProvider.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/ui/IControlModeFragmentDialogProvider.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2016 CEA LIST, Christian W. Damus, 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,14 +8,22 @@
*
* Contributors:
* CEA LIST - Initial API and implementation
+ * Christian W. Damus - bug 497865
*****************************************************************************/
package org.eclipse.papyrus.infra.services.controlmode.ui;
+import static org.eclipse.papyrus.infra.services.controlmode.ControlModeRequestParameters.CREATE_SHARD;
+
+import java.util.Optional;
+
import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.window.Window;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
import org.eclipse.swt.widgets.Shell;
@@ -31,16 +39,33 @@ public interface IControlModeFragmentDialogProvider {
*/
IControlModeFragmentDialogProvider DEFAULT = new IControlModeFragmentDialogProvider() {
+ @Override
public Dialog createDialog(Shell shell, Resource parentUnit, String defaultUnitName) {
return new CreateModelFragmentDialog(shell, parentUnit, defaultUnitName);
}
+ @Override
+ public Dialog createDialog(Shell shell, EObject objectToControl, String defaultUnitName) {
+ return new CreateModelFragmentDialog(shell, objectToControl, defaultUnitName);
+ }
+
+ @Override
public URI getSelectedURI(Dialog dialog) {
- URI result = null;
+ return cast(dialog).map(CreateModelFragmentDialog::getURI).orElse(null);
+ }
+
+ Optional<CreateModelFragmentDialog> cast(Dialog dialog) {
+ return Optional.of(dialog)
+ .filter(d -> d.getReturnCode() == Window.OK)
+ .filter(CreateModelFragmentDialog.class::isInstance)
+ .map(CreateModelFragmentDialog.class::cast);
+ }
+
+ @Override
+ public ControlModeRequest getControlRequest(Dialog dialog, TransactionalEditingDomain domain, EObject objectToControl) {
+ ControlModeRequest result = IControlModeFragmentDialogProvider.super.getControlRequest(dialog, domain, objectToControl);
- if ((dialog.getClass() == CreateModelFragmentDialog.class) && (dialog.getReturnCode() == Window.OK)) {
- result = ((CreateModelFragmentDialog) dialog).getURI();
- }
+ cast(dialog).ifPresent(d -> result.setParameter(CREATE_SHARD, d.isCreateShard()));
return result;
}
@@ -57,10 +82,32 @@ public interface IControlModeFragmentDialogProvider {
* the default suggested name of the new sub-unit. Will not be {@code null}
*
* @return the fragment resource URI selection dialog
+ *
+ * @deprecated As of 1.3, use or implement the {@link #createDialog(Shell, EObject, String)} API, instead.
*/
+ @Deprecated
Dialog createDialog(Shell shell, Resource parentUnit, String defaultUnitName);
/**
+ * Create a new dialog to solicit the new model unit's URI from the user. The new dialog
+ * is <em>not</em> opened.
+ *
+ * @param shell
+ * the new dialog's parent shell
+ * @param objectToControl
+ * the model element that is to be carved out of its resource as a new model unit
+ * @param defaultUnitName
+ * the default suggested name of the new sub-unit. Will not be {@code null}
+ *
+ * @return the fragment resource URI selection dialog
+ *
+ * @since 1.3
+ */
+ default Dialog createDialog(Shell shell, EObject objectToControl, String defaultUnitName) {
+ return createDialog(shell, objectToControl.eResource(), defaultUnitName);
+ }
+
+ /**
* Obtains the model unit URI selected by the user in the given {@code dialog}. If that {@code dialog} was cancelled or was not
* created by this provider, then the result must be {@code null}.
*
@@ -70,4 +117,22 @@ public interface IControlModeFragmentDialogProvider {
* @return the URI selected by the user, or {@code null} if cancelled or an unrecognized dialog
*/
URI getSelectedURI(Dialog dialog);
+
+ /**
+ * Obtains the control request to execute from the given {@code dialog}.
+ *
+ * @param dialog
+ * a dialog created by this provider that has been completed by the user
+ * @param domain
+ * the editing domain in which to perform the request
+ * @param objectToControl
+ * the object to be controlled
+ *
+ * @return the control request configured by the {@code dialog}
+ *
+ * @since 1.3
+ */
+ default ControlModeRequest getControlRequest(Dialog dialog, TransactionalEditingDomain domain, EObject objectToControl) {
+ return ControlModeRequest.createUIControlModelRequest(domain, objectToControl, getSelectedURI(dialog));
+ }
}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/.classpath b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/.classpath
index 2d1a4302f04..eca7bdba8f0 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/.classpath
+++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/.classpath
@@ -1,7 +1,7 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/.settings/org.eclipse.jdt.core.prefs b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/.settings/org.eclipse.jdt.core.prefs
index 4759947300a..62a08f4494d 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/.settings/org.eclipse.jdt.core.prefs
+++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/.settings/org.eclipse.jdt.core.prefs
@@ -1,10 +1,10 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
-org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/META-INF/MANIFEST.MF b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/META-INF/MANIFEST.MF
index 8ce1e4b0c7a..5773a564a7a 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/META-INF/MANIFEST.MF
+++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/META-INF/MANIFEST.MF
@@ -1,5 +1,5 @@
Manifest-Version: 1.0
-Require-Bundle: org.eclipse.papyrus.infra.services.controlmode;bundle-version="[1.2.0,2.0.0)",
+Require-Bundle: org.eclipse.papyrus.infra.services.controlmode;bundle-version="[1.3.0,2.0.0)",
org.eclipse.papyrus.uml.tools;bundle-version="[2.0.0,3.0.0)",
org.eclipse.papyrus.infra.emf.readonly;bundle-version="[2.0.0,3.0.0)",
org.eclipse.papyrus.infra.widgets.toolbox;bundle-version="[1.2.0,2.0.0)",
@@ -8,10 +8,10 @@ Require-Bundle: org.eclipse.papyrus.infra.services.controlmode;bundle-version="[
org.eclipse.emf.validation.ui;bundle-version="[1.7.0,2.0.0)"
Bundle-Vendor: %providerName
Bundle-ActivationPolicy: lazy
-Bundle-Version: 1.2.0.qualifier
+Bundle-Version: 1.2.100.qualifier
Bundle-Localization: plugin
Bundle-Name: %pluginName
Bundle-Activator: org.eclipse.papyrus.uml.controlmode.profile.Activator
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.eclipse.papyrus.uml.controlmode.profile;singleton:=true
-Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/pom.xml b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/pom.xml
index 4e002f4c961..c5283c2bb35 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/pom.xml
+++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/pom.xml
@@ -7,6 +7,6 @@
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.papyrus.uml.controlmode.profile</artifactId>
- <version>1.2.0-SNAPSHOT</version>
+ <version>1.2.100-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/UMLProfileControlParticipant.java b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/UMLProfileControlParticipant.java
index 60575193484..2bc81a0140d 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/UMLProfileControlParticipant.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/UMLProfileControlParticipant.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013, 2014 Atos, CEA LIST and etc..
+ * Copyright (c) 2013, 2016 Atos, CEA LIST and etc., Christian W. Damus, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -10,6 +10,7 @@
* Contributors:
* Arthur Daussy (Atos) arthur.daussy@atos.net - Initial API and implementation
* Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Bug 436947
+ * Christian W. Damus - bug 497865
*
*****************************************************************************/
package org.eclipse.papyrus.uml.controlmode.profile;
@@ -17,17 +18,22 @@ package org.eclipse.papyrus.uml.controlmode.profile;
import java.util.Collections;
import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequestParameters;
import org.eclipse.papyrus.infra.services.controlmode.commands.AskUserCommand;
+import org.eclipse.papyrus.infra.services.controlmode.participants.IControlCommandApprover;
import org.eclipse.papyrus.infra.services.controlmode.participants.IControlCommandParticipant;
+import org.eclipse.papyrus.infra.services.controlmode.participants.IShardModeCommandParticipant;
import org.eclipse.papyrus.infra.services.controlmode.participants.IUncontrolCommandParticipant;
import org.eclipse.papyrus.uml.controlmode.profile.commands.CopyProfileApplicationCommand;
import org.eclipse.papyrus.uml.controlmode.profile.commands.MoveProfileApplicationCommand;
import org.eclipse.papyrus.uml.controlmode.profile.commands.MoveStereotypeApplicationToControlResource;
import org.eclipse.papyrus.uml.controlmode.profile.commands.RemoveDuplicationProfileApplicationCommand;
+import org.eclipse.papyrus.uml.tools.model.UmlModel;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Package;
@@ -39,8 +45,8 @@ import org.eclipse.uml2.uml.Package;
* @author adaussy
*
*/
-public class UMLProfileControlParticipant implements IControlCommandParticipant, IUncontrolCommandParticipant {
-
+public class UMLProfileControlParticipant implements IControlCommandParticipant,
+ IUncontrolCommandParticipant, IShardModeCommandParticipant, IControlCommandApprover {
/** The Constant PRE_UNCONTROL_COMMAND_LABEL. */
private static final String PRE_UNCONTROL_COMMAND_LABEL = Messages.UMLProfileControlParticipant_Pre_Uncontrol_Command_Label;
@@ -61,6 +67,7 @@ public class UMLProfileControlParticipant implements IControlCommandParticipant,
return new CopyProfileApplicationCommand(request);
}
+ @Override
public String getID() {
return "org.eclipse.papyrus.uml.controlmode.profile.UMLProfileControlParticipant"; //$NON-NLS-1$
}
@@ -79,21 +86,32 @@ public class UMLProfileControlParticipant implements IControlCommandParticipant,
return new MoveStereotypeApplicationToControlResource(Collections.singletonList(WorkspaceSynchronizer.getFile(request.getTargetObject().eResource())), request);
}
+ @Override
public ICommand getPostControlCommand(ControlModeRequest request) {
CompositeCommand cc = new CompositeCommand(POST_CONTROL_COMMAND_LABEL);
- // Move stereotype application
- if (request.getTargetObject() instanceof Package) {
+
+ // Do we need to manipulate profile applications? Only if it's a package
+ // that is intended to be an independently openable sub-model unit
+ boolean handleProfileApplications = !ControlModeRequestParameters.isCreateShard(request)
+ && (request.getTargetObject() instanceof Package);
+
+ // Move profile applications if necessary and possible
+ if (handleProfileApplications) {
cc.compose(getMoveProfileAppliationCommand(request));
}
+
// Move stereotype application
cc.compose(getMoveStereotypeCommand(request));
- // Copy profile application
- if (request.getTargetObject() instanceof Package) {
+
+ // Copy profile applications if necessary and possible
+ if (handleProfileApplications) {
cc.compose(getCopyProfileApplication(request));
}
+
return cc;
}
+ @Override
public ICommand getPostUncontrolCommand(ControlModeRequest request) {
CompositeCommand cc = new CompositeCommand(POST_UNCONTROL_COMMAND_LABEL);
@@ -123,15 +141,28 @@ public class UMLProfileControlParticipant implements IControlCommandParticipant,
return new RemoveDuplicationProfileApplicationCommand(request);
}
+ @Override
public ICommand getPreControlCommand(ControlModeRequest request) {
Element elem = (Element) request.getTargetObject();
- if (request.isUIAction() && !(elem instanceof org.eclipse.uml2.uml.Package)) {
+
+ // Populate the source resource
+ request.setSourceResource(elem.eResource(), UmlModel.UML_FILE_EXTENSION);
+
+ // Don't need to worry about this if we're creating a 'shard' resource, because
+ // it cannot be opened independently (that's the whole point of shards)
+ if (!ControlModeRequestParameters.isCreateShard(request) && request.isUIAction()
+ && !(elem instanceof org.eclipse.uml2.uml.Package)) {
+
return new AskUserCommand(request.getEditingDomain(), getPreControlCommandMessage(elem), getPreControlCommandDialogTitle(elem), true, "org.eclipse.papyrus.controlmode.umlprofiles.participants.UMLProfileParticipant.openstandalonemodeldialog"); //$NON-NLS-1$
}
return null;
}
+ @Override
public ICommand getPreUncontrolCommand(ControlModeRequest request) {
+ // Populate the source resource
+ request.setSourceResource(request.getTargetObject().eResource(), UmlModel.UML_FILE_EXTENSION);
+
CompositeCommand cc = new CompositeCommand(PRE_UNCONTROL_COMMAND_LABEL);
// Copy profile application
if (request.getTargetObject() instanceof Package) {
@@ -141,6 +172,22 @@ public class UMLProfileControlParticipant implements IControlCommandParticipant,
return cc;
}
+ @Override
+ public ICommand getPostShardModeCommand(ControlModeRequest request) {
+ ICommand result;
+
+ if (ControlModeRequestParameters.isCreateShard(request)) {
+ // A shard will inherit these
+ result = getRemoveProfileApplication(request);
+ } else {
+ // A sub-model needs redundant profile applications
+ result = (ICommand) getCopyProfileApplication(request);
+ }
+
+ return result;
+ }
+
+ @Override
public int getPriority() {
return 100;
}
@@ -149,11 +196,23 @@ public class UMLProfileControlParticipant implements IControlCommandParticipant,
return Messages.UMLProfileControlParticipant_controlmode_dialog_title;
}
+ @Override
public boolean provideControlCommand(ControlModeRequest request) {
return request.getTargetObject() instanceof Element;
}
+ @Override
public boolean provideUnControlCommand(ControlModeRequest request) {
return request.getTargetObject() instanceof Element;
}
+
+ @Override
+ public boolean providesShardModeCommand(ControlModeRequest request) {
+ return request.getTargetObject() instanceof org.eclipse.uml2.uml.Package;
+ }
+
+ @Override
+ public boolean canCreateSubModel(EObject objectToControl) {
+ return objectToControl instanceof org.eclipse.uml2.uml.Package;
+ }
}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveStereotypeApplicationToControlResource.java b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveStereotypeApplicationToControlResource.java
index c8d0b136d57..595354538a6 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveStereotypeApplicationToControlResource.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveStereotypeApplicationToControlResource.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013, 2014 Atos, Christian W. Damus, and others.
+ * Copyright (c) 2013, 2016 Atos, Christian W. Damus, 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,7 +8,7 @@
*
* Contributors:
* Arthur Daussy (Atos) arthur.daussy@atos.net - Initial API and implementation
- * Christian W. Damus - bug 399859
+ * Christian W. Damus - bugs 399859, 497865
* Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - bug 460435
*
*****************************************************************************/
@@ -85,7 +85,7 @@ public final class MoveStereotypeApplicationToControlResource extends AbstractCo
}
// Retrieve related resources by control command
- Resource sourceResource = getRequest().getModelSet().getAssociatedResource(targetElement, UmlModel.UML_FILE_EXTENSION, false);
+ Resource sourceResource = getRequest().getSourceResource(UmlModel.UML_FILE_EXTENSION);
Resource targetResource = getRequest().getTargetResource(UmlModel.UML_FILE_EXTENSION);
if (targetResource == null) {
@@ -100,4 +100,4 @@ public final class MoveStereotypeApplicationToControlResource extends AbstractCo
return CommandResult.newOKCommandResult();
}
-} \ No newline at end of file
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/ProfileApplicationHelper.java b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/ProfileApplicationHelper.java
index 6e6242a86ce..193231acdfc 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/ProfileApplicationHelper.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/ProfileApplicationHelper.java
@@ -49,11 +49,11 @@ public class ProfileApplicationHelper {
ProfileApplication toCopy = _package.getProfileApplication(profile, true);
// Is it inherited from a parent package and intrinsic to the model?
if (_package.allOwningPackages().contains(toCopy.getApplyingPackage())) {
- _package.applyProfile(profile);
- ProfileApplication profileAppl = _package.getProfileApplication(profile);
- if (profileAppl != null) {
- markAsDuplicate(profileAppl);
- }
+ // Don't apply the profile because this needlessly destroys and
+ // reconstitutes all stereotype applications by a "migration"
+ ProfileApplication profileAppl = EcoreUtil.copy(toCopy);
+ _package.getProfileApplications().add(profileAppl);
+ markAsDuplicate(profileAppl);
}
}
}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/SafeDialogOpenerDuringValidation.java b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/SafeDialogOpenerDuringValidation.java
index 91a333f8d74..7bc79a91aab 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/SafeDialogOpenerDuringValidation.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/SafeDialogOpenerDuringValidation.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2011 Atos Origin.
+ * Copyright (c) 2011, 2016 Atos Origin, Christian W. Damus, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,6 +9,7 @@
*
* Contributors:
* Atos Origin - Initial API and implementation
+ * Christian W. Damus - bug 497865
*
*****************************************************************************/
package org.eclipse.papyrus.uml.controlmode.profile.helpers;
@@ -65,8 +66,11 @@ public abstract class SafeDialogOpenerDuringValidation<ReturnType> {
*/
IOperationHistory history = CheckedOperationHistory.getInstance();
history.addOperationApprover(operationDisapprover);
- ReturnType result = openDialog();
- history.removeOperationApprover(operationDisapprover);
- return result;
+ try {
+ ReturnType result = openDialog();
+ return result;
+ } finally {
+ history.removeOperationApprover(operationDisapprover);
+ }
}
}

Back to the top