How gvSIG MapControl works: flow of control

Within gvSIG design, MapControl is one of the core components. Its main responsibility is to allow users to interact with a map of layers (zoom in/out, edit geometries, …). That goal is achieved through two concrete tasks:

  • Route the user actions to the proper tool which will execute it.
  • Manage the drawing of the layers.

This post covers the first of above tasks in an introductory way.

Flow of control

MapControl is a java component, which uses the idea of Chain of Responsibility to delegate work on others. Let’s see how it works in this case with a good old graphic:


  1. MapControl listen MouseEvents through the MapToolListener. In response to an event, the MapToolListener will call the active tool (let’s say this class is named Behaviour).
  2. The active Behaviour processes the info from the mouse, put together the contextual information needed (let’s call that an Event) and calls the next step in the chain (let’s call it the ToolListener).
  3. Finally, the ToolListener will execute the actions needed to carry on the task an user have asked for.
Some notes before digging into code:
  • MapControl can have only 1 tool (Behaviour) active at any time. It holds the current selection in a private variable: Behaviour currentMapTool
  • MapControl wraps MouseEvents in 4 basic canonical events (see com.iver.cit.gvsig.fmap.tools.Events within libFMap project): MeasureEvent, PointEvent, MoveEvent and RectangleEvent. Any other event will inherit from and extend one of these canonical forms.

A concrete example: how a move event is processed

1 – MapToolListener: listen the mouse event and proxy it to the current selected behaviour (currentMapTool variable).

public void mouseReleased(MouseEvent e) {
    try {
        if (currentMapTool != null)
        currentMapTool.mouseReleased(e);
    } catch (BehaviorException t) {
        throwException(t);
    }
}

2 – Behaviour (MoveBehaviour in this case): takes the event, put together the context (MoveEvent) and redirects the petition to the proper ToolListener (listener variable).

public void mouseReleased(MouseEvent e) throws BehaviorException {
    if (e.getButton() == MouseEvent.BUTTON1 && m_FirstPoint!=null) {
        MoveEvent event = new MoveEvent(m_FirstPoint, e.getPoint(), e);
        listener.move(event);
    }
    m_FirstPoint = null;
}

3 – ToolListener: carry on the task. In this case, the listener (a PanListener) make the viewport to update the extent with the new contents.

public void move(MoveEvent event) {
    ViewPort vp = mapControl.getMapContext().getViewPort();
    Point2D from = vp.toMapPoint(event.getFrom());
    Point2D to = vp.toMapPoint(event.getTo());
    //build the new extent
    Rectangle2D.Double r = new Rectangle2D.Double();
    Rectangle2D extent = vp.getExtent();
    r.x = extent.getX() - (to.getX() - from.getX());
    r.y = extent.getY() - (to.getY() - from.getY());
    r.width = extent.getWidth();
    r.height = extent.getHeight();
    //update the ViewPort
    vp.setExtent(r);
}

Coda

Some useful resources about MapControl in gvSIG wiki:

Links to code:

Comments

One response to “How gvSIG MapControl works: flow of control”

Leave a Reply

Your email address will not be published. Required fields are marked *