Make ids of IDPatterns easier accessible for CustomFeatures

Introduce helper class that contains the coding, the pattern code just
delegates there.

Bug: 573343
Change-Id: Ia98011514e81cd782a085a907800a000bc9bb681
diff --git a/plugins/org.eclipse.graphiti.pattern/.settings/.api_filters b/plugins/org.eclipse.graphiti.pattern/.settings/.api_filters
index a721b87..532a72c 100644
--- a/plugins/org.eclipse.graphiti.pattern/.settings/.api_filters
+++ b/plugins/org.eclipse.graphiti.pattern/.settings/.api_filters
@@ -417,4 +417,12 @@
             </message_arguments>
         </filter>
     </resource>
+    <resource path="src/org/eclipse/graphiti/pattern/id/IdPattern.java" type="org.eclipse.graphiti.pattern.id.IdPattern">
+        <filter id="576725006">
+            <message_arguments>
+                <message_argument value="IPattern"/>
+                <message_argument value="IdPattern"/>
+            </message_arguments>
+        </filter>
+    </resource>
 </component>
diff --git a/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdPattern.java b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdPattern.java
index 681c8d4..ae440a2 100644
--- a/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdPattern.java
+++ b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdPattern.java
@@ -158,9 +158,10 @@
 	 *            The {@link PictogramElement} to set the ID property for
 	 * @param id
 	 *            The {@link String} ID to set.
