private void addPlainAction(RuleAction menuAction) {
    final ToolItem button = new ToolItem(mLayoutToolBar, SWT.PUSH);

    URL iconUrl = menuAction.getIconUrl();
    String title = menuAction.getTitle();
    if (iconUrl != null) {
      button.setImage(IconFactory.getInstance().getIcon(iconUrl));
      button.setToolTipText(title);
    } else {
      button.setText(title);
    }
    button.setData(menuAction);

    button.addSelectionListener(
        new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            RuleAction menuAction = (RuleAction) button.getData();
            menuAction
                .getCallback()
                .action(menuAction, getSelectedNodes(), menuAction.getId(), false);
            updateSelection();
          }
        });
  }
  /**
   * Attempts to update the existing toolbar actions, if the action list is similar to the current
   * list. Returns false if this cannot be done and the contents must be replaced.
   */
  private boolean updateActions(@NonNull List<RuleAction> actions) {
    List<RuleAction> before = mPrevActions;
    List<RuleAction> after = actions;

    if (before == null) {
      return false;
    }

    if (!before.equals(after) || after.size() > mLayoutToolBar.getItemCount()) {
      return false;
    }

    int actionIndex = 0;
    for (int i = 0, max = mLayoutToolBar.getItemCount(); i < max; i++) {
      ToolItem item = mLayoutToolBar.getItem(i);
      int style = item.getStyle();
      Object data = item.getData();
      if (data != null) {
        // One action can result in multiple toolbar items (e.g. a choice action
        // can result in multiple radio buttons), so we've have to replace all of
        // them with the corresponding new action
        RuleAction prevAction = before.get(actionIndex);
        while (prevAction != data) {
          actionIndex++;
          if (actionIndex == before.size()) {
            return false;
          }
          prevAction = before.get(actionIndex);
          if (prevAction == data) {
            break;
          } else if (!(prevAction instanceof RuleAction.Separator)) {
            return false;
          }
        }
        RuleAction newAction = after.get(actionIndex);
        assert newAction.equals(prevAction); // Maybe I can do this lazily instead?

        // Update action binding to the new action
        item.setData(newAction);

        // Sync button states: the checked state is not considered part of
        // RuleAction equality
        if ((style & SWT.CHECK) != 0) {
          assert newAction instanceof Toggle;
          Toggle toggle = (Toggle) newAction;
          item.setSelection(toggle.isChecked());
        } else if ((style & SWT.RADIO) != 0) {
          assert newAction instanceof Choices;
          Choices choices = (Choices) newAction;
          String current = choices.getCurrent();
          String id = (String) item.getData(ATTR_ID);
          boolean selected = Strings.nullToEmpty(current).equals(id);
          item.setSelection(selected);
        }
      } else {
        // Must be a separator, or a label (which we insert for nested widgets)
        assert (style & SWT.SEPARATOR) != 0 || !item.getText().isEmpty() : item;
      }
    }

    return true;
  }
  /** Updates the layout contents based on the current selection */
  void updateSelection() {
    NodeProxy parent = null;
    LayoutCanvas canvas = mEditor.getCanvasControl();
    SelectionManager selectionManager = canvas.getSelectionManager();
    List<SelectionItem> selections = selectionManager.getSelections();
    if (selections.size() > 0) {
      // TODO: better handle multi-selection -- maybe we should disable it or
      // something.
      // What if you select children with different parents? Of different types?
      // etc.
      NodeProxy node = selections.get(0).getNode();
      if (node != null && node.getParent() != null) {
        parent = (NodeProxy) node.getParent();
      }
    }

    if (parent == null) {
      // Show the background's properties
      CanvasViewInfo root = canvas.getViewHierarchy().getRoot();
      if (root == null) {
        return;
      }
      parent = canvas.getNodeFactory().create(root);
      selections = Collections.emptyList();
    }

    RulesEngine engine = mEditor.getRulesEngine();
    List<NodeProxy> selectedNodes = new ArrayList<NodeProxy>();
    for (SelectionItem item : selections) {
      selectedNodes.add(item.getNode());
    }
    List<RuleAction> actions = new ArrayList<RuleAction>();
    engine.callAddLayoutActions(actions, parent, selectedNodes);

    // Place actions in the correct order (the actions may come from different
    // rules and should be merged properly via sorting keys)
    Collections.sort(actions);

    // Add in actions for the child as well, if there is exactly one.
    // These are not merged into the parent list of actions; they are appended
    // at the end.
    int index = -1;
    String label = null;
    if (selectedNodes.size() == 1) {
      List<RuleAction> itemActions = new ArrayList<RuleAction>();
      NodeProxy selectedNode = selectedNodes.get(0);
      engine.callAddLayoutActions(itemActions, selectedNode, null);
      if (itemActions.size() > 0) {
        Collections.sort(itemActions);

        if (!(itemActions.get(0) instanceof RuleAction.Separator)) {
          actions.add(RuleAction.createSeparator(0));
        }
        label = selectedNode.getStringAttr(ANDROID_URI, ATTR_ID);
        if (label != null) {
          label = BaseViewRule.stripIdPrefix(label);
          index = actions.size();
        }
        actions.addAll(itemActions);
      }
    }

    if (!updateActions(actions)) {
      updateToolbar(actions, index, label);
    }
    mPrevActions = actions;
  }