Merge "Bug 385193 - Provide ID pattern to lower development effort"
diff --git a/examples/org.eclipse.graphiti.examples.filesystem/src/org/eclipse/graphiti/examples/filesystem/diagram/FilesystemFeatureProvider.java b/examples/org.eclipse.graphiti.examples.filesystem/src/org/eclipse/graphiti/examples/filesystem/diagram/FilesystemFeatureProvider.java
index 8141a4b..63d9d94 100644
--- a/examples/org.eclipse.graphiti.examples.filesystem/src/org/eclipse/graphiti/examples/filesystem/diagram/FilesystemFeatureProvider.java
+++ b/examples/org.eclipse.graphiti.examples.filesystem/src/org/eclipse/graphiti/examples/filesystem/diagram/FilesystemFeatureProvider.java
@@ -23,6 +23,7 @@
 import org.eclipse.graphiti.examples.filesystem.features.AddContainmentConnectionFeature;

 import org.eclipse.graphiti.examples.filesystem.features.CreateContainmentConnectionFeature;

 import org.eclipse.graphiti.examples.filesystem.features.GradientColorFeature;

+import org.eclipse.graphiti.examples.filesystem.patterns.FilePattern;

 import org.eclipse.graphiti.examples.filesystem.patterns.FolderPattern;

 import org.eclipse.graphiti.examples.filesystem.ui.FilesystemPredefinedColoredAreas;

 import org.eclipse.graphiti.features.IAddFeature;

@@ -42,6 +43,7 @@
 	public FilesystemFeatureProvider(IDiagramTypeProvider dtp) {

 		super(dtp);

 		addPattern(new FolderPattern());

+		addPattern(new FilePattern());

 	}

 

 	@Override

@@ -67,4 +69,4 @@
 		ret = retList.toArray(ret);

 		return ret;

 	}

-}
\ No newline at end of file
+}
diff --git a/examples/org.eclipse.graphiti.examples.filesystem/src/org/eclipse/graphiti/examples/filesystem/patterns/FilePattern.java b/examples/org.eclipse.graphiti.examples.filesystem/src/org/eclipse/graphiti/examples/filesystem/patterns/FilePattern.java
new file mode 100644
index 0000000..03303cb
--- /dev/null
+++ b/examples/org.eclipse.graphiti.examples.filesystem/src/org/eclipse/graphiti/examples/filesystem/patterns/FilePattern.java
@@ -0,0 +1,222 @@
+package org.eclipse.graphiti.examples.filesystem.patterns;

+

+import org.eclipse.emf.common.util.EList;

+import org.eclipse.emf.ecore.EObject;

+import org.eclipse.graphiti.examples.mm.filesystem.File;

+import org.eclipse.graphiti.examples.mm.filesystem.FilesystemFactory;

+import org.eclipse.graphiti.features.IReason;

+import org.eclipse.graphiti.features.context.IAddContext;

+import org.eclipse.graphiti.features.context.ICreateContext;

+import org.eclipse.graphiti.features.context.IDirectEditingContext;

+import org.eclipse.graphiti.features.impl.Reason;

+import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;

+import org.eclipse.graphiti.mm.algorithms.Rectangle;

+import org.eclipse.graphiti.mm.algorithms.RoundedRectangle;

+import org.eclipse.graphiti.mm.algorithms.Text;

+import org.eclipse.graphiti.mm.algorithms.styles.Orientation;

+import org.eclipse.graphiti.mm.pictograms.ContainerShape;

+import org.eclipse.graphiti.mm.pictograms.Diagram;

+import org.eclipse.graphiti.mm.pictograms.PictogramElement;

+import org.eclipse.graphiti.mm.pictograms.Shape;

+import org.eclipse.graphiti.pattern.IPattern;

+import org.eclipse.graphiti.pattern.id.IdAddContext;

+import org.eclipse.graphiti.pattern.id.IdLayoutContext;

+import org.eclipse.graphiti.pattern.id.IdPattern;

+import org.eclipse.graphiti.pattern.id.IdUpdateContext;

+import org.eclipse.graphiti.services.Graphiti;

+import org.eclipse.graphiti.services.IGaService;

+import org.eclipse.graphiti.services.IPeCreateService;

+import org.eclipse.graphiti.util.PredefinedColoredAreas;

+

