001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.actions;
003    
004    import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005    import static org.openstreetmap.josm.tools.I18n.tr;
006    
007    import java.awt.event.ActionEvent;
008    import java.awt.event.KeyEvent;
009    import java.util.Collection;
010    import java.util.Collections;
011    import java.util.List;
012    
013    import org.openstreetmap.josm.Main;
014    import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
015    import org.openstreetmap.josm.gui.layer.Layer;
016    import org.openstreetmap.josm.gui.layer.OsmDataLayer;
017    import org.openstreetmap.josm.gui.util.GuiHelper;
018    import org.openstreetmap.josm.tools.ImageProvider;
019    import org.openstreetmap.josm.tools.Shortcut;
020    
021    public 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.map.mapView.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        public void actionPerformed(ActionEvent e) {
076            Layer sourceLayer = Main.main.getEditLayer();
077            if (sourceLayer == null)
078                return;
079            merge(sourceLayer);
080        }
081    
082        @Override
083        protected void updateEnabledState() {
084            GuiHelper.runInEDT(new Runnable() {
085                @Override
086                public void run() {
087                    if (getEditLayer() == null) {
088                        setEnabled(false);
089                        return;
090                    }
091                    setEnabled(!LayerListDialog.getInstance().getModel().getPossibleMergeTargets(getEditLayer()).isEmpty());
092                }
093            });
094        }
095        
096        /**
097         * returns true if the user wants to cancel, false if they want to continue
098         */
099        public static final boolean warnMergingUploadDiscouragedLayers(Layer sourceLayer, Layer targetLayer) {
100            return GuiHelper.warnUser(tr("Merging layers with different upload policies"),
101                    "<html>" +
102                    tr("You are about to merge data between layers ''{0}'' and ''{1}''.<br /><br />"+
103                            "These layers have different upload policies and should not been merged as it.<br />"+
104                            "Merging them will result to enforce the stricter policy (upload discouraged) to ''{1}''.<br /><br />"+
105                            "<b>This is not the recommended way of merging such data</b>.<br />"+
106                            "You should instead check and merge each object, one by one, by using ''<i>Merge selection</i>''.<br /><br />"+
107                            "Are you sure you want to continue?", sourceLayer.getName(), targetLayer.getName(), targetLayer.getName())+
108                    "</html>",
109                    ImageProvider.get("dialogs", "mergedown"), tr("Ignore this hint and merge anyway"));
110        }
111    }