Skip to content

Commit 62af6e3

Browse files
committed
Refactor Set Concept Type so that invalid relations are fixed after setting element types
- Before now when a concept was changed its source/target relations were set to Association based on the existing element type (before it was changed). Now we set the concept types in one go, and then change any invalid relations afterwards. - And fix several bugs
1 parent c0a8bad commit 62af6e3

File tree

3 files changed

+283
-136
lines changed

3 files changed

+283
-136
lines changed

com.archimatetool.editor/src/com/archimatetool/editor/actions/SetConceptTypeExtensionContributionFactory.java

+55-53
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
/**
2+
* This program and the accompanying materials
3+
* are made available under the terms of the License
4+
* which accompanies this distribution in the file LICENSE.txt
5+
*/
16
package com.archimatetool.editor.actions;
27

8+
import java.util.HashMap;
39
import java.util.HashSet;
4-
import java.util.Hashtable;
10+
import java.util.Map;
511
import java.util.Map.Entry;
612
import java.util.Set;
713

@@ -29,6 +35,7 @@
2935
import com.archimatetool.model.FolderType;
3036
import com.archimatetool.model.IArchimateConcept;
3137
import com.archimatetool.model.IArchimateElement;
38+
import com.archimatetool.model.IArchimateModel;
3239
import com.archimatetool.model.IArchimatePackage;
3340
import com.archimatetool.model.IArchimateRelationship;
3441
import com.archimatetool.model.util.ArchimateModelUtils;
@@ -51,7 +58,7 @@ public void createContributionItems(IServiceLocator serviceLocator, IContributio
5158
ISelectionService selectionService = serviceLocator.getService(ISelectionService.class);
5259

5360
IStructuredSelection selection = (IStructuredSelection)selectionService.getSelection();
54-
if(selection == null) {
61+
if(selection == null || selection.isEmpty()) {
5562
return;
5663
}
5764

@@ -62,17 +69,21 @@ public void createContributionItems(IServiceLocator serviceLocator, IContributio
6269

6370
for(Object o : selection) {
6471
IArchimateConcept concept = null;
72+
6573
if(o instanceof IArchimateConcept) {
6674
concept = (IArchimateConcept)o;
6775
}
68-
else if(o instanceof IAdaptable) {
69-
concept = ((IAdaptable)o).getAdapter(IArchimateConcept.class);
76+
else if(o instanceof IAdaptable adaptable) {
77+
concept = adaptable.getAdapter(IArchimateConcept.class);
7078
}
71-
if(concept instanceof IArchimateElement && !(concept.eClass() == IArchimatePackage.eINSTANCE.getJunction())) { // Not Junctions
72-
selectedElements.add((IArchimateElement)concept);
79+
80+
// Element, but not a Junction
81+
if(concept instanceof IArchimateElement element && element.eClass() != IArchimatePackage.eINSTANCE.getJunction()) {
82+
selectedElements.add(element);
7383
}
74-
else if(concept instanceof IArchimateRelationship) {
75-
selectedRelations.add((IArchimateRelationship)concept);
84+
// Relationship
85+
else if(concept instanceof IArchimateRelationship relationship) {
86+
selectedRelations.add(relationship);
7687
}
7788
}
7889

@@ -153,7 +164,7 @@ public void run() {
153164
boolean hasInvalidConnections = false;
154165

155166
for(IArchimateElement element : elements) {
156-
if(!SetConceptTypeCommandFactory.isValidTypeForConcept(eClass, element)) {
167+
if(!SetConceptTypeCommandFactory.isValidTypeForElement(eClass, element, elements)) {
157168
hasInvalidConnections = true;
158169
}
159170
}
@@ -170,8 +181,8 @@ public void run() {
170181
action.setEnabled(false);
171182

172183
// Enable menu item if any selected element is different to the target type
173-
for(IArchimateElement e : elements) {
174-
if(!e.eClass().equals(eClass)) {
184+
for(IArchimateElement element : elements) {
185+
if(element.eClass() != eClass) {
175186
action.setEnabled(true);
176187
}
177188
}
@@ -191,8 +202,8 @@ public void run() {
191202
action.setEnabled(false);
192203

193204
// Enable menu item if any selected relation is different to the target type and is valid
194-
for(IArchimateRelationship r : relations) {
195-
if(!r.eClass().equals(eClass) && ArchimateModelUtils.isValidRelationship(r.getSource().eClass(), r.getTarget().eClass(), eClass)) {
205+
for(IArchimateRelationship relation : relations) {
206+
if(relation.eClass() != eClass && SetConceptTypeCommandFactory.isValidTypeForRelationship(eClass, relation)) {
196207
action.setEnabled(true);
197208
}
198209
}
@@ -204,62 +215,53 @@ public void run() {
204215
private void changeElementTypes(EClass eClass, Set<IArchimateElement> elements) {
205216
/*
206217
* If changing types from more than one model we need to use the
207-
* Command Stack allocated to each model. And then allocate one CompoundCommand per Command Stack.
218+
* Command Stack allocated to each model. And then execute one CompoundCommand per Command Stack.
208219
*/
209-
Hashtable<CommandStack, CompoundCommand> commandMap = new Hashtable<CommandStack, CompoundCommand>();
210-
211-
for(IArchimateElement element : elements) {
212-
CompoundCommand compoundCmd = getCompoundCommand(element, commandMap);
213-
if(compoundCmd != null) {
214-
compoundCmd.add(SetConceptTypeCommandFactory.createSetElementTypeCommand(eClass, element,
215-
ArchiPlugin.PREFERENCES.getBoolean(IPreferenceConstants.ADD_DOCUMENTATION_NOTE_ON_RELATION_CHANGE)));
216-
}
217-
}
220+
Map<IArchimateModel, Set<IArchimateElement>> elementsMap = getConceptMap(elements);
218221

219-
// Execute the Commands on the CommandStack(s) - there could be more than one if more than one model open in the Tree
220-
for(Entry<CommandStack, CompoundCommand> entry : commandMap.entrySet()) {
221-
entry.getKey().execute(entry.getValue());
222+
for(Entry<IArchimateModel, Set<IArchimateElement>> entry : elementsMap.entrySet()) {
223+
CommandStack stack = (CommandStack)entry.getKey().getAdapter(CommandStack.class);
224+
CompoundCommand cmd = SetConceptTypeCommandFactory.createSetElementTypeCommand(eClass, entry.getValue(),
225+
ArchiPlugin.PREFERENCES.getBoolean(IPreferenceConstants.ADD_DOCUMENTATION_NOTE_ON_RELATION_CHANGE));
226+
if(stack != null && cmd != null) {
227+
// Wrap the command in a NonNotifyingCompoundCommand to minimise event noise
228+
stack.execute(new NonNotifyingCompoundCommand(cmd));
229+
}
222230
}
223231
}
224232

225233
private void changeRelationTypes(EClass eClass, Set<IArchimateRelationship> relations) {
226234
/*
227235
* If changing types from more than one model we need to use the
228-
* Command Stack allocated to each model. And then allocate one CompoundCommand per Command Stack.
236+
* Command Stack allocated to each model. And then execute one CompoundCommand per Command Stack.
229237
*/
230-
Hashtable<CommandStack, CompoundCommand> commandMap = new Hashtable<CommandStack, CompoundCommand>();
231-
232-
for(IArchimateRelationship relation : relations) {
233-
CompoundCommand compoundCmd = getCompoundCommand(relation, commandMap);
234-
if(compoundCmd != null) {
235-
compoundCmd.add(SetConceptTypeCommandFactory.createSetRelationTypeCommand(eClass, relation));
236-
}
237-
}
238+
Map<IArchimateModel, Set<IArchimateRelationship>> relationsMap = getConceptMap(relations);
238239

239-
// Execute the Commands on the CommandStack(s) - there could be more than one if more than one model open in the Tree
240-
for(Entry<CommandStack, CompoundCommand> entry : commandMap.entrySet()) {
241-
entry.getKey().execute(entry.getValue());
240+
for(Entry<IArchimateModel, Set<IArchimateRelationship>> entry : relationsMap.entrySet()) {
241+
CommandStack stack = (CommandStack)entry.getKey().getAdapter(CommandStack.class);
242+
CompoundCommand cmd = SetConceptTypeCommandFactory.createSetRelationTypeCommand(eClass, entry.getValue());
243+
if(stack != null && cmd != null) {
244+
// Wrap the command in a NonNotifyingCompoundCommand to minimise event noise
245+
stack.execute(new NonNotifyingCompoundCommand(cmd));
246+
}
242247
}
243248
}
244-
249+
245250
/**
246-
* Get, and if need be create, a CompoundCommand to which to change the type for each concept in a model
251+
* Get a mapping of IArchimateModel to a set of IArchimateConcepts
247252
*/
248-
private CompoundCommand getCompoundCommand(IArchimateConcept concept, Hashtable<CommandStack, CompoundCommand> commandMap) {
249-
// Get the Command Stack registered to the object
250-
CommandStack stack = (CommandStack)concept.getAdapter(CommandStack.class);
251-
if(stack == null) {
252-
System.err.println("CommandStack was null in getCompoundCommand"); //$NON-NLS-1$
253-
return null;
254-
}
253+
private <T extends IArchimateConcept> Map<IArchimateModel, Set<T>> getConceptMap(Set<T> concepts) {
254+
Map<IArchimateModel, Set<T>> map = new HashMap<>();
255255

256-
// Now get or create a Compound Command
257-
CompoundCommand compoundCommand = commandMap.get(stack);
258-
if(compoundCommand == null) {
259-
compoundCommand = new NonNotifyingCompoundCommand();
260-
commandMap.put(stack, compoundCommand);
256+
for(T concept : concepts) {
257+
Set<T> elementsSet = map.get(concept.getArchimateModel());
258+
if(elementsSet == null) {
259+
elementsSet = new HashSet<>();
260+
map.put(concept.getArchimateModel(), elementsSet);
261+
}
262+
elementsSet.add(concept);
261263
}
262264

263-
return compoundCommand;
265+
return map;
264266
}
265267
}

0 commit comments

Comments
 (0)