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,112 @@ 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+ // Update generates an ADD change -> the removed resource, not the new one
94+ // We have the new one in the editing context
95+ List <DataTreeNode > result = new ArrayList <>();
96+ for (ResourceChange resourceChange : resourceChanges ) {
97+ for (ListChange listChange : resourceChange .getListChanges ()) {
98+ if (listChange .getKind () == ChangeKind .ADD_LITERAL ) {
99+ // A resource has been removed.
100+ Resource changedResource = resourceChange .getResource ();
101+ List <?> resourceContent = resourceChange .getValue ();
102+ result .addAll (this .createResourceDataTreeNodes (changedResource , resourceContent , listChange .getKind ()));
103+ resourceSet .getResources ().stream ()
104+ .filter (resource -> Objects .equals (resource .getURI (), changedResource .getURI ()))
105+ .findFirst ()
106+ .ifPresent (resourceWithSameURI -> {
107+ // There is a resource in the editing context with the same ID, this change is not
108+ // tracked by the change description.
109+ // This is for example the case when updating a library: the old version is removed, the
110+ // new one is added, but the change description will only contain the removal.
111+ result .addAll (this .createResourceDataTreeNodes (resourceWithSameURI , resourceWithSameURI .getContents (), ChangeKind .REMOVE_LITERAL ));
112+ });
113+ } else if (listChange .getKind () == ChangeKind .REMOVE_LITERAL ) {
114+ Resource changedResource = resourceChange .getResource ();
115+ List <?> resourceContent = resourceChange .getValue ();
116+ result .addAll (this .createResourceDataTreeNodes (changedResource , resourceContent , listChange .getKind ()));
117+ } else if (listChange .getKind () == ChangeKind .MOVE_LITERAL ) {
118+ // MOVE_LITERAL is not supported for now.
119+ }
120+ }
121+ }
122+ return result ;
123+ }
124+
125+ private List <DataTreeNode > createResourceDataTreeNodes (Resource resource , List <?> resourceContent , ChangeKind changeKind ) {
126+ List <DataTreeNode > result = new ArrayList <>();
127+ // We need to add a suffix to the ids to ensure they remain unique in case we display 2 resources with the same
128+ // ID. This is for example the case when updating a library, where both the old and new version have the
129+ // same ID.
130+ String idSuffix = "#" + changeKind .getName ();
131+ String resourceId = this .getId (resource ) + idSuffix ;
132+ String resourceLabel = this .labelService .getStyledLabel (resource ) + this .getLibraryLabelFragment (resource ).orElse ("" );
133+ Optional <StyledString > optionalStyledString = this .getResourceNodeStyledString (resourceLabel , changeKind );
134+ Optional <List <List <String >>> optionalEndIconsURLs = this .getResourceNodeEndIconsURLs (changeKind );
135+ if (optionalStyledString .isPresent () && optionalEndIconsURLs .isPresent ()) {
136+ result .add (new DataTreeNode (resourceId , null , optionalStyledString .get (), this .getIconURLs (resource ), optionalEndIconsURLs .get ()));
137+ for (Object resourceObject : resourceContent ) {
138+ result .addAll (this .createResourceChangeContentDataTreeNode (resourceObject , resource , changeKind ));
139+ }
140+ }
141+ return result ;
142+ }
143+
144+ private List <DataTreeNode > createResourceChangeContentDataTreeNode (Object object , Object parent , ChangeKind changeKind ) {
145+ List <DataTreeNode > result = new ArrayList <>();
146+ String idSuffix = "#" + changeKind .getName ();
147+ String objectId = this .getId (object ) + idSuffix ;
148+ String objectLabel = this .labelService .getStyledLabel (object ).toString ();
149+ Optional <StyledString > optionalStyledString = this .getResourceNodeStyledString (objectLabel , changeKind );
150+ Optional <List <List <String >>> optionalEndIconsURLs = this .getResourceNodeEndIconsURLs (changeKind );
151+ if (optionalStyledString .isPresent () && optionalEndIconsURLs .isPresent ()) {
152+ result .add (new DataTreeNode (objectId , this .getId (parent ) + idSuffix , optionalStyledString .get (), this .getIconURLs (object ), optionalEndIconsURLs .get ()));
153+ List <Object > children = this .contentService .getContents (object );
154+ for (Object child : children ) {
155+ result .addAll (this .createResourceChangeContentDataTreeNode (child , object , changeKind ));
156+ }
157+ }
158+ return result ;
159+ }
160+
161+ private Optional <StyledString > getResourceNodeStyledString (String label , ChangeKind changeKind ) {
162+ Optional <StyledString > result = Optional .empty ();
163+ if (changeKind == ChangeKind .ADD_LITERAL ) {
164+ result = Optional .of (this .getDeletionStyledString (label ));
165+ } else if (changeKind == ChangeKind .REMOVE_LITERAL ) {
166+ result = Optional .of (this .getAdditionStyledString (label ));
167+ }
168+ return result ;
169+ }
170+
171+ private Optional <List <List <String >>> getResourceNodeEndIconsURLs (ChangeKind changeKind ) {
172+ Optional <List <List <String >>> result = Optional .empty ();
173+ if (changeKind == ChangeKind .ADD_LITERAL ) {
174+ result = Optional .of (this .getDeletionEndIconsURLs ());
175+ } else if (changeKind == ChangeKind .REMOVE_LITERAL ) {
176+ result = Optional .of (this .getAdditionEndIconsURLs ());
177+ }
178+ return result ;
179+ }
180+
181+ private Optional <String > getLibraryLabelFragment (Resource resource ) {
182+ return resource .eAdapters ().stream ()
183+ .filter (LibraryMetadataAdapter .class ::isInstance )
184+ .map (LibraryMetadataAdapter .class ::cast )
185+ .map (libraryMetadataAdapter -> " (" + libraryMetadataAdapter .getName () + "@" + libraryMetadataAdapter .getVersion () + ")" )
186+ .findFirst ();
187+ }
188+
189+ private List <DataTreeNode > getObjectChangeDataTreeNode (Object object , Object parent , ChangeDescription changeDescription , List <String > allImpactObjectIds ) {
89190 List <DataTreeNode > result = new ArrayList <>();
90191 String objectId = this .getId (object );
91192 if (this .isFeatureChange (object )
92193 || 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 );
194+ result .add (new DataTreeNode (objectId , this .getId (parent ), this .getStyledLabel (object ), this .getIconURLs (object ), this .getEndIconsURL (object , changeDescription )));
195+ List <Object > children = this .getChildren (object , changeDescription );
95196 for (Object child : children ) {
96- result .addAll (this .getDataTreeNode (child , object , editingContext , changeDescription , allImpactObjectIds ));
197+ result .addAll (this .getObjectChangeDataTreeNode (child , object , changeDescription , allImpactObjectIds ));
97198 }
98199 }
99200 return result ;
@@ -117,7 +218,7 @@ private String getId(Object object) {
117218 return result ;
118219 }
119220
120- private List <String > getIconURL (Object object ) {
221+ private List <String > getIconURLs (Object object ) {
121222 List <String > result = List .of ();
122223 if (this .isFeatureChange (object )) {
123224 if (object instanceof FeatureAddition featureAddition ) {
@@ -133,32 +234,49 @@ private List<String> getIconURL(Object object) {
133234 return result ;
134235 }
135236
136- public StyledString getStyledLabel (Object object ) {
237+ private StyledString getStyledLabel (Object object ) {
137238 final StyledString result ;
138239 if (this .isFeatureChange (object )) {
139240 String label = "" ;
140- String foregroundColor = "" ;
141241 if (object instanceof FeatureAddition featureAddition ) {
142242 label = featureAddition .feature () + FEATURE_SEPARATOR + this .getFeatureObjectLabel (featureAddition .newValue ());
143- foregroundColor = "#48752C" ;
243+ result = this . getAdditionStyledString ( label ) ;
144244 } else if (object instanceof FeatureDeletion featureDeletion ) {
145245 label = featureDeletion .feature () + FEATURE_SEPARATOR + this .getFeatureObjectLabel (featureDeletion .oldValue ());
146- foregroundColor = "#BB271A" ;
246+ result = this . getDeletionStyledString ( label ) ;
147247 } else if (object instanceof FeatureModification featureModification ) {
148248 label = featureModification .feature () + FEATURE_SEPARATOR + this .getFeatureObjectLabel (featureModification .oldValue ()) + " -> " + this .getFeatureObjectLabel (featureModification .newValue ());
149- foregroundColor = "#000000" ;
249+ result = this .getModificationStyledString (label );
250+ } else {
251+ result = this .getStyledString ("" , "#000000" );
150252 }
151- result = new StyledString (List .of (
152- new StyledStringFragment (label , StyledStringFragmentStyle .newDefaultStyledStringFragmentStyle ()
153- .foregroundColor (foregroundColor )
154- .build ())
155- ));
156253 } else {
157254 result = this .labelService .getStyledLabel (object );
158255 }
159256 return result ;
160257 }
161258
259+ private StyledString getAdditionStyledString (String label ) {
260+ return this .getStyledString (label , "#48752C" );
261+ }
262+
263+ private StyledString getDeletionStyledString (String label ) {
264+ return this .getStyledString (label , "#BB271A" );
265+ }
266+
267+ private StyledString getModificationStyledString (String label ) {
268+ return this .getStyledString (label , "#000000" );
269+
270+ }
271+
272+ private StyledString getStyledString (String label , String foregroundColor ) {
273+ return new StyledString (List .of (
274+ new StyledStringFragment (label , StyledStringFragmentStyle .newDefaultStyledStringFragmentStyle ()
275+ .foregroundColor (foregroundColor )
276+ .build ())
277+ ));
278+ }
279+
162280 private String getFeatureObjectLabel (Object object ) {
163281 String result ;
164282 if (object instanceof EObject ) {
@@ -172,18 +290,30 @@ private String getFeatureObjectLabel(Object object) {
172290 private List <List <String >> getEndIconsURL (Object object , ChangeDescription changeDescription ) {
173291 List <List <String >> result = new ArrayList <>();
174292 if (object instanceof FeatureAddition featureAddition ) {
175- result . add ( List . of ( "/impact-analysis/FeatureAddition.svg" ) );
293+ result = this . getAdditionEndIconsURLs ( );
176294 } else if (object instanceof FeatureDeletion featureDeletion ) {
177- result . add ( List . of ( "/impact-analysis/FeatureDeletion.svg" ) );
295+ result = this . getDeletionEndIconsURLs ( );
178296 } else if (object instanceof FeatureModification featureModification ) {
179- result . add ( List . of ( "/impact-analysis/FeatureModification.svg" ) );
297+ result = this . getModificationEndIconsURLs ( );
180298 } else if (changeDescription .getObjectChanges ().keySet ().contains (object )) {
181299 result .add (List .of ("/impact-analysis/ChangeMarker.svg" ));
182300 }
183301 return result ;
184302 }
185303
186- private List <Object > getChildren (Object object , IEditingContext editingContext , ChangeDescription changeDescription ) {
304+ private List <List <String >> getAdditionEndIconsURLs () {
305+ return List .of (List .of ("/impact-analysis/FeatureAddition.svg" ));
306+ }
307+
308+ private List <List <String >> getDeletionEndIconsURLs () {
309+ return List .of (List .of ("/impact-analysis/FeatureDeletion.svg" ));
310+ }
311+
312+ private List <List <String >> getModificationEndIconsURLs () {
313+ return List .of (List .of ("/impact-analysis/FeatureModification.svg" ));
314+ }
315+
316+ private List <Object > getChildren (Object object , ChangeDescription changeDescription ) {
187317 List <Object > children = new ArrayList <>();
188318 for (Entry <EObject , EList <FeatureChange >> changes : changeDescription .getObjectChanges ().entrySet ()) {
189319 if (changes .getKey ().equals (object )) {
0 commit comments