Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF » custom labels
custom labels [message #1758736] Sat, 01 April 2017 13:29 Go to next message
Fy Za is currently offline Fy ZaFriend
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 Go to previous messageGo to next message
Aurélien Mora is currently offline Aurélien MoraFriend
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 Go to previous messageGo to next message
Fy Za is currently offline Fy ZaFriend
Messages: 245
Registered: March 2010
Senior Member
Thanks Aurélien Mora!

It works perfetly Very Happy Very Happy
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

Re: custom labels [message #1758744 is a reply to message #1758743] Sat, 01 April 2017 15:14 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33113
Registered: July 2009
Senior Member
It's a wiki, so if you get an Eclipse account

https://accounts.eclipse.org/user/register

you can login with that and make changes. It would be really nice of you to do that!


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: custom labels [message #1758746 is a reply to message #1758744] Sat, 01 April 2017 15:43 Go to previous message
Fy Za is currently offline Fy ZaFriend
Messages: 245
Registered: March 2010
Senior Member
Hi Ed,
It is done
I edited the wiki page.
I will share the corresponding code in my github and I will add the link in the references of this article

best regards,

[Updated on: Sat, 01 April 2017 15:47]

Report message to a moderator

Previous Topic:EAttribute serialized as Element not attribute (override?)
Next Topic:Easy way of Filtering in EMF List Dialogs
Goto Forum:
  


Current Time: Thu Mar 28 08:50:10 GMT 2024

Powered by FUDForum. Page generated in 0.02674 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top