Skip to content

Commit

Permalink
Fixed issue 2.6.89 by calling JOptionPane in a Swing event thread (#9091
Browse files Browse the repository at this point in the history
)

* Modified EventThreadJOptionPane.showConfirmDialog to call JOptionPane and JDialog constructor in a Swing event thread if not in one presently. This fixes issue 2.6.89.

* Fixed CheckStyle issues with modified code.

Co-authored-by: Brian Kelly <bkelly1@mymail.mines.edu>
  • Loading branch information
bkelly1984 and Brian Kelly authored Apr 9, 2021
1 parent 7953dac commit 568957a
Showing 1 changed file with 49 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -211,42 +211,66 @@ public enum ConfirmDialogType {
* @return True if user confirms, false if user closes the confirmation dialog or selects no.
*/
public static boolean showConfirmDialog(
final @Nullable Component parentComponent,
final @Nullable Object message,
final @Nullable String title,
final ConfirmDialogType confirmDialogType) {

// Construct a 'JDialog' the "hard" way through a JOptionPane so that we can
// set modal to be false.
final JOptionPane optionPane =
new JOptionPane(
message, JOptionPane.QUESTION_MESSAGE, confirmDialogType.optionTypeMagicNumber);
final JDialog dialog = optionPane.createDialog(parentComponent, title);
dialog.setAlwaysOnTop(true);
if (!SwingUtilities.isEventDispatchThread()) {
dialog.setModal(false);
}
final @Nullable Component parentComponent,
final @Nullable Object message,
final @Nullable String title,
final ConfirmDialogType confirmDialogType) {

// We want to construct a 'JDialog' the "hard" way through a JOptionPane so
// that we can set modal to be false.
// Only modal dialogs are blocking. To mimic this, we use a latch to block once
// the dialog is set to visible. We use a property listener to capture the users
// confirmation choice and to unblock.
final CountDownLatch latch = new CountDownLatch(1);
final AtomicReference<Boolean> confirmation = new AtomicReference<>();
optionPane.addPropertyChangeListener(
JOptionPane.VALUE_PROPERTY,
ignored -> {
final Object selectedValue = optionPane.getValue();
confirmation.set(selectedValue != null && JOptionPane.OK_OPTION == (int) selectedValue);
latch.countDown();
dialog.dispose();
});

// Swing components must be created in Swing event threads. If we are already
// in one, dialog creation is fairly easy.
if (SwingUtilities.isEventDispatchThread()) {
final JOptionPane optionPane =
new JOptionPane(
message, JOptionPane.QUESTION_MESSAGE,
confirmDialogType.optionTypeMagicNumber);
final JDialog dialog = optionPane.createDialog(parentComponent, title);
dialog.setAlwaysOnTop(true);

optionPane.addPropertyChangeListener(
JOptionPane.VALUE_PROPERTY,
ignored -> {
final Object selectedValue = optionPane.getValue();
confirmation.set(selectedValue != null
&& JOptionPane.OK_OPTION == (int) selectedValue);
latch.countDown();
dialog.dispose();
});

// modal dialog being set to visible is blocking
dialog.setVisible(true);

// For non-Swing event threads, we must request our code be invoked and block manually
} else {
// non modal dialog set to visible is not blocking and must be done on EDT
SwingUtilities.invokeLater(() -> dialog.setVisible(true));
SwingUtilities.invokeLater(() -> {
final JOptionPane optionPane =
new JOptionPane(message, JOptionPane.QUESTION_MESSAGE,
confirmDialogType.optionTypeMagicNumber);
final JDialog dialog = optionPane.createDialog(parentComponent, title);
dialog.setAlwaysOnTop(true);
dialog.setModal(false);

optionPane.addPropertyChangeListener(
JOptionPane.VALUE_PROPERTY,
ignored -> {
final Object selectedValue = optionPane.getValue();
confirmation.set(selectedValue != null
&& JOptionPane.OK_OPTION == (int) selectedValue);
latch.countDown();
dialog.dispose();
});

// non modal dialog set to visible is not blocking and must be done on EDT
dialog.setVisible(true);
});

try {
// start blocking, wait for the dialog property event to fire to clear this latch
latch.await();
Expand Down

0 comments on commit 568957a

Please sign in to comment.