Features Help Download

Lomse Hacking Guide

4.1. The Lomse MVC model

To provide for high levels of modification, maintenance and reuse it is necessary to organise the application components around high level abstractions that provide isolation between the various functions of the GUI. The Model-View-Controller (MVC) architectural pattern is a well known paradigm for this. It provides a clean separation between three responsibilities: maintaining data (the Model), displaying all or a portion of the data (the View), and handling events that affect the model or view(s) (the Controller).

The MVC model has evolved over time. The Model and the View are components with simple and clear responsibilities, but the Controller has to deal with too many responsibilities. Therefore, there are many MVC variations that basically differ on how the Controller is modelled.

The Lomse library uses a MVC model based on ideas taken mainly form the TaskMaster architecture [1] and in minor degree from the Taligent Model-View-Presenter (MVP) pattern [2] and other references [3], [4].

The main objects in the Lomse MVC model are four: the Document (it is the Model), the View, the Interactor (a kind of Controller) and the Presenter (the ‘glue’ to join all the pieces).

The following figure shows the main involved objects and its relationships:

The Lomse MVC model

The Lomse MVC model

4.1.1. Principles and design decisions

Main concerns:

  1. The components around the MVC model (View, Document, Interactor, Presenter, Task, GraphicModel, Command, etc.) must have its responsibilities isolated. The knowledge one object has about the others should be minimized to enforce the single responsibility principle.
  2. Simple API for Lomse user application. It is easy to inadvertely add code that requires knowledge about the other objects internals or to create an architecture that forces the user application to understand and deal with too many objects. Therefore, attention has been payd to not only separating responsibilities but also isolating the participants and channelling all communication through a simple communication protocol.

Application needs and concerns:

  • LDP document data (the Model: Document class)
  • Data specification (Selection class)
  • Data manipulation (Command class)
  • Application/library interface (Presenter class)
  • User interaction (Interactor class, Task objects)
  • User presentation (View class). Different formats: graphical, sound, text-ldp, text-xml, other.
  • Other needs:
    • Relating the internal model and the graphical model
    • Relating the internal model and the sound model
    • Play back: the same view needs to relate graphical & sound models and synchronize them.

4.1.2. Involved objects

Document (the Model)

It is responsible for storing the LDP document content and for notifying other objects when changes occur to the document.

It is owned by the Presenter.

Presenter

The Presenter (short for ‘document presenter’) is a façade object responsible for coordinating all MVC involved classes within an application. It maintains the life cycle and relationships between Views, Interactors, Commands, Selections, and the Document. There is generally a single View per Presenter, though a Presenter may manage multiple logically related Views.

It is owned by user application

Important

As Presenter ownership is transferred to user application, you have to take care of deleting the Presenter when no loger needed. Deleting the Presenter will automaticall cause deletion of all MVC involved objets: the Document, all existing Views and Interactors, etc.

View

The Document is presented to the user by a View. It normally has an associated window where the document is rendered. The Lomse library doesn’t provide any support for building windows or any other kind of GUI controls (all this must be part of the user application). The library just provides: * the bitmaps with the renderized score, and * support for interacting with them.

The View is responsible for providing bitmaps with the rendered score. It is user application responsibility to present this bitmap to the user (i.e. render it on a window, save it in a file, print it, or produce any other desired output).

The Document and its Views (there could be more than one), are related by the observer pattern.

The View is responsible: * for providing output for the user application, usually bitmaps with the rendered music score. * for providing coordinates conversion between the bitmap and the world, and viceversa.

It is owned by the Interactor.

Interactor

It addresses how user events are mapped onto operations performed on the Document, such as mouse movements, keyboard input, and the selection of checkboxes or menu items. The interactor plays the role of the Controller in the MVC model and is responsible for intercepting all the events from the user interface and interpreting them into Commands and Selections that manipulate the Document.

It is responsible for re-directing requests to the appropriate objects.

It is a facade object for receiving user events and user application requests and returning any requested data.

It is owned by the Presenter.

Task

To decide on the appropriate action, the Interactor delegates on a Task that is chosen by using the State pattern: The Task is an abstract object and the real object receiving the user event depends on the Interactor’s state. Each derivative of Task encapsulates an interaction with the user and eventually communicates with the document. The appropriate derivative of Task is selected by a menu command or click on a palette item, etc.

All Task derivatives are finite state machines. The events that drive the finite state machine are the mouse and keyboard events that are delegated by the Interactor to the Task.

Decides on the appropriate action for an event or sequence of events

It is owned by the Interactor.

Task object is described in detail in Task objects.

GraphicModel
Encapsulates the objects that compose the graphical model, providing services for: * traversing the structure * hit testing * rendering (drawing) * Relating the graphical model to the internal model
SoundModel
Encapsulates the objects that compose the sound model, providing services for: * play back * Relating the sound model to the internal model * Play back syncronization (relating graphical & sound models)
Selection
Specify what portion of the data within the Document and/or the GraphicModel is to be operated upon. Examples would be selections which define bars, groups of notes and rests, instruments, columns, or individual elements which meet specific criteria.

(To be continued ...)

4.1.3. User interaction

In the Lomse implementation of the MVC architecture, when user is allowed to interact with the document, the control flow is as follows:

  1. The user interacts with the user interface in some way (for example, presses a mouse button). All the events coming from the user interface are received by the user application window on which the View is rendered. Then, user app. re-directs these events to the associated Interactor object.
  2. The Interactor delegates the handling of the event on the current Task object. The Task object handles the event and converts it into appropriate actions either on the Document (Commands), on the GraphicModel (Selections), or both.
  3. If actions result in a change in the Document’s state:
    1. The Document notifies its observing Views that it has been modified (Observer pattern). A change in the Document would imply, normally the need to update the View.
    2. In response to this notification, each View queries the Document in order to generate the appropriate changes in the user interface. The View gets its own data from the Document (push model. See Push Model vs. Pull Model.)
  4. But if the actions result only in GraphicModel changes, the View is directly asked by the Task to update screen.
  5. If screen needs to be updated, Lomse generates an event for user application.
  6. The user interface waits for further user interactions, which restarts the cycle.

4.1.4. Push Model vs. Pull Model

The Observer relationship between the View and the Document could follow a push or a pull model.

In the push model, the data that the observing view is interested in is “pushed” along with the message that notifies the observing view that the document has changed. For example, if a note is inserted in the score the note instance can be “pushed” in the “hint” argument of the on_update() method.

The alternative to the “push” model is to use the “pull” model. In the “pull” model, no data is sent in the on_update message. Upon receipt of the on_update message, the views must pull all the data from the document and redisplay it all.

For now, Lomse follows a pull model.

4.1.5. References

[1]“TASKMASTER: An Architecture Pattern for GUI Applications”, Robert C. Martin, James W. Newkirk & Bhama Rao. Available at http://www.objectmentor.com/resources/articles/taskmast.pdf
[2]Mike Potel, “MVP: Model-View-Presenter. The Taligent Programming Model for C++ and Java”. Available at http://www.wildcrest.com/Potel/Portfolio/mvp.pdf
[3]Derek Greer, “Interactive Application Architecture Patterns”, August 2007. available at http://aspiringcraftsman.com/2007/08/25/interactive-application-architecture/
[4]Martin Fowler, “GUI Architectures”, July 2006. Available at http://martinfowler.com/eaaDev/uiArchs.html