+public class FilePattern extends IdPattern implements IPattern {

+

+	private static final String ID_NAME_TEXT = "nameText";

+	private static final String ID_OUTER_RECTANGLE = "outerRectangle";

+	private static final String ID_MAIN_RECTANGLE = "mainRectangle";

+

+	public FilePattern() {

+		super();

+	}

+

+	@Override

+	public String getCreateName() {

+		return "File";

+	}

+

+	@Override

+	public boolean isMainBusinessObjectApplicable(Object mainBusinessObject) {

+		return mainBusinessObject instanceof File;

+	}

+

+	@Override

+	public boolean canCreate(ICreateContext context) {

+		return context.getTargetContainer() instanceof Diagram;

+	}

+

+	@Override

+	public Object[] create(ICreateContext context) {

+		File newFile = FilesystemFactory.eINSTANCE.createFile();

+		newFile.setName(createNewName());

+

+		getDiagram().eResource().getContents().add(newFile);

+

+		addGraphicalRepresentation(context, newFile);

+		return new Object[] { newFile };

+	}

+

+	@Override

+	public boolean canAdd(IAddContext context) {

+		return super.canAdd(context) && context.getTargetContainer() instanceof Diagram;

+	}

+

+	@Override

+	public PictogramElement add(IdAddContext context) {

+		Diagram targetDiagram = (Diagram) context.getTargetContainer();

+		File addedDomainObject = (File) context.getNewObject();

+		IPeCreateService peCreateService = Graphiti.getPeCreateService();

+		IGaService gaService = Graphiti.getGaService();

+

+		// Outer container (invisible)

+		ContainerShape outerContainerShape = peCreateService.createContainerShape(targetDiagram, true);

+		Rectangle outerRectangle = gaService.createInvisibleRectangle(outerContainerShape);

+		setId(outerRectangle, ID_OUTER_RECTANGLE);

+		gaService.setLocationAndSize(outerRectangle, context.getX(), context.getY(), context.getWidth(),

+				context.getHeight());

+

+		// Register tab

+		RoundedRectangle registerRectangle = gaService.createRoundedRectangle(outerRectangle, 5, 5);

+		gaService.setLocationAndSize(registerRectangle, 0, 0, 20, 20);

+		registerRectangle.setFilled(true);

+		gaService.setRenderingStyle(registerRectangle, PredefinedColoredAreas.getSilverWhiteGlossAdaptions());

+

+		// Main contents area

+		Rectangle mainRectangle = gaService.createRectangle(outerRectangle);

+		setId(mainRectangle, ID_MAIN_RECTANGLE);

+		mainRectangle.setFilled(true);

+		gaService.setRenderingStyle(mainRectangle, PredefinedColoredAreas.getSilverWhiteGlossAdaptions());

+

+		// File name

+		Shape shape = peCreateService.createShape(outerContainerShape, false);

+		Text text = gaService.createText(shape, addedDomainObject.getName());

+		setId(text, ID_NAME_TEXT);

+		text.setHorizontalAlignment(Orientation.ALIGNMENT_CENTER);

+		text.setVerticalAlignment(Orientation.ALIGNMENT_CENTER);

+

+		peCreateService.createChopboxAnchor(outerContainerShape);

+

+		link(outerContainerShape, addedDomainObject);

+		link(shape, addedDomainObject);

+

+		return outerContainerShape;

+	}

+

+	@Override

+	protected boolean layout(IdLayoutContext context, String id) {

+		boolean changesDone = false;

+

+		Rectangle outerRectangle = (Rectangle) context.getRootPictogramElement().getGraphicsAlgorithm();

+

+		if (id.equals(ID_MAIN_RECTANGLE) || id.equals(ID_NAME_TEXT)) {

+			GraphicsAlgorithm ga = context.getGraphicsAlgorithm();

+			Graphiti.getGaService().setLocationAndSize(ga, 0, 10, outerRectangle.getWidth(),

+					outerRectangle.getHeight() - 10);

+			changesDone = true;

+		}

+

+		return changesDone;

+	}

+

+	@Override

+	protected IReason updateNeeded(IdUpdateContext context, String id) {

+		if (id.equals(ID_NAME_TEXT)) {

+			Text nameText = (Text) context.getGraphicsAlgorithm();

+			File domainObject = (File) context.getDomainObject();

+			if (domainObject.getName() == null || !domainObject.getName().equals(nameText.getValue())) {

+				return Reason.createTrueReason("Name differs. Expected: '" + domainObject.getName() + "'");

+			}

+		}

+

+		return Reason.createFalseReason();

+	}

+

+	@Override

+	protected boolean update(IdUpdateContext context, String id) {

+		if (id.equals(ID_NAME_TEXT)) {

+			Text nameText = (Text) context.getGraphicsAlgorithm();

+			File domainObject = (File) context.getDomainObject();

+			nameText.setValue(domainObject.getName());

+			return true;

+		}

+		return false;

+	}

+

+	@Override

+	public int getEditingType() {

+		return TYPE_TEXT;

+	}

+

+	@Override

+	public boolean canDirectEdit(IDirectEditingContext context) {

+		Object domainObject = getBusinessObjectForPictogramElement(context.getPictogramElement());

+		GraphicsAlgorithm ga = context.getGraphicsAlgorithm();

+		if (domainObject instanceof File && ga instanceof Text) {

+			return true;

+		}

+		return false;

+	}

+

+	@Override

+	public String getInitialValue(IDirectEditingContext context) {

+		File file = (File) getBusinessObjectForPictogramElement(context.getPictogramElement());

+		return file.getName();

+	}

+

+	@Override

+	public String checkValueValid(String value, IDirectEditingContext context) {

+		if (value == null || value.length() == 0) {

+			return "File name must not be empty";

+		}

+

+		File file = (File) getBusinessObjectForPictogramElement(context.getPictogramElement());

+		EList<Shape> children = getDiagram().getChildren();

+		for (Shape child : children) {

+			Object domainObject = getBusinessObjectForPictogramElement(child);

+			if (domainObject instanceof File) {

+				if (!domainObject.equals(file) && value.equals(((File) domainObject).getName())) {

+					return "A file with name '" + ((File) domainObject).getName() + "' already exists.";

+				}

+			}

+		}

+		return null;

+	}

+

+	@Override

+	public void setValue(String value, IDirectEditingContext context) {

+		File file = (File) getBusinessObjectForPictogramElement(context.getPictogramElement());

+		file.setName(value);

+		updatePictogramElement(context.getPictogramElement());

+	}

+

+	private String createNewName() {

+		String initialName = "NewFile";

+		String name = initialName;

+		int number = 0;

+		while (findFile(name) != null) {

+			number++;

+			name = initialName + number;

+		}

+		return name;

+	}

+

+	private File findFile(String name) {

+		EList<EObject> contents = getDiagram().eResource().getContents();

+		for (EObject eObject : contents) {

+			if (eObject instanceof File) {

+				if (name.equals(((File) eObject).getName())) {

+					return (File) eObject;

+				}

+			}

+		}

+		return null;

+	}

+}

