/**
  * Fill the specified tool bar with the elements that have the given URI as their parent.
  *
  * <p>Existing elements on the tool bar will be removed.
  *
  * @param toolbar The {@link JToolBar} to update
  * @param id The {@link URI} of the tool bar
  */
 protected void populateToolBar(JToolBar toolbar, URI id) {
   toolbar.removeAll();
   MenuComponent toolbarDef = uriToMenuElement.get(id);
   if (toolbarDef == null) throw new IllegalArgumentException("Unknown toolBar " + id);
   if (!toolbarDef.getType().equals(MenuType.toolBar))
     throw new IllegalArgumentException(
         "Element " + id + " is not a toolBar, but a " + toolbarDef.getType());
   if (toolbarDef.getAction() != null) {
     String name = (String) toolbarDef.getAction().getValue(Action.NAME);
     toolbar.setName(name);
   } else toolbar.setName("");
   MenuOptions menuOptions = new MenuOptions();
   menuOptions.setToolbar(true);
   for (Component component : makeComponents(id, menuOptions)) {
     if (component == null) {
       toolbar.addSeparator();
       continue;
     }
     if (component instanceof JButton) {
       JButton toolbarButton = (JButton) component;
       toolbarButton.putClientProperty("hideActionText", true);
     }
     toolbar.add(component);
   }
 }
 /**
  * Fill the specified menu bar with the menu elements that have the given URI as their parent.
  *
  * <p>Existing elements on the menu bar will be removed.
  *
  * @param menuBar The {@link JMenuBar} to update
  * @param id The {@link URI} of the menu bar
  */
 protected void populateMenuBar(JMenuBar menuBar, URI id) {
   menuBar.removeAll();
   MenuComponent menuDef = uriToMenuElement.get(id);
   if (menuDef == null) throw new IllegalArgumentException("Unknown menuBar " + id);
   if (!menuDef.getType().equals(MenuType.menu))
     throw new IllegalArgumentException(
         "Element " + id + " is not a menu, but a " + menuDef.getType());
   MenuOptions menuOptions = new MenuOptions();
   for (Component component : makeComponents(id, menuOptions))
     if (component == null) logger.warn("Ignoring separator in menu bar " + id);
     else menuBar.add(component);
 }
 /**
  * Fill the specified menu bar with the menu elements that have the given URI as their parent.
  *
  * <p>Existing elements on the menu bar will be removed.
  *
  * @param popupMenu The {@link JPopupMenu} to update
  * @param id The {@link URI} of the menu bar
  * @param contextualSelection The current selection for the context menu
  */
 protected void populateContextMenu(
     JPopupMenu popupMenu, URI id, ContextualSelection contextualSelection) {
   popupMenu.removeAll();
   MenuComponent menuDef = uriToMenuElement.get(id);
   if (menuDef == null) throw new IllegalArgumentException("Unknown menuBar " + id);
   if (!menuDef.getType().equals(MenuType.menu))
     throw new IllegalArgumentException(
         "Element " + id + " is not a menu, but a " + menuDef.getType());
   MenuOptions menuOptions = new MenuOptions();
   menuOptions.setContextualSelection(contextualSelection);
   for (Component component : makeComponents(id, menuOptions))
     if (component == null) popupMenu.addSeparator();
     else popupMenu.add(component);
 }
  /**
   * Make the list of Swing {@link Component}s that are the children of the given {@link URI}.
   *
   * @param id The {@link URI} of the parent which children are to be made
   * @param menuOptions Options of the created menu, for instance {@link MenuOptions#isToolbar()}.
   * @return A {@link List} of {@link Component}s that can be added to a {@link JMenuBar}, {@link
   *     JMenu} or {@link JToolBar}.
   */
  protected List<Component> makeComponents(URI id, MenuOptions menuOptions) {
    List<Component> components = new ArrayList<>();
    for (MenuComponent childElement : getChildren(id)) {
      if (childElement instanceof ContextualMenuComponent)
        ((ContextualMenuComponent) childElement)
            .setContextualSelection(menuOptions.getContextualSelection());
      /*
       * Important - check this AFTER setContextualSelection so the item
       * can change it's enabled-state if needed.
       */
      if (!childElement.isEnabled()) continue;
      MenuType type = childElement.getType();
      Action action = childElement.getAction();
      URI childId = childElement.getId();
      if (type.equals(MenuType.action)) {
        if (action == null) {
          logger.warn("Skipping invalid action " + childId + " for " + id);
          continue;
        }

        Component actionComponent;
        if (menuOptions.isOptionGroup()) {
          if (menuOptions.isToolbar()) {
            actionComponent = new JToggleButton(action);
            toolbarizeButton((AbstractButton) actionComponent);
          } else actionComponent = new JRadioButtonMenuItem(action);
        } else {
          if (menuOptions.isToolbar()) {
            actionComponent = new JButton(action);
            toolbarizeButton((AbstractButton) actionComponent);
          } else actionComponent = new JMenuItem(action);
        }
        registerComponent(childId, actionComponent);
        components.add(actionComponent);
      } else if (type.equals(MenuType.toggle)) {
        if (action == null) {
          logger.warn("Skipping invalid toggle " + childId + " for " + id);
          continue;
        }
        Component toggleComponent;
        if (menuOptions.isToolbar()) toggleComponent = new JToggleButton(action);
        else toggleComponent = new JCheckBoxMenuItem(action);
        registerComponent(childId, toggleComponent);
        components.add(toggleComponent);
      } else if (type.equals(MenuType.custom)) {
        Component customComponent = childElement.getCustomComponent();
        if (customComponent == null) {
          logger.warn("Skipping null custom component " + childId + " for " + id);
          continue;
        }
        registerComponent(childId, customComponent);
        components.add(customComponent);
      } else if (type.equals(MenuType.optionGroup))
        addOptionGroup(components, childId, menuOptions);
      else if (type.equals(MenuType.section)) addSection(components, childId, menuOptions);
      else if (type.equals(MenuType.menu)) addMenu(components, childElement, menuOptions);
      else {
        logger.warn("Skipping invalid/unknown type " + type + " for " + id);
        continue;
      }
    }
    stripTrailingNullSeparator(components);
    return components;
  }