ImageJ2 has a flexible “extensibility framework” for managing plugins and their cousins, modules. Lately we have been making big improvements that are too numerous to mention here. But we wanted to make note of some of the progress that we made within the past couple of days. Be warned: it is very technical and will likely only be of interest to other ImageJ2 developers.
- We now have a fully working way to create plugins with dynamic numbers of input and output parameters, by extending the
DynamicPluginclass.DynamicPluginTestshows an example. (Feedback on the code is welcome; use ⌃ Ctrl + ⇧ Shift + T in Eclipse to Open Type and jump straight to it. To try it out in the GUI, open a couple of datasets first and then run Plugins › Sandbox › Dynamic Plugin Test. It will produce one output dataset per input, of the specified size squared.) - There is now a
ModuleServicethat tracks all known modules (plugins or otherwise). It publishesModulesChangedEvent(in the case of new modules added,ModulesAddedEvent, and in the case of modules removed,ModulesRemovedEvent) whenever the list of known modules changes. This is similar to theObjectService’sObjectsUpdatedEvent, so we expanded that to have the same hierarchy (Changedat base,AddedandRemovedas subtypes). - The
ObjectService’s index was split out into its own class calledObjectIndex, which maintains the objects on every list that is part of its type hierarchy. For example, an object of typeIntegerwould be registered onto the following lists:Integer,Number,Object,Serializable,Comparable. - We implemented a subclass of
ObjectIndexcalledSortedObjectIndexwhich does the same thing, but keeps all the lists sorted. Then we subclassed that asPluginIndex, and used it with thePluginService. So the plugin service now keeps an index of all its plugins including supertype hierarchies, which it didn’t before. So for example, you can now ask the plugin service for allRunnablePlugins, and getImageJPlugins(a subtype) included in that. ModuleServicealso uses aSortedObjectIndexsubclass calledModuleIndexto maintain its list of modules.ModuleServicehas run methods for executing anyModuleorModuleInfo, with or without spawning a new thread, and with or without a specified set of pre- and postprocessors.- Similarly,
PluginServicehas run methods for executing anyModuleorModuleInfowith its knownPreprocessorPluginsandPostprocessorPlugins. These methods are the central way to run a module programmatically. - The
ShadowMenu, a UI-agnostic menu tree structure, now has each leaf linked to aModuleInfo. This means that menu entries will now be capable of running scripts and other modules, not just plugins.
What’s next:
- Dynamic plugin implementations:
- We are going to update various core plugins which need the dynamic plugin mechanism, to give it a test drive.
- Dynamic menus:
- Update
ShadowMenuto listen toModulesChangedEventandModuleUpdatedEventand change its internal structure accordingly. This will generally entail surgical changes to its structure rather than a full menu rebuild. - Update the UI-toolkit-specific menu builders to keep the resultant menu structures (e.g.,
JMenuBar) linked to theShadowMenu. When theShadowMenupublishes events indicating menu items have changed, the actual UI menu needs to automatically update to reflect that as well. - Maybe: update
ModuleServiceto maintain aShadowMenudata structure, which can be obtained for whatever purpose.
- Update
- More module invocation routines:
- It would be nice to have run methods of
ModuleServiceandPluginServicethat accept parameters programmatically, either as a list or as a map. Grant’sInvokePluginTestshows what we are going for.
- It would be nice to have run methods of