diff --git a/plugins/org.eclipse.graphiti.pattern/META-INF/MANIFEST.MF b/plugins/org.eclipse.graphiti.pattern/META-INF/MANIFEST.MF
index 7b15654..f7267a6 100644
--- a/plugins/org.eclipse.graphiti.pattern/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.graphiti.pattern/META-INF/MANIFEST.MF
@@ -8,6 +8,7 @@
 Bundle-Localization: plugin
 Export-Package: org.eclipse.graphiti.pattern;version="0.10.0",
  org.eclipse.graphiti.pattern.config;version="0.10.0",
+ org.eclipse.graphiti.pattern.id,
  org.eclipse.graphiti.pattern.mapping;version="0.10.0",
  org.eclipse.graphiti.pattern.mapping.data;version="0.10.0"
 Bundle-ActivationPolicy: lazy
diff --git a/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/TypedPattern.java b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/TypedPattern.java
new file mode 100644
index 0000000..f1589a2
--- /dev/null
+++ b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/TypedPattern.java
@@ -0,0 +1,103 @@
+/*******************************************************************************

+ * <copyright>

+ *

+ * Copyright (c) 2012, 2012 SAP AG.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *    SAP AG - initial API, implementation and documentation

+ *

+ * </copyright>

+ *

+ *******************************************************************************/

+package org.eclipse.graphiti.pattern;

+

+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.Diagram;

+import org.eclipse.graphiti.mm.pictograms.PictogramElement;

+import org.eclipse.graphiti.mm.pictograms.Shape;

+import org.eclipse.graphiti.pattern.config.IPatternConfiguration;

+import org.eclipse.graphiti.services.Graphiti;

+

+/**

+ * This class provides the basis for all specific pattern types. It provides

+ * functionality to tag a shape as being created and maintained by a specific

+ * pattern type. Type type is identified using a special {@link Property} with

+ * the key PROPERTY_KEY_PATTERN_TYPE.

+ * 

+ * @since 0.10

+ */

+public abstract class TypedPattern extends AbstractPattern {

+

+	protected static final String PROPERTY_KEY_PATTERN_TYPE = "org.eclipse.graphiti.pattern.patternType";

+

+	public TypedPattern() {

+		super();

+	}

+

+	public TypedPattern(IPatternConfiguration patternConfiguration) {

+		super(patternConfiguration);

+	}

+

+	/**

+	 * Sets the property that indicates that the given root shape of the pattern

+	 * is created and maintained by a specific pattern type.

+	 * 

+	 * @param patternRootShape

+	 *            The {@link PropertyContainer} object that is used as root

+	 *            shape of the pattern.

+	 * @param patternType

+	 *            The {@link String} type of the pattern.

+	 */

+	protected void setPatternType(PropertyContainer patternRootShape, String patternType) {

+		Graphiti.getPeService().setPropertyValue(patternRootShape, PROPERTY_KEY_PATTERN_TYPE, patternType);

+	}

+

+	/**

+	 * Returns the property that indicates that the given root shape of the

+	 * pattern is created and maintained by a specific pattern type if it is set

+	 * for the given shape or one of its parents. If the property is set for the

+	 * given shape it is returned, otherwise the parents are asked for the

+	 * property; first the parent {@link ContainerShape} in the shape hierarchy

+	 * is asked if there is no parent the {@link GraphicsAlgorithm} parent is

+	 * asked.

+	 * 

+	 * @param patternRootShape

+	 *            The {@link PropertyContainer} object that is used as root

+	 *            shape of the pattern.

+	 * @return The {@link String} type of the pattern.

+	 */

+	protected String getPatternType(PropertyContainer patternRootShape) {

+		EList<Property> properties = patternRootShape.getProperties();

+		for (Property property : properties) {

+			if (PROPERTY_KEY_PATTERN_TYPE.equals(property.getKey())) {

+				return property.getValue();

+			}

+		}

+		if (patternRootShape instanceof Shape) {

+			ContainerShape parent = ((Shape) patternRootShape).getContainer();

+			if (parent != null && !(parent instanceof Diagram)) {

+				return getPatternType(parent);

+			}

+		} else if (patternRootShape instanceof GraphicsAlgorithm) {

+			PictogramElement pictogramElement = ((GraphicsAlgorithm) patternRootShape).getPictogramElement();

+			if (pictogramElement != null) {

+				return getPatternType(pictogramElement);

+			} else {

+				GraphicsAlgorithm parentGraphicsAlgorithm = ((GraphicsAlgorithm) patternRootShape)

+						.getParentGraphicsAlgorithm();

+				if (parentGraphicsAlgorithm != null) {

+					return getPatternType(parentGraphicsAlgorithm);

+				}

+			}

+		}

+		return null;

+	}

+}

