/**
   * Add a section to a list of components.
   *
   * @param components List of components
   * @param sectionId The {@link URI} identifying the section
   * @param menuOptions {@link MenuOptions options} for creating the menu
   */
  private void addSection(List<Component> components, URI sectionId, MenuOptions menuOptions) {
    List<Component> childComponents = makeComponents(sectionId, menuOptions);

    MenuComponent sectionDef = uriToMenuElement.get(sectionId);
    addNullSeparator(components);
    if (childComponents.isEmpty()) {
      logger.warn("No sub components found for section " + sectionId);
      return;
    }
    Action sectionAction = sectionDef.getAction();
    if (sectionAction != null) {
      String sectionLabel = (String) sectionAction.getValue(NAME);
      if (sectionLabel != null) {
        // No separators before the label
        stripTrailingNullSeparator(components);
        Color labelColor = (Color) sectionAction.getValue(SECTION_COLOR);
        if (labelColor == null) labelColor = GREEN;
        ShadedLabel label = new ShadedLabel(sectionLabel, labelColor);
        components.add(label);
      }
    }
    for (Component childComponent : childComponents)
      if (childComponent == null) {
        logger.warn("Separator found within section " + sectionId);
        addNullSeparator(components);
      } else components.add(childComponent);
    addNullSeparator(components);
  }
 /**
  * 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);
 }
    private void handlePerspectiveSelect(PerspectiveSelectionEvent event) {
      String perspectiveID = event.getSelectedPerspective().getID();
      boolean isDesign = DESIGN_PERSPECTIVE_ID.equals(perspectiveID);
      boolean isResults = RESULTS_PERSPECTIVE_ID.equals(perspectiveID);

      for (MenuComponent menuComponent : menuComponents)
        if (!(menuComponent instanceof ContextualMenuComponent)) {
          Action action = menuComponent.getAction();
          if (action instanceof DesignOnlyAction) action.setEnabled(isDesign);
          else if (action instanceof DesignOrResultsAction)
            action.setEnabled(isDesign || isResults);
        }
    }
 /**
  * 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);
 }
  /**
   * Add a {@link JMenu} to the list of components as described by the menu component. If there are
   * no children, the menu is not added.
   *
   * @param components List of components where to add the created {@link JMenu}
   * @param menuComponent The {@link MenuComponent} definition for this menu
   * @param isToolbar True if the list of components is to be added to a toolbar
   */
  private void addMenu(
      List<Component> components, MenuComponent menuComponent, MenuOptions menuOptions) {
    URI menuId = menuComponent.getId();
    if (menuOptions.isToolbar()) {
      logger.warn("Can't have menu " + menuComponent + " within toolBar element");
      return;
    }
    MenuOptions childOptions = new MenuOptions(menuOptions);
    List<Component> subComponents = makeComponents(menuId, childOptions);
    if (subComponents.isEmpty()) {
      logger.warn("No sub components found for menu " + menuId);
      return;
    }

    JMenu menu = new JMenu(menuComponent.getAction());
    for (Component menuItem : subComponents)
      if (menuItem == null) menu.addSeparator();
      else menu.add(menuItem);
    registerComponent(menuId, menu);
    components.add(menu);
  }
 /** Find all children for all known menu components. Populates {@link #uriToMenuElement}. */
 protected void findChildren() {
   for (MenuComponent menuElement : menuComponents) {
     uriToMenuElement.put(menuElement.getId(), menuElement);
     logger.debug("Found menu element " + menuElement.getId() + " " + menuElement);
     if (menuElement.getParentId() == null) continue;
     List<MenuComponent> siblings = menuElementTree.get(menuElement.getParentId());
     if (siblings == null) {
       siblings = new ArrayList<>();
       synchronized (menuElementTree) {
         menuElementTree.put(menuElement.getParentId(), siblings);
       }
     }
     siblings.add(menuElement);
   }
   //		if (uriToMenuElement.isEmpty()) {
   //			logger.error("No menu elements found, check classpath/Raven/SPI");
   //		}
 }
 @Override
 public int compare(MenuComponent a, MenuComponent b) {
   return a.getPositionHint() - b.getPositionHint();
 }
  /**
   * 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;
  }