source: josm/trunk/src/org/openstreetmap/josm/actions/MergeLayerAction.java @ 11848

Last change on this file since 11848 was 11848, checked in by Don-vip, 2 years ago

fix #14613 - Special HTML characters not escaped in GUI error messages

  • Property svn:eol-style set to native
File size: 6.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.event.ActionEvent;
8import java.awt.event.KeyEvent;
9import java.util.Collection;
10import java.util.Collections;
11import java.util.List;
12
13import org.openstreetmap.josm.Main;
14import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
15import org.openstreetmap.josm.gui.layer.Layer;
16import org.openstreetmap.josm.gui.layer.OsmDataLayer;
17import org.openstreetmap.josm.gui.util.GuiHelper;
18import org.openstreetmap.josm.tools.ImageProvider;
19import org.openstreetmap.josm.tools.Shortcut;
20import org.openstreetmap.josm.tools.Utils;
21
22/**
23 * Action that merges two or more OSM data layers.
24 * @since 1890
25 */
26public class MergeLayerAction extends AbstractMergeAction {
27
28    /**
29     * Constructs a new {@code MergeLayerAction}.
30     */
31    public MergeLayerAction() {
32        super(tr("Merge layer"), "dialogs/mergedown",
33            tr("Merge the current layer into another layer"),
34            Shortcut.registerShortcut("system:merge", tr("Edit: {0}",
35            tr("Merge")), KeyEvent.VK_M, Shortcut.CTRL),
36            true, "action/mergelayer", true);
37        putValue("help", ht("/Action/MergeLayer"));
38    }
39
40    protected void doMerge(List<Layer> targetLayers, final Collection<Layer> sourceLayers) {
41        final Layer targetLayer = askTargetLayer(targetLayers);
42        if (targetLayer == null)
43            return;
44        final Object actionName = getValue(NAME);
45        Main.worker.submit(() -> {
46                final long start = System.currentTimeMillis();
47                boolean layerMerged = false;
48                for (final Layer sourceLayer: sourceLayers) {
49                    if (sourceLayer != null && !sourceLayer.equals(targetLayer)) {
50                        if (sourceLayer instanceof OsmDataLayer && targetLayer instanceof OsmDataLayer
51                                && ((OsmDataLayer) sourceLayer).isUploadDiscouraged() != ((OsmDataLayer) targetLayer).isUploadDiscouraged()
52                                && Boolean.TRUE.equals(GuiHelper.runInEDTAndWaitAndReturn(() ->
53                                    warnMergingUploadDiscouragedLayers(sourceLayer, targetLayer)))) {
54                            break;
55                        }
56                        targetLayer.mergeFrom(sourceLayer);
57                        GuiHelper.runInEDTAndWait(() -> Main.getLayerManager().removeLayer(sourceLayer));
58                        layerMerged = true;
59                    }
60                }
61                if (layerMerged) {
62                    Main.getLayerManager().setActiveLayer(targetLayer);
63                    Main.info(tr("{0} completed in {1}", actionName, Utils.getDurationString(System.currentTimeMillis() - start)));
64                }
65        });
66    }
67
68    /**
69     * Merges a list of layers together.
70     * @param sourceLayers The layers to merge
71     */
72    public void merge(List<Layer> sourceLayers) {
73        doMerge(sourceLayers, sourceLayers);
74    }
75
76    /**
77     * Merges the given source layer with another one, determined at runtime.
78     * @param sourceLayer The source layer to merge
79     */
80    public void merge(Layer sourceLayer) {
81        if (sourceLayer == null)
82            return;
83        List<Layer> targetLayers = LayerListDialog.getInstance().getModel().getPossibleMergeTargets(sourceLayer);
84        if (targetLayers.isEmpty()) {
85            warnNoTargetLayersForSourceLayer(sourceLayer);
86            return;
87        }
88        doMerge(targetLayers, Collections.singleton(sourceLayer));
89    }
90
91    @Override
92    public void actionPerformed(ActionEvent e) {
93        merge(getSourceLayer());
94    }
95
96    @Override
97    protected void updateEnabledState() {
98        GuiHelper.runInEDT(() -> {
99                final Layer sourceLayer = getSourceLayer();
100                if (sourceLayer == null) {
101                    setEnabled(false);
102                } else {
103                    try {
104                        setEnabled(!LayerListDialog.getInstance().getModel().getPossibleMergeTargets(sourceLayer).isEmpty());
105                    } catch (IllegalStateException e) {
106                        // May occur when destroying last layer / exiting JOSM, see #14476
107                        setEnabled(false);
108                        Main.error(e);
109                    }
110                }
111        });
112    }
113
114    protected Layer getSourceLayer() {
115        return Main.map != null ? Main.getLayerManager().getActiveLayer() : null;
116    }
117
118    /**
119     * Warns about a discouraged merge operation, ask for confirmation.
120     * @param sourceLayer The source layer
121     * @param targetLayer The target layer
122     * @return {@code true} if the user wants to cancel, {@code false} if they want to continue
123     */
124    public static final boolean warnMergingUploadDiscouragedLayers(Layer sourceLayer, Layer targetLayer) {
125        return GuiHelper.warnUser(tr("Merging layers with different upload policies"),
126                "<html>" +
127                tr("You are about to merge data between layers ''{0}'' and ''{1}''.<br /><br />"+
128                        "These layers have different upload policies and should not been merged as it.<br />"+
129                        "Merging them will result to enforce the stricter policy (upload discouraged) to ''{1}''.<br /><br />"+
130                        "<b>This is not the recommended way of merging such data</b>.<br />"+
131                        "You should instead check and merge each object, one by one, by using ''<i>Merge selection</i>''.<br /><br />"+
132                        "Are you sure you want to continue?",
133                        Utils.escapeReservedCharactersHTML(sourceLayer.getName()),
134                        Utils.escapeReservedCharactersHTML(targetLayer.getName()),
135                        Utils.escapeReservedCharactersHTML(targetLayer.getName()))+
136                "</html>",
137                ImageProvider.get("dialogs", "mergedown"), tr("Ignore this hint and merge anyway"));
138    }
139}
Note: See TracBrowser for help on using the repository browser.