diff --git a/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdAddContext.java b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdAddContext.java
new file mode 100644
index 0000000..a2b8df5
--- /dev/null
+++ b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdAddContext.java
@@ -0,0 +1,36 @@
+/*******************************************************************************

+ * <copyright>

+ *

+ * Copyright (c) 2012, 2012 SAP AG.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *    SAP AG - initial API, implementation and documentation

+ *

+ * </copyright>

+ *

+ *******************************************************************************/

+package org.eclipse.graphiti.pattern.id;

+

+import org.eclipse.graphiti.features.context.IAreaContext;

+import org.eclipse.graphiti.features.context.impl.AddContext;

+

+/**

+ * @since 0.10

+ * @experimental This API is in an experimental state and should be used by

+ *               clients, as it not final and can be removed or changed without

+ *               prior notice!

+ */

+public class IdAddContext extends AddContext {

+

+	public IdAddContext() {

+		super();

+	}

+

+	public IdAddContext(IAreaContext context, Object newObject) {

+		super(context, newObject);

+	}

+}

diff --git a/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdLayoutContext.java b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdLayoutContext.java
new file mode 100644
index 0000000..7100190
--- /dev/null
+++ b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdLayoutContext.java
@@ -0,0 +1,55 @@
+/*******************************************************************************

+ * <copyright>

+ *

+ * Copyright (c) 2012, 2012 SAP AG.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *    SAP AG - initial API, implementation and documentation

+ *

+ * </copyright>

+ *

+ *******************************************************************************/

+package org.eclipse.graphiti.pattern.id;

+

+import org.eclipse.graphiti.features.context.impl.LayoutContext;

+import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;

+import org.eclipse.graphiti.mm.pictograms.PictogramElement;

+

+/**

+ * @since 0.10

+ * @experimental This API is in an experimental state and should be used by

+ *               clients, as it not final and can be removed or changed without

+ *               prior notice!

+ */

+public class IdLayoutContext extends LayoutContext {

+

+	private GraphicsAlgorithm graphicsAlgorithm;

+	private PictogramElement rootPictogramElement;

+

+	public IdLayoutContext(PictogramElement pictogramElement, GraphicsAlgorithm graphicsAlgorithm,

+			PictogramElement rootPictogramElement) {

+		super(pictogramElement);

+		this.graphicsAlgorithm = graphicsAlgorithm;

+		this.rootPictogramElement = rootPictogramElement;

+	}

+

+	public GraphicsAlgorithm getGraphicsAlgorithm() {

+		return graphicsAlgorithm;

+	}

+

+	public void setGraphicsAlgorithm(GraphicsAlgorithm graphicsAlgorithm) {

+		this.graphicsAlgorithm = graphicsAlgorithm;

+	}

+

+	public PictogramElement getRootPictogramElement() {

+		return rootPictogramElement;

+	}

+

+	public void setRootPictogramElement(PictogramElement rootPictogramElement) {

+		this.rootPictogramElement = rootPictogramElement;

+	}

+}

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
new file mode 100644
index 0000000..90f6cfa
--- /dev/null
+++ b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdPattern.java
@@ -0,0 +1,577 @@
+/*******************************************************************************

+ * <copyright>

+ *

+ * Copyright (c) 2012, 2012 SAP AG.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *    SAP AG - initial API, implementation and documentation

+ *

+ * </copyright>

+ *

+ *******************************************************************************/

+package org.eclipse.graphiti.pattern.id;

+

+import org.eclipse.emf.common.util.EList;

+import org.eclipse.graphiti.features.IReason;

+import org.eclipse.graphiti.features.context.IAddContext;

+import org.eclipse.graphiti.features.context.IDirectEditingContext;

+import org.eclipse.graphiti.features.context.ILayoutContext;

+import org.eclipse.graphiti.features.context.IUpdateContext;

+import org.eclipse.graphiti.features.context.impl.AreaContext;

+import org.eclipse.graphiti.features.context.impl.LayoutContext;

+import org.eclipse.graphiti.features.impl.Reason;

+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.pattern.IPattern;

+import org.eclipse.graphiti.pattern.TypedPattern;

+import org.eclipse.graphiti.services.Graphiti;

+

+/**

+ * Base class for ID patterns. The basic idea behind is to tag single parts of a

+ * pattern shape with IDs (using {@link Property} objects). These IDs are used

+ * to identify the parts of that shape and to call the update and layout methods

+ * for the shapes with IDs. Clients do not need to search through the shape

+ * hierarchy to find the shapes to update and layout.

+ * 

+ * @since 0.10

+ * @experimental This API is in an experimental state and should be used by

+ *               clients, as it not final and can be removed or changed without

+ *               prior notice!

+ */

