Skip to content

Commit

Permalink
See #23821: Show confirmation dialogs in the order in which the remot…
Browse files Browse the repository at this point in the history
…e control commands were sent to JOSM

git-svn-id: https://josm.openstreetmap.de/svn/trunk@19196 0c6e7542-c601-0410-84e7-c038aed88b3b
  • Loading branch information
taylor.smock committed Aug 16, 2024
1 parent eed40d1 commit eff7e35
Showing 1 changed file with 32 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Pattern;
Expand All @@ -26,6 +27,7 @@
import org.openstreetmap.josm.data.preferences.BooleanProperty;
import org.openstreetmap.josm.data.preferences.IntegerProperty;
import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.util.GuiHelper;
import org.openstreetmap.josm.io.OsmApiException;
import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
import org.openstreetmap.josm.spi.preferences.Config;
Expand All @@ -46,6 +48,8 @@ public abstract class RequestHandler {
public static final BooleanProperty LOAD_IN_NEW_LAYER = new BooleanProperty("remotecontrol.new-layer", false);
/** preference to define OSM download timeout in seconds */
public static final IntegerProperty OSM_DOWNLOAD_TIMEOUT = new IntegerProperty("remotecontrol.osm.download.timeout", 5*60);
/** A lock to ensure that messages are shown in the order the commands were sent from the server (see #23821) */
private static final ReentrantLock MESSAGE_LOCK = new ReentrantLock(true);

protected static final Pattern SPLITTER_COMMA = Pattern.compile(",\\s*");
protected static final Pattern SPLITTER_SEMIC = Pattern.compile(";\\s*");
Expand Down Expand Up @@ -97,7 +101,7 @@ public final void handle() throws RequestHandlerForbiddenException, RequestHandl
/**
* Handle a specific command sent as remote control.
* Any time-consuming operation must be performed asynchronously to avoid delaying the HTTP response.
*
* <p>
* This method of the subclass will do the real work.
*
* @throws RequestHandlerErrorException if an error occurs while processing request
Expand All @@ -108,7 +112,7 @@ public final void handle() throws RequestHandlerForbiddenException, RequestHandl
/**
* Get a specific message to ask the user for permission for the operation
* requested via remote control.
*
* <p>
* This message will be displayed to the user if the preference
* remotecontrol.always-confirm is true.
*
Expand All @@ -120,7 +124,7 @@ public final void handle() throws RequestHandlerForbiddenException, RequestHandl
* Get a PermissionPref object containing the name of a special permission
* preference to individually allow the requested operation and an error
* message to be displayed when a disabled operation is requested.
*
* <p>
* Default is not to check any special preference. Override this in a
* subclass to define permission preference and error message.
*
Expand Down Expand Up @@ -200,18 +204,33 @@ public final void checkPermission() throws RequestHandlerForbiddenException {
/* Does the user want to confirm everything?
* If yes, display specific confirmation message.
*/
if (GLOBAL_CONFIRMATION.get()) {
if (Boolean.TRUE.equals(GLOBAL_CONFIRMATION.get())) {
// Ensure dialog box does not exceed main window size
int maxWidth = (int) Math.max(200, MainApplication.getMainFrame().getWidth() * 0.6);
String message = "<html><div>" + getPermissionMessage() +
final int maxWidth = (int) Math.max(200, MainApplication.getMainFrame().getWidth() * 0.6);
final String message = "<html><div>" + getPermissionMessage() +
"<br/>" + tr("Do you want to allow this?") + "</div></html>";
JLabel label = new JLabel(message);
if (label.getPreferredSize().width > maxWidth) {
label.setText(message.replaceFirst("<div>", "<div style=\"width:" + maxWidth + "px;\">"));
final Object[] choices = {tr("Yes, always"), tr("Yes, once"), tr("No")};
final int choice;
// The ordering of the requests can be important, so we use a fair lock to ensure ordering
// Note that the EDT will be more than happy to show multiple dialogs without blocking.
try {
MESSAGE_LOCK.lock();
final Integer tChoice = GuiHelper.runInEDTAndWaitAndReturn(() -> {
final JLabel label = new JLabel(message);
if (label.getPreferredSize().width > maxWidth) {
label.setText(message.replaceFirst("<div>", "<div style=\"width:" + maxWidth + "px;\">"));
}
return JOptionPane.showOptionDialog(MainApplication.getMainFrame(), label, tr("Confirm Remote Control action"),
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, choices, choices[1]);
});
if (tChoice == null) {
// I have no clue how this would ever happen, but just in case.
throw new RequestHandlerForbiddenException(MessageFormat.format("RemoteControl: ''{0}'' forbidden due to NPE", myCommand));
}
choice = tChoice;
} finally {
MESSAGE_LOCK.unlock();
}
Object[] choices = {tr("Yes, always"), tr("Yes, once"), tr("No")};
int choice = JOptionPane.showOptionDialog(MainApplication.getMainFrame(), label, tr("Confirm Remote Control action"),
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, choices, choices[1]);
if (choice != JOptionPane.YES_OPTION && choice != JOptionPane.NO_OPTION) { // Yes/no refer to always/once
String err = MessageFormat.format("RemoteControl: ''{0}'' forbidden by user''s choice", myCommand);
throw new RequestHandlerForbiddenException(err);
Expand Down Expand Up @@ -239,7 +258,7 @@ public void setUrl(String url) throws RequestHandlerBadRequestException {
/**
* Parse the request parameters as key=value pairs.
* The result will be stored in {@code this.args}.
*
* <p>
* Can be overridden by subclass.
* @throws URISyntaxException if request URL is invalid
*/
Expand Down

0 comments on commit eff7e35

Please sign in to comment.