Lomse Hacking Guide
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:
Main concerns:
Application needs and concerns:
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.
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.
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.
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.
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.
(To be continued ...)
In the Lomse implementation of the MVC architecture, when user is allowed to interact with the document, the control flow is as follows:
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.
[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 |