During the 2013 Spring Canoo Code Camp Dieter and myself with a lot of support from Mittie implemented an Application which we called Dolphin Train Station.
Here is the situation: on the platforms of a train station, say Olten in Switzerland there are many departure boards informing people about trains starting from this station in the near future.
The application implements such a departure board in form of a window with a table showing the next 5 trains. One goal was that the departure boards are displayed on a Raspberry Pi. In addition the application contains a so called admin GUI to maintain information about trains and simulate arrivals and departures of trains. The Admin GUI uses the master-detail paradigm.
The following screenshots of the Admin GUI and the Departure Board should give you an impression on how the two GUIs look like.
To make this post not too boring I will just describe the important things from a concept point of view.
We started with an empty directory and created the initial open dolphin project structure with the open dolphin gdt template which meant our project was up and running within minutes. As GUI technology we decided to use JavaFX and also GroovyFX to make working with JavaFX even easier.
When the Admin GUI shows up a so called named command (COMMAND_GET_ALL_DEPARTURES) is sent to the server asking for all train departure data. The server creates presentation models (PMs) which are sent to the client by dolphin automatically. When the PMs arrive on the client a callback is invoked so that it can bind the PMs to the table on the GUI.
After having put the details view (which we also called editor) next to the table the goal was that it shows the data of the currently selected row in the table. Here the PMs start to shine. We simply created a separate PM which we called selectedDeparturePM.
Note that this selectedDeparturePM is nothing visible by itself. It is simply a placeholder for the concept of the currently selected PM. Whenever the selection in the table changes the newly selected PM of the table got applied to the selectedDeparturePM.
Then we bound the editor’s widgets to selectedDeparturePM. This means the table and the editor are completely decoupled. And if you start typing changes in the editor fields you immediately see the changes in the table while typing (that’s done by open-dolphin in the background). You could easily think of putting a second version or instance of the editor on the GUI (also bound to selectedDeparturePM) and the three views would all be in sync.
When we noticed that the table as a widget was still too much in control we created another “invisible” PM: selectedDepartureIdPM which we bound to the table. This means whenever the selected row in the table changes selectedDepartureIdPM is adapted and vice versa. Now you will ask why is it necessary that the table listens to changes of selectedDepartureIdPM The use case for this was the undo/redo support. We wanted that a change of the selected row in the table is also undoable. Changing the selected row in the table say from row 5 to row 6 now causes a normal value change of selectedDepartureIdPM from 5 to 6. When the user presses undo selectedDepartureIdPM changes back from 6 to 5 and since the table is bound to selectedDepartureIdPM the selection of the table also changes back to row 5. Nice, isn’t it?
And then of course we had to bind selectedDepartureIdPM to selectedDeparturePM and vice versa. This appeared like a best practice to us: views like the editor which are interested in all details of the selected PM bind to the selectedDeparturePM, those (like the master/table view) which are only interested in the id bind to the selectedDepartureIdPM. That’s all.
Now to the Departure Board. This is basically a second client to the same application. You have to know that the server side PMs of the AdminGUI and those of the Departure Board live in their own separate worlds (sessions). Also note that there is no concept of a shared PM. So if we want to show data visible on the Admin GUI on the Departure GUI you have to send the data to it. This is issued by pressing the button ‘erster Eintrag auf Abfahrtstafel’ which sends the PM’s data to the other client(s) by making use of Open Dolphin’s event bus.
The Departure Board clients use a long polling approach to be able to display changes immedately. This means whenever the AdminGUI presses the button they new 5 records appear immediately on the Departure board. And what’s more if you change data in the editor the changes appear on the Departures board which typing. We found that quite impressing.
During the code camp we wanted to use @hansolo_’s very nice departure board custom control on the Raspberry PI. It turned out that some adaptions have to be made first in order to make it PI ready. This is currently on the way. So for the PI we used a normal table for the time being. On the desktop we created a second version of the Departure Board using Swing as GUI technology. See for yourself how nice the result looks like:
It was really easy to add input validation to the Editor using tags of the PM’s attributes. We also made use of tags for the labels of intput fields so that validation and labels (think of internationalization) are defined by the server.
Altogether we were positively surprised how far we got in just a couple of days. It was a real joy to develop this application. If you’re interested you can find it on https://github.com/canoo/dolphin_train_station . The readme file appearing on the github page explains how to build and run the application.
My personal conclusions are:
- Using the presentation model approach with Open Dolphin is the way I want to build GUIs from now on.
- It will be hard if I have to go back and use other paradigms now that I know how to do it right.