Home » Modeling » EMF » custom labels
custom labels [message #1758736] |
Sat, 01 April 2017 13:29 |
Fy Za Messages: 245 Registered: March 2010 |
Senior Member |
|
|
Hi all,
I try to custom labels for my dsl.
So, I found this interesting tutorial that resolve my problem
you want the label to be updated whenever those attribute values may change.
http://wiki.eclipse.org/EMF/Recipes#Recipe:_Custom_Labels
So, I create the metamodel corresponding to the tutorial, Foo.ecore (see below)
and I updated the corresponding class as explained in the tutorial (see below).
So when we have a A instance refers to a B instance and then B name changes, the A label will change.
However, I've noticed that when 2 A instances refer to a B instance and the B name changes, ONLY one A instance label changes.
Is it normal?
The demo in the attachment illustrates that.
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="foo" nsURI="http://foo" nsPrefix="foo">
<eClassifiers xsi:type="ecore:EClass" name="Container">
<eStructuralFeatures xsi:type="ecore:EReference" name="as" upperBound="-1" eType="#//A"
containment="true"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="bs" upperBound="-1" eType="#//B"
containment="true"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="A">
<eStructuralFeatures xsi:type="ecore:EReference" name="b" eType="#//B"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="B">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
</ecore:EPackage>
/**
*/
package foo.provider;
import foo.A;
import foo.FooPackage;
import java.util.Collection;
import java.util.List;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.ResourceLocator;
import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
import org.eclipse.emf.edit.provider.IChangeNotifier;
import org.eclipse.emf.edit.provider.IEditingDomainItemProvider;
import org.eclipse.emf.edit.provider.IItemLabelProvider;
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
import org.eclipse.emf.edit.provider.IItemPropertySource;
import org.eclipse.emf.edit.provider.INotifyChangedListener;
import org.eclipse.emf.edit.provider.IStructuredItemContentProvider;
import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
import org.eclipse.emf.edit.provider.ItemProviderAdapter;
import org.eclipse.emf.edit.provider.ViewerNotification;
/**
* This is the item provider adapter for a {@link foo.A} object.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public class AItemProvider
extends ItemProviderAdapter
implements
IEditingDomainItemProvider,
IStructuredItemContentProvider,
ITreeItemContentProvider,
IItemLabelProvider,
IItemPropertySource {
private ChangeListener changeListener;
/**
* This constructs an instance from a factory and a notifier.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public AItemProvider(AdapterFactory adapterFactory) {
super(adapterFactory);
if(adapterFactory instanceof IChangeNotifier) {
IChangeNotifier cn = (IChangeNotifier) adapterFactory;
changeListener = new ChangeListener();
cn.addListener(changeListener);
}
}
/**
* This returns the property descriptors for the adapted class.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public List<IItemPropertyDescriptor> getPropertyDescriptors(Object object) {
if (itemPropertyDescriptors == null) {
super.getPropertyDescriptors(object);
addBPropertyDescriptor(object);
}
return itemPropertyDescriptors;
}
/**
* This adds a property descriptor for the B feature.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected void addBPropertyDescriptor(Object object) {
itemPropertyDescriptors.add
(createItemPropertyDescriptor
(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
getResourceLocator(),
getString("_UI_A_b_feature"),
getString("_UI_PropertyDescriptor_description", "_UI_A_b_feature", "_UI_A_type"),
FooPackage.Literals.A__B,
true,
false,
true,
null,
null,
null));
}
/**
* This returns A.gif.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public Object getImage(Object object) {
return overlayImage(object, getResourceLocator().getImage("full/obj16/A"));
}
/**
* This returns the label text for the adapted class.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
@Override
public String getText(Object object) {
A aObj = (A) object;
String ref = aObj.getB() == null ? "???" : aObj.getB().getName();
ref = ref == null ? "???" : ref;
return getString("_UI_A_type")+" -> "+ref; //$NON-NLS-1$
}
/**
* This handles model notifications by calling {@link #updateChildren} to update any cached
* children and by creating a viewer notification, which it passes to {@link #fireNotifyChanged}.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void notifyChanged(Notification notification) {
updateChildren(notification);
switch (notification.getFeatureID(A.class)) {
case FooPackage.A__B:
fireNotifyChanged(new ViewerNotification(notification, notification
.getNotifier(), false, true));
return;
}
super.notifyChanged(notification);
}
/**
* This adds {@link org.eclipse.emf.edit.command.CommandParameter}s describing the children
* that can be created under this object.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
protected void collectNewChildDescriptors(Collection<Object> newChildDescriptors, Object object) {
super.collectNewChildDescriptors(newChildDescriptors, object);
}
/**
* Return the resource locator for this item provider's resources.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public ResourceLocator getResourceLocator() {
return FooEditPlugin.INSTANCE;
}
/* (non-Javadoc)
* @see org.eclipse.emf.edit.provider.ItemProviderAdapter#dispose()
*/
public void dispose() {
super.dispose();
if(changeListener != null) {
((IChangeNotifier)getAdapterFactory()).removeListener(changeListener);
}
}
class ChangeListener implements INotifyChangedListener {
public void notifyChanged(Notification notification) {
if(notification.getNotifier() != null && getTarget() != null && notification.getNotifier() == ((A) getTarget()).getB()) {
((IChangeNotifier) getAdapterFactory()).removeListener(this);
fireNotifyChanged(new ViewerNotification(notification, getTarget(), false, true));
((IChangeNotifier) getAdapterFactory()).addListener(this);
}
}
}
}
|
|
|
Re: custom labels [message #1758738 is a reply to message #1758736] |
Sat, 01 April 2017 14:18 |
Aurélien Mora Messages: 38 Registered: July 2014 |
Member |
|
|
Hello,
I suppose there is a missing information on http://wiki.eclipse.org/EMF/Recipes#Recipe:_Custom_Labels
If you want to add some attributes in an item provider, you probably want them specifics to the adapted object. But the default behavior is Singleton : one ItemProvider for all adapted objects ; so all A instances will share the same AItemProvider.
So the problem here is that the ChangeListener is shared between the two instances, but when it calls getTarget(), he only has the last object the itemProvider were attached
to (and not all instances).
A first solution is to make the AItemProvider Statefull : edit the genmodel for the A class : Properties View => Edit => ProviderType => Statefull. Next regenerate the edit code.
Another solution, if you want to keep the item provider Singleton, could be maintaining a list of all A instances the itemProvider is attached to, and use it in the notifyChanged of the change listener in place of the getTarget().
[Updated on: Sat, 01 April 2017 14:21] Report message to a moderator
|
|
|
Re: custom labels [message #1758743 is a reply to message #1758738] |
Sat, 01 April 2017 15:02 |
Fy Za Messages: 245 Registered: March 2010 |
Senior Member |
|
|
Thanks Aurélien Mora!
It works perfetly
I experiment both solutions.
For the second solution, I share the updated notifyChanged method.
public void notifyChanged(Notification notification) {
if(notification.getNotifier() != null && getTarget() != null && notification.getNotifier() == ((A) getTarget()).getB()) {
((IChangeNotifier) getAdapterFactory()).removeListener(this);
fireNotifyChanged(new ViewerNotification(notification, getTarget(), true, true));
((IChangeNotifier) getAdapterFactory()).addListener(this);
}
for (Notifier target : targets){
if(notification.getNotifier() != null && target != null && notification.getNotifier() == ((A) target).getB()) {
((IChangeNotifier) getAdapterFactory()).removeListener(this);
fireNotifyChanged(new ViewerNotification(notification, target, false, true));
((IChangeNotifier) getAdapterFactory()).addListener(this);
}
}
}
How can us update the tutorial to be complete for other users?
best regards,
Faiez
[Updated on: Sat, 01 April 2017 15:02] Report message to a moderator
|
|
| | |
Goto Forum:
Current Time: Thu Mar 28 08:50:10 GMT 2024
Powered by FUDForum. Page generated in 0.02674 seconds
|