Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/adapters/InsertionAdapter.java')
-rw-r--r--plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/adapters/InsertionAdapter.java284
1 files changed, 284 insertions, 0 deletions
diff --git a/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/adapters/InsertionAdapter.java b/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/adapters/InsertionAdapter.java
new file mode 100644
index 00000000..5706950f
--- /dev/null
+++ b/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/adapters/InsertionAdapter.java
@@ -0,0 +1,284 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 Red Hat, Inc.
+ * All rights reserved.
+ * This program is 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:
+ * Red Hat, Inc. - initial API and implementation
+ *
+ * @author Bob Brodt
+ ******************************************************************************/
+
+package org.eclipse.bpmn2.modeler.core.adapters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.bpmn2.ExtensionAttributeValue;
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EContentAdapter;
+import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
+import org.eclipse.emf.edit.domain.EditingDomain;
+
+/**
+ * This adapter will insert a new value into its container feature when the
+ * owning object's content changes. This allows the UI to construct new objects
+ * without inserting them into their container unless the user changes some
+ * feature in the new object. Thus, an empty EObject is available for use by the
+ * UI for rendering only, without creating an EMF transaction, and hence, a
+ * useless entry on the undo stack.
+ */
+public class InsertionAdapter extends EContentAdapter implements IResourceProvider {
+
+ protected Resource resource;
+ protected EObject object;
+ protected EStructuralFeature feature;
+ protected EObject value;
+
+ private InsertionAdapter(EObject object, EStructuralFeature feature, EObject value) {
+ this.resource = object.eResource();
+ this.object = object;
+ this.feature = feature;
+ this.value = value;
+ }
+
+ private InsertionAdapter(EObject object, String featureName, EObject value) {
+ this(object, object.eClass().getEStructuralFeature(featureName), value);
+ }
+
+ /**
+ * Create an InsertionAdapter that will add the value into the given
+ * object's containment feature as soon as some feature in the value is
+ * changed by the user.
+ * <p>
+ * In order for this to work, the object being adapted must be contained in
+ * a Resource, the value must <b>not yet</b> be contained in a Resource, and
+ * the value must be an instance of the feature's EType.
+ *
+ * @param object the object being adapted
+ * @param feature a containment feature of the object
+ * @param value the value to be inserted
+ * @return the value to be inserted
+ */
+ public static EObject add(EObject object, EStructuralFeature feature, EObject value) {
+ if (object!=null) {
+ value.eAdapters().add(
+ new InsertionAdapter(object, feature, value));
+ }
+ return value;
+ }
+
+ /**
+ * Convenience method for creating an InsertionAdapter given a feature name.
+ *
+ * @param object the object being adapted
+ * @param featureName the name of a containment feature of the object
+ * @param value the value to be inserted
+ * @return the value to be inserted
+ */
+ public static EObject add(EObject object, String featureName, EObject value) {
+ if (object!=null) {
+ value.eAdapters().add(
+ new InsertionAdapter(object, featureName, value));
+ }
+ return value;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.emf.ecore.util.EContentAdapter#notifyChanged(org.eclipse.emf.common.notify.Notification)
+ */
+ public void notifyChanged(Notification notification) {
+ if (notification.getNotifier() == value && !(notification.getOldValue() instanceof InsertionAdapter)) {
+ // execute if an attribute in the new value has changed
+ execute();
+ }
+ else if (notification.getNotifier()==object && notification.getNewValue()==value) {
+ // if the new value has been added to the object, we can remove this adapter
+ object.eAdapters().remove(this);
+ }
+ }
+
+ private void executeChildren(List list) {
+ for (Object o : list) {
+ if (o instanceof List) {
+ executeChildren((List)o);
+ }
+ else if (o instanceof EObject) {
+ executeIfNeeded((EObject)o);
+ }
+ }
+ }
+
+ private void executeChildren(EObject value) {
+ // allow other adapters to execute first
+ for (EStructuralFeature f : value.eClass().getEAllStructuralFeatures()) {
+ try {
+ Object v = value.eGet(f);
+ if (v instanceof List) {
+ executeChildren((List)v);
+ }
+ else if (v instanceof EObject) {
+ executeIfNeeded((EObject)v);
+ }
+ }
+ catch (Exception e) {
+ // some getters may throw exceptions - ignore those
+ }
+ }
+ executeIfNeeded(value);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void execute() {
+ // if the object into which this value is being added has other adapters execute those first
+ executeIfNeeded(object);
+
+ // remove this adapter from the value - this adapter is a one-shot deal!
+ value.eAdapters().remove(this);
+
+ try {
+ Object o = object.eGet(feature);
+ }
+ catch (Exception e1) {
+ try {
+ if (value.eClass().getEStructuralFeature(feature.getName())!=null) {
+ Object o = value.eGet(feature);
+ // this is the inverse add of object into value
+ o = value;
+ value = object;
+ object = (EObject)o;
+ }
+ }
+ catch (Exception e2) {
+ }
+ }
+ // if there are any EObjects contained or referenced by this value, execute those adapters first
+ executeChildren(value);
+
+ // set the value in the object
+ boolean valueChanged = false;
+ final EList<EObject> list = feature.isMany() ? (EList<EObject>)object.eGet(feature) : null;
+ if (list==null) {
+ try {
+ valueChanged = object.eGet(feature)!=value;
+ }
+ catch (Exception e) {
+ // feature does not exist, it's a dynamic feature
+ valueChanged = true;
+ }
+ }
+ else
+ valueChanged = !list.contains(value) || value instanceof ExtensionAttributeValue;
+
+ if (valueChanged) {
+ ExtendedPropertiesAdapter adapter = ExtendedPropertiesAdapter.adapt(object);
+ if (adapter!=null) {
+ adapter.getFeatureDescriptor(feature).setValue(value);
+ }
+ }
+ }
+
+ /**
+ * Adds the value to the object's containment feature.
+ *
+ * @param value
+ */
+ public static void executeIfNeeded(EObject value) {
+ List<InsertionAdapter> allAdapters = new ArrayList<InsertionAdapter>();
+
+ for (Adapter adapter : value.eAdapters()) {
+ if (adapter instanceof InsertionAdapter) {
+ allAdapters.add((InsertionAdapter)adapter);
+ }
+ }
+ value.eAdapters().removeAll(allAdapters);
+ for (InsertionAdapter adapter : allAdapters)
+ adapter.execute();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.bpmn2.modeler.core.adapters.IResourceProvider#getResource()
+ */
+ @Override
+ public Resource getResource() {
+ if (resource==null) {
+ Resource res = object.eResource();
+ if (res!=null)
+ return res;
+ InsertionAdapter insertionAdapter = AdapterUtil.adapt(object, InsertionAdapter.class);
+ if (insertionAdapter!=null)
+ return insertionAdapter.getResource();
+ }
+ return resource;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.bpmn2.modeler.core.adapters.IResourceProvider#setResource(org.eclipse.emf.ecore.resource.Resource)
+ */
+ @Override
+ public void setResource(Resource resource) {
+ this.resource = resource;
+ }
+
+ /**
+ * Gets the EMF Resource that contains the given object. If the object has been adapted
+ * for InsertionAdapter, the Resource defined by that adapter is returned.
+ *
+ * @param object the object.
+ * @return an EMF Resource or null.
+ */
+ public static Resource getResource(EObject object) {
+ InsertionAdapter adapter = AdapterUtil.adapt(object, InsertionAdapter.class);
+ if (adapter!=null) {
+ return adapter.getResource();
+ }
+ if (object!=null)
+ return object.eResource();
+ return null;
+ }
+
+ /**
+ * Gets the object managed by this InsertionAdapter.
+ *
+ * @return the object
+ */
+ public EObject getObject() {
+ return object;
+ }
+
+ /**
+ * Gets the object's containment feature managed by this InsertionAdapter
+ *
+ * @return the containment feature
+ */
+ public EStructuralFeature getFeature() {
+ return feature;
+ }
+
+ /**
+ * Gets the object to be inserted into the containment feature.
+ *
+ * @return the value
+ */
+ public EObject getValue() {
+ return value;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.emf.edit.domain.IEditingDomainProvider#getEditingDomain()
+ */
+ @Override
+ public EditingDomain getEditingDomain() {
+ getResource();
+ if (resource!=null)
+ return AdapterFactoryEditingDomain.getEditingDomainFor(resource);
+ return null;
+ }
+}

Back to the top