Skip to main content



      Home
Home » Modeling » EMF » Undo SetCommand of a FeatureMapEntry attribute
Undo SetCommand of a FeatureMapEntry attribute [message #1871886] Tue, 15 October 2024 04:40 Go to next message
Eclipse UserFriend
Hello,
in my ecore model I define a FeatureMapEntry attribute, let's name it myAttr, in a class, let's say MyClass, in order to allow a mixed order of objects from different features.

Now, when I set a new feature map into myAttr of some object of the type MyClass in the generated editor then everything is OK. But when I use CTRL+Z in order to undo the last SetCommand it does not work anymore and I get an exception. The problem is that the SetCommand does not save the original FeatureMap but an EList which in turn cannot be processed when setting it back to the object.

SetCommand line 545+++:
if (owner.eIsSet(feature))
{
    oldValue = new BasicEList<Object>((EList<?>)owner.eGet(feature));
    // oldValue = owner.eGet(feature);
}


BasicFeatureMap line 2555+++:
public void set(Object newValue)
{
    super.set(newValue instanceof FeatureMap ? newValue : ((FeatureMap.Internal.Wrapper)newValue).featureMap());
}


I think there is a reason why FeatureMaps cannot be used as old values. My first tries to solve it in a quick and dirty way failed. When I subclass the SetCommand and use the original FeatureMap as the old value then it has no effect. First the FeatureMap adds the values from the original FeatureMap but then removes the values from the container which in turn is the new container already. I think it is done by the inverseAdd method.

My question is: How can the problem be solved? How can a SetCommand undo the setting of a FeatureMapEntry attribute?
If not possible, do I really have to set all the objects of the FeatureMapEntry object by object?

Best regards
Franz
Re: Undo SetCommand of a FeatureMapEntry attribute [message #1871892 is a reply to message #1871886] Tue, 15 October 2024 09:29 Go to previous messageGo to next message
Eclipse UserFriend
The details aren't entirely clear to me. I would typically that the feature map list is manipulated with AddCommand, RemoveCommand, or with a SetCommand at a specific index of that list. Both add and remove command allow to add/remove collections of things. I could look at how your scenario might be directly supported but I need a test case for that...
Re: Undo SetCommand of a FeatureMapEntry attribute [message #1871922 is a reply to message #1871892] Wed, 16 October 2024 03:33 Go to previous messageGo to next message
Eclipse UserFriend
I would like to transfer all objects from one FeatureMap to another FeatureMap using 1 SetCommand. But if that is not possible then using one RemoveCommand and one AddCommand instead is fine too .

For clarification purposes:

I integrated a new action in the generated editor and try to use a SetCommand in the following way:

Command command = SetCommand.create(getEditingDomain(), objectOfTypeMyClass, myAttrFeature, anotherObjectOfTypeMyClass.eGet(myAttrFeature));
if (command.canExecute()) {
	// at this point the field 'oldValue' of command is NOT a FeatureMap but a BasicEList<Object>
	// that is a problem when command.undo() is called because the set method of BasicFeatureMap needs a FeatureMap
	editingDomain.getCommandStack().execute(command);
}


When I try to undo the SetCommand I get an exception because the 'oldValue' in the SetCommand is a BasicEList and not a FeatureMap, see the snippets above.

Is there a special reason why a SetCommand cannot or should not deal with a collection/multiple values?
Re: Undo SetCommand of a FeatureMapEntry attribute [message #1871937 is a reply to message #1871922] Wed, 16 October 2024 07:58 Go to previous messageGo to next message
Eclipse UserFriend
A "normal list" does this type of thing for eSet:
        getEAnnotations().clear();
        getEAnnotations().addAll((Collection<? extends EAnnotation>)newValue);
        return;

So it's not a question of why doesn't SetCommand for a list, it's more a question of how is a FeatureMap handled in that context. Note that for above, it's a "remove-all" and an "add-all" under the covers. If there is something broken, it's potentially/likely fixable, hence my comment about a test case. Perhaps a simple instance test to create a feature map wrapper list of some sort:

https://github.com/eclipse-emf/org.eclipse.emf/issues

Or you can try using the suggested alternative commands.
Re: Undo SetCommand of a FeatureMapEntry attribute [message #1871955 is a reply to message #1871937] Wed, 16 October 2024 12:31 Go to previous messageGo to next message
Eclipse UserFriend
Thanks for the feedback!

I will try to provide a test case but without any promises.

So far I use the following solution:

Command command = RemoveCommand.create(getEditingDomain(), objectOfTypeMyClass, myAttrFeature, new ArrayList<>((Collection<?>) objectOfTypeMyClass.eGet(myAttrFeature)));
if (command.canExecute()) {
	commandStack.execute(command);
	
	Command addCommand = AddCommand.create(getEditingDomain(), objectOfTypeMyClass, myAttrFeature, new ArrayList<>((Collection<?>) anotherObjectOfTypeMyClass.eGet(myAttrFeature)));
	if (addCommand.canExecute()) {
		commandStack.execute(addCommand);
	} else if (command.canUndo()) {
		command.undo();
	}
}

I tried to use a CompoundCommand but that does not work as long as the subcommands depend on other subcommands. The reason is that CompoundCommand checks in the method prepare() which is called by canExecute() whether each subcommand can execute. That check is performed at the time before any of the subcommands has been executed. And if subcommands depend on the results of other subcommands that will fail. Like in my case.

The AddCommand cannot add objects that are 'equal' to the objects in objectOfTypeMyClass because the myAttrFeature is defined 'unique'. At runtime of a CompoundCommand that would be perfectly fine because the AddCommand would execute after the RemoveCommand and hence there would not be any conflict.

In my opinion CompoundCommand should only check the first command during its own call of prepare() and call canExecute() on subcommands during its execution.

With a StrictCompoundCommand it seems not work either since only the last command will be undone.
I guess I would need to subclass CompoundCommand and relax the prepare() method in order to achieve that one call of undo() performs undo of each subcommand .
Re: Undo SetCommand of a FeatureMapEntry attribute [message #1871973 is a reply to message #1871955] Thu, 17 October 2024 03:42 Go to previous messageGo to next message
Eclipse UserFriend
A test case is worth a thousand words. This works
    AnyType anyType = XMLTypeFactory.eINSTANCE.createAnyType();
    FeatureMap anyAttribute = anyType.getAnyAttribute();
    EStructuralFeature feature = ExtendedMetaData.INSTANCE.demandFeature("namespace", "name", false);
    Entry entry = FeatureMapUtil.createEntry(feature, "value");
    anyAttribute.add(entry);
    BasicCommandStack basicCommandStack = new BasicCommandStack();
    AdapterFactoryEditingDomain adapterFactoryEditingDomain = new AdapterFactoryEditingDomain(new ReflectiveItemProviderAdapterFactory(), basicCommandStack);
    AnyType anyType2 = XMLTypeFactory.eINSTANCE.createAnyType();
    System.err.println("before> " + anyType2.getAnyAttribute());
    Command command = SetCommand.create(adapterFactoryEditingDomain, anyType2, XMLTypePackage.Literals.ANY_TYPE__ANY_ATTRIBUTE, anyAttribute);
    basicCommandStack.execute(command);
    System.err.println("after>  " + anyType2.getAnyAttribute());
The feature you're operating on must be an EReference not a feature map feature, which is an EAttribute, but I cannot deduce your model and scenario to synthesize a representative test case from your description.
Re: Undo SetCommand of a FeatureMapEntry attribute [message #1872036 is a reply to message #1871973] Fri, 18 October 2024 04:23 Go to previous messageGo to next message
Eclipse UserFriend
Thanks for the base of the test case! That saved a lot of time :D!

The complete test case would be as follows (see the lower part):

	AnyType anyType = XMLTypeFactory.eINSTANCE.createAnyType();
	FeatureMap anyAttribute = anyType.getAnyAttribute();
	EStructuralFeature feature = ExtendedMetaData.INSTANCE.demandFeature("namespace", "name", false);
	Entry entry = FeatureMapUtil.createEntry(feature, "value");
	anyAttribute.add(entry);
	BasicCommandStack basicCommandStack = new BasicCommandStack();
	AdapterFactoryEditingDomain adapterFactoryEditingDomain = new AdapterFactoryEditingDomain(new ReflectiveItemProviderAdapterFactory(), basicCommandStack);
	AnyType anyType2 = XMLTypeFactory.eINSTANCE.createAnyType();
	System.err.println("before> " + anyType2.getAnyAttribute());
	Command command = SetCommand.create(adapterFactoryEditingDomain, anyType2, XMLTypePackage.Literals.ANY_TYPE__ANY_ATTRIBUTE, anyAttribute);
	basicCommandStack.execute(command);
	System.err.println("after>  " + anyType2.getAnyAttribute());
	
	// NEW: set the same again and try to undo the command
	command = SetCommand.create(adapterFactoryEditingDomain, anyType2, XMLTypePackage.Literals.ANY_TYPE__ANY_ATTRIBUTE, anyAttribute);
	basicCommandStack.execute(command);
	command.undo();		// <-- throws a ClassCastException
	System.err.println("after undo>  " + anyType2.getAnyAttribute());

I my ecore model the feature is an attribute of type "EFeatureMapEntry".

[Updated on: Fri, 18 October 2024 04:24] by Moderator

Re: Undo SetCommand of a FeatureMapEntry attribute [message #1872042 is a reply to message #1872036] Fri, 18 October 2024 11:34 Go to previous messageGo to next message
Eclipse UserFriend
I addressed the problem via this commit:

https://github.com/eclipse-emf/org.eclipse.emf/commit/27b2e7f38c7f07667f235a793d5e50274dd583a5

The implementation in the super class just does this:
  public void set(Object newValue)
  {
    clear();
    addAll((List<? extends E>)newValue);
  }
So there is no need for a special implementation class for the value, just the need to unwrap it if it's a wrapper.

The fix is available in the nightly build:

https://download.eclipse.org/modeling/emf/emf/builds/nightly/latest
Re: Undo SetCommand of a FeatureMapEntry attribute [message #1872129 is a reply to message #1872042] Wed, 23 October 2024 04:52 Go to previous messageGo to next message
Eclipse UserFriend
Thanks for the super fast fix!

Franz is happy with the solution :D.
Re: Undo SetCommand of a FeatureMapEntry attribute [message #1872141 is a reply to message #1872129] Wed, 23 October 2024 14:24 Go to previous message
Eclipse UserFriend
Thanks for reporting the problem. :)
Previous Topic:Issues Extending OCL Primitive Type String with Custom Operations in Ecore
Next Topic:Remove records from x_y_list table.
Goto Forum:
  


Current Time: Thu Nov 06 04:28:40 EST 2025

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

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

Back to the top