Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/util/PropertyIndexedList.java')
-rw-r--r--extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/util/PropertyIndexedList.java390
1 files changed, 390 insertions, 0 deletions
diff --git a/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/util/PropertyIndexedList.java b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/util/PropertyIndexedList.java
new file mode 100644
index 00000000000..8bf5ff10f14
--- /dev/null
+++ b/extraplugins/layers/org.eclipse.papyrus.layers.stackmodel/src/org/eclipse/papyrus/layers/stackmodel/layers/util/PropertyIndexedList.java
@@ -0,0 +1,390 @@
+/*******************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ * 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:
+ * Cedric Dumoulin - cedric.dumoulin@lifl.fr
+ ******************************************************************************/
+package org.eclipse.papyrus.layers.stackmodel.layers.util;
+
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.common.util.EMap;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.util.EObjectResolvingEList;
+import org.eclipse.papyrus.layers.stackmodel.BadStateException;
+import org.eclipse.papyrus.layers.stackmodel.LayersException;
+import org.eclipse.papyrus.layers.stackmodel.NotFoundException;
+import org.eclipse.papyrus.layers.stackmodel.layers.Property;
+import static org.eclipse.papyrus.layers.stackmodel.Activator.log;
+
+
+/**
+ * An EMF {@link EObjectResolvingEList} that automaticaly reflect a
+ * Map of (String, T). The keys are the names of the Property.
+ * The list also know the list of Properties, and use it to indexing
+ * the types of the Map.
+ * <br>
+ * usage:
+ * <br>
+ * list = new PropertyIndexedList<type>(...);
+ * list.setPropertyList( propertyRegistry.getProperties() );
+ *
+ * @author cedric dumoulin
+ *
+ * @param <T> The type of the objects contained in the list. The type should be
+ * the same as the type of the values in the backuped Map.
+ */
+public class PropertyIndexedList<T> extends EObjectResolvingEList<T> {
+
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The backuped Map. The implementation should be an Observable Map from EMF.
+ *
+ */
+ protected EMap<String, T> map;
+
+ /**
+ * The ordered list of Property, used to indexing this List.
+ * The Property::index should be set.
+ */
+ protected List<Property> propertyList;
+
+ /**
+ * The classtype of the owner of the map
+ */
+ protected Class<?> mapParentClasstype;
+
+ /**
+ * The id of the map property in its parent.
+ */
+ final protected int MAP_FEATURE_ID;
+
+ /**
+ * The value that is used as a "null value".
+ * We can't use 'null' because the list don't support it (even
+ * if we set canSupportNull to true).
+ */
+ final protected T NULL_VALUE;
+
+ /**
+ * Constructor.
+ *
+ * @param dataClass Type of the element of the list
+ * @param layer The owner of this list and of the map
+ * @param featureID The feature Id of this list in the owner
+ *
+ * @param mapFeatureID The map feature id in the owner
+ */
+ public PropertyIndexedList(EMap<String, T> map, Class<T> dataClass, InternalEObject layer, int featureID, int mapFeatureID, T nullValue) {
+ super(dataClass, layer, featureID);
+ MAP_FEATURE_ID = mapFeatureID;
+ NULL_VALUE = nullValue;
+ mapParentClasstype = layer.getClass();
+ this.map= map;
+ init();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param dataClass Type of the element of the list
+ * @param layer The owner of this list and of the map
+ * @param featureID The feature Id of this list in the owner
+ *
+ * @param mapFeatureID The map feature id in the owner
+ */
+ public PropertyIndexedList(Map<String, T> map, Class<T> dataClass, InternalEObject layer, int featureID, int mapFeatureID, T nullValue) {
+ super(dataClass, layer, featureID);
+ MAP_FEATURE_ID = mapFeatureID;
+ NULL_VALUE = nullValue;
+ mapParentClasstype = layer.getClass();
+ this.map= (EMap<String, T>)map;
+ init();
+ }
+
+ /**
+ * Listen on the map for addition/deletion.
+ *
+ */
+ protected void init() {
+ getEObject().eAdapters().add(new PropertyValuesSynchronizer());
+
+ }
+
+ /**
+ * Allows double
+ * @see org.eclipse.emf.ecore.util.EObjectEList#isUnique()
+ *
+ * @return
+ */
+ //
+ protected boolean isUnique() {
+ return false;
+ }
+
+ /**
+ * Allow null values in the list.
+ * @see org.eclipse.emf.ecore.util.EObjectEList#canContainNull()
+ *
+ * @return
+ */
+// @Override
+// protected boolean canContainNull() {
+// return true;
+// }
+
+
+ /**
+ * @param propertyList the propertyList to set
+ */
+ public void setPropertyList(List<Property> propertyList) {
+ this.propertyList = propertyList;
+ try {
+ resetListElements();
+ } catch (BadStateException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Reset the elements of the list, according to the map and the
+ * propertyList.
+ * @throws BadStateException
+ *
+ */
+ private void resetListElements() throws BadStateException {
+ // Reset list
+ this.clear();
+
+ // Check application
+ if(propertyList== null) {
+ // do not synchronize the list
+ return;
+// throw new BadStateException("Property 'application' must be set for resetAllPropertyValuesFromRegistry() to work.");
+ }
+
+ List<Property> availableProperties;
+ int size;
+ try {
+ availableProperties = propertyList;
+ size = availableProperties.size();
+ } catch (NullPointerException e) {
+ throw new BadStateException("Property 'application.propertyRegistry' must be set for resetAllPropertyValuesFromRegistry() to work.");
+ }
+
+ // initialize the list
+ for(int i=0;i<size;i++) {
+ String propertyName = availableProperties.get(i).getName();
+ // Add the value, or null if not found. This ensure
+ // That the list will have the correct size.
+ T value = map.get(propertyName);
+ if( value == null ) {
+ value = NULL_VALUE;
+ }
+ this.add( value);
+ }
+ }
+
+ /**
+ * Get an element by its property.
+ * @param property
+ * @return
+ * @throws NotFoundException If the index of the property is not found.
+ */
+ public T get(Property property) throws NotFoundException {
+ try {
+ return get( property.getIndex());
+ } catch (IndexOutOfBoundsException e) {
+ throw new NotFoundException("Can't get element for Property '" + property.getName()
+ + "'. ", e);
+ }
+ }
+
+ /**
+ * Set the element for the specified Property.
+ * @param property
+ * @param ele
+ * @throws BadStateException When the associated map is not set.
+ */
+ public void set( Property property, T value ) throws BadStateException {
+ if( map == null) {
+ throw new BadStateException("Can't set element for Property '" + property.getName()
+ + "'. The associated map should be set first");
+
+ }
+
+ // Set the element in the map
+ map.put(property.getName(), value);
+ }
+
+ /**
+ * Synchronize the specified propertyName with the value in the {@link #propertyValues} list.
+ * @param propertyName
+ * @param value
+ * @throws NotFoundException
+ */
+ protected void synchronizePropertyValue(String propertyName, T value) throws BadStateException, NotFoundException {
+
+ if( propertyList == null) {
+ //silently fail
+ return;
+ }
+
+ try {
+ int propertyIndex = getPropertyIndex(propertyName);
+ set(propertyIndex, value);
+ } catch (NullPointerException e) {
+ throw new BadStateException("propertyList should be set first.");
+ }
+ }
+
+
+ /**
+ * Get a Property by its name.
+ * Lookup in the {@link #propertyList} property.
+ *
+ * @param propertyName
+ * @return
+ * @throws NotFoundException
+ */
+ protected int getPropertyIndex( String propertyName) throws NotFoundException {
+
+ if(propertyName == null) {
+ throw new NotFoundException("Null name not Allowed");
+ }
+ for( int i=0; i<propertyList.size(); i++) {
+ if( propertyName.equals(propertyList.get(i).getName() ) ) {
+ return i;
+ }
+ }
+
+ // Not found
+ throw new NotFoundException("No property found under name '" + propertyName + "'");
+
+
+ }
+ /**
+ * This class listen to #propertyValueMap, and synchronize propertyValues accordingly.
+ *
+ * This adapter listen on the map's parent to know if a Property key is
+ * added or removed.
+ *
+ */
+ public class PropertyValuesSynchronizer extends AdapterImpl {
+
+
+ @Override
+ public void notifyChanged(Notification msg) {
+ if(log.isDebugEnabled()) {
+ log.debug("event " + msg.getEventType());
+ }
+
+ // Check if the notification comes from the map
+ if( msg.getFeatureID(mapParentClasstype) == MAP_FEATURE_ID) {
+ notifyLayerPropertyValueMapChanged(msg);
+ }
+ }
+
+ /**
+ * The {@link PropertyIndexedList#map} has changed. Synchronize this list.
+ * @param msg
+ */
+ protected void notifyLayerPropertyValueMapChanged(Notification msg) {
+ if(log.isDebugEnabled()) {
+ log.debug("map changed " + msg.getEventType());
+ }
+
+ switch(msg.getEventType()) {
+ case Notification.SET:
+ {
+ // A key is modified
+ // Add the value to other list
+ @SuppressWarnings("unchecked")
+ Map.Entry<String, T> entry = (Map.Entry<String, T>)msg.getNewValue();
+
+ if(log.isDebugEnabled()) {
+ log.debug("SET - newValue=" + entry.getValue()
+ + ", key=" + entry.getKey());
+ }
+
+// String newKey = (String)msg.getNewValue();
+ T value = entry.getValue();
+ if( value != null) {
+ try {
+ synchronizePropertyValue(entry.getKey(), value);
+// synchronizePropertyValue(newKey, value);
+ } catch (BadStateException e) {
+ // Show error for debug
+ e.printStackTrace();
+ } catch (NotFoundException e) {
+ // Show error for debug
+ e.printStackTrace();
+ }
+ }
+
+
+ break;
+ }
+ case Notification.UNSET:
+ // A key is added
+ break;
+ case Notification.ADD:
+ {
+ // An entry is added
+ @SuppressWarnings("unchecked")
+ Map.Entry<String, T> entry = (Map.Entry<String, T>)msg.getNewValue();
+ if(log.isDebugEnabled()) {
+ log.debug("ADD - newValue=" + entry.getValue()
+ + ", key=" + entry.getKey());
+ }
+
+ // Add the corresponding instance to propertyValues
+ try {
+ synchronizePropertyValue(entry.getKey(), entry.getValue());
+ } catch (LayersException e) {
+ // should not happen
+ e.printStackTrace();
+ }
+ break;
+ }
+ case Notification.REMOVE:
+ {
+ // An entry is removed
+ @SuppressWarnings("unchecked")
+ Map.Entry<String, T> entry = (Map.Entry<String, T>)msg.getNewValue();
+ if(log.isDebugEnabled()) {
+ log.debug("REMOVE" + entry.getValue()
+ + ", key=" + entry.getKey());
+ }
+
+ // Add the corresponding instance to propertyValues
+ try {
+ synchronizePropertyValue(entry.getKey(), NULL_VALUE);
+ } catch (LayersException e) {
+ // should not happen
+ e.printStackTrace();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ }
+
+ }
+
+}

Back to the top