In an EMF-generated application, every command that a user makes can be revoked (undo), such as modifying the price of a product, pressing the Undo button to restore the original price, and, of course, Redo it back to the new price. To implement this function, the application maintains a stack-like data structure (Commandstack) for storing commands, and each executed command is stored there, removing the most recent command when it needs to be undone. This data structure is maintained by the Editingdomain object, and Editingdomain is equivalent to the environment when editing the model.
In EMF, the command framework can actually be divided into two parts, a generic command unrelated to the model, and an. Edit command, which is based on the former. Any modification of the EMF to the model is done by means of a command, such as when the user modifies an object's properties in the property view, and then executes its execute () method, which modifies the model (actually through the Doexecute ( ), the command is placed on the command stack for revocation when the execution completes successfully.
Generic commands can be completely detached from EMF, meaning that the command framework can be applied to any application that requires a command framework, including non-EMF applications. It is located in the Org.eclipse.emf.common.command package, where the command interface defines what is "commands", and a command has methods such as execute (), Undo () and Redo (), and CanExecute () and the CanUndo () method is used to determine whether a command can be executed or revoked (given the resource consumption, some commands may be designed to be irrevocable and more reasonable). Another important interface is the previously mentioned Commandstack, which saves all commands and can register listeners with the Addcommandstacklistener () method to observe Commandstack state changes. The Compoundcommand interface can wrap multiple commands in order into a combination command, which is atomic, similar to the concept of a database transaction (Transaction), which can only be executed when all commands are executed, as well as undo.
EMF in the. Edit Framework provides some of the commands (located in the Org.eclipse.emf.edit.command package) needed to edit the EMF model, such as SetCommand for modifying the object's properties. The role of Createchildcommand is to create a child element, as well as Movecommand, Copycommand, Cuttoclipboardcommand, and so on. These commands implement the command interface, and most of them inherit from the Abstractoverrideablecommand abstract class, which has the effect of adding a do in front of the method name in the command interface, such as Execute () Into Doexecute (), CanUndo () into Docanundo () and so on, we're expanding these. Overwrite Doxxx method when edit command ... The edit command modifies the model by reflection.
These commands provided by EMF provide us with basic model editing capabilities, and in most cases we can use them directly, but sometimes some special requirements can be achieved through custom commands. For example, in the case of an online store, the assumption is that the price of the product is only accurate to two digits after the decimal point, then we want to round the value immediately after the user enters the new price, and this operation can be done with the custom command. Because of the use of. Edit provides the class, so generally we should expand. The edit command, specifically, is SetCommand.
First, we create our Setpricecommand by inheriting SetCommand, and in this method we cover the Doexecute () method, there are many environment variables available in SetCommand, and we want to use both owner and value, the former Is the object to be modified, here is the Product object, which is the new value of the property, here is the new price. So our Setpricecommand can be written as follows (in order for the code to be minimalist, we directly convert the Eobject type to the product type, so that we don't need to reflect the way):
public class SetPriceCommand extends SetCommand {
public SetPriceCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Object value) {
super(domain, owner, feature, value);
}
public void doExecute() {
Product product = (Product) owner;
double newPrice = ((Double) value).doubleValue();
newPrice = Math.max(0, newPrice);//New price value must >= 0
newPrice=Math.round(newPrice*100)/100d;//Max fraction digits is 2
product.setPrice(newPrice);
}
}
For this custom command to take effect, you must overwrite the Createsetcommand () method in Productitemprovider, because this method is returned to SetCommand by default, and we have to make a judgment here: if the price attribute is modified, Just return to our custom command, as follows:
protected Command createSetCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Object value,
int index) {
if (feature == ShopPackage.eINSTANCE.getProduct_Price())
return new SetPriceCommand(domain, owner, feature, value);
return super.createSetCommand(domain, owner, feature, value, index);
}
This will call our Setpricecommand when the user changes the price attribute in the property page. Incidentally, there are similar editdomain and command in GEF, but the command in GEF is generally created by the Editpolicy Createxxxcommand () method. Since the two sets of command mechanisms for GEF and EMF do not implement a unified interface, the combination of GEF and EMF often encounters problems that require additional code to help resolve, please refer to these two discussions.
Finally to say, Createchildcommand a little special, it is. The edit command does not inherit Abstractoverrideablecommand, and if you want to do something automatically when you create a child element, you should not do so by extending the class, but by Xxxitemprovider's Collectnewchilddescriptors () method, which determines which child elements each object can create, you can modify its code to do some processing on the newly created element.