Published by Arto Jarvinen on 06 Jun 2013

Understanding the outline view

I’ve been away from this project for a while travelling to customers in Asia (that’s where many customers are these days). This means that it will take me many hours to try to remember what I did the last time. Posts like this one helps me remember where I left the project the last time.

This post describes my first cut on understanding the outline view of a generated (slightly modified) GMF editor. I try to describe what happens when an item is selected in the outline view. The story is not complete as of now as there is a lot going on under the hood when one clicks on an item. I will probably come back to this post and amend it later.

The outline view typically shows to the left of the diagram editors in the Eclipse instance. If not, it can be displayed using the Window -> Show View menu command. It shows the contents of the active diagram in two alternative formats: as an outline (tree) format and as a minimized overview image of the current diagram.

The outline page (DiagramOutlinePage) that contains both the (tree) outline and the (diagram) overview extends ContentOutlinePage. This class contains the edit part viewer of the type TreeViewer. The TreeViewer in turn refers to the GUI tree widget of the type org.eclipse.swt.widgets.Tree which contains TreeItems. The TreeItems are subclasses of Widgets. Widgets can refer to arbitrary application objects. In our case each TreeItem refers to a TreeEditPart.

The TreeViewer edit part viewer listens to selections in the Tree. (The diagram overview does not have any associated edit part viewer and is thus just a “dumb” view.)

The outline view with its TreeViewer (edit part viewer) is activated when a diagram is activated. At that time my ProcessmodelDiagramEditor is adapted with (my version of) a DiagramOutlinePage.

The following code within ProcessmodelDiagramEditor.getAdapter() creates the outline page with an included tree viewer:

   else if (type == IContentOutlinePage.class) {
      TreeViewer viewer = new TreeViewer(); // Also creates a default root edit part
      viewer.setRootEditPart(new DiagramRootTreeEditPart()); // Replace default root edit part
      return new DiagramOutlinePage(viewer);
   }

DiagramOutlinePage is in my modified code defined in my ProcessmodelDiagramEditor and thus overrides the default implementation in DiagramEditor.

The DiagramRootTreeEditPart modifies the default root edit part by also showing a widget representing the diagram which in turn represents a domain element in the model (in my case a Process).

The TreeViewer is populated by edit parts created by my own version of an EditPartFactory. Note that these edit parts are particular to the TreeViewer. The diagram editors contain other types of edit parts.

When a tree item is selected in the outline viewer, the widgetSelected() method of a SelectionListener is called (the SelectionListener is created and its widgetSelected method is defined in the TreeViewer.hookControl() method). The widgetSelected looks like follows:

public void widgetSelected(SelectionEvent e) {
   TreeItem[] ties = tree.getSelection();
   Object newSelection[] = new Object[ties.length];
   for (int i = 0; i < ties.length; i++)
      newSelection[i] = ties[i].getData();
   ignore = true;
   setSelection(new StructuredSelection(newSelection));
   ignore = false;
}

The call to setSelection() calls another setSelection(), that of the tree viewer's SelectionManager. The SelectionManager holds a list of selected edit parts and this list is set by the setSelection() method. The SelectionManager.setSelection() adds the selected edit parts to its selection attribute and also marks the edit parts itself as selected.

After that it (indirectly) calls the AbstractEditPartViewer.fireSelectionChanged() method which tells any class which cares to listen that the selection has changed.

The two classes that listen are a SelectionSynchronizer and the OutlineView which contains the tree viewer (the OutlineView is an Eclipse view just like the PropertySheet).

The SelectionSynchronizer.syncSelection() iterates over all edit part viewers, in my case the TreeViewer and a DiagramGraphicalViewer, and sets the selection of each to the actual selection calling each viewer's setViewerSelection() like this:

private void setViewerSelection(EditPartViewer viewer, ISelection selection) {
   ArrayList result = new ArrayList();
   Iterator iter = ((IStructuredSelection) selection).iterator();
   while (iter.hasNext()) {
      EditPart part = convert(viewer, (EditPart) iter.next());
      if (part != null)
         result.add(part);
   }
   viewer.setSelection(new StructuredSelection(result));
   if (result.size() > 0)
      viewer.reveal((EditPart) result.get(result.size() - 1));
}

A key method here is convert() that finds corresponding edit parts in different viewers:

protected EditPart convert(EditPartViewer viewer, EditPart part) {
   Object temp = viewer.getEditPartRegistry().get(part.getModel());
   EditPart newPart = null;
   if (temp != null) {
      newPart = (EditPart) temp;
   }
   return newPart;
}

Having found the corresponding edit part in the other (to be synchronized) edit part viewer the setSelection() of the viewer is called (see above). It calls SelectionManager.setSelection() which first iterates over all edit parts in the current selection and removes any that are not in the new selection. It then adds any newly selected edit parts to the current selection. Each edit part is also marked as selected or not by calling its setSelected() with the proper argument (selection status).

The setSelected() of the edit part sets the value of the selected attribute and then calls its fireSelectionChanged(). fireSelectionChanged() calls the selectedStateChanged() on the set of listeners which are all edit policies. (This only happens for edit parts in the DiagramGraphicalViewer.) The SelectionEditPolicy adds "selection handles" to the edit part as part of high-lighting the selected edit part(s). I here conveniently ignore how the other edit policies do or don't contribute to the selection process.

