The work that I’m doing right now on moving the console window controls
into the menus of the main application window and editor window has some
impact on the eventual implementation of RFE 1608192, “Ability to add menus
and actions to Main Menu bar”, found here:
sourceforge.net/tracker/index.ph … tid=594234
It’s worth giving some thought to how, at the code level, we want other
parts of VASSAL to interact with the app window menu bar. (This is less
important for the editor menu bar, I guess, but they should probably both
be done the same way.)
Here’s my thinking about this so far:
Modularity seems to demand that it be possible to create menu items from
various places in the code, but it’s fragile to insert menu items into a
menu by index when the menu items are not all created in one place. For
example, if some class supplies us with the “Open Game” and “Close Game”
items, while a different class provides the “Quit” item, how should the
items be added to the menu so that they all end up in the intended order?
Quit should be at the bottom, but when we’re adding “Open Game”, how do
we know whether “Quit” is already there? How do we keep the separators
in the right places?
JMenu doesn’t help us out in this regard, as it treats a menu as not much
more than an array. It gives us no way to say something like “these items
form a group—make this new item the last in its group” or “keep this
item at the bottom of the menu, no matter what”. I searched around on the
net several times looking for some hint of what people have done to make
building dynamic menus easier, but turned up nothing, not even someone
describing the problem. (Maybe I wasn’t searching for the right thing?
If there’s not much on this because it’s a bad idea I’d expect at least
to find someone flaming a novice programmer for coming up with it.)
What I came up with (tentatively) is something I’m calling SectionedMenu,
which extends JMenu and has the following additional Methods:
void addSection(int secId);
void insertSection(int secId, int pos);
void removeSection(int secId);
int getSectionHeadPosition(int secId);
int getSectionTailPosition(int secId);
int getSectionItemCount(int secId);
JMenuItem addToSection(<something>, int secId);
JMenuItem insertInSection(<something>, int secId, int pos);
These do what you’d expect they do. Adjacent sections are divided by
a separator; the separators are managed by the class internally, so
you don’t end up with separators above or below the initial or terminal
sections. is either an Action, a Component, a JMenuItem, or
a String, just like for the JMenu.add() and JMenu.insert() methods. If
you have the ID of the section you want, then you can add items within
that section without needing any knowledge of what the rest of the menu
looks like.
Does this seem like a sane solution to anyone?
Another way to go would be to make the sections objects themselves, so
that you get back a MenuSection when you create a new section, and then
you call add(), insert(), and remove() on the MenuSection, which then
twiddles the JMenu for you. The advantage of this is that you’re not
exposing the error-prone array semantics of the JMenu to the things which
are supplying the items; the disadvantage is that it’s slightly more
complex to code.
Maybe none of these are good, or someone has a better, completely different
approach. Are there any desiderata I’ve not considered? I’d like to get this
right the first time, so that when I (or someone else) eventually implements
the RFE which this affects, we don’t have to rip it all out and start over.