This PR relates to a large amount of changes focused on reworking the application model. That is: the classes and logic that control the end-user application specific to the Mamut application (Spot and Link on a ModelGraph). It contains major API breaking changes which will prompt for a new beta version, hopefully the last one. This PR serves as a holder for the description of the changes as they are committed. Ideally a documentation will be extracted from the text appended here.
These changes try to address old and rather difficult TODOs that sometime appeared rather early in the project. For instance: In the beginning Mastodon had only two views and everything could be hardcoded. But now there are 7 of them, and new ones are coming, yielding a very long window manager class with many similar hard coded methods and many fields. The plugin system was built along the way while the app model was being elaborated. Loading and saving were handled by a component of the window manager (the ProjectManager), that could set, change or nullify the app model within one window manager instance, and dependents of the app model had to deal individually with these possibilities. And Mastodon had a lot of UI-related classes (the Keymaps, CommandDescriptions, SettingsPage frameworks) that Tobi moved recently to upstream packages (BDV-core and ui-behaviour).
This PR tries to address them, adding or tweaking features along the way.
Almost all the changes are invisible to the user. There are no changes in the file format. But developers can expect a lot of compile errors when they will depend on this PR.
The new ProjectModel class.
The MamutAppModel class have been renamed as ProjectModel and is now the central class that manages everything related to one 'session'. That is: when the user loads or creates a project, a new ProjectModel instance is created that has everything needed.
The windowManager is now a field of the project model. The window manager has only fields that relate to views and dialogs, and the related methods.
The project model has general fields, like the image data, the data model, the context, etc.
The project model is immutable and final. Once a session is created it will not change, and never be null. There is no need to test if it's null anymore. When a user loads a project, it gets another instance, but cannot modify an existing one.
The plugins receive directly a ProjectModel instance.
There is no need to make a separate class for the model provided to the plugins. They receive the ProjectModel, and stressing again: which is never null and never changes. So there is no need to check whether its null or to update the commands the plugin provides.
The interface for Mamut plugins is now:
public interface MamutPlugin extends MastodonPlugin< ProjectModel >
{}
Loading and saving.
The ProjectManager class is gone, replaced by 4 classes with only static methods, in the package org.mastodon.mamut.io. Each one takes care about loading, saving, importing or exporting.
The loading methods all produces a new ProjectModel instance. This instance receives the MamutProject it was created on (handy to save it later). The project model is properly initiatialized ONCE with everything. Then a consumer can create a MainWindow to pilot it. Example:
final ProjectModel appModel = ProjectLoader.open( projectPath, new Context() );
final MainWindow win = new MainWindow( appModel );
win.setVisible( true );
The MamutProject and related classes have also been moved. MamutProjectIO has now only static methods.
Generic views for Mastodon in the window manager.
The view (MamutViewBDV, MamutViewTrackScheme, ...) aer now created each by a specific factory, implementing the interface org.mastodon.mamut.views.MamutViewFactory. It is a discoverable SciJavaPlugin, that defines how to create a specific view using a ProjectModel instance, and how to de/serialize its GUI state.
The window manager has now a MamutViews field that is in charge of detecting and managing a collection of these view factories. Each factory is then used by the window manager to make one action that creates a view, registers it in the WM, deals whether it has a context provider or a context chooser, notifies listeners of its creation (see below) and finally shows it.
To create a specific view, you simply have to provide its class. For instance to create and show a BDV view:
the new view will be properly registered and its context provider will be made available to all other context chooser views.
New views are created, registered and managed only via these factories now. Which means that that window manager does not know of any concrete view class. It just manages all the ones it found. This will make it easier to extends Mastodon with new views, without having to touch or even recompile the core.
This also makes the window manager class much shorter. There are much less methods and much less fields, since all views are managed in a generic manner.
The view factory are also nice because they contain in one place all the info related to an action: command name, menu text, description.
For ELEPHANT, Ko requires that there is a view creation listeners list for BDV window. I kept this, but made it generic. There is now one listener list per view type. So you can register a listener for the creation of any type of view, and get it before it is shown.
The factories also handle GUI state serialization. The ProjectLoader and ProjectSaver classes use these factories when loading / saving for restoring / saving the GUI state. There are no specific hard-coded code to handle serialization of GUI state in the io package. This de/serialization also now takes much less code than before, as there were a lot of duplicated code, which is now present once in the mother abstract class for view factories.
Also: the views are now decoupled from saving or restoring the GUI state. The factory does it, which is cleaner.
All the view classes have been moved to subpackages, organized as follow:
Style managers and Settings pages are also managed by a factory pattern.
The various managers (RenderSettingsManager, ...) are managed in a similar way in the window manager. There is a factory interface for each (org.mastodon.mamut.managers.StyleManagerFactory), and it can return whether the style manager has a Settings page. If it is the case, it is automatically added to the PreferencesDialog.
Replace KeyMap and associated classes by upstream implementations.
The Keymap, KeymapManager, CommandDescriptions, SettingsPage and all associated classes have been migrated in upstream repos, mainly the BDV-core and ui-behaviour. Their initial implementation have been removed from Mastodon, which now use the common ones.
There are two adaptations specific for Mastodon:
1/ The KeymapManager class is extended by a specific one for Mastodon so that we can load and save keymaps in the Mastodon folder, and so that we load the builtin keymaps we had before.
2/ The new CommandDescription requires specifying a context AND now a scope. I made two scopes: one for the actions that are generic to Mastodon (everything in views, that do not know of the Mamut model), and one specific for the Mamut application (everything under org.mastodon.mamut, which is the one users have).
I could not replace one class:
KeymapSettingsPage: There is the equivalent in BDV-core, but it does not 'see' the builtin keymaps we have in Mastodon.
Better error messages and failing gracefully when opening projects.
I also worked on having the launcher not hang when something wrong happens. It should now show a meaningful error message to the user and allows them to open another project.
The views and dialogs show the current project name.
And it is updated when the user saves the project under a different name.
This PR relates to a large amount of changes focused on reworking the application model. That is: the classes and logic that control the end-user application specific to the Mamut application (Spot and Link on a ModelGraph). It contains major API breaking changes which will prompt for a new beta version, hopefully the last one. This PR serves as a holder for the description of the changes as they are committed. Ideally a documentation will be extracted from the text appended here.
These changes try to address old and rather difficult TODOs that sometime appeared rather early in the project. For instance: In the beginning Mastodon had only two views and everything could be hardcoded. But now there are 7 of them, and new ones are coming, yielding a very long window manager class with many similar hard coded methods and many fields. The plugin system was built along the way while the app model was being elaborated. Loading and saving were handled by a component of the window manager (the ProjectManager), that could set, change or nullify the app model within one window manager instance, and dependents of the app model had to deal individually with these possibilities. And Mastodon had a lot of UI-related classes (the Keymaps, CommandDescriptions, SettingsPage frameworks) that Tobi moved recently to upstream packages (BDV-core and ui-behaviour).
This PR tries to address them, adding or tweaking features along the way.
Almost all the changes are invisible to the user. There are no changes in the file format. But developers can expect a lot of compile errors when they will depend on this PR.
The new
ProjectModel
class.The
MamutAppModel
class have been renamed asProjectModel
and is now the central class that manages everything related to one 'session'. That is: when the user loads or creates a project, a newProjectModel
instance is created that has everything needed.The plugins receive directly a
ProjectModel
instance.There is no need to make a separate class for the model provided to the plugins. They receive the
ProjectModel
, and stressing again: which is never null and never changes. So there is no need to check whether its null or to update the commands the plugin provides.The interface for Mamut plugins is now:
Loading and saving.
The
ProjectManager
class is gone, replaced by 4 classes with only static methods, in the packageorg.mastodon.mamut.io
. Each one takes care about loading, saving, importing or exporting.The loading methods all produces a new
ProjectModel
instance. This instance receives theMamutProject
it was created on (handy to save it later). The project model is properly initiatialized ONCE with everything. Then a consumer can create a MainWindow to pilot it. Example:The
MamutProject
and related classes have also been moved.MamutProjectIO
has now only static methods.Generic views for Mastodon in the window manager.
The view (
MamutViewBDV
,MamutViewTrackScheme
, ...) aer now created each by a specific factory, implementing the interfaceorg.mastodon.mamut.views.MamutViewFactory
. It is a discoverableSciJavaPlugin
, that defines how to create a specific view using aProjectModel
instance, and how to de/serialize its GUI state.The window manager has now a
MamutViews
field that is in charge of detecting and managing a collection of these view factories. Each factory is then used by the window manager to make one action that creates a view, registers it in the WM, deals whether it has a context provider or a context chooser, notifies listeners of its creation (see below) and finally shows it.To create a specific view, you simply have to provide its class. For instance to create and show a BDV view:
the new view will be properly registered and its context provider will be made available to all other context chooser views.
New views are created, registered and managed only via these factories now. Which means that that window manager does not know of any concrete view class. It just manages all the ones it found. This will make it easier to extends Mastodon with new views, without having to touch or even recompile the core.
This also makes the window manager class much shorter. There are much less methods and much less fields, since all views are managed in a generic manner.
The view factory are also nice because they contain in one place all the info related to an action: command name, menu text, description.
For ELEPHANT, Ko requires that there is a view creation listeners list for BDV window. I kept this, but made it generic. There is now one listener list per view type. So you can register a listener for the creation of any type of view, and get it before it is shown.
The factories also handle GUI state serialization. The
ProjectLoader
andProjectSaver
classes use these factories when loading / saving for restoring / saving the GUI state. There are no specific hard-coded code to handle serialization of GUI state in the io package. This de/serialization also now takes much less code than before, as there were a lot of duplicated code, which is now present once in the mother abstract class for view factories. Also: the views are now decoupled from saving or restoring the GUI state. The factory does it, which is cleaner.All the view classes have been moved to subpackages, organized as follow:![Screenshot 2023-08-25 at 10 36 42](https://github.com/mastodon-sc/mastodon/assets/3583203/90335c99-249c-4056-990b-737900498a04)
Style managers and Settings pages are also managed by a factory pattern.
The various managers (
RenderSettingsManager
, ...) are managed in a similar way in the window manager. There is a factory interface for each (org.mastodon.mamut.managers.StyleManagerFactory
), and it can return whether the style manager has a Settings page. If it is the case, it is automatically added to thePreferencesDialog
.Replace
KeyMap
and associated classes by upstream implementations.The
Keymap
,KeymapManager
,CommandDescriptions
,SettingsPage
and all associated classes have been migrated in upstream repos, mainly the BDV-core and ui-behaviour. Their initial implementation have been removed from Mastodon, which now use the common ones.There are two adaptations specific for Mastodon:
1/ The
KeymapManager
class is extended by a specific one for Mastodon so that we can load and save keymaps in the Mastodon folder, and so that we load the builtin keymaps we had before.2/ The new
CommandDescription
requires specifying a context AND now a scope. I made two scopes: one for the actions that are generic to Mastodon (everything in views, that do not know of the Mamut model), and one specific for the Mamut application (everything underorg.mastodon.mamut
, which is the one users have).I could not replace one class:
KeymapSettingsPage
: There is the equivalent in BDV-core, but it does not 'see' the builtin keymaps we have in Mastodon.Better error messages and failing gracefully when opening projects.
I also worked on having the launcher not hang when something wrong happens. It should now show a meaningful error message to the user and allows them to open another project.![Screenshot 2023-08-25 at 10 38 05](https://github.com/mastodon-sc/mastodon/assets/3583203/4f4ac2ab-80c7-4b9c-835c-91daf63dc6d8)
The views and dialogs show the current project name.
And it is updated when the user saves the project under a different name.