+public abstract class IdPattern extends TypedPattern implements IPattern {

+

+	protected static final String PROPERTY_VALUE_PATTERN_TYPE_ID = "org.eclipse.graphiti.pattern.idpattern"; //$NON-NLS-1$

+	protected static final String PROPERTY_KEY_ID = "org.eclipse.graphiti.pattern.id.id"; //$NON-NLS-1$

+

+	public IdPattern() {

+		super();

+	}

+

+	/*

+	 * Base functionality

+	 */

+

+	@Override

+	protected boolean isPatternControlled(PictogramElement pictogramElement) {

+		Object domainObject = getBusinessObjectForPictogramElement(pictogramElement);

+		return isMainBusinessObjectApplicable(domainObject);

+	}

+

+	@Override

+	protected boolean isPatternRoot(PictogramElement pictogramElement) {

+		Object domainObject = getBusinessObjectForPictogramElement(pictogramElement);

+		if (!isMainBusinessObjectApplicable(domainObject)) {

+			return false;

+		}

+		EList<Property> properties = pictogramElement.getProperties();

+		boolean rootPropertyFound = false;

+		for (Property property : properties) {

+			if (PROPERTY_KEY_PATTERN_TYPE.equals(property.getKey())

+					&& PROPERTY_VALUE_PATTERN_TYPE_ID.equals(property.getValue())) {

+				rootPropertyFound = true;

+			}

+		}

+		return rootPropertyFound;

+	}

+

+	/*

+	 * ID handling

+	 */

+

+	protected void setId(PropertyContainer container, String id) {

+		Graphiti.getPeService().setPropertyValue(container, PROPERTY_KEY_ID, id);

+	}

+

+	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;

+	}

+

+	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;

+	}

+

+	/*

+	 * Add functionality

+	 */

+

+	@Override

+	public boolean canAdd(IAddContext context) {

+		return isMainBusinessObjectApplicable(context.getNewObject());

+	}

+

+	@Override

+	public PictogramElement add(IAddContext context) {

+		AreaContext areaContext = new AreaContext();

+		areaContext.setHeight(context.getHeight());

+		areaContext.setWidth(context.getWidth());

+		areaContext.setLocation(context.getX(), context.getY());

+		IdAddContext addContext = new IdAddContext(areaContext, context.getNewObject());

+		addContext.setTargetConnection(context.getTargetConnection());

+		addContext.setTargetConnectionDecorator(context.getTargetConnectionDecorator());

+		addContext.setTargetContainer(context.getTargetContainer());

+		PictogramElement pictogramElement = add(addContext);

+		setPatternType(pictogramElement, PROPERTY_VALUE_PATTERN_TYPE_ID);

+		layout(new LayoutContext(pictogramElement));

+		return pictogramElement;

+	}

+

+	abstract protected PictogramElement add(IdAddContext context);

+

+	/*

+	 * Layout functionality

+	 */

+

+	@Override

+	public boolean canLayout(ILayoutContext context) {

+		return PROPERTY_VALUE_PATTERN_TYPE_ID.equals(getPatternType(context.getPictogramElement()))

+				&& isMainBusinessObjectApplicable(getBusinessObjectForPictogramElement(context.getPictogramElement()));

+	}

+

+	@Override

+	public boolean layout(ILayoutContext context) {

+		boolean changesDone = false;

+

+		PictogramElement rootPictogramElement;

+		if (context instanceof IdLayoutContext) {

+			rootPictogramElement = ((IdLayoutContext) context).getRootPictogramElement();

+		} else {

+			rootPictogramElement = context.getPictogramElement();

+			while (!isPatternRoot(rootPictogramElement)) {

+				if (rootPictogramElement instanceof Shape) {

+					ContainerShape container = ((Shape) rootPictogramElement).getContainer();

+					if (container != null) {

+						rootPictogramElement = container;

+					} else {

+						break;

+					}

+				} else {

+					if (rootPictogramElement instanceof GraphicsAlgorithm) {

+						PictogramElement pictogramElement = ((GraphicsAlgorithm) rootPictogramElement)

+								.getPictogramElement();

+						if (pictogramElement != null) {

+							rootPictogramElement = pictogramElement;

+						} else {

+							break;

+						}

+					}

+				}

+			}

+		}

+

+		// Check id for PE

+		PictogramElement pictogramElement = context.getPictogramElement();

+		String id = getId(pictogramElement);

+		if (id != null) {

+			IdLayoutContext layoutContext = new IdLayoutContext(pictogramElement,

+					pictogramElement.getGraphicsAlgorithm(), rootPictogramElement);

+			if (layout(layoutContext, id)) {

+				changesDone = true;

+			}

+		}

+

+		// Check id for GA

+		GraphicsAlgorithm graphicsAlgorithm = pictogramElement.getGraphicsAlgorithm();

+		id = getId(graphicsAlgorithm);

+		if (id != null) {

+			IdLayoutContext layoutContext = new IdLayoutContext(graphicsAlgorithm.getPictogramElement(),

+					graphicsAlgorithm, rootPictogramElement);

+			if (layout(layoutContext, id)) {

+				changesDone = true;

+			}

+		}

+

+		// Check children of PE

+		if (pictogramElement instanceof ContainerShape) {

+			EList<Shape> children = ((ContainerShape) pictogramElement).getChildren();

+			for (Shape shape : children) {

+				LayoutContext idContext = new IdLayoutContext(shape, shape.getGraphicsAlgorithm(), rootPictogramElement);

+				if (layout(idContext)) {

+					changesDone = true;

+				}

+			}

+		}

+

+		// Check children of GA

+		IdLayoutContext layoutContext;

+		if (context instanceof IdLayoutContext) {

+			layoutContext = (IdLayoutContext) context;

+		} else {

+			layoutContext = new IdLayoutContext(null, graphicsAlgorithm, rootPictogramElement);

+		}

+		if (checkLayoutChildren(graphicsAlgorithm, layoutContext)) {

+			changesDone = true;

+		}

+

+		return changesDone;

+	}