+	 * @deprecated Use {@link IdPatternHelper.setId(container, id)} instead.
 	 */
 	protected void setId(PropertyContainer container, String id) {
-		Graphiti.getPeService().setPropertyValue(container, PROPERTY_KEY_ID, id);
+		IdPatternHelper.setId(container, id);
 	}
 
 	/**
@@ -173,15 +174,10 @@
 	 * @return A {@link String} representing the value of the property or
 	 *         <code>null</code> in case the property is not set, see
 	 *         {@link #setId(PropertyContainer, String)}.
+	 * @deprecated Use {@link IdPatternHelper.getId(container)} instead.
 	 */
 	protected String getId(PropertyContainer container) {
-		EList<Property> properties = container.getProperties();
-		for (Property property : properties) {
-			if (PROPERTY_KEY_ID.equals(property.getKey())) {
-				return property.getValue();
-			}
-		}
-		return null;
+		return IdPatternHelper.getId(container);
 	}
 
 	/**
@@ -202,59 +198,11 @@
 	 *            A {@link String} representing the ID to search for
 	 * @return The {@link PictogramElement} that has the given ID property, in
 	 *         case none id found <code>null</code>.
+	 * @deprecated Use {@link IdPatternHelper.findById(pictogramElement,
+	 *             idToFind)} instead.
 	 */
 	protected PropertyContainer findById(PictogramElement pictogramElement, String idToFind) {
-		if (idToFind == null || idToFind.length() == 0) {
-			return null;
-		}
-
-		// Check id for PE
-		String id = getId(pictogramElement);
-		if (idToFind.equals(id)) {
-			return pictogramElement;
-		}
-
-		// Check id for GA
-		GraphicsAlgorithm graphicsAlgorithm = pictogramElement.getGraphicsAlgorithm();
-		id = getId(graphicsAlgorithm);
-		if (idToFind.equals(id)) {
-			return graphicsAlgorithm;
-		}
-
-		// Check children of PE
-		if (pictogramElement instanceof ContainerShape) {
-			EList<Shape> children = ((ContainerShape) pictogramElement).getChildren();
-			for (Shape shape : children) {
-				PropertyContainer propertyContainer = findById(shape, idToFind);
-				if (propertyContainer != null) {
-					return propertyContainer;
-				}
-			}
-		}
-
-		// Check children of GA
-		PropertyContainer propertyContainer = findByIdInGraphicsAlgorithmChildren(graphicsAlgorithm, idToFind);
-		if (propertyContainer != null) {
-			return propertyContainer;
-		}
-
-		return null;
-	}
-
-	private PropertyContainer findByIdInGraphicsAlgorithmChildren(GraphicsAlgorithm graphicsAlgorithm, String idToFind) {
-		EList<GraphicsAlgorithm> graphicsAlgorithmChildren = graphicsAlgorithm.getGraphicsAlgorithmChildren();
-		for (GraphicsAlgorithm graphicsAlgorithmChild : graphicsAlgorithmChildren) {
-			String id = getId(graphicsAlgorithmChild);
-			if (idToFind.equals(id)) {
-				return graphicsAlgorithmChild;
-			}
-
-			PropertyContainer propertyContainer = findByIdInGraphicsAlgorithmChildren(graphicsAlgorithmChild, idToFind);
-			if (propertyContainer != null) {
-				return propertyContainer;
-			}
-		}
-		return null;
+		return IdPatternHelper.findById(pictogramElement, idToFind);
 	}
 
 	/**
diff --git a/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdPatternHelper.java b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdPatternHelper.java
new file mode 100644
index 0000000..c22776b
--- /dev/null
+++ b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdPatternHelper.java
@@ -0,0 +1,158 @@
+/*********************************************************************
+* Copyright (c) 2021, 2021 SAP SE
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* Contributors:
+*    SAP SE - initial API, implementation and documentation
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipse.graphiti.pattern.id;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.graphiti.mm.Property;
+import org.eclipse.graphiti.mm.PropertyContainer;
+import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;
+import org.eclipse.graphiti.mm.pictograms.ContainerShape;
+import org.eclipse.graphiti.mm.pictograms.PictogramElement;
+import org.eclipse.graphiti.mm.pictograms.Shape;
+import org.eclipse.graphiti.services.Graphiti;
+
+/**
+ * Some helper methods to be used in ID patterns and related features.
+ * 
+ * @since 0.18
+ */
+public class IdPatternHelper {
+
+	/**
+	 * Returns any ID that has been set for the given {@link PictogramElement};
+	 * it can be any {@link PropertyContainer}, especially {@link Shape}s or
+	 * {@link GraphicsAlgorithm}s are allowed.
+	 * 
+	 * @param container
+	 *            The {@link PictogramElement} to get the ID property from
+	 * @return A {@link String} representing the value of the property or
+	 *         <code>null</code> in case the property is not set, see
+	 *         {@link #setId(PropertyContainer, String)}.
+	 */
+	public static String getId(PropertyContainer container) {
+		EList<Property> properties = container.getProperties();
+		for (Property property : properties) {
+			if (IdPattern.PROPERTY_KEY_ID.equals(property.getKey())) {
+				return property.getValue();
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Set the ID property ({@link #PROPERTY_KEY_ID}) for the given
+	 * {@link PictogramElement}; it can be any {@link PropertyContainer}
+	 * ,especially {@link Shape}s or {@link GraphicsAlgorithm}s are allowed. The
+	 * used ID string can later be used to identify the shape, e.g. in the
+	 * update or layout methods.
+	 * 
+	 * @param container
+	 *            The {@link PictogramElement} to set the ID property for
+	 * @param id
+	 *            The {@link String} ID to set.
+	 */
+	public static void setId(PropertyContainer container, String id) {
+		Graphiti.getPeService().setPropertyValue(container, IdPattern.PROPERTY_KEY_ID, id);
+	}
+
+	/**
+	 * Searches for a {@link PictogramElement} that has the given ID starting
+	 * from the given {@link PictogramElement}. First the given element is
+	 * checked, then its {@link GraphicsAlgorithm}; after that the
+	 * {@link PictogramElement} children are checked recursively and last the
+	 * {@link GraphicsAlgorithm} children also recursively. The first
+	 * {@link PictogramElement} that has the given ID is returned, in case none
+	 * is found in the tree spanned by the given {@link PictogramElement},
+	 * <code>null</code> is returned.
+	 * 
+	 * @param pictogramElement
+	 *            The {@link PictogramElement} at which the search shall start,
+	 *            any {@link Shape}s or {@link GraphicsAlgorithm}s on top of
+	 *            this element are ignored.
+	 * @param idToFind
+	 *            A {@link String} representing the ID to search for
+	 * @return The {@link PictogramElement} that has the given ID property, in
+	 *         case none id found <code>null</code>.
+	 */
+	public static PropertyContainer findById(PictogramElement pictogramElement, String idToFind) {
+		if (idToFind == null || idToFind.length() == 0) {
+			return null;
+		}
+
+		// Check id for PE
+		String id = getId(pictogramElement);
+		if (idToFind.equals(id)) {
+			return pictogramElement;
+		}
+
+		// Check id for GA
+		GraphicsAlgorithm graphicsAlgorithm = pictogramElement.getGraphicsAlgorithm();
+		id = getId(graphicsAlgorithm);
+		if (idToFind.equals(id)) {
+			return graphicsAlgorithm;
+		}
+
+		// Check children of PE
+		if (pictogramElement instanceof ContainerShape) {
+			EList<Shape> children = ((ContainerShape) pictogramElement).getChildren();
+			for (Shape shape : children) {
+				PropertyContainer propertyContainer = findById(shape, idToFind);
+				if (propertyContainer != null) {
+					return propertyContainer;
+				}
+			}
+		}
+
+		// Check children of GA
+		PropertyContainer propertyContainer = findByIdInGraphicsAlgorithmChildren(graphicsAlgorithm, idToFind);
+		if (propertyContainer != null) {
+			return propertyContainer;
+		}
+
+		return null;
+	}
+
+	/**
+	 * Searches for a {@link PictogramElement} that has the given ID starting
+	 * from the given {@link PictogramElement}. The {@link PictogramElement}
+	 * children are checked recursively and last the {@link GraphicsAlgorithm}
+	 * children also recursively. The first {@link PictogramElement} that has
+	 * the given ID is returned, in case none is found in the tree spanned by
+	 * the given {@link PictogramElement}, <code>null</code> is returned.
+	 * 
+	 * @param pictogramElement
+	 *            The {@link PictogramElement} at which the search shall start,
+	 *            any {@link Shape}s or {@link GraphicsAlgorithm}s on top of
+	 *            this element are ignored.
+	 * @param idToFind
+	 *            A {@link String} representing the ID to search for
+	 * @return The {@link PictogramElement} that has the given ID property, in
+	 *         case none id found <code>null</code>.
+	 */
+	public static PropertyContainer findByIdInGraphicsAlgorithmChildren(GraphicsAlgorithm graphicsAlgorithm,
+			String idToFind) {
+		EList<GraphicsAlgorithm> graphicsAlgorithmChildren = graphicsAlgorithm.getGraphicsAlgorithmChildren();
+		for (GraphicsAlgorithm graphicsAlgorithmChild : graphicsAlgorithmChildren) {
+			String id = getId(graphicsAlgorithmChild);
+			if (idToFind.equals(id)) {
+				return graphicsAlgorithmChild;
+			}
+
+			PropertyContainer propertyContainer = findByIdInGraphicsAlgorithmChildren(graphicsAlgorithmChild, idToFind);
+			if (propertyContainer != null) {
+				return propertyContainer;
+			}
+		}
+		return null;
+	}
+}