Changeset 18849 in josm


Ignore:
Timestamp:
2023-10-03T17:20:32+02:00 (17 months ago)
Author:
taylor.smock
Message:

Fix #16485: Modal dialogs may occasionally be behind another dialog

From the Modality javadocs:

  • keeps its Z-order below the modal dialog that blocks it

Warning! Some window managers allow users to change the window Z-order in an arbitrary way — in that case the last requirement may not be met.

The workaround is to set the blocking dialog as always on top.

Location:
trunk/src/org/openstreetmap/josm/gui
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/ConditionalOptionPaneUtil.java

    r14380 r18849  
    55
    66import java.awt.Component;
     7import java.awt.Dialog;
    78import java.awt.GridBagLayout;
    89import java.util.HashMap;
     
    1516import javax.swing.JPanel;
    1617import javax.swing.JRadioButton;
     18import javax.swing.event.AncestorEvent;
     19import javax.swing.event.AncestorListener;
    1720
    1821import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
     
    2427 * ConditionalOptionPaneUtil provides static utility methods for displaying modal message dialogs
    2528 * which can be enabled/disabled by the user.
    26  *
     29 * <p>
    2730 * They wrap the methods provided by {@link JOptionPane}. Within JOSM you should use these
    2831 * methods rather than the bare methods from {@link JOptionPane} because the methods provided
     
    9396     * It is always on top even if there are other open windows like detached dialogs,
    9497     * relation editors, history browsers and the like.
    95      *
     98     * <p>
    9699     * Set <code>optionType</code> to {@link JOptionPane#YES_NO_OPTION} for a dialog with a YES and
    97100     * a NO button.
    98 
     101     * <p>
    99102     * Set <code>optionType</code> to {@link JOptionPane#YES_NO_CANCEL_OPTION} for a dialog with a YES,
    100103     * a NO and a CANCEL button
    101      *
     104     * <p>
    102105     * Returns one of the constants JOptionPane.YES_OPTION, JOptionPane.NO_OPTION,
    103106     * JOptionPane.CANCEL_OPTION or JOptionPane.CLOSED_OPTION depending on the action chosen by
     
    133136     * It is always on top even if there are other open windows like detached dialogs,
    134137     * relation editors, history browsers and the like.
    135      *
     138     * <p>
    136139     * Set <code>optionType</code> to {@link JOptionPane#YES_NO_OPTION} for a dialog with a YES and
    137140     * a NO button.
    138 
     141     * <p>
    139142     * Set <code>optionType</code> to {@link JOptionPane#YES_NO_CANCEL_OPTION} for a dialog with a YES,
    140143     * a NO and a CANCEL button
    141      *
     144     * <p>
    142145     * Replies true, if the selected option is equal to <code>trueOption</code>, otherwise false.
    143146     * Replies true, if the dialog is not displayed because the respective preference option
     
    181184     * is always on top even if there are other open windows like detached dialogs,
    182185     * relation editors, history browsers and the like.
    183      *
     186     * <p>
    184187     * If there is a preference with key <code>preferenceKey</code> and value <code>false</code>
    185188     * the dialog is not show.
     
    284287            }
    285288            add(cbStandard, GBC.eol());
     289
     290            this.addAncestorListener(new AncestorListener() {
     291                boolean wasAlwaysOnTop;
     292                @Override
     293                public void ancestorAdded(AncestorEvent event) {
     294                    if (event.getAncestor() instanceof Dialog) {
     295                        Dialog dialog = (Dialog) event.getAncestor();
     296                        wasAlwaysOnTop = dialog.isAlwaysOnTop();
     297                        if (dialog.isVisible() && dialog.isModal()) {
     298                            dialog.setAlwaysOnTop(true);
     299                        }
     300                    }
     301                }
     302
     303                @Override
     304                public void ancestorRemoved(AncestorEvent event) {
     305                    if (event.getAncestor() instanceof Dialog) {
     306                        Dialog dialog = (Dialog) event.getAncestor();
     307                        if (dialog.isVisible() && dialog.isModal()) {
     308                            dialog.setAlwaysOnTop(wasAlwaysOnTop);
     309                        }
     310                    }
     311                }
     312
     313                @Override
     314                public void ancestorMoved(AncestorEvent event) {
     315                    // Do nothing
     316                }
     317            });
    286318        }
    287319
  • trunk/src/org/openstreetmap/josm/gui/ExtendedDialog.java

    r18211 r18849  
    460460            }
    461461        }
     462        if (visible && isModal()) {
     463            this.setAlwaysOnTop(true);
     464        }
    462465        super.setVisible(visible);
    463466
  • trunk/src/org/openstreetmap/josm/gui/HelpAwareOptionPane.java

    r16217 r18849  
    219219     * user clicks on the "Help" button the option dialog remains open and JOSM launches the help
    220220     * browser.
    221      *
     221     * <p>
    222222     * <code>helpTopic</code> is the trailing part of a JOSM online help URL, i.e. the part after the leading
    223      * <code>https://josm.openstreetmap.de/wiki/Help</code>. It should start with a leading '/' and it
     223     * {@code https://josm.openstreetmap.de/wiki/Help}. It should start with a leading '/' and it
    224224     * may include an anchor after a '#'.
    225      *
     225     * <p>
    226226     * <strong>Examples</strong>
    227227     * <ul>
     
    351351            HelpUtil.setHelpContext(dialog.getRootPane(), helpTopic);
    352352        }
     353        if (dialog.isModal()) {
     354            dialog.setAlwaysOnTop(true);
     355        }
    353356        dialog.setVisible(true);
    354357    }
     
    372375     * Run it in Event Dispatch Thread.
    373376     * This version does not return anything, so it is more like {@code showMessageDialog}.
    374      *
     377     * <p>
    375378     * It can be used, when you need to show a message dialog from a worker thread,
    376379     * e.g. from {@code PleaseWaitRunnable}.
Note: See TracChangeset for help on using the changeset viewer.