/**
   * Reconfigures the dialog if settings have changed, such as the errorInfo, errorIcon,
   * warningIcon, etc
   */
  protected void reinit() {
    setDetailsVisible(false);
    Action reportAction = pane.getActionMap().get(JXErrorPane.REPORT_ACTION_KEY);
    reportButton.setAction(reportAction);
    reportButton.setVisible(
        reportAction != null && reportAction.isEnabled() && pane.getErrorReporter() != null);
    reportButton.setEnabled(reportButton.isVisible());
    ErrorInfo errorInfo = pane.getErrorInfo();
    if (errorInfo == null) {
      iconLabel.setIcon(pane.getIcon());
      setErrorMessage("");
      closeButton.setText(
          UIManagerExt.getString(CLASS_NAME + ".ok_button_text", closeButton.getLocale()));
      setDetails("");
      // TODO Does this ever happen? It seems like if errorInfo is null and
      // this is called, it would be an IllegalStateException.
    } else {
      // change the "closeButton"'s text to either the default "ok"/"close" text
      // or to the "fatal" text depending on the error level of the incident info
      if (errorInfo.getErrorLevel() == ErrorLevel.FATAL) {
        closeButton.setText(
            UIManagerExt.getString(CLASS_NAME + ".fatal_button_text", closeButton.getLocale()));
      } else {
        closeButton.setText(
            UIManagerExt.getString(CLASS_NAME + ".ok_button_text", closeButton.getLocale()));
      }

      // if the icon for the pane has not been specified by the developer,
      // then set it to the default icon based on the error level
      Icon icon = pane.getIcon();
      if (icon == null || icon instanceof UIResource) {
        if (errorInfo.getErrorLevel().intValue() <= Level.WARNING.intValue()) {
          icon = getDefaultWarningIcon();
        } else {
          icon = getDefaultErrorIcon();
        }
      }
      iconLabel.setIcon(icon);
      setErrorMessage(errorInfo.getBasicErrorMessage());
      String details = errorInfo.getDetailedErrorMessage();
      if (details == null) {
        details = getDetailsAsHTML(errorInfo);
      }
      setDetails(details);
    }
  }
  /**
   * Creates and initializes the components which make up the aggregate combo box. This method is
   * called as part of the UI installation process.
   */
  protected void installComponents() {
    iconLabel = new JLabel(pane.getIcon());

    errorMessage = new JEditorPane();
    errorMessage.setEditable(false);
    errorMessage.setContentType("text/html");
    errorMessage.setEditorKitForContentType("text/plain", new StyledEditorKit());
    errorMessage.setEditorKitForContentType("text/html", new HTMLEditorKit());

    errorMessage.setOpaque(false);
    errorMessage.putClientProperty(JXEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);

    closeButton =
        new JButton(
            UIManagerExt.getString(CLASS_NAME + ".ok_button_text", errorMessage.getLocale()));

    reportButton = new EqualSizeJButton(pane.getActionMap().get(JXErrorPane.REPORT_ACTION_KEY));

    detailButton =
        new EqualSizeJButton(
            UIManagerExt.getString(CLASS_NAME + ".details_expand_text", errorMessage.getLocale()));

    details = new JXEditorPane();
    details.setContentType("text/html");
    details.putClientProperty(JXEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
    details.setTransferHandler(createDetailsTransferHandler(details));
    detailsScrollPane = new JScrollPane(details);
    detailsScrollPane.setPreferredSize(new Dimension(10, 250));
    details.setEditable(false);
    detailsPanel = new JPanel();
    detailsPanel.setVisible(false);
    copyToClipboardButton =
        new JButton(
            UIManagerExt.getString(
                CLASS_NAME + ".copy_to_clipboard_button_text", errorMessage.getLocale()));
    copyToClipboardListener =
        new ActionListener() {
          public void actionPerformed(ActionEvent ae) {
            details.copy();
          }
        };
    copyToClipboardButton.addActionListener(copyToClipboardListener);

    detailsPanel.setLayout(createDetailPanelLayout());
    detailsPanel.add(detailsScrollPane);
    detailsPanel.add(copyToClipboardButton);

    // Create error scroll pane. Make sure this happens before call to createErrorPaneLayout() in
    // case any extending
    // class wants to manipulate the component there.
    errorScrollPane = new JScrollPane(errorMessage);
    errorScrollPane.setBorder(new EmptyBorder(0, 0, 5, 0));
    errorScrollPane.setOpaque(false);
    errorScrollPane.getViewport().setOpaque(false);

    // initialize the gui. Most of this code is similar between Mac and PC, but
    // where they differ protected methods have been written allowing the
    // mac implementation to alter the layout of the dialog.
    pane.setLayout(createErrorPaneLayout());

    // An empty border which constitutes the padding from the edge of the
    // dialog to the content. All content that butts against this border should
    // not be padded.
    Insets borderInsets = new Insets(16, 24, 16, 17);
    pane.setBorder(
        BorderFactory.createEmptyBorder(
            borderInsets.top, borderInsets.left, borderInsets.bottom, borderInsets.right));

    // add the JLabel responsible for displaying the icon.
    // TODO: in the future, replace this usage of a JLabel with a JXImagePane,
    // which may add additional "coolness" such as allowing the user to drag
    // the image off the dialog onto the desktop. This kind of coolness is common
    // in the mac world.
    pane.add(iconLabel);
    pane.add(errorScrollPane);
    pane.add(closeButton);
    pane.add(reportButton);
    reportButton.setVisible(false); // not visible by default
    pane.add(detailButton);
    pane.add(detailsPanel);

    // make the buttons the same size
    EqualSizeJButton[] buttons =
        new EqualSizeJButton[] {(EqualSizeJButton) detailButton, (EqualSizeJButton) reportButton};
    ((EqualSizeJButton) reportButton).setGroup(buttons);
    ((EqualSizeJButton) detailButton).setGroup(buttons);

    reportButton.setMinimumSize(reportButton.getPreferredSize());
    detailButton.setMinimumSize(detailButton.getPreferredSize());

    // set the event handling
    detailListener = new DetailsClickEvent();
    detailButton.addActionListener(detailListener);
  }