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 021/** 022 * Action that merges two or more OSM data layers. 023 * @since 1890 024 */ 025public class MergeLayerAction extends AbstractMergeAction { 026 027 /** 028 * Constructs a new {@code MergeLayerAction}. 029 */ 030 public MergeLayerAction() { 031 super(tr("Merge layer"), "dialogs/mergedown", 032 tr("Merge the current layer into another layer"), 033 Shortcut.registerShortcut("system:merge", tr("Edit: {0}", 034 tr("Merge")), KeyEvent.VK_M, Shortcut.CTRL), 035 true, "action/mergelayer", true); 036 putValue("help", ht("/Action/MergeLayer")); 037 } 038 039 protected void doMerge(List<Layer> targetLayers, final Collection<Layer> sourceLayers) { 040 final Layer targetLayer = askTargetLayer(targetLayers); 041 if (targetLayer == null) 042 return; 043 Main.worker.submit(new Runnable() { 044 @Override 045 public void run() { 046 boolean layerMerged = false; 047 for (final Layer sourceLayer: sourceLayers) { 048 if (sourceLayer != null && sourceLayer != targetLayer) { 049 if (sourceLayer instanceof OsmDataLayer && targetLayer instanceof OsmDataLayer 050 && ((OsmDataLayer)sourceLayer).isUploadDiscouraged() != ((OsmDataLayer)targetLayer).isUploadDiscouraged()) { 051 if (warnMergingUploadDiscouragedLayers(sourceLayer, targetLayer)) { 052 break; 053 } 054 } 055 targetLayer.mergeFrom(sourceLayer); 056 GuiHelper.runInEDTAndWait(new Runnable() { 057 @Override 058 public void run() { 059 Main.main.removeLayer(sourceLayer); 060 } 061 }); 062 layerMerged = true; 063 } 064 } 065 if (layerMerged) { 066 Main.map.mapView.setActiveLayer(targetLayer); 067 } 068 } 069 }); 070 } 071 072 /** 073 * Merges a list of layers together. 074 * @param sourceLayers The layers to merge 075 */ 076 public void merge(List<Layer> sourceLayers) { 077 doMerge(sourceLayers, sourceLayers); 078 } 079 080 /** 081 * Merges the given source layer with another one, determined at runtime. 082 * @param sourceLayer The source layer to merge 083 */ 084 public void merge(Layer sourceLayer) { 085 if (sourceLayer == null) 086 return; 087 List<Layer> targetLayers = LayerListDialog.getInstance().getModel().getPossibleMergeTargets(sourceLayer); 088 if (targetLayers.isEmpty()) { 089 warnNoTargetLayersForSourceLayer(sourceLayer); 090 return; 091 } 092 doMerge(targetLayers, Collections.singleton(sourceLayer)); 093 } 094 095 @Override 096 public void actionPerformed(ActionEvent e) { 097 Layer sourceLayer = Main.main.getEditLayer(); 098 if (sourceLayer == null) 099 return; 100 merge(sourceLayer); 101 } 102 103 @Override 104 protected void updateEnabledState() { 105 GuiHelper.runInEDT(new Runnable() { 106 @Override 107 public void run() { 108 if (getEditLayer() == null) { 109 setEnabled(false); 110 return; 111 } 112 setEnabled(!LayerListDialog.getInstance().getModel().getPossibleMergeTargets(getEditLayer()).isEmpty()); 113 } 114 }); 115 } 116 117 /** 118 * Warns about a discouraged merge operation, ask for confirmation. 119 * @param sourceLayer The source layer 120 * @param targetLayer The target layer 121 * @return {@code true} if the user wants to cancel, {@code false} if they want to continue 122 */ 123 public static final boolean warnMergingUploadDiscouragedLayers(Layer sourceLayer, Layer targetLayer) { 124 return GuiHelper.warnUser(tr("Merging layers with different upload policies"), 125 "<html>" + 126 tr("You are about to merge data between layers ''{0}'' and ''{1}''.<br /><br />"+ 127 "These layers have different upload policies and should not been merged as it.<br />"+ 128 "Merging them will result to enforce the stricter policy (upload discouraged) to ''{1}''.<br /><br />"+ 129 "<b>This is not the recommended way of merging such data</b>.<br />"+ 130 "You should instead check and merge each object, one by one, by using ''<i>Merge selection</i>''.<br /><br />"+ 131 "Are you sure you want to continue?", sourceLayer.getName(), targetLayer.getName(), targetLayer.getName())+ 132 "</html>", 133 ImageProvider.get("dialogs", "mergedown"), tr("Ignore this hint and merge anyway")); 134 } 135}