Changeset 19196 in josm


Ignore:
Timestamp:
2024-08-16T14:19:50+02:00 (3 months ago)
Author:
taylor.smock
Message:

See #23821: Show confirmation dialogs in the order in which the remote control commands were sent to JOSM

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/RequestHandler.java

    r18801 r19196  
    1414import java.util.Map;
    1515import java.util.Set;
     16import java.util.concurrent.locks.ReentrantLock;
    1617import java.util.function.Function;
    1718import java.util.function.Supplier;
     
    2728import org.openstreetmap.josm.data.preferences.IntegerProperty;
    2829import org.openstreetmap.josm.gui.MainApplication;
     30import org.openstreetmap.josm.gui.util.GuiHelper;
    2931import org.openstreetmap.josm.io.OsmApiException;
    3032import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
     
    4749    /** preference to define OSM download timeout in seconds */
    4850    public static final IntegerProperty OSM_DOWNLOAD_TIMEOUT = new IntegerProperty("remotecontrol.osm.download.timeout", 5*60);
     51    /** A lock to ensure that messages are shown in the order the commands were sent from the server (see #23821) */
     52    private static final ReentrantLock MESSAGE_LOCK = new ReentrantLock(true);
    4953
    5054    protected static final Pattern SPLITTER_COMMA = Pattern.compile(",\\s*");
     
    98102     * Handle a specific command sent as remote control.
    99103     * Any time-consuming operation must be performed asynchronously to avoid delaying the HTTP response.
    100      *
     104     * <p>
    101105     * This method of the subclass will do the real work.
    102106     *
     
    109113     * Get a specific message to ask the user for permission for the operation
    110114     * requested via remote control.
    111      *
     115     * <p>
    112116     * This message will be displayed to the user if the preference
    113117     * remotecontrol.always-confirm is true.
     
    121125     * preference to individually allow the requested operation and an error
    122126     * message to be displayed when a disabled operation is requested.
    123      *
     127     * <p>
    124128     * Default is not to check any special preference. Override this in a
    125129     * subclass to define permission preference and error message.
     
    201205         * If yes, display specific confirmation message.
    202206         */
    203         if (GLOBAL_CONFIRMATION.get()) {
     207        if (Boolean.TRUE.equals(GLOBAL_CONFIRMATION.get())) {
    204208            // Ensure dialog box does not exceed main window size
    205             int maxWidth = (int) Math.max(200, MainApplication.getMainFrame().getWidth() * 0.6);
    206             String message = "<html><div>" + getPermissionMessage() +
     209            final int maxWidth = (int) Math.max(200, MainApplication.getMainFrame().getWidth() * 0.6);
     210            final String message = "<html><div>" + getPermissionMessage() +
    207211                    "<br/>" + tr("Do you want to allow this?") + "</div></html>";
    208             JLabel label = new JLabel(message);
    209             if (label.getPreferredSize().width > maxWidth) {
    210                 label.setText(message.replaceFirst("<div>", "<div style=\"width:" + maxWidth + "px;\">"));
     212            final Object[] choices = {tr("Yes, always"), tr("Yes, once"), tr("No")};
     213            final int choice;
     214            // The ordering of the requests can be important, so we use a fair lock to ensure ordering
     215            // Note that the EDT will be more than happy to show multiple dialogs without blocking.
     216            try {
     217                MESSAGE_LOCK.lock();
     218                final Integer tChoice = GuiHelper.runInEDTAndWaitAndReturn(() -> {
     219                    final JLabel label = new JLabel(message);
     220                    if (label.getPreferredSize().width > maxWidth) {
     221                        label.setText(message.replaceFirst("<div>", "<div style=\"width:" + maxWidth + "px;\">"));
     222                    }
     223                    return JOptionPane.showOptionDialog(MainApplication.getMainFrame(), label, tr("Confirm Remote Control action"),
     224                            JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, choices, choices[1]);
     225                });
     226                if (tChoice == null) {
     227                    // I have no clue how this would ever happen, but just in case.
     228                    throw new RequestHandlerForbiddenException(MessageFormat.format("RemoteControl: ''{0}'' forbidden due to NPE", myCommand));
     229                }
     230                choice = tChoice;
     231            } finally {
     232                MESSAGE_LOCK.unlock();
    211233            }
    212             Object[] choices = {tr("Yes, always"), tr("Yes, once"), tr("No")};
    213             int choice = JOptionPane.showOptionDialog(MainApplication.getMainFrame(), label, tr("Confirm Remote Control action"),
    214                     JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, choices, choices[1]);
    215234            if (choice != JOptionPane.YES_OPTION && choice != JOptionPane.NO_OPTION) { // Yes/no refer to always/once
    216235                String err = MessageFormat.format("RemoteControl: ''{0}'' forbidden by user''s choice", myCommand);
     
    240259     * Parse the request parameters as key=value pairs.
    241260     * The result will be stored in {@code this.args}.
    242      *
     261     * <p>
    243262     * Can be overridden by subclass.
    244263     * @throws URISyntaxException if request URL is invalid
Note: See TracChangeset for help on using the changeset viewer.