Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8148556

[macosx] Application locks up trying to display JOptionPane.showConfirmDialog over JFXPanel

XMLWordPrintable

    • x86
    • other

      FULL PRODUCT VERSION :
      java version "1.8.0_72"
      Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
      Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode

      ADDITIONAL OS VERSION INFORMATION :
      Yosemite 10.10.5


      A DESCRIPTION OF THE PROBLEM :
      I am displaying a web page in a browser, when the page generates a javascript popup, we catch the event and try to JOptionPane.showConfirmDialog and the whole app locks up. Only occurs on mac.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      I wrote a sample app, run it, click the button will launch a browser page, in the browser page there is a try it button that will generate a event, click that button locks up the whole app


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      the app not to lock up and display my JOptionPane.showConfirmDialog
      ACTUAL -
      Application Locks up

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      //----------------Test.java----------------------


      import javax.swing.*;
      import java.awt.*;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;



      public class Test {

          private class MainFrame extends JFrame
          {
              JButton openWindowButton = new JButton("Click Me");

             public MainFrame(){
                super("Test Frame");
                 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                 openWindowButton.setPreferredSize(new Dimension(500,500));
                 getContentPane().add(openWindowButton, BorderLayout.CENTER);
                 pack();
                 setVisible(true);
                 openWindowButton.addActionListener(new ActionListener() {
                     public void actionPerformed(final ActionEvent ev) {
                      Viewer view = new Viewer(MainFrame.this);
                         try{
                             view.loadURL("http://www.w3schools.com/js/tryit.asp?filename=tryjs_alert");}
                         catch (Exception e){
                             System.out.println(e.getMessage());
                         }
                         view.pack();
                         view.setVisible(true);


                     }
                 });
             }

          }

          private class Viewer extends JDialog{

              private JButton closeButton = new JButton("Close");
              private Browser browser;
              public Viewer(Window owner){
                  super(owner, "Viewer", ModalityType.APPLICATION_MODAL);
                  JComponent contentView = initUI();

                  MStandardDialogPanel decoratedPane = new MStandardDialogPanel(null,
                          MStandardDialogPanel.SeparatorStyle.BOTTOM, MStandardDialogPanel.BodyPaneInsetStyle.NONE);
                  decoratedPane.setMinimumButtonWidth(new Double(100));
                  decoratedPane.addButton(closeButton,SwingConstants.CENTER);
                  decoratedPane.setBodyPane(contentView);
                  decoratedPane.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 15));
                  this.add(decoratedPane, BorderLayout.CENTER);


              }
              public void loadURL(String url){

                  try{
                      browser.loadURL(url);}
                  catch (Exception e){
                      System.out.println(e.getMessage());
                  }

              }
              private JComponent initUI() {

                  JPanel contentPane = new JPanel();
                  contentPane.setLayout(new GridBagLayout());
                  contentPane.setPreferredSize(new Dimension(800,600));
                  browser= new Browser();
                  JComponent browserPane = browser.getWebBrowserPanel();
                  contentPane.add(browserPane, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
                  return contentPane;
              }
          }

          public Test(){
              new MainFrame();
          }

          public static void main(String [] args){
              Test thisTest = new Test();

          }
      }

      //---------------- End Test.java----------------------





      //----------------Browser.java-----------------------

      import java.awt.*;
      import java.awt.event.WindowEvent;
      import java.net.MalformedURLException;
      import java.net.URL;
      import javax.swing.*;
      import javafx.application.Platform;
      import javafx.beans.value.ChangeListener;
      import javafx.beans.value.ObservableValue;
      import javafx.concurrent.Worker;
      import javafx.embed.swing.JFXPanel;
      import javafx.event.EventHandler;
      import javafx.scene.Scene;
      import javafx.scene.web.WebEngine;
      import javafx.scene.web.WebEvent;
      import javafx.scene.web.WebView;
      import javafx.util.Callback;



      public class Browser {

          private final JFXPanel jFXPanel;
          private WebEngine webEngine;

          public Browser() {

              jFXPanel = new JFXPanel();
              jFXPanel.setVisible(true);
              createScene();
              Platform.setImplicitExit(false);
          }

          private void createScene() {

              Platform.runLater(new Runnable() {
                  // The Scene must be created on the JavaFX thread
                  @Override
                  public void run() {

                      final WebView webView = new WebView();
                      webView.setContextMenuEnabled(false);
                      webEngine = webView.getEngine();

                      jFXPanel.setScene(new Scene(webView));
                  }
              });
          }
          public void loadErrorPage() {

              final String ERROR_PAGE = "<html><body><h4>Your request cannot be completed, please call support for assistance.</h4></body></html>";

              Platform.runLater(new Runnable() {
                  @Override
                  public void run() {
                      webEngine.loadContent(ERROR_PAGE);
                  }
              });
          }

          public void loadURL(final String url) throws MalformedURLException {

              final String urlExternalForm = new URL(url).toExternalForm();

              Platform.runLater(new Runnable() {

                  // Forwarded location flag (YM)
                  boolean loadedForwardedLocation = false;
                  int loadWorkerCount = 0;

                  // The URL must be loaded on the JavaFX thread
                  @Override
                  public void run() {

                      webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
                          @Override
                          public void changed(@SuppressWarnings("rawtypes") ObservableValue ov, Worker.State oldState, Worker.State newState) {
                              if (newState == Worker.State.SUCCEEDED) {

                                  // For Java 7: check whether load worker has loaded twice per single url request (YM)
                                  if(System.getProperty("java.runtime.version", "").startsWith("1.7")) {
                                      if(!loadedForwardedLocation) {
                                          loadWorkerCount++;

                                          // If so, reload current location to set corresponding view state (YM)
                                          if(loadWorkerCount == 2) {
                                              webEngine.load(webEngine.getLocation());
                                              loadedForwardedLocation = true;
                                          }
                                      }
                                  }
                              }
                              // Load error page if target location request fails (YM)
                              else if (newState == Worker.State.FAILED) {
                                  loadErrorPage();
                              }
                          }
                      });

                      // Capture and display JavaScript alert messages (YM)
                      webEngine.setOnAlert(new EventHandler<WebEvent<String>>() {
                          @Override
                          public void handle(final WebEvent<String> event) {

                                  JOptionPane.showConfirmDialog(jFXPanel, "Test");
                          }
                      });


                      if (urlExternalForm != null) {
                          webEngine.load(urlExternalForm);
                      }
                  }
              });
          }

          public JFXPanel getWebBrowserPanel() {
              return jFXPanel;
          }
          /*----------- Close window that contains this browser instance (YM)-----------*/
          private void closeBrowserContainer() {
              JDialog container = (JDialog) SwingUtilities.getWindowAncestor(jFXPanel);
              container.dispatchEvent(new WindowEvent(container, WindowEvent.WINDOW_CLOSING));
              container.dispose();
          }

      }


      //------------------End Browser.java------------------------------


      //-----------------MStandardDialogPanel.java ------------------


      import java.awt.BorderLayout;
      import java.awt.Color;
      import java.awt.Component;
      import java.awt.Dimension;
      import java.awt.FlowLayout;
      import java.awt.Font;
      import java.awt.GridBagConstraints;
      import java.awt.GridBagLayout;
      import java.awt.Insets;

      import javax.swing.AbstractButton;
      import javax.swing.BorderFactory;
      import javax.swing.JButton;
      import javax.swing.JComponent;
      import javax.swing.JLabel;
      import javax.swing.JPanel;
      import javax.swing.JSeparator;
      import javax.swing.SwingConstants;
      import javax.swing.border.Border;

      public class MStandardDialogPanel
              extends JPanel {

          public static enum SeparatorStyle {
              TOP,
              BOTTOM,
              BOTH,
              NONE
          }

          public static enum BodyPaneInsetStyle {
              NORMAL,
              WIDE,
              NONE
          }

          public static final int OUTER_PADDING_HORIZONTAL = 16;
          public static final int OUTER_PADDING_VERTICAL = 16;
          public static final Border OUTER_BORDER = BorderFactory.createEmptyBorder(
                  OUTER_PADDING_VERTICAL, OUTER_PADDING_HORIZONTAL,
                  OUTER_PADDING_VERTICAL, OUTER_PADDING_HORIZONTAL);

          private static final long serialVersionUID = 1L;
          private HeaderPane headerPane;
          private JPanel bodyPane;
          private FooterPane footerPane;

          public MStandardDialogPanel() {
              this(null, SeparatorStyle.NONE, BodyPaneInsetStyle.NORMAL);
          }

          public MStandardDialogPanel(final String titleText) {
              this(titleText, SeparatorStyle.TOP, BodyPaneInsetStyle.NORMAL);
          }

          public MStandardDialogPanel(final SeparatorStyle separatorStyle) {
              this(null, separatorStyle, BodyPaneInsetStyle.NORMAL);
          }

          public MStandardDialogPanel(final SeparatorStyle separatorStyle, final BodyPaneInsetStyle bodyPaneInsetStyle) {
              this(null, separatorStyle, bodyPaneInsetStyle);
          }

          public MStandardDialogPanel(final String titleText, final SeparatorStyle separatorStyle) {
              this(titleText, separatorStyle, BodyPaneInsetStyle.NORMAL);
          }

          public MStandardDialogPanel(final String titleText,
                                      final SeparatorStyle separatorStyle,
                                      final BodyPaneInsetStyle bodyPaneInsetStyle) {
              {
                  setLayout(new BorderLayout(0, 0));
                  setBorder(OUTER_BORDER);
                  setBackground(Color.white);

                  // do we need to add a header pane?
                  if (titleText != null || separatorStyle == SeparatorStyle.TOP ||
                          separatorStyle == SeparatorStyle.BOTH) {
                      headerPane = new HeaderPane(titleText, separatorStyle);
                      add(headerPane, BorderLayout.NORTH);
                  }

                  // always add a body and a footer pane (for the buttons)
                  bodyPane = new JPanel(new BorderLayout(0, 0));
                  bodyPane.setOpaque(false);
                  if (bodyPaneInsetStyle == BodyPaneInsetStyle.NORMAL) {
                      bodyPane.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 15));
                  } else if (bodyPaneInsetStyle == BodyPaneInsetStyle.WIDE) {
                      bodyPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
                  }

                  footerPane = new FooterPane(separatorStyle);

                  add(bodyPane, BorderLayout.CENTER);
                  add(footerPane, BorderLayout.SOUTH);
              }
          }

          public MStandardDialogPanel setTitle(String titleText) {
              if (headerPane == null) {
                  headerPane = new HeaderPane(titleText, SeparatorStyle.NONE);
                  add(headerPane, BorderLayout.NORTH);
              } else {
                  headerPane.setTitle(titleText);
              }
              return this;
          }

          public MStandardDialogPanel setBodyPane(Component bodyComponent) {
              bodyPane.add(bodyComponent);
              return this;
          }

          public MStandardDialogPanel setBodyPane(Component bodyComponent, int index) {
              bodyPane.add(bodyComponent, index);
              return this;
          }

          public MStandardDialogPanel addButton(AbstractButton button, int alignment) {
              footerPane.add(button, alignment);
              return this;
          }

          public MStandardDialogPanel addButton(AbstractButton button) {
              footerPane.add(button, SwingConstants.RIGHT);
              return this;
          }

          public MStandardDialogPanel addComponent(JComponent component, int alignment) {
              footerPane.add(component, alignment);
              return this;
          }

          public MStandardDialogPanel setMinimumButtonWidth (Double width) {
              footerPane.setMinimumButtonWidth(width);
              return this;
          }

          @Override
          public Component add(Component comp) {
              setBodyPane(comp);
              return comp;
          }

          @Override
          public Component add(Component comp, int index) {
              setBodyPane(comp, index);
              return comp;
          }


          private class HeaderPane extends JPanel {
              /**
               *
               */
              private static final long serialVersionUID = 1L;

              private JLabel titleLabel;

              private HeaderPane(final String title, final SeparatorStyle separatorStyle) {

                  setOpaque(false);

                  GridBagLayout gridBagLayout = new GridBagLayout();
                  gridBagLayout.columnWidths = new int[] { 1, 0 };
                  gridBagLayout.rowHeights = new int[] { 8, 0, 0 };
                  gridBagLayout.columnWeights = new double[] { 1.0, Double.MIN_VALUE };
                  gridBagLayout.rowWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE };
                  setLayout(gridBagLayout);


                  titleLabel = new JLabel(title);
                  titleLabel.setForeground(Color.BLACK); // CHANGE THIS
                  titleLabel.setFont(getFont().deriveFont(Font.PLAIN, getFont().getSize() * 1.5f));
                  titleLabel.setHorizontalAlignment(SwingConstants.LEFT);

                  GridBagConstraints gbc_titleLbl = new GridBagConstraints();
                  //gbc_titleLbl.ipady = 4;
                  //gbc_titleLbl.ipadx = 16;
                  gbc_titleLbl.weightx = 1.0;
                  gbc_titleLbl.fill = GridBagConstraints.BOTH;
                  gbc_titleLbl.insets = new Insets(0, 0, 7, 0);
                  gbc_titleLbl.anchor = GridBagConstraints.WEST;
                  gbc_titleLbl.gridx = 0;
                  gbc_titleLbl.gridy = 0;
                  add(titleLabel, gbc_titleLbl);

                  if (separatorStyle == SeparatorStyle.TOP || separatorStyle == SeparatorStyle.BOTH) {
                      JSeparator separator = new JSeparator();
                      separator.setForeground(Color.ORANGE);
                      GridBagConstraints gbc_separator = new GridBagConstraints();
                      gbc_separator.fill = GridBagConstraints.HORIZONTAL;
                      gbc_separator.insets = new Insets(0, 0, 7, 0);
                      gbc_separator.gridwidth = 2;
                      gbc_separator.weightx = 1.0;
                      gbc_separator.anchor = GridBagConstraints.NORTHWEST;
                      gbc_separator.gridx = 0;
                      gbc_separator.gridy = 1;
                      add(separator, gbc_separator);
                  }

              }

              public void setTitle(final String titleText) {
                  titleLabel.setText(titleText);
              }

          }


          private class FooterPane extends JPanel {
              /**
               *
               */
              private static final long serialVersionUID = 1L;

              final JPanel left;
              final JPanel center;
              final JPanel right;
              private Double minimumButtonWidth;

              private FooterPane(final SeparatorStyle separatorStyle) {

                  /*
      setLayout(new BorderLayout(0, 0));

                  if (separatorStyle == SeparatorStyle.BOTTOM || separatorStyle == SeparatorStyle.BOTH) {
      JSeparator separator = new JSeparator();
      separator.setForeground(Color.ORANGE);
      add(separator, BorderLayout.NORTH);
                  }

      add(left, BorderLayout.WEST);
      add(center, BorderLayout.CENTER);
      add(right, BorderLayout.EAST);
      left.setOpaque(false);
      right.setOpaque(false);
      center.setOpaque(false);
                  */

                  setOpaque(false);

                  GridBagLayout gridBagLayout = new GridBagLayout();
                  gridBagLayout.columnWidths = new int[] { 1, 0 };
                  gridBagLayout.rowHeights = new int[] { 0, 1, 0 };
                  gridBagLayout.columnWeights = new double[] { 1.0, Double.MIN_VALUE };
                  gridBagLayout.rowWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
                  setLayout(gridBagLayout);


                  if (separatorStyle == SeparatorStyle.BOTTOM || separatorStyle == SeparatorStyle.BOTH) {
                      JSeparator separator = new JSeparator();
                      separator.setForeground(Color.ORANGE);
                      GridBagConstraints gbc_separator = new GridBagConstraints();
                      gbc_separator.fill = GridBagConstraints.HORIZONTAL;
                      gbc_separator.insets = new Insets(7, 0, 0, 0);
                      gbc_separator.gridwidth = 2;
                      gbc_separator.weightx = 1.0;
                      gbc_separator.anchor = GridBagConstraints.SOUTHWEST;
                      gbc_separator.gridx = 0;
                      gbc_separator.gridy = 0;
                      add(separator, gbc_separator);
                  }


                  final JPanel buttonPanel = new JPanel(new BorderLayout(0, 0));
                  left = new JPanel(new FlowLayout(FlowLayout.LEFT));
                  center = new JPanel(new FlowLayout(FlowLayout.CENTER));
                  right = new JPanel(new FlowLayout(FlowLayout.RIGHT));

                  buttonPanel.setOpaque(false);
                  left.setOpaque(false);
                  right.setOpaque(false);
                  center.setOpaque(false);

                  buttonPanel.add(left, BorderLayout.WEST);
                  buttonPanel.add(center, BorderLayout.CENTER);
                  buttonPanel.add(right, BorderLayout.EAST);


                  GridBagConstraints gbc_buttonPanel = new GridBagConstraints();
                  //gbc_buttonPanel.ipady = 4;
                  //gbc_buttonPanel.ipadx = 16;
                  gbc_buttonPanel.weightx = 1.0;
                  gbc_buttonPanel.fill = GridBagConstraints.BOTH;
                  gbc_buttonPanel.insets = new Insets(7, 0, 0, 0);
                  gbc_buttonPanel.anchor = GridBagConstraints.SOUTH;
                  gbc_buttonPanel.gridx = 0;
                  gbc_buttonPanel.gridy = 1;
                  add(buttonPanel, gbc_buttonPanel);

              }

              public void add(AbstractButton button, final int alignment) {

                  // see if we need to apply a minimum width to the button
                  if (this.minimumButtonWidth != null) {

                      // if it's any other kind of button, we'll resize it here (but changing the text later
                      // might cause the button to be resized to a smaller size)
                      Dimension buttonSize = button.getPreferredSize();
                      if (buttonSize.getWidth() < this.minimumButtonWidth) {
                          buttonSize.setSize((double) this.minimumButtonWidth, buttonSize.getHeight());
                          button.setPreferredSize(buttonSize);
                      }
                  }


                  switch (alignment) {
                      case SwingConstants.LEFT:
                          left.add(button);
                          break;
                      case SwingConstants.CENTER:
                          center.add(button);
                          break;
                      case SwingConstants.RIGHT:
                          right.add(button);
                          break;
                      default:
                          break;
                  }
              }

              public void add(JComponent component, final int alignment) {

                  switch (alignment) {
                      case SwingConstants.LEFT:
                          left.add(component);
                          break;
                      case SwingConstants.CENTER:
                          center.add(component);
                          break;
                      case SwingConstants.RIGHT:
                          right.add(component);
                          break;
                      default:
                          break;
                  }
              }

              public void setMinimumButtonWidth (Double width) {
                  this.minimumButtonWidth = width;
              }

          }

         
          /**
           * Method will place find button on header of dialog.
           *
           * @param findButton
           */
          public void setFindButtonOnHeader(JButton findButton) {
              if(headerPane!=null){
                  headerPane.add(findButton);
              }
          }
      }


      //-----------------End MStandardDialogPanel.java---------------------

      ---------- END SOURCE ----------

            azvegint Alexander Zvegintsev
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: