001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.actions;
003
004import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005import static org.openstreetmap.josm.tools.I18n.tr;
006
007import java.awt.event.ActionEvent;
008import java.awt.event.KeyEvent;
009import java.util.Collection;
010import java.util.Collections;
011import java.util.List;
012
013import org.openstreetmap.josm.Main;
014import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
015import org.openstreetmap.josm.gui.layer.Layer;
016import org.openstreetmap.josm.gui.layer.OsmDataLayer;
017import org.openstreetmap.josm.gui.util.GuiHelper;
018import org.openstreetmap.josm.tools.ImageProvider;
019import org.openstreetmap.josm.tools.Shortcut;
020
021public class MergeLayerAction extends AbstractMergeAction {
022
023    public MergeLayerAction() {
024        super(tr("Merge layer"), "dialogs/mergedown",
025            tr("Merge the current layer into another layer"),
026            Shortcut.registerShortcut("system:merge", tr("Edit: {0}",
027            tr("Merge")), KeyEvent.VK_M, Shortcut.CTRL),
028            true, "action/mergelayer", true);
029        putValue("help", ht("/Action/MergeLayer"));
030    }
031
032    protected void doMerge(List<Layer> targetLayers, final Collection<Layer> sourceLayers) {
033        final Layer targetLayer = askTargetLayer(targetLayers);
034        if (targetLayer == null)
035            return;
036        Main.worker.submit(new Runnable() {
037            @Override
038            public void run() {
039                boolean layerMerged = false;
040                for (Layer sourceLayer: sourceLayers) {
041                    if (sourceLayer != null && sourceLayer != targetLayer) {
042                        if (sourceLayer instanceof OsmDataLayer && targetLayer instanceof OsmDataLayer
043                                && ((OsmDataLayer)sourceLayer).isUploadDiscouraged() != ((OsmDataLayer)targetLayer).isUploadDiscouraged()) {
044                            if (warnMergingUploadDiscouragedLayers(sourceLayer, targetLayer)) {
045                                break;
046                            }
047                        }
048                        targetLayer.mergeFrom(sourceLayer);
049                        Main.main.removeLayer(sourceLayer);
050                        layerMerged = true;
051                    }
052                }
053                if (layerMerged) {
054                    Main.map.mapView.setActiveLayer(targetLayer);
055                }
056            }
057        });
058    }
059
060    public void merge(List<Layer> sourceLayers) {
061        doMerge(sourceLayers, sourceLayers);
062    }
063
064    public void merge(Layer sourceLayer) {
065        if (sourceLayer == null)
066            return;
067        List<Layer> targetLayers = LayerListDialog.getInstance().getModel().getPossibleMergeTargets(sourceLayer);
068        if (targetLayers.isEmpty()) {
069            warnNoTargetLayersForSourceLayer(sourceLayer);
070            return;
071        }
072        doMerge(targetLayers, Collections.singleton(sourceLayer));
073    }
074
075    @Override
076    public void actionPerformed(ActionEvent e) {
077        Layer sourceLayer = Main.main.getEditLayer();
078        if (sourceLayer == null)
079            return;
080        merge(sourceLayer);
081    }
082
083    @Override
084    protected void updateEnabledState() {
085        GuiHelper.runInEDT(new Runnable() {
086            @Override
087            public void run() {
088                if (getEditLayer() == null) {
089                    setEnabled(false);
090                    return;
091                }
092                setEnabled(!LayerListDialog.getInstance().getModel().getPossibleMergeTargets(getEditLayer()).isEmpty());
093            }
094        });
095    }
096
097    /**
098     * returns true if the user wants to cancel, false if they want to continue
099     */
100    public static final boolean warnMergingUploadDiscouragedLayers(Layer sourceLayer, Layer targetLayer) {
101        return GuiHelper.warnUser(tr("Merging layers with different upload policies"),
102                "<html>" +
103                tr("You are about to merge data between layers ''{0}'' and ''{1}''.<br /><br />"+
104                        "These layers have different upload policies and should not been merged as it.<br />"+
105                        "Merging them will result to enforce the stricter policy (upload discouraged) to ''{1}''.<br /><br />"+
106                        "<b>This is not the recommended way of merging such data</b>.<br />"+
107                        "You should instead check and merge each object, one by one, by using ''<i>Merge selection</i>''.<br /><br />"+
108                        "Are you sure you want to continue?", sourceLayer.getName(), targetLayer.getName(), targetLayer.getName())+
109                "</html>",
110                ImageProvider.get("dialogs", "mergedown"), tr("Ignore this hint and merge anyway"));
111    }
112}