Changeset 7204 in josm for trunk/src


Ignore:
Timestamp:
2014-06-01T14:07:18+02:00 (6 years ago)
Author:
Don-vip
Message:

fix #10086 - fix EDT violation causing freeze of Save/upload dialog for empty or conflicting layers

Location:
trunk/src/org/openstreetmap/josm
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java

    r7026 r7204  
    5656    }
    5757
    58     public static boolean doSave(Layer layer, File file) {
    59         if(!layer.checkSaveConditions())
     58    /**
     59     * Saves a layer to a given file.
     60     * @param layer The layer to save
     61     * @param file The destination file
     62     * @param checkSaveConditions if {@code true}, checks preconditions before saving. Set it to {@code false} to skip it
     63     * if preconditions have already been checked (as this check can prompt UI dialog in EDT it may be best in some cases
     64     * to do it earlier).
     65     * @return {@code true} if the layer has been successfully saved, {@code false} otherwise
     66     * @since 7204
     67     */
     68    public static boolean doSave(Layer layer, File file, boolean checkSaveConditions) {
     69        if (checkSaveConditions && !layer.checkSaveConditions())
    6070            return false;
    6171        return doInternalSave(layer, file);
  • trunk/src/org/openstreetmap/josm/gui/io/SaveLayerInfo.java

    r6084 r7204  
    1616    /** the osm data layer */
    1717    private OsmDataLayer layer;
     18    private boolean doCheckSaveConditions;
    1819    private boolean doSaveToFile;
    1920    private boolean doUploadToServer;
     
    2324
    2425    /**
    25      *
     26     * Constructs a new {@code SaveLayerInfo}.
    2627     * @param layer the layer. Must not be null.
    2728     * @throws IllegalArgumentException thrown if layer is null
     
    3031        CheckParameterUtil.ensureParameterNotNull(layer, "layer");
    3132        this.layer = layer;
     33        this.doCheckSaveConditions = true;
    3234        this.doSaveToFile = layer.requiresSaveToFile();
    3335        this.doUploadToServer = layer.requiresUploadToServer() && !layer.isUploadDiscouraged();
     
    4244    public OsmDataLayer getLayer() {
    4345        return layer;
     46    }
     47
     48    /**
     49     * Replies true if preconditions should be checked before saving; false, otherwise
     50     *
     51     * @return true if preconditions should be checked before saving; false, otherwise
     52     * @since 7204
     53     */
     54    public boolean isDoCheckSaveConditions() {
     55        return doCheckSaveConditions;
     56    }
     57
     58    /**
     59     * Sets whether preconditions should be checked before saving
     60     *
     61     * @param doCheckSaveConditions true to check save preconditions; false, to skip checking
     62     * @since 7204
     63     */
     64    public void setDoCheckSaveConditions(boolean doCheckSaveConditions) {
     65        this.doCheckSaveConditions = doCheckSaveConditions;
    4466    }
    4567
  • trunk/src/org/openstreetmap/josm/gui/io/SaveLayerTask.java

    r6830 r7204  
    4949        try {
    5050            parentMonitor.subTask(tr("Saving layer to ''{0}'' ...", layerInfo.getFile().toString()));
    51             if (!SaveAction.doSave(layerInfo.getLayer(), layerInfo.getFile())) {
     51            if (!SaveAction.doSave(layerInfo.getLayer(), layerInfo.getFile(), layerInfo.isDoCheckSaveConditions())) {
    5252                setFailed(true);
    5353                return;
  • trunk/src/org/openstreetmap/josm/gui/io/SaveLayersDialog.java

    r7029 r7204  
    506506                    continue;
    507507                }
    508                 currentTask= new SaveLayerTask(layerInfo, monitor);
     508                // Check save preconditions earlier to avoid a blocking reentring call to EDT (see #10086)
     509                if (layerInfo.isDoCheckSaveConditions()) {
     510                    if (!layerInfo.getLayer().checkSaveConditions()) {
     511                        continue;
     512                    }
     513                    layerInfo.setDoCheckSaveConditions(false);
     514                }
     515                currentTask = new SaveLayerTask(layerInfo, monitor);
    509516                currentFuture = worker.submit(currentTask);
    510517
  • trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

    r7026 r7204  
    11// License: GPL. See LICENSE file for details.
    2 
    32package org.openstreetmap.josm.gui.layer;
    43
     
    2827import java.util.List;
    2928import java.util.Map;
     29import java.util.concurrent.Callable;
    3030import java.util.concurrent.CopyOnWriteArrayList;
    3131
     
    7878import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
    7979import org.openstreetmap.josm.gui.progress.ProgressMonitor;
     80import org.openstreetmap.josm.gui.util.GuiHelper;
    8081import org.openstreetmap.josm.gui.widgets.JosmTextArea;
    8182import org.openstreetmap.josm.tools.DateUtils;
     
    750751    public boolean checkSaveConditions() {
    751752        if (isDataSetEmpty()) {
    752             ExtendedDialog dialog = new ExtendedDialog(
    753                     Main.parent,
    754                     tr("Empty document"),
    755                     new String[] {tr("Save anyway"), tr("Cancel")}
    756             );
    757             dialog.setContent(tr("The document contains no data."));
    758             dialog.setButtonIcons(new String[] {"save.png", "cancel.png"});
    759             dialog.showDialog();
    760             if (dialog.getValue() != 1) return false;
     753            if (1 != GuiHelper.runInEDTAndWaitAndReturn(new Callable<Integer>() {
     754                @Override
     755                public Integer call() {
     756                    ExtendedDialog dialog = new ExtendedDialog(
     757                            Main.parent,
     758                            tr("Empty document"),
     759                            new String[] {tr("Save anyway"), tr("Cancel")}
     760                    );
     761                    dialog.setContent(tr("The document contains no data."));
     762                    dialog.setButtonIcons(new String[] {"save.png", "cancel.png"});
     763                    return dialog.showDialog().getValue();
     764                }
     765            })) {
     766                return false;
     767            }
    761768        }
    762769
    763770        ConflictCollection conflicts = getConflicts();
    764771        if (conflicts != null && !conflicts.isEmpty()) {
    765             ExtendedDialog dialog = new ExtendedDialog(
    766                     Main.parent,
    767                     /* I18N: Display title of the window showing conflicts */
    768                     tr("Conflicts"),
    769                     new String[] {tr("Reject Conflicts and Save"), tr("Cancel")}
    770             );
    771             dialog.setContent(tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"));
    772             dialog.setButtonIcons(new String[] {"save.png", "cancel.png"});
    773             dialog.showDialog();
    774             if (dialog.getValue() != 1) return false;
     772            if (1 != GuiHelper.runInEDTAndWaitAndReturn(new Callable<Integer>() {
     773                @Override
     774                public Integer call() {
     775                    ExtendedDialog dialog = new ExtendedDialog(
     776                            Main.parent,
     777                            /* I18N: Display title of the window showing conflicts */
     778                            tr("Conflicts"),
     779                            new String[] {tr("Reject Conflicts and Save"), tr("Cancel")}
     780                    );
     781                    dialog.setContent(tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"));
     782                    dialog.setButtonIcons(new String[] {"save.png", "cancel.png"});
     783                    return dialog.showDialog().getValue();
     784                }
     785            })) {
     786                return false;
     787            }
    775788        }
    776789        return true;
  • trunk/src/org/openstreetmap/josm/gui/util/GuiHelper.java

    r7004 r7204  
    2222import java.util.Arrays;
    2323import java.util.List;
     24import java.util.concurrent.Callable;
     25import java.util.concurrent.ExecutionException;
     26import java.util.concurrent.FutureTask;
    2427
    2528import javax.swing.GrayFilter;
     
    6871    }
    6972
     73    /**
     74     * Executes asynchronously a runnable in
     75     * <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html">Event Dispatch Thread</a>.
     76     * @param task The runnable to execute
     77     * @see SwingUtilities#invokeLater
     78     */
    7079    public static void runInEDT(Runnable task) {
    7180        if (SwingUtilities.isEventDispatchThread()) {
     
    7685    }
    7786
     87    /**
     88     * Executes synchronously a runnable in
     89     * <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html">Event Dispatch Thread</a>.
     90     * @param task The runnable to execute
     91     * @see SwingUtilities#invokeAndWait
     92     */
    7893    public static void runInEDTAndWait(Runnable task) {
    7994        if (SwingUtilities.isEventDispatchThread()) {
     
    8499            } catch (InterruptedException | InvocationTargetException e) {
    85100                Main.error(e);
     101            }
     102        }
     103    }
     104
     105    /**
     106     * Executes synchronously a callable in
     107     * <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html">Event Dispatch Thread</a>
     108     * and return a value.
     109     * @param callable The callable to execute
     110     * @return The computed result
     111     * @since 7204
     112     */
     113    public static <V> V runInEDTAndWaitAndReturn(Callable<V> callable) {
     114        if (SwingUtilities.isEventDispatchThread()) {
     115            try {
     116                return callable.call();
     117            } catch (Exception e) {
     118                Main.error(e);
     119                return null;
     120            }
     121        } else {
     122            FutureTask<V> task = new FutureTask<V>(callable);
     123            SwingUtilities.invokeLater(task);
     124            try {
     125                return task.get();
     126            } catch (InterruptedException | ExecutionException e) {
     127                Main.error(e);
     128                return null;
    86129            }
    87130        }
Note: See TracChangeset for help on using the changeset viewer.