// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.utilsplugin2.actions; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Predicate; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.actions.JosmAction; import org.openstreetmap.josm.command.ChangePropertyCommand; import org.openstreetmap.josm.command.Command; import org.openstreetmap.josm.command.SequenceCommand; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.tools.Shortcut; import org.openstreetmap.josm.tools.SubclassFilteredCollection; /** * Remembers tags of selected object(s) and when clicked, pastes them onto selection. * * @author Zverik */ public class TagBufferAction extends JosmAction { private static final String TITLE = tr("Copy tags from previous selection"); private static final Predicate<OsmPrimitive> IS_TAGGED_PREDICATE = object -> object.isTagged(); private Map<String, String> tags = new HashMap<>(); private Map<String, String> currentTags = new HashMap<>(); private Set<OsmPrimitive> selectionBuf = new HashSet<>(); /** * Constructs a new {@code TagBufferAction}. */ public TagBufferAction() { super(TITLE, "dumbutils/tagbuffer", tr("Pastes tags of previously selected object(s)"), Shortcut.registerShortcut("tools:tagbuffer", tr("Tool: {0}", tr("Copy tags from previous selection")), KeyEvent.VK_R, Shortcut.SHIFT), true, false); // The fields are not initialized while the super constructor is running, so we have to call this afterwards: installAdapters(); } @Override public void actionPerformed(ActionEvent e) { Collection<OsmPrimitive> selection = getLayerManager().getEditDataSet().getSelected(); if (selection.isEmpty()) return; List<Command> commands = new ArrayList<>(); for (String key : tags.keySet()) { String value = tags.get(key); boolean foundNew = false; for (OsmPrimitive p : selection) { if (!p.hasKey(key) || !p.get(key).equals(value)) { foundNew = true; break; } } if (foundNew) commands.add(new ChangePropertyCommand(selection, key, value)); } if (!commands.isEmpty()) Main.main.undoRedo.add(new SequenceCommand(TITLE, commands)); } @Override protected void updateEnabledState() { if (getLayerManager().getEditDataSet() == null) { setEnabled(false); if (selectionBuf != null) selectionBuf.clear(); } else updateEnabledState(getLayerManager().getEditDataSet().getSelected()); } @Override protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) { // selection changed => check if selection is completely different from before boolean foundOld = false; if (selection != null) { for (OsmPrimitive p : selectionBuf) { if (selection.contains(p)) { foundOld = true; break; } } selectionBuf.clear(); selectionBuf.addAll(selection); } else { foundOld = selectionBuf.isEmpty(); selectionBuf.clear(); } if (!foundOld) { // selection has completely changed, remember tags tags.clear(); tags.putAll(currentTags); } if (getLayerManager().getEditDataSet() != null) rememberSelectionTags(); setEnabled(selection != null && !selection.isEmpty() && !tags.isEmpty()); } private void rememberSelectionTags() { // Fix #8350 - only care about tagged objects final Collection<OsmPrimitive> selectedTaggedObjects = SubclassFilteredCollection.filter( getLayerManager().getEditDataSet().getSelected(), IS_TAGGED_PREDICATE); if (!selectedTaggedObjects.isEmpty()) { currentTags.clear(); Set<String> bad = new HashSet<>(); for (OsmPrimitive p : selectedTaggedObjects) { if (currentTags.isEmpty()) { for (String key : p.keySet()) { currentTags.put(key, p.get(key)); } } else { for (String key : p.keySet()) { if (!currentTags.containsKey(key) || !currentTags.get(key).equals(p.get(key))) bad.add(key); } for (String key : currentTags.keySet()) { if (!p.hasKey(key)) bad.add(key); } } } for (String key : bad) { currentTags.remove(key); } } } }