+

+	protected boolean checkLayoutChildren(GraphicsAlgorithm graphicsAlgorithm, IdLayoutContext context) {

+		boolean changesDone = false;

+		EList<GraphicsAlgorithm> graphicsAlgorithmChildren = graphicsAlgorithm.getGraphicsAlgorithmChildren();

+		for (GraphicsAlgorithm graphicsAlgorithmChild : graphicsAlgorithmChildren) {

+			String id = getId(graphicsAlgorithmChild);

+			if (id != null) {

+				IdLayoutContext layoutContext = new IdLayoutContext(graphicsAlgorithmChild.getPictogramElement(),

+						graphicsAlgorithmChild, context.getRootPictogramElement());

+				if (layout(layoutContext, id)) {

+					changesDone = true;

+				}

+			}

+			if (checkLayoutChildren(graphicsAlgorithmChild, context)) {

+				changesDone = true;

+			}

+		}

+		return changesDone;

+	}

+

+	abstract protected boolean layout(IdLayoutContext context, String id);

+

+	/*

+	 * Update functionality

+	 */

+

+	@Override

+	public boolean canUpdate(IUpdateContext context) {

+		return PROPERTY_VALUE_PATTERN_TYPE_ID.equals(getPatternType(context.getPictogramElement()))

+				&& isMainBusinessObjectApplicable(getBusinessObjectForPictogramElement(context.getPictogramElement()));

+	}

+

+	@Override

+	public IReason updateNeeded(IUpdateContext context) {

+

+		PictogramElement rootPictogramElement;

+		if (context instanceof IdUpdateContext) {

+			rootPictogramElement = ((IdUpdateContext) context).getRootPictogramElement();

+		} else {

+			rootPictogramElement = context.getPictogramElement();

+		}

+

+		// Check id for PE

+		PictogramElement pictogramElement = context.getPictogramElement();

+		String id = getId(pictogramElement);

+		if (id != null) {

+			IdUpdateContext updateContext = new IdUpdateContext(pictogramElement,

+					pictogramElement.getGraphicsAlgorithm(), rootPictogramElement,

+					getBusinessObjectForPictogramElement(pictogramElement));

+			IReason reason = updateNeeded(updateContext, id);

+			if (reason.toBoolean()) {

+				return reason;

+			}

+		}

+

+		// Check id for GA

+		GraphicsAlgorithm graphicsAlgorithm = pictogramElement.getGraphicsAlgorithm();

+		id = getId(graphicsAlgorithm);

+		if (id != null) {

+			PictogramElement element = graphicsAlgorithm.getPictogramElement();

+			IdUpdateContext updateContext = new IdUpdateContext(element, graphicsAlgorithm, rootPictogramElement,

+					getBusinessObjectForPictogramElement(element));

+			IReason reason = updateNeeded(updateContext, id);

+			if (reason.toBoolean()) {

+				return reason;

+			}

+		}

+

+		// Check children of PE

+		if (pictogramElement instanceof ContainerShape) {

+			EList<Shape> children = ((ContainerShape) pictogramElement).getChildren();

+			for (Shape shape : children) {

+				IdUpdateContext updateContext = new IdUpdateContext(shape, shape.getGraphicsAlgorithm(),

+						rootPictogramElement, getBusinessObjectForPictogramElement(shape));

+				IReason reason = updateNeeded(updateContext);

+				if (reason.toBoolean()) {

+					return reason;

+				}

+			}

+		}

+

+		// Check children of GA

+		IdUpdateContext updateContext;

+		if (context instanceof IdUpdateContext) {

+			updateContext = (IdUpdateContext) context;

+		} else {

+			updateContext = new IdUpdateContext(null, graphicsAlgorithm, rootPictogramElement, null);

+		}

+		IReason reason = checkUpdateNeededChildren(graphicsAlgorithm, updateContext);

+		if (reason.toBoolean()) {

+			return reason;

+		}

+

+		return Reason.createFalseReason();

+	}

+

