Expansion Points

Expansion points define growth points for groups at runtime. A typical example would be a plugin that provides its own menu, or one that adds additional content to an existing menu. Expansion points ensure the new content is inserted at the correct point.

The expansion point location is defined by the expand member. Expansion points can be configured to place separators before, after and around any members it contains. The separators are only shown when the expansion point contains one or more members. This is covered in more detail in the Group Configuration section.

The following is an example of specifying an expansion point that places a separator before its content:

   group!file-menu@members=\
      new, \
      open, \
      save, \
      save-as, \
      expand(separatorBefore), \
      separator, \
      exit

The content of expansion points is managed using ExpansionPointBuilders. The following is a typical example:

   CommandGroup group = new CommandGroup("file-menu");
   // get the builder
   ExpansionPointBuilder builder = group.getExpansionPointBuilder();

   // remove any existing members from the expansion point.
   builder.clear();

   // add a command.
   builder.add(anotherCommand);
   builder.addSeparator();
   // and an inline group.
   builder.addInline(anotherGroup);

   // apply the changes
   builder.applyChanges();

Unlike Group Builders expansion point builders only let you add actual command instances. You can't add commands or groups using just the command Id.

Embedding

Expansion point builders allow you to embed new members within an existing group structure. Embedded groups are automatically added inline to existing group members that have matching text. If no match is found the group is added normally to the main group's expansion point.

Example

The following is the main menu definition from the online demo.

   group!main-menu@members=\
      file-menu, \
      view-menu, \
      edit-menu, \
      download-menu, \
      expand, \
      help-menu

   group!help-menu@face.text=_Help
   group!help-menu@members=help-about, expand(separatorBefore)

This produces the standard menu as shown below:

Standard Menu
Standard Menu

Each example withing the demo can provide one or more contributions for the main menu. The face example provides two menus, face.menu and face.help-menu defined as follows:

   group!face.menu@face.text=Face Menu
   group!face.menu@members=\
     face.basic-command,\
     face.text-leading,\
     face.text-bottom,\
     face.icon-factory-example,\
     face.rollover-example,\
     face.selected-icon-example,\
     face.disabled-icon-example,\
     face.client-property-example

   group!face.help-menu@face.text=_Help
   group!face.help-menu@members=face.help-about

When ever you select a new example, the main frame retrieves its menu contributions and embedds them into the main menu. This is achieved as follows:

   CommandGroup mainMenuGroup = ...;

   // get the builder
   ExpansionPointBuilder builder = mainMenuGroup.getExpansionPointBuilder();

   // clear any previous contributions from the menu, returning
   // it to its original state
   builder.clear();

   // Now add all the contributions. The face demo returns the
   // fac.menu and face.help-menu defined above.
   CommandGroup[] contributions = demoPanel.getMenuContributions();
   for (CommandGroup group : contributions)
   {
      // embed each contribution, matching on the menu face.
      builder.addEmbedded(group, Face.MENU);
   }
   builder.applyChanges();

The following shows the before and after menu structure after selecting the face examples:

Before:

Menu Before Embedding

After:

Menu After Embedding

Notice how face.menu (text="Face Menu") has been inserted into the main menu bar between the Download and Help menus. The face.help-menu (text="Help") however has been added as an inline member of the top level "Help" menu since their text values matched.

Using Custom Comparators

The builder also supports embedding using an arbitrary Comparator if you'd prefer no to match based on the text properties of the groups. The following is an example.

   ExpansionPointBuilder builder = group.getExpansionPointBuilder();

   // use a custom comparator when embedding groups.
   builder.addEmbedded(contribution, new CustomComparator());

   builder.applyChanges();