Back to the FAQ

Picking services

Modelio v3

In several places in Modelio, when a form or a dialog requires a model element to be chosen to fill a particular field, the user can directly designate a particular element by simply clicking on it. In Modelio this specific interaction is called “picking”, it can be briefly described as the following sequence:

  • A form or dialog field, called the picking client, requires a model element to be chosen (usually there is a small symbol next to the field)
  • The user clicks into the client field thereby activating or entering the picking session
  • The mouse cursor shape on the screen changes for the picking cursor when the mouse is hovering a valid element for the client field. Note that only certain parts of the GUI are able to provide a picking cursor (for example the explorer or diagrams) while some others will not react at all. Picking-able GUI parts are called picking providers
  • If the user left-clicks while hovering a valid element (picking cursor is displayed) the hovered element is selected in the client field and the picking session ends
  • The picking session can be aborted at anytime either by pressing the ESC key or by selecting another (non-picking client) field in the form/dialog.

Modelio API picking services can be used by a module to either implement a picking client, a picking provider or both.

The Picking services

Using the Modelio picking services is quite straigthforward.

  1. get the Modelio picking service object IPickingService from the modeling session
  2. call one of the IPickingService provided methods

Implementing a picking client

You may want to implement a picking client when you need the end-user to designate a particular element in the application.

In the following code fragment, a SWT Text widget is configured to behave as a picking client.

A picking client is an object that implements the IPickingClient interface. The responsibilities of a picking client are:

  1. To start a picking session at a given moment
  2. To accept or refuse the model elements hovered by the mouse cursor while the user is navigating in the application to choose an element. This will change the cursor shape accordingly.
  3. To process the picked element, which is the (accepted) element clicked on by the user, and end the picking session.
  4. To manages the eventual aborting of the picking session it has started

In most cases, a dedicated class will be in charge of these responsibilities.

 1class MyPickingClient implements IPickingClient {
 2    private IPickingSession pickSession;
 3
 4    //...
 5    @Override
 6    public boolean acceptElement(MObject target) {
 7        return true;
 8    }
 9
10    @Override
11    public boolean setElement(MObject target) {
12        System.out.println("picked element" + target.getName());
13        Modelio.getInstance().getPickingService().endPickingSession(this.pickSession);
14
15        return true;
16    }
17
18    @Override
19    public void pickingAborted() {
20        this.pickSession = null;
21    }
22
23    public void setSession(IPickingSession aPickSession) {
24        this.pickSession = aPickSession;
25    }
26
27    ...
28}
29

Line 6: the acceptElement() method
This method is called for each model element hovered by the mouse. In this method you can choose which elements can be picked or not for example by testing the target type, name, status… Returning true will change the mouse cursor to the picking accepted cursor shape (a hand symbol), returning false will change the cursor to a forbidden cursor shape.

Line 11: the setElement() method
This method is called when the user clicks on a model element previously accepted by the acceptElement()method above. The target element is the element finally chosen by the end-user, ie the picked element. In this method you have to process the chosen element (what has to be done is application specific and cannot be detailed here). This method is also responsible for ending the picking session (line 9) by calling the endPickingSession()method. Note that this latter method requires the currently active picking client as parameter.

Line 19: the pickingAborted() method
This method is called by Modelio whenever the current picking has to terminate for any reason (for example the user canceled the picking interaction by pressing the ESC key, or he has activated another picking field somewhere else which has the main effect of aborting the current picking session to start a new one). Usually, this method only cares about ending the current picking session, but it might be used to carry out some additional cleanup if needed (resetting variables, freeing resources and so on).

Branching the picking client to the gui

In a GUI, such a picking client object could typically be created and activated in the FocusListener of a Text field as shown in the following code fragment.

 1class MyTextFocusListener implements FocusListener {
 2    //...
 3    @Override
 4    public void focusGained(FocusEvent e) {
 5       // create and initialize a picking client instance
 6       MyPickingClient pickingClient = new MyPickingClient();
 7       
 8       // start the picking session, passing the picking client
 9       IPickingSession pickSession = Modelio.getInstance().getPickingService().startPickingSession( pickingClient );
10       pickingClient.setSession(pickSession);
11                
12    }
13    ...
14}
15

When the text field gets the focus, a picking session is started. The picking client is usually in charge of filling the text field with the picked element in its selectElement()method.

So far we have seen how you can configure a GUI component to become a picking client, allowing quick and easy choice of a model element by the user. In Modelio, model elements can mainly be picked from the explorer or the diagrams. This is because these GUI parts are currently designed to be picking providers. When developing a module and using the Modelio API picking services, you can also define any GUI component of your module to become picking providers

Implementing a picking provider

