/**
   * Displays an information bubble pointing to an ExecuteProcess operator to indicate a {@link
   * UserError} occurred inside the process executed by the operator.
   *
   * @param error the error instance
   * @param i18nKey the i18n key which defines the title, text and button label for the bubble.
   *     Format is "gui.bubble.{i18nKey}.title", "gui.bubble.{i18nKey}.body" and
   *     "gui.bubble.{i18nKey}.button.label".
   * @param arguments optional i18n arguments
   * @return the {@link OperatorInfoBubble} instance, never {@code null}
   */
  private static OperatorInfoBubble displayUserErrorInExecutedProcess(
      final ProcessExecutionUserErrorError error, final String i18nKey, final Object... arguments) {
    final JButton ackButton =
        new JButton(I18N.getGUIMessage("gui.bubble." + i18nKey + ".button.label", arguments));
    ackButton.setToolTipText(I18N.getGUIMessage("gui.bubble." + i18nKey + ".button.tip"));

    final BubbleDelegator bubbleDelegator = new BubbleDelegator();
    LinkButton showDetailsButton =
        new LinkButton(
            new ResourceAction(i18nKey + ".button_show_details") {

              private static final long serialVersionUID = 1L;

              @Override
              public void actionPerformed(final ActionEvent e) {
                if (RapidMinerGUI.getMainFrame().close(true)) {
                  // kill bubble
                  BubbleWindow bubble = bubbleDelegator.getBubble();
                  if (bubble != null) {
                    bubble.killBubble(true);
                  }

                  // open process which caused the error
                  Operator op = error.getUserError().getOperator();
                  final Process causingProcess = op.getProcess();
                  RapidMinerGUI.getMainFrame()
                      .setOpenedProcess(
                          causingProcess, false, causingProcess.getProcessLocation().toString());

                  // show new error bubble in the newly opened process
                  displayBubbleForUserError(error.getUserError());
                }
              }
            });
    showDetailsButton.setToolTipText(
        I18N.getGUIMessage("gui.action." + i18nKey + ".button_show_details.tip"));

    OperatorBubbleBuilder builder =
        new OperatorBubbleBuilder(
            RapidMinerGUI.getMainFrame(), error.getOperator(), i18nKey, arguments);
    final OperatorInfoBubble userErrorBubble =
        builder
            .setHideOnDisable(true)
            .setHideOnProcessRun(true)
            .setAlignment(AlignedSide.BOTTOM)
            .setStyle(BubbleStyle.ERROR)
            .setEnsureVisible(true)
            .hideCloseButton()
            .setHideOnProcessRun(true)
            .setAdditionalComponents(new JComponent[] {ackButton, showDetailsButton})
            .build();
    ackButton.addActionListener(
        new ActionListener() {

          @Override
          public void actionPerformed(ActionEvent e) {
            userErrorBubble.killBubble(true);
          }
        });
    bubbleDelegator.setBubbleWindow(userErrorBubble);

    userErrorBubble.setVisible(true);
    return userErrorBubble;
  }