Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Papyrus/Papyrus Developer Guide/Editing Domains and Commands
Contents
Initialize a new command with an editing domain
The same editing domain must always be used. Otherwise, you can result in actions which are stored in different domains and different stacks, which leads to several operation history which manage the same diagram but different operations.
The best way to achieve this is to always recover the editing domain using the method
org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart.getEditingDomain()
when you have an edit part at hand, or the static method
org.eclipse.papyrus.core.utils.EditorUtils.getTransactionalEditingDomain()
otherwise.
EMF Transaction framework
Always use a transactional command and domain when you can. The avantages of the EMF Transaction framework are :
- Operations will be validated (emf validation is called by gmf framework on the editing domain). This validation can check a model or eventually correct it or reject modifications (using rules defined with the
org.eclipse.emf.validation.constraintBindings
extension point).
- Operations in a same transaction, will be rejected (in case validation fails), or undone, or will fail (in case an exception occurs) all at the same time. This avoids having unconsistent models with half-executed actions.
Implementing new commands
- For model changes commands, try using transactionnal commands, by implementing
org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand
They may seem painfull to implement, but it ensures a better model consistency and its the only way to respect the EMF_Transaction_framework. In most cases, extending
org.eclipse.gmf.runtime.common.core.command.CompositeCommand
to add classic commands (AddCommand, SetPropertyCommand, ...) to make the job works fine and avoids any coding error.
- You may also use GEF commands for graphical changes, inheriting
org.eclipse.gef.commands.Command
- GMF non transactional commands extending
org.eclipse.gmf.runtime.common.core.command.AbstractCommand
are rarely used. Generally, they act like a proxy for GEF or transactional EMF commands, or may extend
org.eclipse.gmf.runtime.common.core.command.CompositeCommand
to enclose other GMF commands (which themselves follow the same rules). Otherwise, they must have no impact on the resource, for example, opening a popup.
Call a command's execution
Classic way
- Changes which impact the diagram or the model should call the method
org.eclipse.gmf.runtime.diagram.ui.parts.DiagramCommandStack.execute(ICommand, IProgressMonitor)
(this method encloses the IOperationHistory.execute method, but catches raised exceptions to avoid the diagram exploding in front of the user).
- Make a single call per action, by constructing a compound (or composite) command.
- You may use proxies or other execute methods of the same class to call any kind of commands (GEF, GMF, transactional EMF). The java compiler will avoid your getting lost in the commands hierarchies.
The diagram command stack can be obtained from an edit part with
getDiagramEditDomain().getDiagramCommandStack();
You can also use, in case there is no edit part at your disposition :
CommandStack stack = (CommandStack)EditorUtils.getMultiDiagramEditor().getAdapter(CommandStack.class); if(stack != null) { stack.execute(org.eclipse.gef.commands.Command); }
This call is in fact hiding a call to the same method by inheritance (Papyrus editor has a diagram command stack). But this call is less satisfying, because it can be confused with
org.eclipse.emf.edit.domain.EditingDomain.getCommandStack().execute(...)
which MUST NOT be used (often called with the wrong editing domain, Initialize a new command with an editing domain).
Commands executed in a Post-Commit context (for advanced users)
In a post-commit context, you may call directly
org.eclipse.gmf.runtime.diagram.core.util.ViewUtil.setStructuralFeatureValue(View, EStructuralFeature, Object)
(for graphical changes), or use
org.eclipse.emf.common.command.CompoundCommand.execute()
only in case your operation must not be undone nor logged in the history.
There are very few examples of such a case. In fact, I have met only two cases so far :
- When the figure is being updated in an edit part thanks to a listener on the model (generally through the usage of
org.eclipse.papyrus.diagram.common.helper.NotificationHelper
). In such a case, the graphic change is only a consequence of the model change, and undoing the model change will modify the figure again through the same listener.
- In a validator registered with
org.eclipse.emf.validation.constraintProviders
extension point. You can make a corrector, which will correct the model at each modification instead of simply validate and reject an unvalid modification. Any other way will raise an exception since the operation being validated/corrected is in post-commit state. This corrector approach works only in case you have redundant information in the model. For examples, a call behavior action's pins are heavily synchronized with the behavior's parameters ; when parameters are modified, you can deduce that the same modifications must occur on the corresponding pin (as implemented in org.eclipse.papyrus.diagram.activity.helper.PinAndParameterSynchronizer).