The reason why you may want your module to implement a picking provider, is that your module is somewhat displaying a set of model elements that are of interest for a user to be quickly and easily chosen. For example, the diagrams, which are great model elements displayer, are typical picking providers. A picking click in a diagram to designate an element is definitely a quick and easy interaction for a end-user. So when your module is displaying a valuable list of model elements, consider making of it a picking provider.

Being a picking provider implies several responsibilities which are defined by the interface IPickingProvider and several methods of the IPickingService. The overall process of implementing a picking provider consists in:

  • designing an implementation of the IPickingProvider
  • registering this provider in the picking service (typically at module start)
  • firing picking events according to user’s mouse activity

The IPickingProvider interface

In most cases, a dedicated class will be in charge of these responsibilities. The methods of this interface are called by Modelio to notify your provider about the starting, respectively ending, of picking session. Remember that a picking session is started when the user activates a picking client (ie a gui component requiring the selection of a model element).

 1class MyPickingProvider implements IPickingProvider {
 2    private IPickingSession pickSession;
 3
 4    ...
 5    @Override
 6    public void enterPickingMode(IPickingSession session) {
 7        System.out.println("entering picking mode");
 8        this.pickSession = session;
 9        
10        //... code is really application specific here ...
11    }
12
13    @Override
14    public void leavePickingMode(IPickingSession session) {
15        System.out.println("leaving picking mode");
16        this.pickSession = null;
17
18        //... code is really application specific here, probably undoing what has been done in the enterPickingMode() method.
19    }
20    
21    
22    ...
23

Line 6: the enterPickingMode(IPickingSession session) method
This method is called by Modelio when a picking session is started. From this moment, your picking provider must be able to fire proper picking events depending on the user mouse activity. You should also take care of animating the mouse cursor depending on these events.
For example, if your module is displaying a list of elements in a SWT List, you have to configure this list to fire picking events when the user hovers over its elements or when he selects a particular element in it.

Line 15: the leavePickingMode(IPickingSession session) method
This method is called by Modelio when a picking session is ended whatever the reason. From this moment your provider should not fire any picking events anymore. Usually, actions carried out in this method consists more or less in un-doing what has been done in the enterPickingMode() method. In our example of a SWT list of elements previously configured to fire picking events, the leavePickingMode()would probably reconfigure this list listeners so that no more events are sent.

Registering the provider

Once you have designed and implemented your picking provider, you have to register an instance of it to the picking service. Being registered, your provider will be called by Modelio each time a picking session is started or ended. The proper place to register your provider is typically the start method of your module, once your module GUI components are initialized, but other solutions are possible.

 1    ...
 2    
 3    MyPickingProvider pickingProvider = new MyPickingProvider(...);
 4    ...
 5    // Registering a picking provider
 6    Modelio.getInstance().getPickingService().registerPickingProvider(pickingProvider );
 7    ...
 8    // Unregistering a picking provider
 9    Modelio.getInstance().getPickingService().unregisterPickingProvider(pickingProvider ); 
10    ...
11

The above code fragment is straightforward. Simply call the register/unregister methods of the picking service and you are done. Note, however, that you have to keep the picking object instance to be able to pass it back to the unregisterPickingProvider() method when unregistering it.

Firing picking events

Obviously, one of the main role of a picking provider is to animate the picking session by firing so-called picking events. There are only two kind of events:

  1. hovering events, which have to be fired while the mouse is hovering model elements. These events are transmitted to the active picking clients by calling its acceptElement() method. Hovering events are fired by calling the hoverElement() method of IPickingSession and passing the hovered element as parameter. The returned boolean is the value returned by the picking client acceptElement() method.
  2. selection events, which have to be fired when the user actually clicks on a hovered element. These events are transmitted to the active picking client by calling its setElement() method. Selection events are fired by calling the selectElement() method of IPickingSession and passing the selected element as parameter.

Where and when firing events methods should be called highly depends on the application and the GUI component actually used to display and select elements. For a SWT List, a typical place to fire selection events is the ISelectionListener() of the List. Hovering the List is probably more tricky and may deal with MouseListener events.

A SWT Canvas based event firer could look like this:

 1class MyPickingEventFirer implements MouseListener {
 2    private IPickingSession pickSession;
 3    private Canvas swtCanvas;
 4
 5    ...
 6
 7    public void activate(IPickingSession pickSession) {
 8        this.pickSession = pickSession;
 9        this.swtCanvas.addMouseListener(this);
10    }
11
12    public void disable() {
13        this.pickSession = null;
14        this.swtCanvas.removeMouseListener(this);
15    }
16
17    @Override
18    public void mouseUp(MouseEvent e) {
19        if (e.button == 1) {
20            MObject selectedElement = ... // application specific
21            if (selectedElement != null && this.pickSession.hoverElement(selectedElement)) {
22                this.pickSession.selectElement(selectedElement);
23            }
24        }
25    }    
26