EMF Derived Attribute Notifier [message #613814] |
Wed, 07 January 2009 12:28 |
No real name Messages: 4 Registered: July 2009 |
Junior Member |
|
|
If you have a derived attribute in EMF and change one of the attributes
that the derived value depends on, then no notification will be sent for
the derived attribute - so it will not change in any editor etc. You have
to write these yourself.
Here's a class I wrote that I've found useful and perhaps it may be useful
to others (all comments etc. gratefully received). You can specify your
derived attribute, and also which other attributes it depends on.
Listeners are then added as appropriate and when any of your dependant
attributes change, you'll fire an event for your derived attribute.
E.g. You have a Class Library and a set of Books in it. Each Book has a
pageCount attribute. The Library has a derived attribute totalPageCount
that adds up all the pages of all the books. Then you can just write...
/**
* @generated NOT
*/
protected LibraryImpl() {
super();
DerivedAttributeAdapter daa = new DerivedAttributeAdapter(this,
MyPackage.LIBRARY__TOTALPAGECOUNT);
daa.addNavigatedDependency(MyPackage.LIBRARY__BOOKS,
MyPackage.BOOK__PAGECOUNT);
}
A local dependency is another attribute in the same class. A navigated
dependency is to an attribute in a class that you have an association
with. You can add many local dependencies, but only one remote one (though
it can be a one to many association).
Here it is...
package put.it.where.you.like;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.impl.EObjectImpl;
public class DerivedAttributeAdapter extends AdapterImpl {
private final EObjectImpl source;
private final int derivedFeature;
private List<Integer> localFeatures = new ArrayList<Integer>();
// TODO this lot could be put into a subclass and put in a list to allow
for
// multiple navigated dependencies
private int dependantFeature = Notification.NO_FEATURE_ID;
private Class<?> dependantClass = null;
private int navigationFeature = Notification.NO_FEATURE_ID;
private AdapterImpl dependantAdapter = new AdapterImpl() {
@Override
public void notifyChanged(Notification msg) {
if (msg.getFeatureID(dependantClass) == dependantFeature &&
msg.getEventType() == Notification.SET) {
notifyDerivedAttributeChange();
}
}
};
/*
* Convenience constructor for a local and navigated dependency
*/
public DerivedAttributeAdapter(EObjectImpl source, int derivedFeature,
int navigationFeature, int dependantFeature, int localFeature) {
this(source, derivedFeature);
addNavigatedDependency(navigationFeature, dependantFeature);
addLocalDependency(localFeature);
}
/*
* Convenience constructor for a navigated dependency
*/
public DerivedAttributeAdapter(EObjectImpl source, int derivedFeature,
int navigationFeature, int dependantFeature) {
this(source, derivedFeature);
addNavigatedDependency(navigationFeature, dependantFeature);
}
/*
* Convenience constructor for a local dependency
*/
public DerivedAttributeAdapter(EObjectImpl source, int derivedFeature,
int localFeature) {
this(source, derivedFeature);
addLocalDependency(localFeature);
}
public DerivedAttributeAdapter(EObjectImpl source, int derivedFeature) {
super();
this.source = source;
this.derivedFeature = derivedFeature;
source.eAdapters().add(this);
}
public void addNavigatedDependency(int navigationFeature, int
dependantFeature) {
this.dependantFeature = dependantFeature;
this.navigationFeature = navigationFeature;
this.dependantClass =
source.eClass().getEStructuralFeature(navigationFeature).get EType().getInstanceClass();
}
public void addLocalDependency(int localFeature) {
localFeatures.add(localFeature);
}
@Override
public void notifyChanged(Notification notification) {
if (notification.getFeatureID(source.getClass()) == navigationFeature) {
switch (notification.getEventType()) {
// TODO support ADD_MANY/REMOVE_MANY?
case Notification.ADD:
EObject added = (EObject) notification.getNewValue();
added.eAdapters().add(dependantAdapter);
break;
case Notification.SET:
EObject newValue = (EObject) notification.getNewValue();
EObject oldValue = (EObject) notification.getOldValue();
if (oldValue != null) oldValue.eAdapters().remove(dependantAdapter);
if (newValue != null) newValue.eAdapters().add(dependantAdapter);
break;
case Notification.REMOVE:
EObject removed = (EObject) notification.getOldValue();
removed.eAdapters().remove(dependantAdapter);
break;
default:
return; // No notification
}
notifyDerivedAttributeChange();
} else if
(localFeatures.contains(notification.getFeatureID(source.get Class()))) {
if (notification.getEventType() == Notification.SET) {
notifyDerivedAttributeChange();
}
}
}
private void notifyDerivedAttributeChange() {
if (source.eNotificationRequired()) {
source.eNotify(new ENotificationImpl(source, Notification.SET,
derivedFeature, null, source.eGet(
derivedFeature, true, true)));
}
}
}
|
|
|
Powered by
FUDForum. Page generated in 0.02619 seconds