The basic point of Names on Nodes, as I've mentioned before, is to automate taxonomy. That is, you feed it:
- a bunch of phylogenetic definitions,
- a phylogeny, and
- specifier links, that is, correlations between definition specifiers (apomorphies, species, specimens) and units in the phylogeny (e.g., taxa in NEXUS trees).
That part of it is pretty much done. But there are two tricky parts I have yet to complete: data persistence and user interface. And what both basically boil down to is CRUD.
I've mentioned CRUD before here. It's an acronym for the four basic operations involved with data persistence, the four things you can do to a stored object. Those are:
As often happens in programming, I started out with an ad hoc sort of approach that worked well enough up to a point, but then I started finding myself in trouble. Duplicated code. Unnecessarily complex code. Code that was hard to update.
It was time to refactor.
Here's a breakdown of the new system.
Every user interface involved with persistent objects is managed by something called a
FlowManager. This stores a navigable tree of
FlowEntryobjects, each associated with a visual
The main application handles requests from all components within. These are sent to the application as bubbling events, that is, events that "bubble" up through the display hierarchy (say, from a button, to the form that contains it, to the flow manager, on up to the main application). Two of the major types of request are
EditEntityEventcomes with a persistent object (e.g., a species, a definition, a NEXUS file, etc.). The application's responsibility is to create a
FlowComponentobject that will display the entity and allow the user to edit it (Update).
DemandEntityEventcomes with a class of persistent object (e.g.,
Nexus, etc.). The application's responsibility, then, is to provide the "demander" with an object of that class, either by making a new one (Create) or by selecting an existing one (Retrieve).
(Note that I haven't mentioned Delete. I'm leaving that out of the first version. Any deletions will have to be made by myself, manually.)
One problem with my old approach was that I had different user interface components for each combination of CRU[D] action and persistent object. Take a couple dozen types of persistent object and multiply by three: that's how many components I had to make.
The new system, though, has just two types of
FlowComponent: one for handling
EditEntityEventrequests and the other for handling
The first one is the simplest:
EntityEditor. It basically consists of the following components:
- a form which shows all data in the persistent entity;
- a bit of text that summarizes the entity in its current state (e.g., for a
Binomenentity, something like "Prenomen nomen Author 1970");
- a button that updates the entity in the database, or, if it is a new entity, creates it in the database; and
- a "cancel" button.
EntitySupplier, actually uses an
EntityEditorobject. Once the
EntitySupplierobject is given the class of entity that it's supposed to supply, it creates a default instance of that class and gives it to an
EntityEditor, which it displays to the left. To the right, it displays a
SuggestionBox, a grid showing various existing entities that might match what's in the editor.
SuggestionBoxuses a nonvisual object called an
EntitySuggester, whose job is to watch for changes that the user makes to the persistent entity and come up with relevant, existing suggestions. For example, suppose the user is editing a new
Publicationobject and starts to type in the authorship as "Linn". The
PublicationSuggestersees this and checks the database for possible matches, coming up with "Linnaeus 1758". If this is the publication that the user wanted, then they can select it from the
SuggestionBoxwithout having to fill in any more information.
I still have to create a form and a suggester for every type of persistent entity, but this is a much neater division of labor than I had in the last version, where forms generated their own suggestions (which would be wasteful if you were just editing an existing entity).
Hope to get much done this weekend.
(Have to get much done this weekend....)