/*****************************************************************************
* Copyright (c) 2010 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:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
*****************************************************************************/
package org.eclipse.papyrus.views.properties.modelelement;
import org.eclipse.core.databinding.observable.IObservable;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.emf.databinding.EMFProperties;
import org.eclipse.emf.databinding.FeaturePath;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.papyrus.infra.emf.databinding.EMFObservableList;
import org.eclipse.papyrus.infra.emf.databinding.EMFObservableValue;
import org.eclipse.papyrus.infra.emf.providers.EMFContentProvider;
import org.eclipse.papyrus.infra.emf.providers.EMFLabelProvider;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.infra.widgets.creation.ReferenceValueFactory;
import org.eclipse.papyrus.infra.widgets.providers.IStaticContentProvider;
import org.eclipse.papyrus.views.properties.Activator;
import org.eclipse.papyrus.views.properties.creation.EcorePropertyEditorFactory;
/**
* A ModelElement to manipulate EMF objects.
* This ModelElement uses EMFProperties to retrieve Observables when there
* is no Editing Domain, and {@link EMFObservableValue} / {@link EMFObservableList} when
* an Editing domain is available
*
* @author Camille Letavernier
*/
public class EMFModelElement extends AbstractModelElement {
/**
* The EObject manipulated by this ModelElement
*/
protected EObject source;
/**
* The Editing Domain of the EObject for this ModelElement
*/
protected EditingDomain domain;
/**
*
* Constructs a new EMFModelElement for the given EObject
*
* @param source
*/
public EMFModelElement(EObject source) {
this(source, null);
}
/**
*
* Constructs a new EMFModelElement for the given EObject and Editing Domain
*
* @param source
* @param domain
*/
public EMFModelElement(EObject source, EditingDomain domain) {
this.source = source;
this.domain = domain;
}
/**
* @return the EditingDomain for this ModelElement
*/
public EditingDomain getDomain() {
return domain;
}
/**
* @return the EObject for this ModelElement
*/
public EObject getSource() {
return source;
}
@Override
protected IObservable doGetObservable(String propertyPath) {
FeaturePath featurePath = getFeaturePath(propertyPath);
EStructuralFeature feature = getFeature(propertyPath);
if(feature == null) {
return null;
}
if(feature.getUpperBound() != 1) {
IObservableList list = domain == null ? EMFProperties.list(featurePath).observe(source) : new EMFObservableList(EMFProperties.list(featurePath).observe(source), domain, getSource(featurePath), feature);
return list;
}
IObservableValue value = domain == null ? EMFProperties.value(featurePath).observe(source) : new EMFObservableValue(getSource(featurePath), feature, domain);
return value;
}
/**
* Returns the last EObject by following the given featurePath from the {@link #source} EObject
* The last feature of the featurePath can be used to retrieve value from the returned EObject
*
* @param featurePath
* @return the EObject found by resolving to the given FeaturePath
*/
public EObject getSource(FeaturePath featurePath) {
EObject currentSource = source;
EStructuralFeature[] features = featurePath.getFeaturePath();
for(int i = 0; i < features.length - 1; i++) {
currentSource = (EObject)currentSource.eGet(features[i]);
}
return currentSource;
}
/**
* Returns the feature represented by the given FeaturePath
*
* @param featurePath
* @return
* The last feature obtained by navigating the feature path
*/
public EStructuralFeature getFeature(FeaturePath featurePath) {
EStructuralFeature[] features = featurePath.getFeaturePath();
return features[features.length - 1];
}
/**
* Returns the feature represented by the given propertyPath.
*
* @param propertyPath
* The property path may contain one or more dots to navigate the properties (e.g. : feature1.feature2.feature3)
* @return
* The last feature obtained by resolving the full property path
*/
public EStructuralFeature getFeature(String propertyPath) {
FeaturePath featurePath = getFeaturePath(propertyPath);
return getFeature(featurePath);
}
/**
* Returns the featurePath corresponding to the given propertyPath
*
* @param propertyPath
* The property path may contain one or more dots to navigate the properties (e.g. : feature1.feature2.feature3)
* @return
* The featurePath corresponding to the given propertyPath
*/
public FeaturePath getFeaturePath(String propertyPath) {
String[] featureNames = propertyPath.split("\\."); //$NON-NLS-1$
EStructuralFeature[] features = new EStructuralFeature[featureNames.length];
int i = 0;
EClass currentClass = source.eClass();
for(String featureName : featureNames) {
EStructuralFeature feature = currentClass.getEStructuralFeature(featureName);
features[i++] = feature;
if(i < featureNames.length) {
if(feature instanceof EReference) {
EReference reference = (EReference)feature;
EClassifier type = reference.getEType();
if(type instanceof EClass) {
currentClass = (EClass)type;
continue;
}
}
Activator.log.warn("Cannot find feature path " + propertyPath + " for EClass " + source.eClass()); //$NON-NLS-1$ //$NON-NLS-2$
return null;
}
}
return FeaturePath.fromList(features);
}
@Override
public IStaticContentProvider getContentProvider(String propertyPath) {
FeaturePath featurePath = getFeaturePath(propertyPath);
EStructuralFeature feature = getFeature(featurePath);
if(feature != null) {
return new EMFContentProvider(getSource(featurePath), feature);
}
return super.getContentProvider(propertyPath);
}
@Override
public ILabelProvider getLabelProvider(String propertyPath) {
return new EMFLabelProvider();
}
@Override
public boolean isOrdered(String propertyPath) {
EStructuralFeature feature = getFeature(propertyPath);
if(feature == null) {
return true;
}
return feature.isOrdered();
}
@Override
public boolean isUnique(String propertyPath) {
EStructuralFeature feature = getFeature(propertyPath);
if(feature == null) {
return false;
}
return feature.isUnique();
}
@Override
public boolean isMandatory(String propertyPath) {
EStructuralFeature feature = getFeature(propertyPath);
if(feature == null) {
return false;
}
return EMFHelper.isRequired(feature);
}
@Override
public boolean isEditable(String propertyPath) {
EStructuralFeature feature = getFeature(propertyPath);
if(feature == null) {
return false;
}
return feature.isChangeable() && !EMFHelper.isReadOnly(source);
}
@Override
public boolean forceRefresh(String propertyPath) {
EStructuralFeature feature = getFeature(propertyPath);
if(feature == null) {
return false;
}
return feature.isDerived();
}
@Override
public ReferenceValueFactory getValueFactory(String propertyPath) {
EStructuralFeature feature = getFeature(propertyPath);
if(feature != null) {
if(feature instanceof EReference) {
EReference reference = (EReference)feature;
if(reference.isContainment()) {
return new EcorePropertyEditorFactory(reference);
}
}
}
return super.getValueFactory(propertyPath);
}
@Override
public Object getDefaultValue(String propertyPath) {
EStructuralFeature feature = getFeature(propertyPath);
if(feature == null) {
return null;
}
return feature.getDefaultValue();
}
@Override
public boolean getDirectCreation(String propertyPath) {
EStructuralFeature feature = getFeature(propertyPath);
if(feature == null) {
return false;
}
if(feature instanceof EAttribute) {
return false;
}
return ((EReference)feature).isContainment();
}
}