+	protected IReason checkUpdateNeededChildren(GraphicsAlgorithm graphicsAlgorithm, IdUpdateContext context) {

+		EList<GraphicsAlgorithm> graphicsAlgorithmChildren = graphicsAlgorithm.getGraphicsAlgorithmChildren();

+		for (GraphicsAlgorithm graphicsAlgorithmChild : graphicsAlgorithmChildren) {

+			String id = getId(graphicsAlgorithmChild);

+			if (id != null) {

+				PictogramElement pictogramElement = graphicsAlgorithmChild.getPictogramElement();

+				IdUpdateContext updateContext = new IdUpdateContext(pictogramElement, graphicsAlgorithmChild,

+						context.getRootPictogramElement(), getBusinessObjectForPictogramElement(pictogramElement));

+				IReason reason = updateNeeded(updateContext, id);

+				if (reason.toBoolean()) {

+					return reason;

+				}

+			}

+			IReason reason = checkUpdateNeededChildren(graphicsAlgorithmChild, context);

+			if (reason.toBoolean()) {

+				return reason;

+			}

+		}

+		return Reason.createFalseReason();

+	}

+

+	abstract protected IReason updateNeeded(IdUpdateContext context, String id);

+

+	@Override

+	public boolean update(IUpdateContext context) {

+		boolean result = false;

+

+		PictogramElement rootPictogramElement;

+		if (context instanceof IdUpdateContext) {

+			rootPictogramElement = ((IdUpdateContext) context).getRootPictogramElement();

+		} else {

+			rootPictogramElement = context.getPictogramElement();

+		}

+

+		// Check id for PE

+		PictogramElement pictogramElement = context.getPictogramElement();

+		String id = getId(pictogramElement);

+		if (id != null) {

+			IdUpdateContext updateContext = new IdUpdateContext(pictogramElement,

+					pictogramElement.getGraphicsAlgorithm(), rootPictogramElement,

+					getBusinessObjectForPictogramElement(pictogramElement));

+			if (update(updateContext, id)) {

+				result = true;

+			}

+		}

+

+		// Check id for GA

+		GraphicsAlgorithm graphicsAlgorithm = pictogramElement.getGraphicsAlgorithm();

+		id = getId(graphicsAlgorithm);

+		if (id != null) {

+			PictogramElement element = graphicsAlgorithm.getPictogramElement();

+			IdUpdateContext updateContext = new IdUpdateContext(element, graphicsAlgorithm, rootPictogramElement,

+					getBusinessObjectForPictogramElement(element));

+			if (update(updateContext, id)) {

+				result = true;

+			}

+		}

+

+		// Check children of PE

+		if (pictogramElement instanceof ContainerShape) {

+			EList<Shape> children = ((ContainerShape) pictogramElement).getChildren();

+			for (Shape shape : children) {

+				IdUpdateContext updateContext = new IdUpdateContext(shape, shape.getGraphicsAlgorithm(),

+						rootPictogramElement, getBusinessObjectForPictogramElement(shape));

+				if (update(updateContext)) {

+					result = true;

+				}

+			}

+		}

+

+		// Check children of GA

+		IdUpdateContext updateContext;

+		if (context instanceof IdUpdateContext) {

+			updateContext = (IdUpdateContext) context;

+		} else {

+			updateContext = new IdUpdateContext(null, graphicsAlgorithm, rootPictogramElement, null);

+		}

+		if (checkUpdateChildren(graphicsAlgorithm, updateContext)) {

+			result = true;

+		}

+

+		return result;

+	}

+

+	protected boolean checkUpdateChildren(GraphicsAlgorithm graphicsAlgorithm, IdUpdateContext context) {

+		boolean result = false;

+		EList<GraphicsAlgorithm> graphicsAlgorithmChildren = graphicsAlgorithm.getGraphicsAlgorithmChildren();

+		for (GraphicsAlgorithm graphicsAlgorithmChild : graphicsAlgorithmChildren) {

+			String id = getId(graphicsAlgorithmChild);

+			if (id != null) {

+				PictogramElement pictogramElement = graphicsAlgorithmChild.getPictogramElement();

+				IdUpdateContext updateContext = new IdUpdateContext(pictogramElement, graphicsAlgorithmChild,

+						context.getRootPictogramElement(), getBusinessObjectForPictogramElement(pictogramElement));

+				if (update(updateContext, id)) {

+					result = true;

+				}

+			}

+			if (checkUpdateChildren(graphicsAlgorithmChild, context)) {

+				result = true;

+			}

+		}

+		return result;

+	}

+

+	abstract protected boolean update(IdUpdateContext context, String id);

+

+	/*

+	 * Direct editing functionality

+	 */

+

+	@Override

+	public int getEditingType() {

+		// TODO how to use different editing types for different parts of the

+		// pattern? No context to identify id...

+		return TYPE_TEXT;

+	}

+

+	@Override

+	public boolean canDirectEdit(IDirectEditingContext context) {

+		PictogramElement pictogramElement = context.getPictogramElement();

+		Object domainObject = getBusinessObjectForPictogramElement(pictogramElement);

+		boolean patternResponsible = PROPERTY_VALUE_PATTERN_TYPE_ID.equals(getPatternType(pictogramElement))

+				&& isMainBusinessObjectApplicable(domainObject);

+

+		if (patternResponsible) {

+			String id = getId(pictogramElement);

+			if (id == null) {

+				id = getId(context.getGraphicsAlgorithm());

+

+				if (id != null) {

+					return canDirectEdit(context, id);

+				}

+			}

+		}

+		return false;

+	}

