From 18008b3f4473e694ac96d6b7d4b5944c1b58858f Mon Sep 17 00:00:00 2001 From: Cedric Dumoulin Date: Thu, 12 Dec 2013 09:42:45 +0100 Subject: First working RegExp Add NotyfyingList and ExpressionMatcher Update layers model.--- .../META-INF/MANIFEST.MF | 3 +- .../model/layers.ecore | 4 +- .../model/layers.notation | 22 +- .../model/layers.uml | 6 +- .../stackmodel/exprmatcher/ExpressionMatcher.java | 153 +++++++--- .../layers/stackmodel/layers/RegExpLayer.java | 8 +- .../stackmodel/layers/impl/LayersPackageImpl.java | 4 +- .../stackmodel/layers/impl/RegExpLayerImpl.java | 314 +++++++++++++++++++-- .../layers/stackmodel/util/NotyfyingList.java | 2 - .../exprmatcher/ExpressionMatcherTest.java | 195 ++++++++++++- .../layers/stackmodel/util/NotyfyingListTest.java | 2 +- 11 files changed, 617 insertions(+), 96 deletions(-) (limited to 'extraplugins/layers/org.eclipse.papyrus.layers.stackmodel') diff --git a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/META-INF/MANIFEST.MF b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/META-INF/MANIFEST.MF index e86c17d97e2..19497f1825a 100644 --- a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/META-INF/MANIFEST.MF +++ b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/META-INF/MANIFEST.MF @@ -11,7 +11,8 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.emf.ecore.xmi;bundle-version="2.9.0", org.eclipse.uml2.uml;bundle-version="4.1.0", org.eclipse.ocl.ecore;bundle-version="3.3.0", - org.eclipse.emf.query.ocl;bundle-version="2.0.0" + org.eclipse.emf.query.ocl;bundle-version="2.0.0", + com.google.guava;bundle-version="11.0.2" Bundle-ActivationPolicy: lazy Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.ecore b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.ecore index dd85962cf69..a491914feb3 100644 --- a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.ecore +++ b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.ecore @@ -405,7 +405,7 @@ - @@ -416,7 +416,7 @@ - diff --git a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.notation b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.notation index bcebd0a76d6..622401c1477 100644 --- a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.notation +++ b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.notation @@ -838,7 +838,7 @@ - + @@ -870,7 +870,7 @@ - + @@ -974,7 +974,7 @@ - + @@ -1057,7 +1057,7 @@ - + @@ -1249,7 +1249,7 @@ - + @@ -1337,7 +1337,7 @@ - + @@ -1369,7 +1369,7 @@ - + @@ -1473,8 +1473,8 @@ - - + + @@ -1593,7 +1593,7 @@ - + @@ -1614,7 +1614,7 @@ - + diff --git a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.uml b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.uml index 1c7c1bcb720..04dcde06218 100644 --- a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.uml +++ b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/model/layers.uml @@ -908,8 +908,8 @@ This class carry a referenceto the Application. - - + + @@ -949,6 +949,8 @@ This class carry a referenceto the Application. + + diff --git a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/exprmatcher/ExpressionMatcher.java b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/exprmatcher/ExpressionMatcher.java index f19b59841c5..8d33a4547c9 100644 --- a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/exprmatcher/ExpressionMatcher.java +++ b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/exprmatcher/ExpressionMatcher.java @@ -34,6 +34,9 @@ import org.eclipse.gmf.runtime.notation.View; import org.eclipse.ocl.ParserException; import org.eclipse.ocl.ecore.OCL; import org.eclipse.papyrus.layers.stackmodel.LayersException; +import org.eclipse.papyrus.layers.stackmodel.util.NotyfyingList; + +import com.google.common.collect.Lists; /** * This class evaluate its associated expression against the associated models. @@ -48,13 +51,13 @@ import org.eclipse.papyrus.layers.stackmodel.LayersException; */ public class ExpressionMatcher { - protected String expression; + protected String expression=""; /** * List of element matching the expression. * This class maintains the list. */ - protected List matchingElements; + protected NotyfyingList matchingElements; /** * List of element used as starting point for search. @@ -68,6 +71,38 @@ public class ExpressionMatcher { protected OCL ocl; + public ExpressionMatcher() { + this.expression = ""; + this.searchRoots = Collections.emptyList(); + // init matchingElements + matchingElements = new NotyfyingList(new ArrayList()); + } + + /** + * + * Constructor. + * + * @param searchRoots + * @throws LayersException + */ + public ExpressionMatcher(List searchRoots) { + this.expression = ""; + this.searchRoots = searchRoots; + // init matchingElements + matchingElements = new NotyfyingList(new ArrayList()); + } + + /** + * + * Constructor. + * + * @param searchRoot + * @throws LayersException + */ + public ExpressionMatcher(EObject searchRoot) { + this(Collections.singletonList(searchRoot)); + } + /** * Constructor. * @@ -76,13 +111,22 @@ public class ExpressionMatcher { * @throws LayersException If the Condition can't be computed from the expression. */ public ExpressionMatcher(String expression, List searchRoots) throws LayersException { - this.expression = expression; this.searchRoots = searchRoots; - matchingElements = new ArrayList(); + matchingElements = new NotyfyingList(new ArrayList()); // compute expr - computeCondition(); - refreshMatchingElements(); + setExpression(expression); + } + + /** + * Constructor. + * + * @param expression + * @param searchRoots + * @throws LayersException If the Condition can't be computed from the expression. + */ + public ExpressionMatcher(String expression, EObject searchRoot) throws LayersException { + this(expression, Collections.singletonList(searchRoot)); } /** @@ -99,6 +143,8 @@ public class ExpressionMatcher { } // Create the condition try { + // If the 3rd args is null, this is a context free condition. + condition = new BooleanOCLCondition( ocl.getEnvironment(), // "self.oclIsKindOf(Shape)", @@ -106,16 +152,16 @@ public class ExpressionMatcher { // "self.oclAsType(Shape).visible = true", getExpression(), NotationPackage.Literals.VIEW +// null ); } catch (ParserException e) { // TODO Auto-generated catch block condition = null; - throw new LayersException("Can't parse expression", e); + throw new LayersException("Can't parse expression : " + e.getMessage(), e); } } - /** * Recompute the matching elements. * This lead to firing Events (added and removed) @@ -152,36 +198,39 @@ public class ExpressionMatcher { * @param results */ private void resetMatchingElements(Collection newElements) { - // Compute views to add - // This are views in the newElements, but not in the actual list of matchingElement - // viewsToAdd = results - getViews() - List viewsToAdd = new ArrayList(); - for( Object o : newElements ) { - View v = (View)o; - if( !getMatchingElements().contains(v)) { - viewsToAdd.add(v); - } - } - // Compute views to remove - // Their is two ways to compute it: - // - viewsToremove = diagramViews - results - // - or viewsToremove = getViews() - result - // Use the cheaper one. - // The computed viewsToRemove list contains also views that are not in the layer, - // But this is cheaper than checking for the existence. + matchingElements.resetTo((Collection)newElements); -// List viewsToRemove = new ArrayList(); -// for( View v : (views.size() viewsToAdd = new ArrayList(); +// for( Object o : newElements ) { +// View v = (View)o; +// if( !getMatchingElements().contains(v)) { +// viewsToAdd.add(v); // } // } - - // Do operations - getMatchingElements().retainAll(newElements); -// getViews().removeAll(viewsToRemove); - getMatchingElements().addAll(viewsToAdd); +// +// // Compute views to remove +// // Their is two ways to compute it: +// // - viewsToremove = diagramViews - results +// // - or viewsToremove = getViews() - result +// // Use the cheaper one. +// // The computed viewsToRemove list contains also views that are not in the layer, +// // But this is cheaper than checking for the existence. +// +//// List viewsToRemove = new ArrayList(); +//// for( View v : (views.size() getMatchingElements() { + public NotyfyingList getMatchingElements() { return matchingElements; } @@ -220,5 +278,30 @@ public class ExpressionMatcher { return searchRoots; } + /** + * + * @param searchRoots + */ + public void setSearchRoots(List searchRoots) { + if( searchRoots == null) { + searchRoots = Collections.emptyList(); + } + this.searchRoots = searchRoots; + // Do not refresh. Let user do it. + } + + /** + * + * @param searchRoots + */ + public void setSearchRoots(EObject searchRoot) { + if( searchRoot == null) { + searchRoots = Collections.emptyList(); + return; + } + + setSearchRoots( Collections.singletonList(searchRoot) ); + } + } diff --git a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/RegExpLayer.java b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/RegExpLayer.java index 9d173c2a901..d259d1b068a 100644 --- a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/RegExpLayer.java +++ b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/RegExpLayer.java @@ -248,10 +248,10 @@ public interface RegExpLayer extends AbstractLayer { /** * * - * @model dataType="org.eclipse.papyrus.layers.stackmodel.layers.boolean" ordered="false" exceptions="org.eclipse.papyrus.layers.stackmodel.layers.LayersException" viewRequired="true" viewOrdered="false" + * @model dataType="org.eclipse.papyrus.layers.stackmodel.layers.boolean" required="true" ordered="false" exceptions="org.eclipse.papyrus.layers.stackmodel.layers.LayersException" viewRequired="true" viewOrdered="false" * @generated */ - EList isDerivedView(View view) throws LayersException; + boolean isDerivedView(View view) throws LayersException; /** * @@ -280,8 +280,8 @@ public interface RegExpLayer extends AbstractLayer { /** * * - * @model required="true" ordered="false" exceptions="org.eclipse.papyrus.layers.stackmodel.layers.LayersException" viewsMany="true" viewsOrdered="false" + * @model ordered="false" exceptions="org.eclipse.papyrus.layers.stackmodel.layers.LayersException" viewsMany="true" viewsOrdered="false" * @generated */ - View lookupDerivedViews(EList views) throws LayersException; + EList lookupDerivedViews(EList views) throws LayersException; } // RegExpLayer diff --git a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/impl/LayersPackageImpl.java b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/impl/LayersPackageImpl.java index 64816c0a985..9be752e4abf 100644 --- a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/impl/LayersPackageImpl.java +++ b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/impl/LayersPackageImpl.java @@ -3443,7 +3443,7 @@ public class LayersPackageImpl extends EPackageImpl implements LayersPackage { op = initEOperation(getRegExpLayer__Deactivate__AbstractLayerOperator(), null, "deactivate", 1, 1, IS_UNIQUE, !IS_ORDERED); addEParameter(op, this.getAbstractLayerOperator(), "oldParentLayer", 1, 1, IS_UNIQUE, !IS_ORDERED); - op = initEOperation(getRegExpLayer__IsDerivedView__View(), this.getboolean(), "isDerivedView", 0, -1, IS_UNIQUE, !IS_ORDERED); + op = initEOperation(getRegExpLayer__IsDerivedView__View(), this.getboolean(), "isDerivedView", 1, 1, IS_UNIQUE, !IS_ORDERED); addEParameter(op, theNotationPackage.getView(), "view", 1, 1, IS_UNIQUE, !IS_ORDERED); addEException(op, this.getLayersException()); @@ -3458,7 +3458,7 @@ public class LayersPackageImpl extends EPackageImpl implements LayersPackage { op = initEOperation(getRegExpLayer__AttachDerivedViews(), null, "attachDerivedViews", 1, 1, IS_UNIQUE, !IS_ORDERED); addEException(op, this.getLayersException()); - op = initEOperation(getRegExpLayer__LookupDerivedViews__EList(), theNotationPackage.getView(), "lookupDerivedViews", 1, 1, IS_UNIQUE, !IS_ORDERED); + op = initEOperation(getRegExpLayer__LookupDerivedViews__EList(), theNotationPackage.getView(), "lookupDerivedViews", 0, -1, IS_UNIQUE, !IS_ORDERED); addEParameter(op, theNotationPackage.getView(), "views", 0, -1, IS_UNIQUE, !IS_ORDERED); addEException(op, this.getLayersException()); diff --git a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/impl/RegExpLayerImpl.java b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/impl/RegExpLayerImpl.java index 6d378c4eba0..24ad2517609 100644 --- a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/impl/RegExpLayerImpl.java +++ b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/impl/RegExpLayerImpl.java @@ -13,17 +13,33 @@ package org.eclipse.papyrus.layers.stackmodel.layers.impl; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.impl.AdapterImpl; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.impl.ENotificationImpl; +import org.eclipse.emf.query.conditions.eobjects.EObjectCondition; +import org.eclipse.emf.query.ocl.conditions.BooleanOCLCondition; +import org.eclipse.emf.query.statements.FROM; +import org.eclipse.emf.query.statements.IQueryResult; +import org.eclipse.emf.query.statements.SELECT; +import org.eclipse.emf.query.statements.WHERE; +import org.eclipse.gmf.runtime.notation.NotationPackage; import org.eclipse.gmf.runtime.notation.View; +import org.eclipse.ocl.ParserException; +import org.eclipse.ocl.ecore.OCL; import org.eclipse.papyrus.layers.stackmodel.LayersException; import org.eclipse.papyrus.layers.stackmodel.NotFoundException; +import org.eclipse.papyrus.layers.stackmodel.exprmatcher.ExpressionMatcher; import org.eclipse.papyrus.layers.stackmodel.layers.AbstractLayerOperator; import org.eclipse.papyrus.layers.stackmodel.layers.EventLevel; import org.eclipse.papyrus.layers.stackmodel.layers.LayersPackage; @@ -31,6 +47,9 @@ import org.eclipse.papyrus.layers.stackmodel.layers.LayersStack; import org.eclipse.papyrus.layers.stackmodel.layers.RegExpLayer; import org.eclipse.papyrus.layers.stackmodel.notifier.DiagramViewEventNotifier; import org.eclipse.papyrus.layers.stackmodel.notifier.IDiagramViewEventListener; +import org.eclipse.papyrus.layers.stackmodel.util.NotyfyingList; + +import com.google.common.eventbus.Subscribe; /** * @@ -190,17 +209,11 @@ public class RegExpLayerImpl extends AbstractLayerImpl implements RegExpLayer { switch(msg.getEventType()) { case Notification.SET: // - Object newValue = msg.getNewValue(); - if( newValue == null) { - deactivate((AbstractLayerOperator)msg.getOldValue()); - } - else { - activate((AbstractLayerOperator)msg.getNewValue()); - } + parentLayerChanged((AbstractLayerOperator)msg.getNewValue(), (AbstractLayerOperator)msg.getOldValue()); break; case Notification.UNSET: - deactivate((AbstractLayerOperator)msg.getOldValue()); + parentLayerChanged((AbstractLayerOperator)msg.getNewValue(), (AbstractLayerOperator)msg.getOldValue()); break; default: @@ -212,6 +225,11 @@ public class RegExpLayerImpl extends AbstractLayerImpl implements RegExpLayer { }; protected DiagramViewEventNotifier diagramViewEventNotifier; + + /** + * Expression matcher computing the expr, and firing events when the matching elements change. + */ + protected ExpressionMatcher expressionMatcher; /** * @@ -220,9 +238,16 @@ public class RegExpLayerImpl extends AbstractLayerImpl implements RegExpLayer { */ protected RegExpLayerImpl() { super(); + + // Initialize expressionmatcher + expressionMatcher = new ExpressionMatcher(); + resetExpressionMatcherRoots(); + + // listen to expression matcher changes + expressionMatcher.getMatchingElements().getEventBus().register(this); + // Listen on this object attachment / detachment from its container. eAdapters().add(containerListener); - } /** @@ -247,15 +272,32 @@ public class RegExpLayerImpl extends AbstractLayerImpl implements RegExpLayer { /** * * - * @generated + * @generated NOT */ public void setExpr(String newExpr) { String oldExpr = expr; expr = newExpr; + // Try to set the expression + try { + // First, reset expr roots. Do it because actually the roots are not properly set. + resetExpressionMatcherRoots(); + // Change the expression, and recompute the matching elements. + expressionMatcher.setExpression(newExpr); + expressionMatcher.refreshMatchingElements(); + } catch (LayersException e) { + // silently fails, but log the error. + System.err.println( "Error - " + this.getClass().getSimpleName() + " - " + e.getMessage()); + } if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, LayersPackage.REG_EXP_LAYER__EXPR, oldExpr, expr)); } + /** + * OCL Condition computed from the expr. + */ + protected EObjectCondition condition; + protected OCL ocl; + /** * * @@ -382,6 +424,57 @@ public class RegExpLayerImpl extends AbstractLayerImpl implements RegExpLayer { eNotify(new ENotificationImpl(this, Notification.SET, LayersPackage.REG_EXP_LAYER__EXPRESSION_CONTEXT_OBJECT_TYPE, oldExpressionContextObjectType, expressionContextObjectType)); } + /** + * The parent that contains this Layer has changed. + * Check if the associated Diagram has changed, and if true, change it in the ExpressionMatcher. + * + * + * + * @param newLayerParent + * @generated NOT + */ + public void parentLayerChanged(AbstractLayerOperator newLayerParent, AbstractLayerOperator oldLayerParent) { + + // Try to change the diagram in the expressionMatcher. + // The expressionMatcher takes care to change it only if it this changed. + resetExpressionMatcherRoots(); + } + + /** + * Listener on {@link NotyfyingList} eventBus. This method is called each time a change occurs in the + * result of the expression. + * When the result change, the list of attached views is updated accordingly. + * + * + * @param event + */ + @Subscribe + public void expressionResultChanged( NotyfyingList.NotifyingListEvent event) { + + System.out.println( this.getClass().getSimpleName() + ".expressionResultChanged()"); + if( ! event.getAddedElements().isEmpty()) { + getViews().addAll(event.getAddedElements()); + } + if( ! event.getRemovedElements().isEmpty()) { + getViews().removeAll(event.getRemovedElements()); + } + + } + + /** + * Check if the associated Diagram has changed, and if true, change it in the ExpressionMatcher. + */ + private void resetExpressionMatcherRoots() { + + try { + expressionMatcher.setSearchRoots( getLayersStack().getDiagram() ); + } catch (NotFoundException e) { + // layerStack not found ==> no roots + expressionMatcher.setSearchRoots( (List)Collections.EMPTY_LIST); + } + + } + /** * * @@ -434,56 +527,215 @@ public class RegExpLayerImpl extends AbstractLayerImpl implements RegExpLayer { /** * * - * @generated + * @generated NOT */ - public EList isDerivedView(View view) throws LayersException { - // TODO: implement this method - // Ensure that you remove @generated or mark it @generated NOT - throw new UnsupportedOperationException(); + public boolean isDerivedView(View view) throws LayersException { + + if(condition == null) { + return false; + } + + // Create the OCL statement + SELECT statement = new SELECT(SELECT.UNBOUNDED, false, + new FROM(view), new WHERE(condition), + new NullProgressMonitor()); + + // Execute the OCL statement + IQueryResult results = statement.execute(); + + // the view is derived if the condition match the view. + return !results.isEmpty(); } /** * + * Check if the view satisfy the expr condition. + * If the condition is satisfied, ensure that the view is attached. + * If the condition is not satisfied, ensure that the view is not attached. + * + * * - * @generated + * @generated NOT */ public void attachDerivedView(View view) throws LayersException { // TODO: implement this method - // Ensure that you remove @generated or mark it @generated NOT - throw new UnsupportedOperationException(); + if(condition == null) { + return; + } + + // Create the OCL statement + SELECT statement = new SELECT(SELECT.UNBOUNDED, false, + new FROM(view), new WHERE(condition), + new NullProgressMonitor()); + + // Execute the OCL statement + IQueryResult results = statement.execute(); + + // + if( ! results.isEmpty()) { + // The condition is satisfied. Ensure the view is attached + List attachedViews = getViews(); + if (attachedViews.contains(view)) { + return; + } + attachedViews.add(view); + } + else { + // The condition is not satisfied. Ensure the view is not attached. + getViews().remove(view); + } } /** * + * Attach each view that satisfy the condition. + * Detach each view that do not satisfy the condition. + * TODO rename to updateDerivedViews() ? * - * @generated + * @generated NOT */ public void attachDerivedViews(EList views) throws LayersException { - // TODO: implement this method - // Ensure that you remove @generated or mark it @generated NOT - throw new UnsupportedOperationException(); + + if(condition == null) { + return; + } + + // Create the OCL statement + SELECT statement = new SELECT(SELECT.UNBOUNDED, false, + new FROM(views), new WHERE(condition), + new NullProgressMonitor()); + + // Execute the OCL statement + IQueryResult results = statement.execute(); + + // viewsToCheck + // attachedViews -- list of views that are attached + // -- getViews() + // viewsToAttach -- list of views that should be attached + // -- query result + // toAdd - views that are in viewsToAttach, but not in attachedViews + // -- + // toRemove - views that are in attachedViews, and viewsToCheck, but not in viewsToAttach + + // Compute views to add + // This are views in the result, but not in the list of attached + // viewsToAdd = results - getViews() + List viewsToAdd = new ArrayList(); + List attachedViews = getViews(); + for( Object o : results ) { + View v = (View)o; + if( !attachedViews.contains(v)) { + viewsToAdd.add(v); + } + } + + // Compute views to remove + // Their is two ways to compute it: + // - viewsToremove = diagramViews - results + // - or viewsToremove = getViews() - result + // Use the cheaper one. + // The computed viewsToRemove list contains also views that are not in the layer, + // But this is cheaper than checking for the existence. + + List viewsToRemove = new ArrayList(); + for( View v : (views.size() + * Update all views directly own by the diagram. + * + * If a view satisfy the expr condition, attach it to the Layer. + * Remove all others view from the layer. + *
+ * To avoid multiple events, we compute the list of views to remove from the layer, and the list + * of views to add to layer. Then, we preform two operations; removeAll(toRemove) and addAll(toAdd); + * * - * @generated + * @generated NOT */ public void attachDerivedViews() throws LayersException { - // TODO: implement this method - // Ensure that you remove @generated or mark it @generated NOT - throw new UnsupportedOperationException(); + + if(condition == null) { + return; + } + + // Check views from the diagram. + @SuppressWarnings("unchecked") + EList diagramViews = (EList)getLayersStack().getDiagram().getChildren(); + + // Create the OCL statement + SELECT statement = new SELECT(SELECT.UNBOUNDED, false, + new FROM(diagramViews), new WHERE(condition), + new NullProgressMonitor()); + + // Execute the OCL statement + IQueryResult results = statement.execute(); + + // Compute views to add + // This are views in the result, but not in the list of attached + // viewsToAdd = results - getViews() + List viewsToAdd = new ArrayList(); + List attachedViews = getViews(); + for( Object o : results ) { + View v = (View)o; + if( !attachedViews.contains(v)) { + viewsToAdd.add(v); + } + } + + // Compute views to remove + // Their is two ways to compute it: + // - viewsToremove = diagramViews - results + // - or viewsToremove = getViews() - result + // Use the cheaper one. + // The computed viewsToRemove list contains also views that are not in the layer, + // But this is cheaper than checking for the existence. + +// List viewsToRemove = new ArrayList(); +// for( View v : (views.size() * - * @generated + * @generated NOT */ - public View lookupDerivedViews(EList views) throws LayersException { - // TODO: implement this method - // Ensure that you remove @generated or mark it @generated NOT - throw new UnsupportedOperationException(); + public EList lookupDerivedViews(EList views) throws LayersException { +// if(condition == null) { +// return EList.EMPTY_LIST; +// } +// +// // Check views from the diagram. +// @SuppressWarnings("unchecked") +// EList diagramViews = (EList)getLayersStack().getDiagram().getChildren(); +// +// // Create the OCL statement +// SELECT statement = new SELECT(SELECT.UNBOUNDED, false, +// new FROM(diagramViews), new WHERE(condition), +// new NullProgressMonitor()); +// +// // Execute the OCL statement +// IQueryResult results = statement.execute(); +// return new ; + return null; } /** diff --git a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/util/NotyfyingList.java b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/util/NotyfyingList.java index 007160bfd95..228930b6f9a 100644 --- a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/util/NotyfyingList.java +++ b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/util/NotyfyingList.java @@ -19,8 +19,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import org.eclipse.gmf.runtime.notation.View; - import com.google.common.collect.ForwardingList; import com.google.common.collect.Lists; import com.google.common.eventbus.EventBus; diff --git a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/test/org/eclipse/papyrus/layers/stackmodel/exprmatcher/ExpressionMatcherTest.java b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/test/org/eclipse/papyrus/layers/stackmodel/exprmatcher/ExpressionMatcherTest.java index d33830e3ef1..567cf6343e7 100644 --- a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/test/org/eclipse/papyrus/layers/stackmodel/exprmatcher/ExpressionMatcherTest.java +++ b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/test/org/eclipse/papyrus/layers/stackmodel/exprmatcher/ExpressionMatcherTest.java @@ -14,10 +14,13 @@ package org.eclipse.papyrus.layers.stackmodel.exprmatcher; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; -import java.util.Collection; import java.util.List; import org.eclipse.core.runtime.CoreException; @@ -27,13 +30,17 @@ import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.gmf.runtime.notation.Diagram; +import org.eclipse.gmf.runtime.notation.NotationFactory; +import org.eclipse.gmf.runtime.notation.NotationPackage; +import org.eclipse.gmf.runtime.notation.Shape; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.layers.stackmodel.LayersException; +import org.eclipse.papyrus.layers.stackmodel.util.FakeNotifyingListListener; +import org.eclipse.papyrus.layers.stackmodel.util.NotyfyingList; +import org.eclipse.uml2.uml.NamedElement; import org.junit.After; -import org.junit.Assume; import org.junit.Before; import org.junit.Test; -import org.junit.experimental.categories.Categories.ExcludeCategory; /** * @author cedric dumoulin @@ -113,6 +120,34 @@ public class ExpressionMatcherTest { } + /** + * Test an expression + * @throws LayersException + */ + @Test + public void testExpression() throws LayersException { + +// Shape s; +// ((NamedElement)s.getElement()).getName().startsWith(prefix); + + String expression = "self.element.oclAsType(uml::NamedElement).name.startsWith('C') = true"; +// self.oclAsType(Shape).element.oclAsType(uml::NamedElement).name.startsWith('C') = true +// "self.element.oclAsType(uml::NamedElement).name.startsWith('C') = true"; +// "self.oclIsKindOf(Shape)", +// "self.oclIsKindOf(Shape) and self.oclAsType(Shape).visible = true", +// "self.oclAsType(Shape).visible = true", + + String modelFileName = "/test/models/model1"; + Diagram diagram = getDiagram(modelFileName); + List searchRoots = diagram.getChildren(); + + ExpressionMatcher expressionMatcher = new ExpressionMatcher(expression, searchRoots); + assertNotNull("object created", expressionMatcher); + + assertTrue("result not empty", !expressionMatcher.getMatchingElements().isEmpty()); + + } + /** * Test method for {@link org.eclipse.papyrus.layers.stackmodel.exprmatcher.ExpressionMatcher#ExpressionMatcher(java.lang.String, java.util.List)}. * @throws LayersException @@ -258,5 +293,155 @@ public class ExpressionMatcherTest { assertNotNull("Diagram exist", diagram); } - + /** + * Test removing elements. + * @throws LayersException + */ + @Test + public void testRemoveElements() throws LayersException { + String expression = "self.oclIsKindOf(Shape)"; +// "self.oclIsKindOf(Shape)", +// "self.oclIsKindOf(Shape) and self.oclAsType(Shape).visible = true", +// "self.oclAsType(Shape).visible = true", + + String modelFileName = "/test/models/model1"; + Diagram diagram = getDiagram(modelFileName); + + int removedElementCount = 5; + int addedElementCount = 0; + int expectedEventCount = 1; + + FakeNotifyingListListener notifyingListListener = new FakeNotifyingListListener(); + ExpressionMatcher expressionMatcher = new ExpressionMatcher(expression, diagram); + + expressionMatcher.getMatchingElements().getEventBus().register(notifyingListListener); + + // Action + notifyingListListener.traces.clear(); + removeElements(diagram, removedElementCount); + expressionMatcher.refreshMatchingElements(); + + // Assert + assertSame("event propagated", expectedEventCount, notifyingListListener.traces.size()); + + NotyfyingList.NotifyingListEvent event = notifyingListListener.traces.get(0).notifier; + + assertEquals("expected removed count", removedElementCount, event.getRemovedElements().size()); + assertEquals("expected added count", addedElementCount, event.getAddedElements().size()); + } + + /** + * Test removing elements. + * @throws LayersException + */ + @Test + public void testAddElements() throws LayersException { + String expression = "self.oclIsKindOf(Shape)"; +// "self.oclIsKindOf(Shape)", +// "self.oclIsKindOf(Shape) and self.oclAsType(Shape).visible = true", +// "self.oclAsType(Shape).visible = true", + + String modelFileName = "/test/models/model1"; + Diagram diagram = getDiagram(modelFileName); + + int removedElementCount = 0; + int addedElementCount = 5; + int expectedEventCount = 1; + int viewsCount = diagram.getChildren().size(); + + FakeNotifyingListListener notifyingListListener = new FakeNotifyingListListener(); + ExpressionMatcher expressionMatcher = new ExpressionMatcher(expression, diagram); + + expressionMatcher.getMatchingElements().getEventBus().register(notifyingListListener); + + // Action + notifyingListListener.traces.clear(); + addShapeElements(diagram, addedElementCount); + removeElements(diagram, removedElementCount); + expressionMatcher.refreshMatchingElements(); + + // Assert + assertSame("elements added", viewsCount+addedElementCount, diagram.getChildren().size()); + + assertSame("event propagated", expectedEventCount, notifyingListListener.traces.size()); + + NotyfyingList.NotifyingListEvent event = notifyingListListener.traces.get(0).notifier; + + assertEquals("expected removed count", removedElementCount, event.getRemovedElements().size()); + assertEquals("expected added count", addedElementCount, event.getAddedElements().size()); + } + + /** + * Test removing elements. + * @throws LayersException + */ + @Test + public void testAddAndRemoveElements() throws LayersException { + String expression = "self.oclIsKindOf(Shape)"; +// "self.oclIsKindOf(Shape)", +// "self.oclIsKindOf(Shape) and self.oclAsType(Shape).visible = true", +// "self.oclAsType(Shape).visible = true", + + String modelFileName = "/test/models/model1"; + Diagram diagram = getDiagram(modelFileName); + + int removedElementCount = 4; + int addedElementCount = 5; + int expectedEventCount = 1; + int viewsCount = diagram.getChildren().size(); + + FakeNotifyingListListener notifyingListListener = new FakeNotifyingListListener(); + ExpressionMatcher expressionMatcher = new ExpressionMatcher(expression, diagram); + + expressionMatcher.getMatchingElements().getEventBus().register(notifyingListListener); + + // Action + notifyingListListener.traces.clear(); + removeElements(diagram, removedElementCount); + addShapeElements(diagram, addedElementCount); + expressionMatcher.refreshMatchingElements(); + + // Assert + assertSame("elements added", viewsCount+addedElementCount-removedElementCount, diagram.getChildren().size()); + + assertSame("event propagated", expectedEventCount, notifyingListListener.traces.size()); + + NotyfyingList.NotifyingListEvent event = notifyingListListener.traces.get(0).notifier; + + assertEquals("expected removed count", removedElementCount, event.getRemovedElements().size()); + assertEquals("expected added count", addedElementCount, event.getAddedElements().size()); + } + + + /** + * Remove n Views from the provided diagram + * @param diagram + * @param removedElementCount + */ + private void removeElements(Diagram diagram, int removedElementCount) { + + List views = diagram.getChildren(); + + int index = views.size()-1; + for( int i=0; i=0; i++) { + diagram.removeChild(views.get(index)); + index = views.size()-1; + } + + } + + /** + * Add n Views to the provided diagram + * @param diagram + * @param removedElementCount + */ + private void addShapeElements(Diagram diagram, int elementCount) { + + for( int i=0; i list = Lists.newArrayList( "red", "orange", "yellow", "green", "blue", "purple"); List listToReset = Lists.newArrayList( "red", "orange", "yellow", "green", "blue", "purple", "falseColor"); -- cgit v1.2.3