When the selection manager has iterated over all selected edit parts it fires its fireSelectionChanged() in a never-ending chain reaction. This call eventually ends upp in DiagramGraphicalViewer.fireSelectionChanged() which calls (asynchronously) flushSelectionEvents (when single-stepping, this method never gets called). flushSelectionEvents tells each of a number of listeners that the selection has changed. Among these listeners are yet another SelectionSynchronizer but also the DeleteElementActions that are prebuilt (the tree viewers context menu delete command is built when the context menu is shown). The SelectionSynchronizer synchronizes (back) the tree viewer with the diagram edit part viewer. This seems a bit superfluous since the diagram edit part viewer was just a bit earlier synchronized with the tree edit part viewer. No harm done I guess as long as the avalanche of fireSelectionChanged() doesn't end up in a loop. The DeleteElementActions are rebuilt to target the newly selected edit parts and the corresponding commands are enabled.

The thread that redraws the editor pane doesn't seem to get reached at all when debugging the above sequence of events. It's only when one hits F8 (Resume) when the editor pane is refreshed and one can see the actual changes. This confused me for a while as I thought I saw where the selection was changed but nothing happened.

Published by Arto Jarvinen on 06 Apr 2013

The invisible outline view

I’ve toyed with different ways to create a tree editor containing the full model (including the notation objects). One attempt has been described patch-wise in earlier posts: the attempt to integrate the generated EMF and GMF editors. The problem there is that EMF and GMF use different command stacks and different command types.

I haven’t realized it before but there is actually a tree outline view available for diagrams in the generated GMF diagram editor. The reason I have missed it is that the icons representing the model elements are null and the names of the model elements are “”! This gives an outline view of limited value. It actually works kind-of though if you manage to find the invisible placeholders for the invisible icons; the selection in the outline view is synchronized with the diagram.

The icon for an item in the outline view is fetched by IconService.getInstance().getIcon(), the name by EMFCoreUtil.getName(). Both are called from TreeEditPart which is the edit part for the items in the outline tree. Both calls obviously fail to find anything useful. It looks like the getName() method is looking for an attribute “name” (with a lower-case “n“). I tried to change my “Name“s to “name“s but somewhere in the diagram generation process the upper-case “N” jumped right back in again so couldn’t easily test whether getName() was case-sensitive.

Anyway, the outline view should be possible to tweak along the lines of what’s done in the Shapes example. There the outline view has both icons and text and a context menu to boot. Exactly what I need.

Published by Arto Jarvinen on 01 Apr 2013

Editing domains

The documentation of org.eclipse.emf.edit.domain.EditingDomain says:

An editing domain manages a self-contained set of interrelated EMF models and the Commands that modify them. The models are maintained in the form of a ResourceSet. Commands that modify the model are typically created through the domain and are executed using the CommandStack.

This is all fine and well. The problem is that in the combined EMF-GMF editor there is a plethora of editing domains and command stacks. To add to the confusion they sometimes have similar class names such as DiagramEditDomain and DiagramEditingDomain. Before getting down to the problem of creating “universal commands” over the EMF and GMF editors, I believe I must understand what editing domains and command stacks that are actually used. (An alternative would be to scrap the generated EMF editor entirely but that is still a plan B – it’s always nice to start with something that works, even if you end up tweaking it to something completely different at the end. And I don’t quite feel up to the task yet.)

GMF

The constructor of the diagram editor (a ProcessmodelDiagramEditor in my case) initiates a sequence of calls that ends up calling org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor.createDiagramEditDomain(). This method creates a DiagramEditDomain. A reference to the editing domain is stored in the field editDomain in the superclass GraphicalEditor.

The created editing domain contains a command stack of type org.eclipse.gef.commands.CommandStack. It is stored in the field commandStack in the superclass EditDomain. So far nothing useful at all seems to have happened; nothing of the above is ever going to be used.

During the initialization of the ProcessmodelDiagramEditor, the method doSetInput() is called. Its purpose is to connect the document provider to an input (file). Hunting for editing domains, the following looks suspicious:

...
   if (!(input instanceof MEditingDomainElement)) {
      input = ((IDiagramDocumentProvider)provider).createInputWithEditingDomain(input, createEditingDomain());
   }
   provider.connect(input);
   ...

Here you might think a new editing domain is created but whatever is returned from createEditingDomain() is actually totally ignored in:

public IEditorInput createInputWithEditingDomain(IEditorInput editorInput, TransactionalEditingDomain domain) {
   return editorInput;
}

This is as close to a Koan as one can get in Java I guess.

Still within the doSetInput() a document holding the resources of the editor is created and an editing domain to be associated with the document is created in ProcessModel.diagram.part.ProcessmodelDocumentProvider.createEditingDomain(). To keep all resources in the same editing domain, I attempt to give all editors the same editing domain stored statically in TransactionalEditingDomain:

private TransactionalEditingDomain createEditingDomain() {
   TransactionalEditingDomain editingDomain = TransactionalEditingDomain.Registry.INSTANCE
      .getEditingDomain("com.ostrogothia.processmodel.diagram.EditingDomain");

Each time the editing domain is needed, an attempt is first made to get it from the TransactionalEditingDomain based on a unique id (com.ostrogothia.processmodel.diagram.EditingDomain above). If that fails, then a pristine instance of an editing domain is created in org.eclipse.emf.transaction.impl.EditingDomainManager.createEditingDomain() which calls org.eclipse.gmf.runtime.diagram.core.DiagramEditingDomainFactory.createEditingDomain():

public TransactionalEditingDomain createEditingDomain() {
   TransactionalEditingDomain result = createEditingDomain(OperationHistoryFactory.getOperationHistory());
   return result;
}

The editing domain factory to be used above is declared as an extension in plugin.xml of the ...diagram generated package.

<extension point="org.eclipse.emf.transaction.editingDomains">
   <editingDomain
      factory="org.eclipse.gmf.runtime.diagram.core.DiagramEditingDomainFactory"
      id="com.ostrogothia.processmodel.diagram.EditingDomain"/>
</extension>

The extension point is resolved in org.eclipse.emf.transaction.impl.EditingDomainManager.createEditingDomain().

The editing domain above gets a command stack of the type WorkspaceCommandStackImpl which in turn holds the operation history sent as an argument to the createEditingDomain() (see above). Using OperationHistoryFactory.getOperationHistory() to get the operation history ensures that the same instance is got each time. This command stack (that can only handle EMF commands) is not used by the GMF editor but is used by the EMF editor (see below).

The GMF editor instead uses a command stack of type org.eclipse.gmf.runtime.diagram.ui.parts.DiagramCommandStack. This stack replaces the original command stack of the editor’s DiagramEditDomain in ProcessmodelDiagramEditor(DiagramEditor).configureDiagramEditDomain() which is also called from doSetInput(). There is one edit domain and thus one command stack per editor part (even though they share the same operation history).

When the command stack has been replaced, the undo context of the command stack is set to an EditingDomainUndoContext which refers to the statically registered editing domain. The operation history of the new command stack is set to an instance of org.eclipse.core.commands.operations.DefaultOperationHistory. The operation history is fetched from an org.eclipse.gmf.runtime.common.ui.action.ActionManager which is instantiated during the construction of the ProcessmodelDiagramEditor. Also this operation history is obtained by calling OperationHistoryFactory.getOperationHistory() ensuring that the same operation history instance is obtained each time.

A summary so far:

  • Each graphical editor has its own editing domain which in turn contain their unique command stacks. These are the command stacks used for executing editor commands.
  • The graphical editors are connected to their separate documents that in turn share the same editing domain, in my case the statically created one. The command stack of this editing domain is not used but this ensures that all resources can be accessed through the same editing domain (the GMF default is that each editor has its own editing domain which only gives access the the resources edited in that editor).
  • The graphical editors share the same document provider that manages several documents and connects them to their files.
  • All command stacks (EMF and GMF) share the same operation history that executed commands adhering to the interface IUndoableOperation. Both the EMF and the GMF commands can be tweaked into implementing this interface (see an earlier post).

I attempted to draw a class diagram illustrating the above but it became so cluttered that I decided not to include it here.

EMF

The constructor of the ProcessModelEditor calls initializeEditingDomain which in my modified editor fetches the editing domain in the same way as the document provider did above:

private TransactionalEditingDomain createEditingDomain() {
   TransactionalEditingDomain editingDomain = TransactionalEditingDomain.Registry.INSTANCE
      .getEditingDomain("com.ostrogothia.processmodel.diagram.EditingDomain");

Contrary to the GMF editor, the EMF editor is actually using the command stack of the above editing domain for executing commands. Unfortunately the command stack is of type WorkspaceCommandStackImpl which is different from the what is used in the GMF editor and has a different undo context. Its undo context cannot be set either which makes it impossible to undo GMF commands while the EMF editor has focus. Not even the Undo command will in fact show since its activation code can’t find any undoable commands (commands with the right undo context) in the operation history.

Still a lot of talk and very little workshop as we say in Sweden.

Links

[1] Integrating EMF and GMF Generated Editors.

Published by Arto Jarvinen on 26 Mar 2013

Closer to a unified EMF – GMF command handling

An operation history class manages a list of executed operations (commands) so that these may later be undone (see an earlier post). The same instance of an org.eclipse.core.commands.operations.DefaultOperationHistory is used in both the EMF editor and the GMF editor. This is because the operation history is created with and associated to the editing domain which in this modified editor is the same for both the EMF and the GMF editors.

A common operation history is a good and necessary foundation for being able to undo commands independent of which editor that happens to be active. The undoable commands are extracted from the operation history using the undo context label that labels the current state of the editor; only certain commands in the operation history are valid in a certain state.

Since both editors are using the same operation history, they need to be running commands that share a common superclass.

The EMF editor is executing CompoundCommand’s that inherit like this:

java.lang.Object
  extended byorg.eclipse.emf.common.command.AbstractCommand
      extended byorg.eclipse.emf.common.command.CompoundCommand

Before these are passed to the operation history for execution they are wrapped into a EMFCommandOperation which inherits like this:

java.lang.Object
  extended by org.eclipse.core.commands.operations.AbstractOperation
      extended by org.eclipse.emf.workspace.AbstractEMFOperation
          extended by org.eclipse.emf.workspace.EMFCommandOperation

The GMF editor is executing CompositeTransactionalCommand‘s that inherit like this:

java.lang.Object
  extended byorg.eclipse.core.commands.operations.AbstractOperation
      extended byorg.eclipse.emf.workspace.AbstractEMFOperation
          extended byorg.eclipse.emf.workspace.CompositeEMFOperation
              extended byorg.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand

As can be seen from the above, both inherit from AbstractEMFOperation which in turn implements the org.eclipse.core.commands.operations.IUndoableOperation interface. So as long as the command exhibits that interface they can use the same operation history.

This was in conclusion a rather unnecessary post as it explains why something that works works. But sometimes it is useful the check so that one has understood a piece of code by trying to understand the nuts and bolts of it.

It was already obvious from the earlier post that the different undo contexts came from the fact that the two types of editors (EMF and GMF) use different command stacks and that the commands are therefore labeled with different undo contexts. A straightforward way of giving all commands the same undo context would therefore be to use the same command stack class for both editors. This in turn would require that the command types were also unified. This is not the case today:

  • EMF: The org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl executes commands of the type org.eclipse.emf.common.command.Command.
  • GMF: The org.eclipse.gmf.runtime.diagram.ui.parts.DiagramCommandStack executes commands of type org.eclipse.gef.commands.Command.

If we thus wish to use the same command stack, say DiagramCommandStack, for both editors, then the EMF org.eclipse.emf.common.command.Commands must be wrapped into GMF org.eclipse.gef.commands.Commands. I’ll try that.

Published by Arto Jarvinen on 17 Mar 2013

The undo context

The undo context is used to label commands in the operation history to later determine whether they are eligible for undo in a particular context. Afaik a context can be pretty much anything that represents a certain state in an Eclipse editor.

The undo context is a class without much content except what is needed to identify a unique instance of it. It implements IUndoContext. The only interesting thing about it is thus its identity that can be compared with the identity of other undo contexts with various methods depending on the exact type of the undo context.

EMF commands are labeled with several undo contexts. Two are immediately relevant here:

  1. A context of the type EditingDomainUndoContext which is equal to another EditingDomainUndoContext if they both refer to the same editing domain. This undo context matches the undoContext in the GMF UndoActionHandler (through its superclass OperationHistoryActionHandler) which means that EMF commands can be undone in a GMF editor.
  2. A context of the type WorkspaceCommandStackImpl$1 which is equal to another WorkspaceCommandStackImpl$1 if the instances are the same object. This undo context matches the defaultContext in the EMF undo operation in WorkspaceCommandStackImpl which means that EMF commands can be undone in an EMF editor (wouldn’t be much of an undo otherwise I guess).

GMF commands are labeled with the same undo contexts as the EMF commands are except for the WorkspaceCommandStackImpl$1 one. This means that they do not match the EMF undo context and can thus not be undone in EMF.

I thus need to find a way to add yet another undo context into GMF commands or change the defaultContext in org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl to something more appropriate if I want to undo GMF commands in the EMF editor. Whatever is easiest.

Published by Arto Jarvinen on 17 Mar 2013

Integrating EMF and GMF – the delete from model command

This turned out to be an extremely long post. I (again) blame the complexity of the EMF / GFM framework. Maybe these posts should later be moved to some kind of manual section of this blog instead but for the time being they will end up here on the “trunk”.

I guess that what I’m going to discuss in this post has already been discussed many times in the GMF forum and other places. But I’m a stubborn Finn and I like to find out things by myself. Perhaps I can add just a tiny bit of understanding to the world by writing down my slant of it.

So, as those before me, I’m trying to make the generated EMF and GMF editors to cooperate in a reasonable and consistent way. Since both are already generated I’m betting on that the changes are small compared to writing an editor from scratch. The behavior I want is:

  • No synchronization shall be done via the file system; the whole model (domain model and notation model) shall be kept consistent at all times and should therefore be loaded into memory at all times.
  • When a domain object is deleted in the EMF editor then the corresponding notation objects (views) shall be deleted (whether they are visible in an open editor or not).
  • When a domain object is deleted in an GMF editor then the corresponding noation objects shall be deleted, just like in the EMF case above.
  • When a notation object is deleted in the EMF editor then the changes shall be visible in any open GMF editor immediately.
  • The undo operation shall have the same effect regardless of which editor that is open when it is executed..

Since it is the editing domain that manages the resources, it seems reasonable to associate one and the same editing domain for all editors so as to only get one set of loaded resources. These resources must furthermore be loaded at all times. The resource set can be obtained through the method getResourceSet.

The rest of this post describes how the Delete from Model action and its Undo is implemented in an EMF editor and a GMF editor respectively. In EMF this is understood to mean the plain Delete action available from the context menu. In GMF this is understood to mean the Delete from Model action available from the context menu.

EMF Delete from Model

In an EMF editor, the delete action is created in the ProcessModel.presentation.ProcessModelActionBarContributor and is then in the superclass of ProcessModelActionBarContributor associated with the context menu. like this:

protected DeleteAction createDeleteAction() {
   DeleteAction deleteAction = new MyDeleteAction(removeAllReferencesOnDelete());
   return deleteAction;
}

MyDeleteAction in my case inherits from org.eclipse.emf.edit.ui.action.DeleteAction and creates a MyDeleteCommand so:

public Command createCommand(Collection selection) {
   return removeAllReferences ? MyDeleteCommand.create(domain, selection) :
      RemoveCommand.create(domain, selection);
}

The Command here is of the type org.eclipse.emf.common.command.Command which is an interface but interestingly enough it does not inherit from org.eclipse.core.resources.ICommand.

The EMF command is then executed as follows in MyDeleteAction -> DeleteAction -> org.eclipse.emf.edit.ui.action.CommandActionHandler:

public void run() {
   domain.getCommandStack().execute(command);
}

The domain is of type org.eclipse.gmf.runtime.diagram.core.DiagramEditingDomainFactory$DiagramEditingDomain.

The command stack is of type org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl. It executes commands of the type org.eclipse.emf.common.command.Command which is exactly what is created in org.eclipse.emf.edit.ui.action.DeleteAction. So far so good.

A couple of delegations later org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl.doExecute() is called.

First an IUndoContext is added to the operation for later use in a potential Undo action.

Since the WorkspaceCommandStackImpl is as lazy as so many other EMF / GMF classes it then delegates the execution of the command to a org.eclipse.core.commands.operations.DefaultOperationHistory that according to the docs

…should be used by classes that access the undo or redo history and add undoable operations to the history.

Here the Command is morfed into an org.eclipse.emf.workspace.EMFCommandOperation.EMFCommandOperation which implements the IUndoableOperation interface that the command stack can handle:

EMFCommandOperation oper = new EMFCommandOperation(getDomain(), command, options);

The operation history executes each of the compound commands in turn in the execute() method (with some checks and stuff removed):

public IStatus execute(IUndoableOperation operation,
   IProgressMonitor monitor, IAdaptable info)
   throws ExecutionException {
   ...
   try {

      status = operation.execute(monitor, info);
      ...
      // if successful, the notify listeners are notified and the operation is
      // added to the history
 
      if (status.isOK()) {
         notifyDone(operation);
         add(operation);
         ---
   return status;
}

Here the command is executed by calling the execute() method of the command (which all of a sudden is denoted operation). The command is also added to the operation history for a later potential undo.

When done, the menus are updated (the Undo selection is activated) in org.eclipse.emf.edit.ui.action.EditingDomainActionBarContributor.update(). It calls org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl.canUndo() which in turn calls org.eclipse.core.commands.operations.DefaultOperationHistory.canUndo() which looks like this:

public boolean canUndo(IUndoContext context) {
   IUndoableOperation operation = getUndoOperation(context);
   return (operation != null && operation.canUndo());
}

For an operation to be a valid “undo operation” its context must be (object) identical to the context passed to the canUndo() method.

EMF Undo Delete from Model

The Undo action is implemented in the org.eclipse.emf.edit.ui.action.UndoAction like this:

public void run()
{
   domain.getCommandStack().undo();
}

The command stack in turn does the following:

public void undo() {
   try {
      getOperationHistory().undo(getDefaultUndoContext(), new NullProgressMonitor(), null);
      ...

The operation history is of type org.eclipse.core.commands.operations.DefaultOperationHistory.

The org.eclipse.core.commands.operations.DefaultOperationHistory.undo() method first finds the undoable org.eclipse.emf.workspace.EMFCommandOperation from the command history by looking for operations in the history that have the context context like this:

public IStatus undo(IUndoContext context, IProgressMonitor monitor,
   IAdaptable info) throws ExecutionException {
   Assert.isNotNull(context);
   IUndoableOperation operation = getUndoOperation(context);
   ...
   return doUndo(monitor, info, operation);
}

It the doUndo then calls undo() of the operation to be undone:

private IStatus doUndo(IProgressMonitor monitor, IAdaptable info,
   IUndoableOperation operation) throws ExecutionException {
   IStatus status = getUndoApproval(operation, info);
   if (status.isOK()) {
      notifyAboutToUndo(operation);
      try {
         status = operation.undo(monitor, info);
         ...

Here finally the command found from the operation history is “run backwards” by calling undo() on all the subcommands in reverse order.

GMF Delete from Model

All context menu commands are created initially when the editor is opened. When the selection of notation objects change, the commands are refreshed by a call to ProcessModel.diagram.part.DeleteElementAction.selectionChanged().

After a few calls we end up in getCommand of the same class. For more on this customized class, see this post. It returns a CompositeTransactionalCommand wrapped into an ICommandProxy (which inherits from org.eclipse.gef.commands.Command). The ICommandProxy can then be executed in DeleteElementAction as follows:

protected final void execute(Command command, IProgressMonitor progressMonitor) {
   if (command == null || !command.canExecute())
      return;
   if (getDiagramCommandStack() != null)
      getDiagramCommandStack().execute(command, progressMonitor);
}

The command stack of type org.eclipse.gmf.runtime.diagram.ui.parts.DiagramCommandStack is obtained through org.eclipse.gmf.runtime.diagram.ui.actions.DiagramAction.getDiagramCommandStack():

protected DiagramCommandStack getDiagramCommandStack() {
   Object stack = getWorkbenchPart().getAdapter(CommandStack.class);
   return (stack instanceof DiagramCommandStack) ? (DiagramCommandStack) stack: null;
}

The DiagramCommandStack.execute() looks like this:

public void execute(Command command, IProgressMonitor progressMonitor) {
   if (command == null || !command.canExecute()) return;
   execute(getICommand(command), progressMonitor);
}

Note the conversion of an org.eclipse.gef.commands.Command to an ICommand. Then there is another execute() that actually does something:

protected void execute(ICommand command, IProgressMonitor progressMonitor) {
   if (progressMonitor != null) {
   try {
      command.addContext(getUndoContext());
      getOperationHistory().execute(command, progressMonitor, null);
      ...
}

First an IUndoContext that contains the DiagramEditingDomain object is added to the command. We’ll later see how this is used to filter out the operation to undo, if the Undo command is issued.

The DiagramCommandStack then delegates the execution of the command to a org.eclipse.core.commands.operations.DefaultOperationHistory which executes the subcommands one after another. This is possible since org.eclipse.gmf.runtime.common.core.command.ICommand inherits from IUndoableOperation. For a glimpse of the operation history execute() code, see above.

GMF Undo Delete from Model

The Undo action is implemented in the org.eclipse.gmf.runtime.common.ui.action.actions.global.GlobalUndoAction.run() which in turn calls doRun() in the same class. doRun() then delegates to a org.eclipse.ui.operations.UndoActionHandler like this:

protected void doRun(IProgressMonitor progressMonitor) {
   if (delegate != null) {
   Object key = new Object();
   if (GlobalUndoRedoLock.INSTANCE.acquire(key)) {
   try {
      delegate.run();
      ...

The org.eclipse.ui.operations.UndoActionHandler.run() spawns off a new runnable which basically calls org.eclipse.ui.operations.UndoActionHandler.runCommand() which looks like this:

IStatus runCommand(IProgressMonitor pm) throws ExecutionException  {
   return getHistory().undo(getUndoContext(), pm, this);
}

The operation history is of type org.eclipse.core.commands.operations.DefaultOperationHistory.

The org.eclipse.core.commands.operations.DefaultOperationHistory.undo() method first finds the undoable org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand from the command history by looking for operations in the history that have the context context like this:

public IStatus undo(IUndoContext context, IProgressMonitor monitor,
   IAdaptable info) throws ExecutionException {
   Assert.isNotNull(context);
   IUndoableOperation operation = getUndoOperation(context);
   ...
   return doUndo(monitor, info, operation);
}

In doUndo it then calls undo() of the operation to be undone:

private IStatus doUndo(IProgressMonitor monitor, IAdaptable info,
   IUndoableOperation operation) throws ExecutionException {
   IStatus status = getUndoApproval(operation, info);
   if (status.isOK()) {
      notifyAboutToUndo(operation);
      try {
         status = operation.undo(monitor, info);
         ...

Here finally the command found from the operation history is “run backwards” by calling undo() on all the subcommands in reverse order.

Published by Arto Jarvinen on 16 Mar 2013

Trust, transparency and Toyota

A recent article in The Economist [1] ascribed some of the economic and social success of the Nordic countries to a high level of trust. In the period of large-scale emigration of Swedes to America, they came to be known as “dumb Swedes” in the new country because their high level of trust in people. Today the descendants of these dumb Swedes still have higher that average trust in their fellow citizens and tend to live in rather well-run states such as Minnesota.

It is possible to have relatively high taxes (such as in Minnesota or Sweden) if people trust that taxes are used for good purposes. Trust in the Nordic countries emanate from many sources but transparency is a major one. It is not easy to embezzle public funds when all records are public and subject to the scrutiny of the press and of curious citizens.

I claim that the same goes for corporations. With a high level of trust between employees, departments, country organizations etc the transaction costs can be low. Transaction costs in a corporate setting are typically different types of follow-up and reporting procedures, elaborate internal pricing schemes, and in more extreme cases, turf wars.

Toyota
A car and a process you can trust.

A typical scenario is that when a particular problem area catches the eye of a particular manager (or a group of managers) who doesn’t entirely trust the organization’s ability to handle the problem then they feel the natural, and in this situation perfectly responsible, need to alleviate their uncertainty by starting to make inquiries. If the situation gets more serious the managers start requiring extra (ad-hoc) reporting on the progress of the resolution of the problem or feel that they need to put together a “tiger team” to expedite the resolution process.

Despite superficial similarities, the above behavior is the antithesis of the Toyota Production System where managers likewise come running when there is a problem. But unlike in the scene described above, they don’t come running to expedite the process, they come running to help solving the root cause of the disturbance.

The extra reporting, the extra phone calls, the extra emails etc are all caused by the lack of trust in the process and add little value to the actual problem resolution process. They in fact make the process less efficient. A “tiger team” furthermore masks any deficiencies in the regular process by effectively bypassing it, preventing the organization from addressing the root cause of the lack of trust.

The explicit goal of building trust has not afaik been on the top of any process improvement models. Many models do result in higher trust when successfully implemented but I believe more explicit actions can be taken to improve trust faster. Some such actions could be:

  • Make all processes extremely transparent; make it easy for anybody to see the backlogs and progress of every department. This facilitates the Genchi Genbutsu, “go and see”, of the Toyota Production System, an attitude that helps managers to stay informed about what’s going on in the organization on a continuous basis.
  • When the organization is more mature, make metrics about performance visible for everyone.
  • Make decisions and their rationales visible.
  • When communicating about your area of responsibilities, make sure that you are well read. When uncertain, state this and the reason for the uncertainty.
  • State clearly who’s responsible for what. If nobody steps forward and clearly takes charge of an issue, then uncertainty thrives.

Last but not least: do a good job (and make it known to others that you did a good job)!

Links

[1] The secret of their success.

Published by Arto Jarvinen on 06 Jan 2013

Delete from model revisited

Trying to share a few more nuggets of insight as my understanding of GMF increases. I needed to go back to edit this post a bit since I missed to describe the part of the command that deletes the notation object even though I claimed to understand that the command is put together by all edit policies.

The Delete from Model command thus comes from two edit policies as now more correctly described in the blog post referred to above. Since I allow multiple notation objects for each domain object, I need to potentially delete more notation objects than domain objects when I wish to delete a domain object from the model.

I modified the getCommand method in DeleteElementAction as shown below. The modified code first goes through all open editors and creates delete command for all notation objects and domain objects given by the initially for deletion selected notation objects. It then iterates over all unopened resources and does the same. This is somewhat of a brute force approach. An alternative could be to fix a diagram when it is opened the next time. It seems a bit ugly though to have latent inconsistencies in the persisted model.

The code for removing views is now removed from the RoleItemSemanticEditPolicy.

/**
 * @NOT generated
 */
protected Command getCommand(Request request) {
   List operationSet = getOperationSet(); // The selected notation objects
   if (operationSet.isEmpty()) {
      return UnexecutableCommand.INSTANCE;
   }
      
   CompositeTransactionalCommand command = new CompositeTransactionalCommand(
            getEditingDomain(), getCommandLabel());

   // In this editor several notation objects may refer to the same domain object.
   // This means that when deleting something from the model,  all such notation
   // objects must be deleted. The code below finds all such notation objects
   // in all open diagrams by looping through all edit parts and comparing the
   // domain objects related to the notation objects related to the selected edit
   // parts with those of each looped over edit part (got it?). This will be an
   // ugly loop...
            
   Iterator editParts = operationSet.iterator();

   while (editParts.hasNext()) { // For each selected edit part
      EditPart editPart = (EditPart) editParts.next();
      View viewToDestroy = (View) editPart.getModel();
      EObject elementToDestroy = viewToDestroy.getElement();

      IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
      if (windows[0] != null) {
         IWorkbenchPage[] pages = windows[0].getPages(); // Betting on only one window
         if (pages != null) {
            for (int page = 0; page < pages.length; page++) {
               IEditorReference[] editors = pages[page].getEditorReferences();
               for (int editor = 0; editor < editors.length; editor++) {
                  IEditorPart editorPart = editors[editor].getEditor(true);
                  if (editorPart != null) {
                     if (editorPart instanceof GraphicalEditor) {
                        GraphicalEditor graphicalEditor = (GraphicalEditor) editorPart;
                        // System.out.println("   >>>Editor input: " + editorPart.getEditorInput().getName());
                        RootEditPart rootEditPart = (RootEditPart) graphicalEditor.getAdapter(EditPart.class);
                        EditPart topEditPart = rootEditPart.getContents();
                        if (topEditPart != null) {
                           List childrenEditParts = topEditPart.getChildren();
                           Iterator children = childrenEditParts.iterator();
                           while (children.hasNext()) {
                              EditPart e = (EditPart) children.next();
                              View v = (View) e.getModel();
                              EObject o = v.getElement();
                              if (o == elementToDestroy) {
                                 // The edit part creates commands both for deleting the
                                 // notation object and the domain object. The domain
                                 // object will be deleted many times over but the delete
                                 // command seems to handle that gracefully.
                                 Command curCommand = e.getCommand(request);
                                 if (curCommand != null) {
                                    command.compose(new CommandProxy(curCommand));
                                 }
                              }
                           }
                        }
                     }
                  }
               }
            }
         }
      }
   }
      
   // Do the same with all models that aren't loaded. Maybe this must be changed later to an
   // on-demand editing as the corresponding editor is loaded. But it is a bit unsatisfactory to
   // have latent inconsistencies among the persisted resources.

   IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
   IProject[] projects = workspaceRoot.getProjects();
   IResource[] members;

   for (int i = 0; i < projects.length; i++) {
      try {
         members = projects[i].members(0);
         for (int j = 0; j < members.length; j++) {
            int memberType = members[j].getType();
            if (memberType == IResource.FILE) {
               IFile file = (IFile) members[j];
               String ext = file.getFileExtension();
               if (ext.equals("processmodel_diagram")) { // At this point we only read diagram files
                  IFileEditorInput input = new FileEditorInput(file);
                  ProcessmodelDocumentProvider documentProvider = ProcessModel.diagram.part.ProcessmodelDiagramEditorPlugin
                        .getInstance().getDocumentProvider();
                  ResourceSetInfo resourceSetInfo = documentProvider.getResourceSetInfo(input);
                  if (resourceSetInfo == null) { // Not loaded
                     IDiagramDocument document = (IDiagramDocument) documentProvider.createEmptyDocument();
                     documentProvider.setDocumentContent(document, input);
                     Diagram diagram = document.getDiagram();
                     List childrenViews = diagram.getChildren();
                     Iterator children = childrenViews.iterator();
      
                     Iterator eParts = operationSet.iterator();
                     while (eParts.hasNext()) {
                        EditPart ePart = (EditPart) eParts.next();
                        View viewToDestroy = (View) ePart.getModel();
                        EObject elementToDestroy = viewToDestroy.getElement();
                        while (children.hasNext()) {
                           View v = (View) children.next();
                           EObject e = v.getElement();
                           if (e == elementToDestroy) {
                              DeleteCommand cmd = new DeleteCommand(getEditingDomain(), v);
                              command.compose(cmd);
                           }
                        }
                     }
                  }
               }
            }
         }
      } catch (CoreException e) {
         e.printStackTrace();
      }
      }

   if (command.isEmpty()) {
      return UnexecutableCommand.INSTANCE;
   }
   command.compose(new CommandProxy(traceCommand));
   return new ICommandProxy(command);
}

Published by Arto Jarvinen on 26 Dec 2012

Adding diagram objects

It’s Christmas, a few days off, and I’ve got the flu so skiing and riding, some of my favorite wastes of time don’t seem all that attractive; I’m panting just from negotiating the stairs in my house. What better time to return to the GMF project?

I wish to add EMF objects representing diagrams into the EMF tree editor, much in the same way as is done in many UML editors. The corresponding diagrams shall then be possible to edit with GMF editors, e.g. by double-clicking on the diagram object in the EMF editor. I have therefore added a Class Diagram metaclass to my metamodel (see below). This caused some agonizing as it is questionable whether the diagram is a proper metaclass but I have decided to ignore that issue for now.

My hypothesis is that as I create the diagram objects I should also create the diagram resource and do any other necessary initilizations. I should be able to copy a lot of code from the Initialize ??? diagram file menu action. This post explores where in the generated code such additions can be made.

The menu for creating new EMF child objects is created in ProcessModelActionBarContributor:

protected Collection generateCreateChildActions(Collection descriptors, ISelection selection) {
   Collection actions = new ArrayList();
   if (descriptors != null) {
      for (Object descriptor : descriptors) {
         actions.add(new CreateChildAction(activeEditorPart, selection, descriptor));
      }
   }
   return actions;
}

A few calls later we create the command that implements the action like this (actually, commands for all types of child insertions are created on a “just in case basis”):

protected Command createActionCommand(EditingDomain editingDomain, Collection collection)
{
   if (collection.size() == 1)
   {
      Object owner = collection.iterator().next();
      return CreateChildCommand.create(editingDomain, owner, descriptor, collection);
   }
   return UnexecutableCommand.INSTANCE;
}

The above method calls the static method create in class org.eclipse.emf.edit.command.CreateChildCommand which in turn calls the createCommand function of the editing domain like this:

public static Command create(EditingDomain domain, Object owner, Object newChildDescriptor, Collection selection)
{
   return domain.createCommand(CreateChildCommand.class,
   new CommandParameter(owner, null, newChildDescriptor, new ArrayList<Object>(selection)));
}

The createCommand method of the standard EMF editing domain of class AdapterFactoryEditingDomain delegates to the IEditingDomainItemProvider of the owner, i.e. the object to which a child is to be added:

   ...
   IEditingDomainItemProvider editingDomainItemProvider =
      (IEditingDomainItemProvider) adapterFactory.adapt(owner, IEditingDomainItemProvider.class);

   return editingDomainItemProvider != null ?
      editingDomainItemProvider.createCommand(owner, this, commandClass, commandParameter) :
      new ItemProviderAdapter(null).createCommand(owner, this, commandClass, commandParameter);
   ...

In my case I wish to add a new Class Diagram object as a child to a Process object (see the metamode below). In this case the createCommand method of ProcessItemProvider will be called.

Metamodel
The experimental metamodel.

To insert an alternative CreateMyChildCommand that not only adds a child but also does some other stuff, one can add all variants of the createCreateChildCommand in the ProcessItemProvider to override the corresponding methods in the superclass ItemProviderAdapter, in particular this one:

protected Command createCreateChildCommand(EditingDomain domain,
   EObject owner, EReference feature, EObject value, int index, Collection collection) {
   return new CreateMyChildCommand(domain, owner, feature, value, index, collection, this);
}

The CreateMyChildCommand‘s execute method can now be modified to do whatever.

There’s a bit of uglyness in the above: we call the create method of the original CreateChildCommand but in the end end up with the alternative CreateMyChildCommand. I tried chaining commands but didn’t get that to work immediately. Have to think of ways to make this a bit prettier…

Published by Arto Jarvinen on 04 Dec 2012

Product, not project – part 2

Something caught my eye yesterday when I helped my son to get started with Code::Blocks, a light-weight integrated software development environment (IDE): in all IDEs that I’ve worked with lately (Eclipse, Visual Studio and Code::Blocks) the collection of source code and other files is collective called “project”. This may seem like an unimportant little observation but again I believe that using the right term is important for people’s mental models of what’s going on. A “project” is something temporary while a “product” would be something rather more persistent. I would have suggested the “product” word here instead. See also my earlier post on this topic.

Next »