+

+	protected boolean canDirectEdit(IDirectEditingContext context, String id) {

+		return false;

+	}

+

+	@Override

+	public String getInitialValue(IDirectEditingContext context) {

+		PictogramElement pictogramElement = context.getPictogramElement();

+		Object domainObject = getBusinessObjectForPictogramElement(pictogramElement);

+		boolean patternResponsible = PROPERTY_VALUE_PATTERN_TYPE_ID.equals(getPatternType(pictogramElement))

+				&& isMainBusinessObjectApplicable(domainObject);

+

+		if (patternResponsible) {

+			String id = getId(pictogramElement);

+			if (id == null) {

+				id = getId(context.getGraphicsAlgorithm());

+

+				if (id != null) {

+					return getInitialValue(context, id);

+				}

+			}

+		}

+		return null;

+	}

+

+	protected String getInitialValue(IDirectEditingContext context, String id) {

+		return null;

+	}

+

+	@Override

+	public String checkValueValid(String value, IDirectEditingContext context) {

+		PictogramElement pictogramElement = context.getPictogramElement();

+		Object domainObject = getBusinessObjectForPictogramElement(pictogramElement);

+		boolean patternResponsible = PROPERTY_VALUE_PATTERN_TYPE_ID.equals(getPatternType(pictogramElement))

+				&& isMainBusinessObjectApplicable(domainObject);

+

+		if (patternResponsible) {

+			String id = getId(pictogramElement);

+			if (id == null) {

+				id = getId(context.getGraphicsAlgorithm());

+

+				if (id != null) {

+					return checkValueValid(value, context, id);

+				}

+			}

+		}

+		return null;

+	}

+

+	protected String checkValueValid(String value, IDirectEditingContext context, String id) {

+		return null;

+	}

+

+	@Override

+	public void setValue(String value, IDirectEditingContext context) {

+		PictogramElement pictogramElement = context.getPictogramElement();

+		Object domainObject = getBusinessObjectForPictogramElement(pictogramElement);

+		boolean patternResponsible = PROPERTY_VALUE_PATTERN_TYPE_ID.equals(getPatternType(pictogramElement))

+				&& isMainBusinessObjectApplicable(domainObject);

+

+		if (patternResponsible) {

+			String id = getId(pictogramElement);

+			if (id == null) {

+				id = getId(context.getGraphicsAlgorithm());

+

+				if (id != null) {

+					setValue(value, context, id);

+				}

+			}

+		}

+	}

+

+	protected void setValue(String value, IDirectEditingContext context, String id) {

+	}

+}

diff --git a/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdUpdateContext.java b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdUpdateContext.java
new file mode 100644
index 0000000..b9e8510
--- /dev/null
+++ b/plugins/org.eclipse.graphiti.pattern/src/org/eclipse/graphiti/pattern/id/IdUpdateContext.java
@@ -0,0 +1,65 @@
+/*******************************************************************************

+ * <copyright>

+ *

+ * Copyright (c) 2012, 2012 SAP AG.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *    SAP AG - initial API, implementation and documentation

+ *

+ * </copyright>

+ *

+ *******************************************************************************/

+package org.eclipse.graphiti.pattern.id;

+

+import org.eclipse.graphiti.features.context.impl.UpdateContext;

+import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;

+import org.eclipse.graphiti.mm.pictograms.PictogramElement;

+

+/**

+ * @since 0.10

+ * @experimental This API is in an experimental state and should be used by

+ *               clients, as it not final and can be removed or changed without

+ *               prior notice!

+ */

+public class IdUpdateContext extends UpdateContext {

+

+	private GraphicsAlgorithm graphicsAlgorithm;

+	private PictogramElement rootPictogramElement;

+	private Object domainObject;

+

+	public IdUpdateContext(PictogramElement pictogramElement, GraphicsAlgorithm graphicsAlgorithm,

+			PictogramElement rootPictogramElement, Object domainObject) {

+		super(pictogramElement);

+		this.graphicsAlgorithm = graphicsAlgorithm;

+		this.rootPictogramElement = rootPictogramElement;

+		this.setDomainObject(domainObject);

+	}

+

+	public GraphicsAlgorithm getGraphicsAlgorithm() {

+		return graphicsAlgorithm;

+	}

+

+	public void setGraphicsAlgorithm(GraphicsAlgorithm graphicsAlgorithm) {

+		this.graphicsAlgorithm = graphicsAlgorithm;

+	}

+

+	public PictogramElement getRootPictogramElement() {

+		return rootPictogramElement;

+	}

+

+	public void setRootPictogramElement(PictogramElement rootPictogramElement) {

+		this.rootPictogramElement = rootPictogramElement;

+	}

+

+	public Object getDomainObject() {

+		return domainObject;

+	}

+

+	public void setDomainObject(Object domainObject) {

+		this.domainObject = domainObject;

+	}

+}