2727import org .eclipse .emf .ecore .change .ChangeKind ;
2828import org .eclipse .emf .ecore .change .FeatureChange ;
2929import org .eclipse .emf .ecore .change .ListChange ;
30+ import org .eclipse .emf .ecore .change .ResourceChange ;
3031import org .eclipse .emf .ecore .resource .Resource ;
32+ import org .eclipse .emf .ecore .resource .ResourceSet ;
3133import org .eclipse .sirius .components .core .api .IContentService ;
3234import org .eclipse .sirius .components .core .api .IEditingContext ;
3335import org .eclipse .sirius .components .core .api .IIdentityService ;
3941import org .eclipse .sirius .components .datatree .DataTreeNode ;
4042import org .eclipse .sirius .components .emf .services .api .IEMFEditingContext ;
4143import org .eclipse .sirius .web .application .impactanalysis .services .api .IDefaultChangeDescriptionDataTreeProvider ;
44+ import org .eclipse .sirius .web .application .library .services .LibraryMetadataAdapter ;
4245import org .springframework .stereotype .Service ;
4346
4447/**
@@ -69,13 +72,14 @@ public Optional<DataTree> getDataTree(IEditingContext editingContext, ChangeDesc
6972 if (editingContext instanceof IEMFEditingContext emfEditingContext ) {
7073 List <String > allImpactedObjectIds = this .getAllImpactedObjectIds (changeDescription );
7174 List <DataTreeNode > dataTreeNodes = new ArrayList <>();
75+ dataTreeNodes .addAll (this .createAllResourcesDataTreeNodes (emfEditingContext .getDomain ().getResourceSet (), changeDescription .getResourceChanges ()));
7276 for (Resource resource : emfEditingContext .getDomain ().getResourceSet ().getResources ()) {
7377 String resourceId = this .getId (resource );
7478 if (allImpactedObjectIds .contains (resourceId )) {
75- dataTreeNodes .add (new DataTreeNode (resourceId , null , this .getStyledLabel (resource ), this .getIconURL (resource ), List .of (List .of ())));
76- List <Object > children = this .getChildren (resource , editingContext , changeDescription );
79+ dataTreeNodes .add (new DataTreeNode (resourceId , null , this .getStyledLabel (resource ), this .getIconURLs (resource ), List .of (List .of ())));
80+ List <Object > children = this .getChildren (resource , changeDescription );
7781 for (Object child : children ) {
78- dataTreeNodes .addAll (this .getDataTreeNode (child , resource , emfEditingContext , changeDescription , allImpactedObjectIds ));
82+ dataTreeNodes .addAll (this .getObjectChangeDataTreeNode (child , resource , changeDescription , allImpactedObjectIds ));
7983 }
8084 }
8185 }
@@ -85,15 +89,109 @@ public Optional<DataTree> getDataTree(IEditingContext editingContext, ChangeDesc
8589 return result ;
8690 }
8791
88- private List <DataTreeNode > getDataTreeNode (Object object , Object parent , IEditingContext editingContext , ChangeDescription changeDescription , List <String > allImpactObjectIds ) {
92+ private List <DataTreeNode > createAllResourcesDataTreeNodes (ResourceSet resourceSet , List <ResourceChange > resourceChanges ) {
93+ List <DataTreeNode > result = new ArrayList <>();
94+ for (ResourceChange resourceChange : resourceChanges ) {
95+ for (ListChange listChange : resourceChange .getListChanges ()) {
96+ if (listChange .getKind () == ChangeKind .ADD_LITERAL ) {
97+ Resource changedResource = resourceChange .getResource ();
98+ List <?> resourceContent = resourceChange .getValue ();
99+ result .addAll (this .createResourceDataTreeNodes (changedResource , resourceContent , listChange .getKind ()));
100+ resourceSet .getResources ().stream ()
101+ .filter (resource -> Objects .equals (resource .getURI (), changedResource .getURI ()))
102+ .findFirst ()
103+ .ifPresent (resourceWithSameURI -> {
104+ // There is a resource in the editing context with the same ID, this change is not
105+ // tracked by the change description.
106+ // This is for example the case when updating a library: the old version is removed, the
107+ // new one is added, but the change description will only contain the removal.
108+ result .addAll (this .createResourceDataTreeNodes (resourceWithSameURI , resourceWithSameURI .getContents (), ChangeKind .REMOVE_LITERAL ));
109+ });
110+ } else if (listChange .getKind () == ChangeKind .REMOVE_LITERAL ) {
111+ Resource changedResource = resourceChange .getResource ();
112+ List <?> resourceContent = resourceChange .getValue ();
113+ result .addAll (this .createResourceDataTreeNodes (changedResource , resourceContent , listChange .getKind ()));
114+ } else if (listChange .getKind () == ChangeKind .MOVE_LITERAL ) {
115+ // MOVE_LITERAL is not supported for now.
116+ }
117+ }
118+ }
119+ return result ;
120+ }
121+
122+ private List <DataTreeNode > createResourceDataTreeNodes (Resource resource , List <?> resourceContent , ChangeKind changeKind ) {
123+ List <DataTreeNode > result = new ArrayList <>();
124+ // We need to add a suffix to the ids to ensure they remain unique in case we display 2 resources with the same
125+ // ID. This is for example the case when updating a library, where both the old and new version have the
126+ // same ID.
127+ String idSuffix = "#" + changeKind .getName ();
128+ String resourceId = this .getId (resource ) + idSuffix ;
129+ String resourceLabel = this .labelService .getStyledLabel (resource ) + this .getLibraryLabelFragment (resource ).orElse ("" );
130+ Optional <StyledString > optionalStyledString = this .getResourceNodeStyledString (resourceLabel , changeKind );
131+ Optional <List <List <String >>> optionalEndIconsURLs = this .getResourceNodeEndIconsURLs (changeKind );
132+ if (optionalStyledString .isPresent () && optionalEndIconsURLs .isPresent ()) {
133+ result .add (new DataTreeNode (resourceId , null , optionalStyledString .get (), this .getIconURLs (resource ), optionalEndIconsURLs .get ()));
134+ for (Object resourceObject : resourceContent ) {
135+ result .addAll (this .createResourceChangeContentDataTreeNode (resourceObject , resource , changeKind ));
136+ }
137+ }
138+ return result ;
139+ }
140+
141+ private List <DataTreeNode > createResourceChangeContentDataTreeNode (Object object , Object parent , ChangeKind changeKind ) {
142+ List <DataTreeNode > result = new ArrayList <>();
143+ String idSuffix = "#" + changeKind .getName ();
144+ String objectId = this .getId (object ) + idSuffix ;
145+ String objectLabel = this .labelService .getStyledLabel (object ).toString ();
146+ Optional <StyledString > optionalStyledString = this .getResourceNodeStyledString (objectLabel , changeKind );
147+ Optional <List <List <String >>> optionalEndIconsURLs = this .getResourceNodeEndIconsURLs (changeKind );
148+ if (optionalStyledString .isPresent () && optionalEndIconsURLs .isPresent ()) {
149+ result .add (new DataTreeNode (objectId , this .getId (parent ) + idSuffix , optionalStyledString .get (), this .getIconURLs (object ), optionalEndIconsURLs .get ()));
150+ List <Object > children = this .contentService .getContents (object );
151+ for (Object child : children ) {
152+ result .addAll (this .createResourceChangeContentDataTreeNode (child , object , changeKind ));
153+ }
154+ }
155+ return result ;
156+ }
157+
158+ private Optional <StyledString > getResourceNodeStyledString (String label , ChangeKind changeKind ) {
159+ Optional <StyledString > result = Optional .empty ();
160+ if (changeKind == ChangeKind .ADD_LITERAL ) {
161+ result = Optional .of (this .getDeletionStyledString (label ));
162+ } else if (changeKind == ChangeKind .REMOVE_LITERAL ) {
163+ result = Optional .of (this .getAdditionStyledString (label ));
164+ }
165+ return result ;
166+ }
167+
168+ private Optional <List <List <String >>> getResourceNodeEndIconsURLs (ChangeKind changeKind ) {
169+ Optional <List <List <String >>> result = Optional .empty ();
170+ if (changeKind == ChangeKind .ADD_LITERAL ) {
171+ result = Optional .of (this .getDeletionEndIconsURLs ());
172+ } else if (changeKind == ChangeKind .REMOVE_LITERAL ) {
173+ result = Optional .of (this .getAdditionEndIconsURLs ());
174+ }
175+ return result ;
176+ }
177+
178+ private Optional <String > getLibraryLabelFragment (Resource resource ) {
179+ return resource .eAdapters ().stream ()
180+ .filter (LibraryMetadataAdapter .class ::isInstance )
181+ .map (LibraryMetadataAdapter .class ::cast )
182+ .map (libraryMetadataAdapter -> " (" + libraryMetadataAdapter .getName () + "@" + libraryMetadataAdapter .getVersion () + ")" )
183+ .findFirst ();
184+ }
185+
186+ private List <DataTreeNode > getObjectChangeDataTreeNode (Object object , Object parent , ChangeDescription changeDescription , List <String > allImpactObjectIds ) {
89187 List <DataTreeNode > result = new ArrayList <>();
90188 String objectId = this .getId (object );
91189 if (this .isFeatureChange (object )
92190 || allImpactObjectIds .contains (objectId )) {
93- result .add (new DataTreeNode (objectId , this .getId (parent ), this .getStyledLabel (object ), this .getIconURL (object ), this .getEndIconsURL (object , changeDescription )));
94- List <Object > children = this .getChildren (object , editingContext , changeDescription );
191+ result .add (new DataTreeNode (objectId , this .getId (parent ), this .getStyledLabel (object ), this .getIconURLs (object ), this .getEndIconsURL (object , changeDescription )));
192+ List <Object > children = this .getChildren (object , changeDescription );
95193 for (Object child : children ) {
96- result .addAll (this .getDataTreeNode (child , object , editingContext , changeDescription , allImpactObjectIds ));
194+ result .addAll (this .getObjectChangeDataTreeNode (child , object , changeDescription , allImpactObjectIds ));
97195 }
98196 }
99197 return result ;
@@ -117,7 +215,7 @@ private String getId(Object object) {
117215 return result ;
118216 }
119217
120- private List <String > getIconURL (Object object ) {
218+ private List <String > getIconURLs (Object object ) {
121219 List <String > result = List .of ();
122220 if (this .isFeatureChange (object )) {
123221 if (object instanceof FeatureAddition featureAddition ) {
@@ -133,32 +231,49 @@ private List<String> getIconURL(Object object) {
133231 return result ;
134232 }
135233
136- public StyledString getStyledLabel (Object object ) {
234+ private StyledString getStyledLabel (Object object ) {
137235 final StyledString result ;
138236 if (this .isFeatureChange (object )) {
139237 String label = "" ;
140- String foregroundColor = "" ;
141238 if (object instanceof FeatureAddition featureAddition ) {
142239 label = featureAddition .feature () + FEATURE_SEPARATOR + this .getFeatureObjectLabel (featureAddition .newValue ());
143- foregroundColor = "#48752C" ;
240+ result = this . getAdditionStyledString ( label ) ;
144241 } else if (object instanceof FeatureDeletion featureDeletion ) {
145242 label = featureDeletion .feature () + FEATURE_SEPARATOR + this .getFeatureObjectLabel (featureDeletion .oldValue ());
146- foregroundColor = "#BB271A" ;
243+ result = this . getDeletionStyledString ( label ) ;
147244 } else if (object instanceof FeatureModification featureModification ) {
148245 label = featureModification .feature () + FEATURE_SEPARATOR + this .getFeatureObjectLabel (featureModification .oldValue ()) + " -> " + this .getFeatureObjectLabel (featureModification .newValue ());
149- foregroundColor = "#000000" ;
246+ result = this .getModificationStyledString (label );
247+ } else {
248+ result = this .getStyledString ("" , "#000000" );
150249 }
151- result = new StyledString (List .of (
152- new StyledStringFragment (label , StyledStringFragmentStyle .newDefaultStyledStringFragmentStyle ()
153- .foregroundColor (foregroundColor )
154- .build ())
155- ));
156250 } else {
157251 result = this .labelService .getStyledLabel (object );
158252 }
159253 return result ;
160254 }
161255
256+ private StyledString getAdditionStyledString (String label ) {
257+ return this .getStyledString (label , "#48752C" );
258+ }
259+
260+ private StyledString getDeletionStyledString (String label ) {
261+ return this .getStyledString (label , "#BB271A" );
262+ }
263+
264+ private StyledString getModificationStyledString (String label ) {
265+ return this .getStyledString (label , "#000000" );
266+
267+ }
268+
269+ private StyledString getStyledString (String label , String foregroundColor ) {
270+ return new StyledString (List .of (
271+ new StyledStringFragment (label , StyledStringFragmentStyle .newDefaultStyledStringFragmentStyle ()
272+ .foregroundColor (foregroundColor )
273+ .build ())
274+ ));
275+ }
276+
162277 private String getFeatureObjectLabel (Object object ) {
163278 String result ;
164279 if (object instanceof EObject ) {
@@ -172,18 +287,30 @@ private String getFeatureObjectLabel(Object object) {
172287 private List <List <String >> getEndIconsURL (Object object , ChangeDescription changeDescription ) {
173288 List <List <String >> result = new ArrayList <>();
174289 if (object instanceof FeatureAddition featureAddition ) {
175- result . add ( List . of ( "/impact-analysis/FeatureAddition.svg" ) );
290+ result = this . getAdditionEndIconsURLs ( );
176291 } else if (object instanceof FeatureDeletion featureDeletion ) {
177- result . add ( List . of ( "/impact-analysis/FeatureDeletion.svg" ) );
292+ result = this . getDeletionEndIconsURLs ( );
178293 } else if (object instanceof FeatureModification featureModification ) {
179- result . add ( List . of ( "/impact-analysis/FeatureModification.svg" ) );
294+ result = this . getModificationEndIconsURLs ( );
180295 } else if (changeDescription .getObjectChanges ().keySet ().contains (object )) {
181296 result .add (List .of ("/impact-analysis/ChangeMarker.svg" ));
182297 }
183298 return result ;
184299 }
185300
186- private List <Object > getChildren (Object object , IEditingContext editingContext , ChangeDescription changeDescription ) {
301+ private List <List <String >> getAdditionEndIconsURLs () {
302+ return List .of (List .of ("/impact-analysis/FeatureAddition.svg" ));
303+ }
304+
305+ private List <List <String >> getDeletionEndIconsURLs () {
306+ return List .of (List .of ("/impact-analysis/FeatureDeletion.svg" ));
307+ }
308+
309+ private List <List <String >> getModificationEndIconsURLs () {
310+ return List .of (List .of ("/impact-analysis/FeatureModification.svg" ));
311+ }
312+
313+ private List <Object > getChildren (Object object , ChangeDescription changeDescription ) {
187314 List <Object > children = new ArrayList <>();
188315 for (Entry <EObject , EList <FeatureChange >> changes : changeDescription .getObjectChanges ().entrySet ()) {
189316 if (changes .getKey ().equals (object )) {
0 commit comments