Providing Context Buttons

Context buttons allow adding actions as small, automatically appearing icons for each pictogram element in the diagram.

They are shown along the borders of a pictogram element when the mouse is positioned on that pictogram element. They are hidden again when the mouse is positioned outside the area built by the pictogram element and the context buttons.

Context buttons can provide the same functionality as a context menu, but in a nicer and quicker way: the context buttons are shown immediately. Another advantage of context buttons over context menus is, that each context button can have several drag and drop features, which get activated when the user drags from a context button and drops onto the canvas or another object.

Enhancing the Tool Behavior Provider

Context buttons are defined in the tool behavior provider.

If you didn’t do so already you must first create a tool behavior provider and add it to the diagram type provider as described here.

There is one method of the tool behavior provider to overwrite:

The method getContextButtonPad has to return the context buttons for the given context (which implement IContextButtonEntry).

There are different groups of context buttons:

The following restrictions are defined by usability engineers of SAP AG (but currently not checked technically): there can be 0-3 generic context buttons, 0-5 domain specific context buttons and 0-1 collapse context button.

The functionality of context buttons is always provided by features.

Each context button can have one click-feature, which is executed when clicking the context-button, and/or several drag & drop features, which are executed when the user starts dragging a connection from the context button. If several drag & drop features are available, a context-menu will be offered to the user when he drops the connection, and he can choose the feature to execute.

In this example we want to create one context button, which offers all available create connection features as drag & drop features, but has no click-feature. Additionally, we implement a collapse context button, which will pop up a message, that it has not a final implementation.

 

Figure: A context button, which the user can click or start drag & drop from it

 

 

Figure: The user started dragging from the context button

 

Figure: A context button, which the user can click

 

You can see the complete implementation of the context and collapse buttons here:

 

@Override
public IContextButtonPadData getContextButtonPad(
                                   IPictogramElementContext context) {
    IContextButtonPadData data = super.getContextButtonPad(context);
    PictogramElement pe = context.getPictogramElement();
 
    // 1. set the generic context buttons
    // note, that we do not add 'remove' (just as an example)
    setGenericContextButtons(data, pe, CONTEXT_BUTTON_DELETE |
                                               CONTEXT_BUTTON_UPDATE);
       
    // 2. set the collapse button
    // simply use a dummy custom feature (senseless example)

    CustomContext cc = new CustomContext(new PictogramElement[] { pe });
    ICustomFeature[] cf = getFeatureProvider().getCustomFeatures(cc);
    for (int i = 0; i < cf.length; i++) {
        ICustomFeature iCustomFeature = cf[i];
        if (iCustomFeature instanceof TutorialCollapseDummyFeature) {
            IContextButtonEntry collapseButton = ContextEntryHelper.
               createCollapseContextButton(true, iCustomFeature, cc);
            data.setCollapseContextButton(collapseButton);
            break;
           }
    }
        
    // 3. add one domain specific context-button, which offers all
    // available connection-features as drag&drop features...
 
    // 3.a. create new CreateConnectionContext

    CreateConnectionContext ccc = new CreateConnectionContext();
    ccc.setSourcePictogramElement(pe);
    Anchor anchor = null;
    if (pe instanceof Anchor) {
        anchor = (Anchor) pe;
    } else if (pe instanceof AnchorContainer) {
        // assume, that our shapes always have chopbox anchors
        anchor = Graphiti.getPeService()
                 .getChopboxAnchor((AnchorContainer) pe);
    }
    ccc.setSourceAnchor(anchor);
       
    // 3.b. create context button and add all applicable features
    ContextButtonEntry button = new ContextButtonEntry(null, context);
    button.setText("Create connection");
    button.setIconId(MyTutorialImageProvider.IMG_EREFERENCE);
    ICreateConnectionFeature[] features =
        getFeatureProvider().getCreateConnectionFeatures();
    for (ICreateConnectionFeature feature : features) {
        if (feature.isAvailable(ccc) && feature.canStartConnection(ccc))
            button.addDragAndDropFeature(feature);
    }
 
    // 3.c. add context button, if it contains at least one feature
    if (button.getDragAndDropFeatures().size() > 0) {
       data.getDomainSpecificContextButtons().add(button);
    }
   
    return data;
}

 

 

The implementation of MyTutorialImageProvider can be found here. The implementation of the TutorialCollapseDummyFeature can be found at the end of this page.

The context button entries contain information about icon, display text and tooltip description.

The positioning of the context buttons can be influenced by changing the rectangle around which the context buttons are placed (see getPadLocation). By default the selection area is used (see selection behavior) if defined, or otherwise the bounds of the pictogram elements main graphics algorithm are used.

Test: Create a Connection by Drag & Drop from a Context Button

Note that previously we implemented one create connection feature which allows creating an association between two EClasses.

Now start the editor and test this new context button:

  1. Create or open a diagram and create two EClasses in the diagram.
  2. Position the mouse on top of the first EClass and the context button should appear in the south-east of the shape.
  3. Start dragging with the mouse from the context-button.
  4. Drop the connection onto the second EClass, which will result in one of the following possibilities:
    1. If only one create connection feature for the EClass exists, then the association will be created immediately.
    2. If several create connection features for the EClass exist, then a context-menu will be shown to the user, where he can choose the feature to execute. Tip: if you have only one create connection feature you can try this behaviour by simply duplicating the line "button.addDragAndDropFeature(feature);"

Note, that our implementation of the create connection feature does not allow a connection, if the source and target business object are identical. If you have two different shapes associated with the same business object (e.g. via copy & paste), then creating a connection between them is not possible.

Implementation of the Tutorial Collapse Dummy Feature

 

package org.eclipse.graphiti.examples.tutorial.features;
 
public class TutorialCollapseDummyFeature extends AbstractCustomFeature {
 
      public TutorialCollapseDummyFeature(IFeatureProvider fp) {
            super(fp);
      }
 
      @Override
      public boolean canExecute(ICustomContext context) {
            boolean ret = false;
            PictogramElement[] pes = context.getPictogramElements();
            if (pes != null && pes.length == 1) {
                  Object bo = getBusinessObjectForPictogramElement(pes[0]);
                  if (bo instanceof EClass) {
                      ret = true;
                  }
            }
            return ret;
      }
 
      @Override
      public String getName() {
            return "Collapse";
      }
 
      @Override
      public String getDescription() {
 
            return "Collapse Figure";
      }
 
      @Override
      public String getImageId() {
            return IPlatformImageConstants.IMG_EDIT_COLLAPSE;
      }
 
      @Override
      public boolean isAvailable(IContext context) {
            return true;
      }
 
      @Override
      public void execute(ICustomContext context) {
            MessageDialog.openInformation(PlatformUI.getWorkbench()
              .getActiveWorkbenchWindow().getShell(), "Information",
            "The 'Collapse Feature' is intentionally not implemented yet.");
      }

 

Finally the feature provider has to deliver our newly created custom feature (overwrite the method getCustomFeatures(..)).

This implementation can be seen here:

 

@Override
public ICustomFeature[] getCustomFeatures(ICustomContext context) {
       return new ICustomFeature[]
          { new TutorialRenameEClassFeature(this),
              new TutorialDrillDownEClassFeature(this),
              new TutorialAssociateDiagramEClassFeature(this),
              new TutorialCollapseDummyFeature(this)};
}

 

Figure: Clicking the collapse button