Ticket #12478: patch-patch-ccp-primitives-copy-no-layers.patch
File patch-patch-ccp-primitives-copy-no-layers.patch, 162.3 KB (added by , 8 years ago) |
---|
-
src/org/openstreetmap/josm/Main.java
diff --git a/src/org/openstreetmap/josm/Main.java b/src/org/openstreetmap/josm/Main.java index 09e5a10..93ace13 100644
a b import org.openstreetmap.josm.gui.MainMenu; 83 83 import org.openstreetmap.josm.gui.MainPanel; 84 84 import org.openstreetmap.josm.gui.MapFrame; 85 85 import org.openstreetmap.josm.gui.MapFrameListener; 86 import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler; 86 87 import org.openstreetmap.josm.gui.help.HelpUtil; 87 88 import org.openstreetmap.josm.gui.io.SaveLayersDialog; 88 89 import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer; … … public abstract class Main { 177 178 178 179 /** 179 180 * The global paste buffer. 181 * @deprecated Use swing CCP instead. See {@link OsmTransferHandler} 180 182 */ 183 @Deprecated 181 184 public static final PrimitiveDeepCopy pasteBuffer = new PrimitiveDeepCopy(); 182 185 183 186 /** 184 187 * The layer source from which {@link Main#pasteBuffer} data comes from. 188 * @deprecated During a copy operation, the layer should be added. See {@link OsmLayerTransferData}. 185 189 */ 190 @Deprecated 186 191 public static Layer pasteSource; 187 192 188 193 /** -
src/org/openstreetmap/josm/actions/CopyAction.java
diff --git a/src/org/openstreetmap/josm/actions/CopyAction.java b/src/org/openstreetmap/josm/actions/CopyAction.java index 6db64bf..e509506 100644
a b import static org.openstreetmap.josm.tools.I18n.tr; 8 8 import java.awt.event.ActionEvent; 9 9 import java.awt.event.KeyEvent; 10 10 import java.util.Collection; 11 import java.util.Collections; 11 12 12 13 import javax.swing.JOptionPane; 13 14 14 15 import org.openstreetmap.josm.Main; 16 import org.openstreetmap.josm.data.osm.DataSet; 15 17 import org.openstreetmap.josm.data.osm.OsmPrimitive; 16 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 18 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 19 import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable; 20 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 17 21 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 18 22 import org.openstreetmap.josm.tools.Shortcut; 19 import org.openstreetmap.josm.tools.Utils;20 23 21 24 /** 22 25 * Copy OSM primitives to clipboard in order to paste them, or their tags, somewhere else. 23 26 * @since 404 24 27 */ 25 public final class CopyAction extends JosmAction { 26 27 /** regular expression that matches text clipboard contents after copying */ 28 public static final String CLIPBOARD_REGEXP = "((node|way|relation)\\s\\d+,)*(node|way|relation)\\s\\d+"; 29 28 public class CopyAction extends JosmAction { 30 29 /** 31 30 * Constructs a new {@code CopyAction}. 32 31 */ … … public final class CopyAction extends JosmAction { 42 41 43 42 @Override 44 43 public void actionPerformed(ActionEvent e) { 45 if (isEmptySelection()) return; 46 Collection<OsmPrimitive> selection = getLayerManager().getEditDataSet().getSelected(); 44 DataSet set = getLayerManager().getEditDataSet(); 45 Collection<OsmPrimitive> selection = set == null ? Collections.<OsmPrimitive>emptySet() : set.getSelected(); 46 if (selection.isEmpty()) { 47 showEmptySelectionWarning(); 48 return; 49 } 47 50 48 51 copy(getLayerManager().getEditLayer(), selection); 49 52 } … … public final class CopyAction extends JosmAction { 56 59 */ 57 60 public static void copy(OsmDataLayer source, Collection<OsmPrimitive> primitives) { 58 61 // copy ids to the clipboard 59 String ids = getCopyString(primitives); 60 Utils.copyToClipboard(ids); 61 62 Main.pasteBuffer.makeCopy(primitives); 63 Main.pasteSource = source; 64 } 65 66 static String getCopyString(Collection<? extends OsmPrimitive> primitives) { 67 StringBuilder idsBuilder = new StringBuilder(); 68 for (OsmPrimitive p : primitives) { 69 idsBuilder.append(OsmPrimitiveType.from(p).getAPIName()).append(' ').append(p.getId()).append(','); 70 } 71 return idsBuilder.substring(0, idsBuilder.length() - 1); 62 PrimitiveTransferData data = PrimitiveTransferData.getDataWithReferences(primitives); 63 ClipboardUtils.copy(new PrimitiveTransferable(data, source)); 72 64 } 73 65 74 66 @Override … … public final class CopyAction extends JosmAction { 81 73 setEnabled(selection != null && !selection.isEmpty()); 82 74 } 83 75 84 private boolean isEmptySelection() { 85 Collection<OsmPrimitive> sel = getLayerManager().getEditDataSet().getSelected(); 86 if (sel.isEmpty()) { 87 JOptionPane.showMessageDialog( 88 Main.parent, 89 tr("Please select something to copy."), 90 tr("Information"), 91 JOptionPane.INFORMATION_MESSAGE 92 ); 93 return true; 94 } 95 return false; 76 protected void showEmptySelectionWarning() { 77 JOptionPane.showMessageDialog( 78 Main.parent, 79 tr("Please select something to copy."), 80 tr("Information"), 81 JOptionPane.INFORMATION_MESSAGE 82 ); 96 83 } 97 84 } -
src/org/openstreetmap/josm/actions/CopyCoordinatesAction.java
diff --git a/src/org/openstreetmap/josm/actions/CopyCoordinatesAction.java b/src/org/openstreetmap/josm/actions/CopyCoordinatesAction.java index 2394349..f13f2db 100644
a b import java.util.Collections; 11 11 import org.openstreetmap.josm.data.osm.DataSet; 12 12 import org.openstreetmap.josm.data.osm.Node; 13 13 import org.openstreetmap.josm.data.osm.OsmPrimitive; 14 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 14 15 import org.openstreetmap.josm.tools.Shortcut; 15 16 import org.openstreetmap.josm.tools.Utils; 16 17 … … public class CopyCoordinatesAction extends JosmAction { 34 35 s.append(n.getCoor().lon()); 35 36 s.append('\n'); 36 37 } 37 Utils.copyToClipboard(s.toString().trim());38 ClipboardUtils.copyString(s.toString().trim()); 38 39 } 39 40 40 41 @Override -
src/org/openstreetmap/josm/actions/DuplicateAction.java
diff --git a/src/org/openstreetmap/josm/actions/DuplicateAction.java b/src/org/openstreetmap/josm/actions/DuplicateAction.java index 488b119..8467c3e 100644
a b import java.util.Collection; 11 11 12 12 import org.openstreetmap.josm.Main; 13 13 import org.openstreetmap.josm.data.osm.OsmPrimitive; 14 import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy; 14 import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler; 15 import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable; 16 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 15 17 import org.openstreetmap.josm.tools.Shortcut; 16 18 19 /** 20 * An action that dupplicates the given nodes. They are not added to the clippboard. 21 */ 17 22 public final class DuplicateAction extends JosmAction { 18 23 19 24 /** … … public final class DuplicateAction extends JosmAction { 21 26 */ 22 27 public DuplicateAction() { 23 28 super(tr("Duplicate"), "duplicate", 24 tr("Duplicate selection by copy and immediate paste."),29 tr("Duplicate selection."), 25 30 Shortcut.registerShortcut("system:duplicate", tr("Edit: {0}", tr("Duplicate")), KeyEvent.VK_D, Shortcut.CTRL), true); 26 31 putValue("help", ht("/Action/Duplicate")); 27 32 } 28 33 29 34 @Override 30 35 public void actionPerformed(ActionEvent e) { 31 Main.main.menu.paste.pasteData(32 new PrimitiveDeepCopy(getLayerManager().getEditDataSet().getSelected()), getLayerManager().getEditLayer(), e);36 PrimitiveTransferData data = PrimitiveTransferData.getDataWithReferences(getLayerManager().getEditDataSet().getSelected()); 37 new OsmTransferHandler().pasteOn(Main.getLayerManager().getEditLayer(), data.getCenter(), new PrimitiveTransferable(data)); 33 38 } 34 39 35 40 @Override -
src/org/openstreetmap/josm/actions/MapRectifierWMSmenuAction.java
diff --git a/src/org/openstreetmap/josm/actions/MapRectifierWMSmenuAction.java b/src/org/openstreetmap/josm/actions/MapRectifierWMSmenuAction.java index 12f5bdb..6fb6424 100644
a b import javax.swing.JRadioButton; 22 22 import org.openstreetmap.josm.Main; 23 23 import org.openstreetmap.josm.data.imagery.ImageryInfo; 24 24 import org.openstreetmap.josm.gui.ExtendedDialog; 25 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 25 26 import org.openstreetmap.josm.gui.layer.WMSLayer; 26 27 import org.openstreetmap.josm.gui.widgets.JosmTextField; 27 28 import org.openstreetmap.josm.gui.widgets.UrlLabel; 28 29 import org.openstreetmap.josm.tools.GBC; 29 30 import org.openstreetmap.josm.tools.Shortcut; 30 import org.openstreetmap.josm.tools.Utils;31 31 32 32 /** 33 33 * Download rectified images from various services. … … public class MapRectifierWMSmenuAction extends JosmAction { 123 123 124 124 JosmTextField tfWmsUrl = new JosmTextField(30); 125 125 126 String clip = Utils.getClipboardContent();126 String clip = ClipboardUtils.getClipboardStringContent(); 127 127 clip = clip == null ? "" : clip.trim(); 128 128 ButtonGroup group = new ButtonGroup(); 129 129 -
src/org/openstreetmap/josm/actions/PasteAction.java
diff --git a/src/org/openstreetmap/josm/actions/PasteAction.java b/src/org/openstreetmap/josm/actions/PasteAction.java index d0a1b4b..19f076b 100644
a b import static org.openstreetmap.josm.tools.I18n.tr; 7 7 8 8 import java.awt.MouseInfo; 9 9 import java.awt.Point; 10 import java.awt.datatransfer.FlavorEvent; 11 import java.awt.datatransfer.FlavorListener; 10 12 import java.awt.event.ActionEvent; 11 13 import java.awt.event.KeyEvent; 12 import java.util.ArrayList;13 import java.util.HashMap;14 import java.util.List;15 import java.util.Map;16 14 17 15 import org.openstreetmap.josm.Main; 18 import org.openstreetmap.josm.command.AddPrimitivesCommand;19 16 import org.openstreetmap.josm.data.coor.EastNorth; 20 import org.openstreetmap.josm.data.osm.NodeData; 21 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 22 import org.openstreetmap.josm.data.osm.PrimitiveData; 23 import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy; 24 import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy.PasteBufferChangedListener; 25 import org.openstreetmap.josm.data.osm.RelationData; 26 import org.openstreetmap.josm.data.osm.RelationMemberData; 27 import org.openstreetmap.josm.data.osm.WayData; 28 import org.openstreetmap.josm.gui.ExtendedDialog; 29 import org.openstreetmap.josm.gui.layer.Layer; 17 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 18 import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler; 30 19 import org.openstreetmap.josm.tools.Shortcut; 31 20 32 21 /** 33 22 * Paste OSM primitives from clipboard to the current edit layer. 34 23 * @since 404 35 24 */ 36 public final class PasteAction extends JosmAction implements PasteBufferChangedListener { 25 public final class PasteAction extends JosmAction implements FlavorListener { 26 27 private final OsmTransferHandler transferHandler; 37 28 38 29 /** 39 30 * Constructs a new {@code PasteAction}. … … public final class PasteAction extends JosmAction implements PasteBufferChangedL 45 36 // CUA shortcut for paste (https://en.wikipedia.org/wiki/IBM_Common_User_Access#Description) 46 37 Main.registerActionShortcut(this, 47 38 Shortcut.registerShortcut("system:paste:cua", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_INSERT, Shortcut.SHIFT)); 48 Main.pasteBuffer.addPasteBufferChangedListener(this); 39 transferHandler = new OsmTransferHandler(); 40 ClipboardUtils.getClipboard().addFlavorListener(this); 49 41 } 50 42 51 43 @Override 52 44 public void actionPerformed(ActionEvent e) { 53 if (!isEnabled())54 return;55 pasteData(Main.pasteBuffer, Main.pasteSource, e);56 }57 58 /**59 * Paste OSM primitives from the given paste buffer and OSM data layer source to the current edit layer.60 * @param pasteBuffer The paste buffer containing primitive ids to copy61 * @param source The OSM data layer used to look for primitive ids62 * @param e The ActionEvent that triggered this operation63 */64 public void pasteData(PrimitiveDeepCopy pasteBuffer, Layer source, ActionEvent e) {65 /* Find the middle of the pasteBuffer area */66 double maxEast = -1E100;67 double minEast = 1E100;68 double maxNorth = -1E100;69 double minNorth = 1E100;70 boolean incomplete = false;71 for (PrimitiveData data : pasteBuffer.getAll()) {72 if (data instanceof NodeData) {73 NodeData n = (NodeData) data;74 if (n.getEastNorth() != null) {75 double east = n.getEastNorth().east();76 double north = n.getEastNorth().north();77 if (east > maxEast) {78 maxEast = east;79 }80 if (east < minEast) {81 minEast = east;82 }83 if (north > maxNorth) {84 maxNorth = north;85 }86 if (north < minNorth) {87 minNorth = north;88 }89 }90 }91 if (data.isIncomplete()) {92 incomplete = true;93 }94 }95 96 // Allow to cancel paste if there are incomplete primitives97 if (incomplete && !confirmDeleteIncomplete()) {98 return;99 }100 101 45 // default to paste in center of map (pasted via menu or cursor not in MapView) 102 46 EastNorth mPosition = Main.map.mapView.getCenter(); 103 47 // We previously checked for modifier to know if the action has been trigerred via shortcut or via menu … … public final class PasteAction extends JosmAction implements PasteBufferChangedL 112 56 } 113 57 } 114 58 115 double offsetEast = mPosition.east() - (maxEast + minEast)/2.0; 116 double offsetNorth = mPosition.north() - (maxNorth + minNorth)/2.0; 117 118 // Make a copy of pasteBuffer and map from old id to copied data id 119 List<PrimitiveData> bufferCopy = new ArrayList<>(); 120 List<PrimitiveData> toSelect = new ArrayList<>(); 121 Map<Long, Long> newNodeIds = new HashMap<>(); 122 Map<Long, Long> newWayIds = new HashMap<>(); 123 Map<Long, Long> newRelationIds = new HashMap<>(); 124 for (PrimitiveData data: pasteBuffer.getAll()) { 125 if (data.isIncomplete()) { 126 continue; 127 } 128 PrimitiveData copy = data.makeCopy(); 129 copy.clearOsmMetadata(); 130 if (data instanceof NodeData) { 131 newNodeIds.put(data.getUniqueId(), copy.getUniqueId()); 132 } else if (data instanceof WayData) { 133 newWayIds.put(data.getUniqueId(), copy.getUniqueId()); 134 } else if (data instanceof RelationData) { 135 newRelationIds.put(data.getUniqueId(), copy.getUniqueId()); 136 } 137 bufferCopy.add(copy); 138 if (pasteBuffer.getDirectlyAdded().contains(data)) { 139 toSelect.add(copy); 140 } 141 } 142 143 // Update references in copied buffer 144 for (PrimitiveData data:bufferCopy) { 145 if (data instanceof NodeData) { 146 NodeData nodeData = (NodeData) data; 147 if (Main.getLayerManager().getEditLayer() == source) { 148 nodeData.setEastNorth(nodeData.getEastNorth().add(offsetEast, offsetNorth)); 149 } 150 } else if (data instanceof WayData) { 151 List<Long> newNodes = new ArrayList<>(); 152 for (Long oldNodeId: ((WayData) data).getNodes()) { 153 Long newNodeId = newNodeIds.get(oldNodeId); 154 if (newNodeId != null) { 155 newNodes.add(newNodeId); 156 } 157 } 158 ((WayData) data).setNodes(newNodes); 159 } else if (data instanceof RelationData) { 160 List<RelationMemberData> newMembers = new ArrayList<>(); 161 for (RelationMemberData member: ((RelationData) data).getMembers()) { 162 OsmPrimitiveType memberType = member.getMemberType(); 163 Long newId; 164 switch (memberType) { 165 case NODE: 166 newId = newNodeIds.get(member.getMemberId()); 167 break; 168 case WAY: 169 newId = newWayIds.get(member.getMemberId()); 170 break; 171 case RELATION: 172 newId = newRelationIds.get(member.getMemberId()); 173 break; 174 default: throw new AssertionError(); 175 } 176 if (newId != null) { 177 newMembers.add(new RelationMemberData(member.getRole(), memberType, newId)); 178 } 179 } 180 ((RelationData) data).setMembers(newMembers); 181 } 182 } 183 184 /* Now execute the commands to add the duplicated contents of the paste buffer to the map */ 185 Main.main.undoRedo.add(new AddPrimitivesCommand(bufferCopy, toSelect)); 186 Main.map.mapView.repaint(); 187 } 188 189 private static boolean confirmDeleteIncomplete() { 190 ExtendedDialog ed = new ExtendedDialog(Main.parent, 191 tr("Delete incomplete members?"), 192 new String[] {tr("Paste without incomplete members"), tr("Cancel")}); 193 ed.setButtonIcons(new String[] {"dialogs/relation/deletemembers", "cancel"}); 194 ed.setContent(tr("The copied data contains incomplete objects. " 195 + "When pasting the incomplete objects are removed. " 196 + "Do you want to paste the data without the incomplete objects?")); 197 ed.showDialog(); 198 return ed.getValue() == 1; 59 transferHandler.pasteOn(Main.getLayerManager().getEditLayer(), mPosition); 199 60 } 200 61 201 62 @Override 202 63 protected void updateEnabledState() { 203 if (getLayerManager().getEditDataSet() == null || Main.pasteBuffer == null) { 204 setEnabled(false); 205 return; 206 } 207 setEnabled(!Main.pasteBuffer.isEmpty()); 64 setEnabled(getLayerManager().getEditDataSet() != null && transferHandler.isDataAvailable()); 208 65 } 209 66 210 67 @Override 211 public void pasteBufferChanged(PrimitiveDeepCopy pasteBuffer) {68 public void flavorsChanged(FlavorEvent e) { 212 69 updateEnabledState(); 213 70 } 214 71 } -
src/org/openstreetmap/josm/actions/PasteTagsAction.java
diff --git a/src/org/openstreetmap/josm/actions/PasteTagsAction.java b/src/org/openstreetmap/josm/actions/PasteTagsAction.java index 18791ce..027de5d 100644
a b import org.openstreetmap.josm.data.osm.PrimitiveData; 25 25 import org.openstreetmap.josm.data.osm.Tag; 26 26 import org.openstreetmap.josm.data.osm.TagCollection; 27 27 import org.openstreetmap.josm.gui.conflict.tags.PasteTagsConflictResolverDialog; 28 import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler; 28 29 import org.openstreetmap.josm.tools.I18n; 29 30 import org.openstreetmap.josm.tools.Shortcut; 30 31 import org.openstreetmap.josm.tools.TextTagParser; 31 import org.openstreetmap.josm.tools.Utils;32 32 33 33 /** 34 34 * Action, to paste all tags from one primitive to another. … … import org.openstreetmap.josm.tools.Utils; 41 41 public final class PasteTagsAction extends JosmAction { 42 42 43 43 private static final String help = ht("/Action/PasteTags"); 44 private final OsmTransferHandler transferHandler = new OsmTransferHandler(); 44 45 45 46 /** 46 47 * Constructs a new {@code PasteTagsAction}. … … public final class PasteTagsAction extends JosmAction { 53 54 putValue("help", help); 54 55 } 55 56 57 /** 58 * Used to update the tags. 59 */ 56 60 public static class TagPaster { 57 61 58 62 private final Collection<PrimitiveData> source; … … public final class PasteTagsAction extends JosmAction { 258 262 if (selection.isEmpty()) 259 263 return; 260 264 261 String buf = Utils.getClipboardContent(); 262 if (buf == null || buf.isEmpty() || buf.matches(CopyAction.CLIPBOARD_REGEXP)) { 263 pasteTagsFromJOSMBuffer(selection); 264 } else { 265 // Paste tags from arbitrary text 266 pasteTagsFromText(selection, buf); 267 } 265 transferHandler.pasteTags(selection); 268 266 } 269 267 270 268 /** … … public final class PasteTagsAction extends JosmAction { 292 290 } 293 291 294 292 /** 295 * Paste tags from JOSM buffer296 * @param selection objects that will have the tags297 * @return false if JOSM buffer was empty298 */299 public static boolean pasteTagsFromJOSMBuffer(Collection<OsmPrimitive> selection) {300 List<PrimitiveData> directlyAdded = Main.pasteBuffer.getDirectlyAdded();301 if (directlyAdded == null || directlyAdded.isEmpty()) return false;302 303 PasteTagsAction.TagPaster tagPaster = new PasteTagsAction.TagPaster(directlyAdded, selection);304 List<Command> commands = new ArrayList<>();305 for (Tag tag : tagPaster.execute()) {306 commands.add(new ChangePropertyCommand(selection, tag.getKey(), "".equals(tag.getValue()) ? null : tag.getValue()));307 }308 commitCommands(selection, commands);309 return true;310 }311 312 /**313 293 * Create and execute SequenceCommand with descriptive title 314 294 * @param selection selected primitives 315 295 * @param commands the commands to perform in a sequential command -
src/org/openstreetmap/josm/data/osm/PrimitiveData.java
diff --git a/src/org/openstreetmap/josm/data/osm/PrimitiveData.java b/src/org/openstreetmap/josm/data/osm/PrimitiveData.java index 5664dd3..693d277 100644
a b public abstract class PrimitiveData extends AbstractPrimitive implements Seriali 80 80 oos.writeInt(version); 81 81 oos.writeInt(changesetId); 82 82 oos.writeInt(timestamp); 83 oos.writeObject(keys); 83 84 oos.defaultWriteObject(); 84 85 } 85 86 … … public abstract class PrimitiveData extends AbstractPrimitive implements Seriali 91 92 version = ois.readInt(); 92 93 changesetId = ois.readInt(); 93 94 timestamp = ois.readInt(); 95 keys = (String[]) ois.readObject(); 94 96 ois.defaultReadObject(); 95 97 } 96 98 } -
src/org/openstreetmap/josm/data/osm/PrimitiveDeepCopy.java
diff --git a/src/org/openstreetmap/josm/data/osm/PrimitiveDeepCopy.java b/src/org/openstreetmap/josm/data/osm/PrimitiveDeepCopy.java index 03db280..3fc21ea 100644
a b 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.osm; 3 3 4 import java.awt.datatransfer.UnsupportedFlavorException; 5 import java.io.IOException; 4 6 import java.util.ArrayList; 5 7 import java.util.Collection; 6 import java.util. HashSet;8 import java.util.Collections; 7 9 import java.util.List; 8 import java.util.Set;9 import java.util.concurrent.CopyOnWriteArrayList;10 10 11 import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor; 11 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 12 import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler; 13 import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable; 14 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 12 15 13 16 /** 14 17 * This class allows to create and keep a deep copy of primitives. Provides methods to access directly added 15 18 * primitives and reference primitives 19 * <p> 20 * To be removed end of 2016 16 21 * @since 2305 22 * @deprecated This has been replaced by Swing Copy+Paste support. Use {@link OsmTransferHandler} instead. 17 23 */ 24 @Deprecated 18 25 public class PrimitiveDeepCopy { 19 26 20 27 public interface PasteBufferChangedListener { 21 28 void pasteBufferChanged(PrimitiveDeepCopy pasteBuffer); 22 29 } 23 30 24 private final List<PrimitiveData> directlyAdded = new ArrayList<>();25 private final List<PrimitiveData> referenced = new ArrayList<>();26 private final CopyOnWriteArrayList<PasteBufferChangedListener> listeners = new CopyOnWriteArrayList<>();27 28 31 /** 29 32 * Constructs a new {@code PrimitiveDeepCopy} without data. Use {@link #makeCopy(Collection)} after that. 30 33 */ 31 34 public PrimitiveDeepCopy() { 32 // Do nothing33 35 } 34 36 35 37 /** … … public class PrimitiveDeepCopy { 45 47 * Replace content of the object with copy of provided primitives. 46 48 * @param primitives OSM primitives to copy 47 49 * @since 7961 50 * @deprecated Call {@link OsmTransferHandler#copyToClippboard(PrimitiveTransferData)} yourself 48 51 */ 52 @Deprecated 49 53 public final void makeCopy(final Collection<? extends OsmPrimitive> primitives) { 50 directlyAdded.clear(); 51 referenced.clear(); 52 53 final Set<Long> visitedNodeIds = new HashSet<>(); 54 final Set<Long> visitedWayIds = new HashSet<>(); 55 final Set<Long> visitedRelationIds = new HashSet<>(); 56 57 new AbstractVisitor() { 58 private boolean firstIteration; 59 60 @Override 61 public void visit(Node n) { 62 if (!visitedNodeIds.add(n.getUniqueId())) 63 return; 64 (firstIteration ? directlyAdded : referenced).add(n.save()); 65 } 66 67 @Override 68 public void visit(Way w) { 69 if (!visitedWayIds.add(w.getUniqueId())) 70 return; 71 (firstIteration ? directlyAdded : referenced).add(w.save()); 72 firstIteration = false; 73 for (Node n : w.getNodes()) { 74 visit(n); 75 } 76 } 77 78 @Override 79 public void visit(Relation r) { 80 if (!visitedRelationIds.add(r.getUniqueId())) 81 return; 82 (firstIteration ? directlyAdded : referenced).add(r.save()); 83 firstIteration = false; 84 for (RelationMember m : r.getMembers()) { 85 m.getMember().accept(this); 86 } 87 } 88 89 public void visitAll() { 90 for (OsmPrimitive osm : primitives) { 91 firstIteration = true; 92 osm.accept(this); 93 } 94 } 95 }.visitAll(); 96 97 firePasteBufferChanged(); 54 ClipboardUtils.copy(new PrimitiveTransferable(PrimitiveTransferData.getDataWithReferences(primitives))); 98 55 } 99 56 57 /** 58 * Gets the list of primitives that were explicitly added to this copy. 59 * @return The added primitives 60 */ 100 61 public List<PrimitiveData> getDirectlyAdded() { 101 return directlyAdded; 62 try { 63 PrimitiveTransferData data = (PrimitiveTransferData) ClipboardUtils.getClipboard().getData(PrimitiveTransferData.DATA_FLAVOR); 64 return new ArrayList<>(data.getDirectlyAdded()); 65 } catch (UnsupportedFlavorException | IOException e) { 66 return Collections.emptyList(); 67 } 102 68 } 103 69 70 /** 71 * Gets the list of primitives that were implicitly added because they were referenced. 72 * @return The primitives 73 */ 104 74 public List<PrimitiveData> getReferenced() { 105 return referenced; 75 try { 76 PrimitiveTransferData data = (PrimitiveTransferData) ClipboardUtils.getClipboard().getData(PrimitiveTransferData.DATA_FLAVOR); 77 return new ArrayList<>(data.getReferenced()); 78 } catch (UnsupportedFlavorException | IOException e) { 79 return Collections.emptyList(); 80 } 106 81 } 107 82 83 /** 84 * Gets a list of all primitives in this copy. 85 * @return The primitives 86 * @see #getDirectlyAdded() 87 * @see #getReferenced() 88 */ 108 89 public List<PrimitiveData> getAll() { 109 List<PrimitiveData> result = new ArrayList<>(directlyAdded.size() + referenced.size()); 110 result.addAll(directlyAdded); 111 result.addAll(referenced); 112 return result; 90 try { 91 PrimitiveTransferData data = (PrimitiveTransferData) ClipboardUtils.getClipboard().getData(PrimitiveTransferData.DATA_FLAVOR); 92 return new ArrayList<>(data.getAll()); 93 } catch (UnsupportedFlavorException | IOException e) { 94 return Collections.emptyList(); 95 } 113 96 } 114 97 115 98 public boolean isEmpty() { 116 return directlyAdded.isEmpty() && referenced.isEmpty(); 117 } 118 119 private void firePasteBufferChanged() { 120 for (PasteBufferChangedListener listener: listeners) { 121 listener.pasteBufferChanged(this); 122 } 99 return !ClipboardUtils.getClipboard().isDataFlavorAvailable(PrimitiveTransferData.DATA_FLAVOR); 123 100 } 124 101 102 /** 103 * Deactivated. To be removed as soon as we think nobody uses it. 104 * @param listener 105 * @deprecated You can detect buffer changes by registering a listener on {@link OsmTransferHandler#getClipboard()} 106 */ 107 @Deprecated 125 108 public void addPasteBufferChangedListener(PasteBufferChangedListener listener) { 126 listeners.addIfAbsent(listener);127 109 } 128 110 111 @Deprecated 129 112 public void removePasteBufferChangedListener(PasteBufferChangedListener listener) { 130 listeners.remove(listener);131 113 } 132 114 } -
src/org/openstreetmap/josm/data/osm/TagMap.java
diff --git a/src/org/openstreetmap/josm/data/osm/TagMap.java b/src/org/openstreetmap/josm/data/osm/TagMap.java index ce49e40..7f413ca 100644
a b 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.osm; 3 3 4 import java.io.Serializable; 4 5 import java.util.AbstractMap; 5 6 import java.util.AbstractSet; 7 import java.util.ArrayList; 6 8 import java.util.Arrays; 7 9 import java.util.ConcurrentModificationException; 8 10 import java.util.Iterator; 11 import java.util.List; 12 import java.util.Map; 9 13 import java.util.NoSuchElementException; 10 14 import java.util.Set; 11 15 … … import java.util.Set; 16 20 * 17 21 * @author Michael Zangl 18 22 */ 19 public class TagMap extends AbstractMap<String, String> { 23 public class TagMap extends AbstractMap<String, String> implements Serializable { 24 static final long serialVersionUID = 1; 20 25 /** 21 26 * We use this array every time we want to represent an empty map. 22 27 * This saves us the burden of checking for null every time but saves some object allocations. … … public class TagMap extends AbstractMap<String, String> { 107 112 * Creates a new, empty tag map. 108 113 */ 109 114 public TagMap() { 110 this(null); 115 this((String[]) null); 116 } 117 118 /** 119 * Create a new tag map and load it from the other map. 120 * @param tags The map to load from. 121 */ 122 public TagMap(Map<String, String> tags) { 123 putAll(tags); 124 } 125 126 /** 127 * Copy constructor 128 * @param tagMap The map to copy from. 129 */ 130 public TagMap(TagMap tagMap) { 131 this(tagMap.tags); 111 132 } 112 133 113 134 /** … … public class TagMap extends AbstractMap<String, String> { 209 230 } 210 231 211 232 /** 233 * Gets a list of all tags contained in this map. 234 * @return The list of tags in the order they were added. 235 */ 236 public List<Tag> getTags() { 237 String[] tags = this.tags; 238 List<Tag> tagList = new ArrayList<>(); 239 for (int i = 0; i < tags.length; i+=2) { 240 tagList.add(new Tag(tags[i], tags[i+1])); 241 } 242 return tagList; 243 } 244 245 /** 212 246 * Finds a key in an array that is structured like the {@link #tags} array and returns the position. 213 247 * <p> 214 248 * We allow the parameter to be passed to allow for better synchronization. -
src/org/openstreetmap/josm/gui/MapFrame.java
diff --git a/src/org/openstreetmap/josm/gui/MapFrame.java b/src/org/openstreetmap/josm/gui/MapFrame.java index e3ab5cc..80ce939 100644
a b import java.awt.Component; 8 8 import java.awt.Container; 9 9 import java.awt.Dimension; 10 10 import java.awt.Font; 11 import java.awt.GraphicsEnvironment;12 11 import java.awt.GridBagLayout; 13 12 import java.awt.Rectangle; 14 13 import java.awt.event.ActionEvent; … … public class MapFrame extends JPanel implements Destroyable, ActiveLayerChangeLi 196 195 setLayout(new BorderLayout()); 197 196 198 197 mapView = new MapView(Main.getLayerManager(), contentPane, viewportData); 199 if (!GraphicsEnvironment.isHeadless()) {200 new FileDrop(mapView);201 }202 198 203 199 splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true); 204 200 -
src/org/openstreetmap/josm/gui/MapView.java
diff --git a/src/org/openstreetmap/josm/gui/MapView.java b/src/org/openstreetmap/josm/gui/MapView.java index da3079e..c20ee16 100644
a b import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors; 52 52 import org.openstreetmap.josm.data.osm.visitor.paint.Rendering; 53 53 import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache; 54 54 import org.openstreetmap.josm.gui.MapViewState.MapViewRectangle; 55 import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler; 55 56 import org.openstreetmap.josm.gui.layer.AbstractMapViewPaintable; 56 57 import org.openstreetmap.josm.gui.layer.GpxLayer; 57 58 import org.openstreetmap.josm.gui.layer.ImageryLayer; … … LayerManager.LayerChangeListener, MainLayerManager.ActiveLayerChangeListener { 579 580 for (JComponent c : getMapNavigationComponents(MapView.this)) { 580 581 add(c); 581 582 } 583 setTransferHandler(new OsmTransferHandler()); 582 584 } 583 585 584 586 /** -
new file src/org/openstreetmap/josm/gui/datatransfer/ClipboardUtils.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/ClipboardUtils.java b/src/org/openstreetmap/josm/gui/datatransfer/ClipboardUtils.java new file mode 100644 index 0000000..f320a99
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.datatransfer; 3 4 import java.awt.GraphicsEnvironment; 5 import java.awt.HeadlessException; 6 import java.awt.Toolkit; 7 import java.awt.datatransfer.Clipboard; 8 import java.awt.datatransfer.ClipboardOwner; 9 import java.awt.datatransfer.DataFlavor; 10 import java.awt.datatransfer.StringSelection; 11 import java.awt.datatransfer.Transferable; 12 import java.awt.datatransfer.UnsupportedFlavorException; 13 import java.io.IOException; 14 import java.util.concurrent.Callable; 15 16 import org.openstreetmap.josm.Main; 17 import org.openstreetmap.josm.gui.util.GuiHelper; 18 import org.openstreetmap.josm.tools.Utils; 19 20 /** 21 * This is a utility class that provides methods useful for general data transfer support. 22 * 23 * @author Michael Zangl 24 * @since xxx 25 */ 26 public final class ClipboardUtils { 27 private static final class DoNothingClipboardOwner implements ClipboardOwner { 28 @Override 29 public void lostOwnership(Clipboard clpbrd, Transferable t) { 30 // Do nothing 31 } 32 } 33 34 private static Clipboard clipboard; 35 36 private ClipboardUtils() { 37 } 38 39 /** 40 * This method should be used from all of JOSM to access the clipboard. 41 * <p> 42 * It will default to the system clipboard except for cases where that clipboard is not accessible. 43 * @return A clipboard. 44 * @see #getClipboardContent() 45 */ 46 public static synchronized Clipboard getClipboard() { 47 // Might be unsupported in some more cases, we need a fake clipboard then. 48 if (clipboard == null) { 49 try { 50 clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); 51 } catch (HeadlessException e) { 52 Main.warn("Headless. Using fake clipboard.", e); 53 clipboard = new Clipboard("fake"); 54 } 55 } 56 return clipboard; 57 } 58 59 /** 60 * Gets the singleton instance of the system selection as a <code>Clipboard</code> object. 61 * This allows an application to read and modify the current, system-wide selection. 62 * @return the system selection as a <code>Clipboard</code>, or <code>null</code> if the native platform does not 63 * support a system selection <code>Clipboard</code> or if GraphicsEnvironment.isHeadless() returns true 64 * @see Toolkit#getSystemSelection 65 * @since xxx 66 */ 67 public static Clipboard getSystemSelection() { 68 if (GraphicsEnvironment.isHeadless()) { 69 return null; 70 } else { 71 return Toolkit.getDefaultToolkit().getSystemSelection(); 72 } 73 } 74 75 /** 76 * Gets the clipboard content as string. 77 * @return the content if available, <code>null</code> otherwise. 78 */ 79 public static String getClipboardStringContent() { 80 try { 81 Transferable t = getClipboardContent(); 82 if (t != null && t.isDataFlavorSupported(DataFlavor.stringFlavor)) { 83 return (String) t.getTransferData(DataFlavor.stringFlavor); 84 } 85 } catch (UnsupportedFlavorException | IOException ex) { 86 Main.error(ex); 87 } 88 return null; 89 } 90 91 /** 92 * Extracts clipboard content as {@code Transferable} object. Using this method avoids some problems on some platforms. 93 * @return The content or <code>null</code> if it is not available 94 */ 95 public static synchronized Transferable getClipboardContent() { 96 return getClipboardContent(getClipboard()); 97 } 98 99 /** 100 * Extracts clipboard content as {@code Transferable} object. Using this method avoids some problems on some platforms. 101 * @param clipboard clipboard from which contents are retrieved 102 * @return clipboard contents if available, {@code null} otherwise. 103 * @since xx 104 */ 105 public static Transferable getClipboardContent(Clipboard clipboard) { 106 Transferable t = null; 107 for (int tries = 0; t == null && tries < 10; tries++) { 108 try { 109 t = clipboard.getContents(null); 110 } catch (IllegalStateException e) { 111 // Clipboard currently unavailable. 112 // On some platforms, the system clipboard is unavailable while it is accessed by another application. 113 Main.trace("Clipboard unavailable.", e); 114 try { 115 Thread.sleep(1); 116 } catch (InterruptedException ex) { 117 Main.warn("InterruptedException in " + Utils.class.getSimpleName() 118 + " while getting clipboard content"); 119 } 120 } catch (NullPointerException e) { 121 // JDK-6322854: On Linux/X11, NPE can happen for unknown reasons, on all versions of Java 122 Main.error(e); 123 } 124 } 125 return t; 126 } 127 128 /** 129 * Copy the given string to the clipboard. 130 * @param s The string to copy. 131 * @return True if the copy was successful 132 */ 133 public static boolean copyString(String s) { 134 return copy(new StringSelection(s)); 135 } 136 137 /** 138 * Copies the given transferable to the clipboard. Handles state problems that occur on some platforms. 139 * @param transferable The transferable to copy. 140 * @return True if the copy was successful 141 */ 142 public static boolean copy(final Transferable transferable) { 143 return GuiHelper.runInEDTAndWaitAndReturn(new Callable<Boolean>() { 144 @Override 145 public Boolean call() throws Exception { 146 try { 147 getClipboard().setContents(transferable, new DoNothingClipboardOwner()); 148 return true; 149 } catch (IllegalStateException ex) { 150 Main.error(ex); 151 return false; 152 } 153 } 154 }); 155 } 156 } -
new file src/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandler.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandler.java b/src/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandler.java new file mode 100644 index 0000000..9f47fd2
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.datatransfer; 3 4 import java.awt.datatransfer.DataFlavor; 5 import java.awt.datatransfer.Transferable; 6 import java.awt.datatransfer.UnsupportedFlavorException; 7 import java.io.IOException; 8 import java.util.Arrays; 9 import java.util.Collection; 10 11 import javax.swing.TransferHandler; 12 13 import org.openstreetmap.josm.Main; 14 import org.openstreetmap.josm.data.coor.EastNorth; 15 import org.openstreetmap.josm.data.osm.OsmPrimitive; 16 import org.openstreetmap.josm.gui.datatransfer.importers.AbstractOsmDataPaster; 17 import org.openstreetmap.josm.gui.datatransfer.importers.FilePaster; 18 import org.openstreetmap.josm.gui.datatransfer.importers.PrimitiveDataPaster; 19 import org.openstreetmap.josm.gui.datatransfer.importers.TagTransferPaster; 20 import org.openstreetmap.josm.gui.datatransfer.importers.TextTagPaster; 21 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 22 23 /** 24 * This transfer hanlder provides the ability to transfer OSM data. It allows you to receive files, primitives or tags. 25 * @author Michael Zangl 26 * @since xxx 27 */ 28 public class OsmTransferHandler extends TransferHandler { 29 30 private static final Collection<AbstractOsmDataPaster> SUPPORTED = Arrays.asList( 31 new FilePaster(), new PrimitiveDataPaster(), 32 new TagTransferPaster(), new TextTagPaster()); 33 34 @Override 35 public boolean canImport(TransferSupport support) { 36 // import everything for now, only support copy. 37 for (AbstractOsmDataPaster df : SUPPORTED) { 38 if (df.supports(support)) { 39 return true; 40 } 41 } 42 return false; 43 } 44 45 @Override 46 public boolean importData(TransferSupport support) { 47 return importData(support, Main.getLayerManager().getEditLayer(), null); 48 } 49 50 private boolean importData(TransferSupport support, OsmDataLayer layer, EastNorth center) { 51 for (AbstractOsmDataPaster df : SUPPORTED) { 52 if (df.supports(support)) { 53 try { 54 if (df.importData(support, layer, center)) { 55 return true; 56 } 57 } catch (UnsupportedFlavorException | IOException e) { 58 Main.warn(e); 59 } 60 } 61 } 62 return super.importData(support); 63 } 64 65 private boolean importTags(TransferSupport support, Collection<? extends OsmPrimitive> primitives) { 66 for (AbstractOsmDataPaster df : SUPPORTED) { 67 if (df.supports(support)) { 68 try { 69 if (df.importTagsOn(support, primitives)) { 70 return true; 71 } 72 } catch (UnsupportedFlavorException | IOException e) { 73 Main.warn(e); 74 } 75 } 76 } 77 return super.importData(support); 78 } 79 80 /** 81 * Paste the current clippboard current at the given position 82 * @param editLayer The layer to paste on. 83 * @param mPosition The position to paste at. 84 */ 85 public void pasteOn(OsmDataLayer editLayer, EastNorth mPosition) { 86 Transferable transferable = ClipboardUtils.getClipboard().getContents(null); 87 pasteOn(editLayer, mPosition, transferable); 88 } 89 90 /** 91 * Paste the given clippboard current at the given position 92 * @param editLayer The layer to paste on. 93 * @param mPosition The position to paste at. 94 * @param transferable The transferable to use. 95 */ 96 public void pasteOn(OsmDataLayer editLayer, EastNorth mPosition, Transferable transferable) { 97 importData(new TransferSupport(Main.panel, transferable), editLayer, mPosition); 98 } 99 100 /** 101 * Paste the given tags on the primitives. 102 * @param primitives The primitives to paste on. 103 */ 104 public void pasteTags(Collection<? extends OsmPrimitive> primitives) { 105 Transferable transferable = ClipboardUtils.getClipboard().getContents(null); 106 importTags(new TransferSupport(Main.panel, transferable), primitives); 107 } 108 109 /** 110 * Check if any primitive data or any other supported data is available in the clippboard. 111 * @return <code>true</code> if any flavor is supported. 112 */ 113 public boolean isDataAvailable() { 114 Collection<DataFlavor> available = Arrays.asList(ClipboardUtils.getClipboard().getAvailableDataFlavors()); 115 for (AbstractOsmDataPaster s : SUPPORTED) { 116 if (s.supports(available)) { 117 return true; 118 } 119 } 120 return false; 121 } 122 } -
src/org/openstreetmap/josm/gui/datatransfer/PrimitiveTransferable.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/PrimitiveTransferable.java b/src/org/openstreetmap/josm/gui/datatransfer/PrimitiveTransferable.java index cd91a24..21e302a 100644
a b package org.openstreetmap.josm.gui.datatransfer; 4 4 import java.awt.datatransfer.DataFlavor; 5 5 import java.awt.datatransfer.Transferable; 6 6 import java.awt.datatransfer.UnsupportedFlavorException; 7 import java.io.Serializable;8 7 import java.util.ArrayList; 9 import java.util.Collection; 8 import java.util.Arrays; 9 import java.util.List; 10 10 11 import org.openstreetmap.josm.data.osm.OsmPrimitive ;11 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 12 12 import org.openstreetmap.josm.data.osm.PrimitiveData; 13 import org.openstreetmap.josm.gui.DefaultNameFormatter; 14 import org.openstreetmap.josm.tools.CheckParameterUtil; 13 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 14 import org.openstreetmap.josm.gui.datatransfer.data.TagTransferData; 15 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 15 16 16 17 /** 17 * Transferable objects for {@link Primitive Data}.18 * Transferable objects for {@link PrimitiveTransferData} objects 18 19 * @since 9369 20 * @since xxx Complete rework 19 21 */ 20 22 public class PrimitiveTransferable implements Transferable { 21 23 22 24 /** 23 * A wrapper for a collection of {@link PrimitiveData}.25 * The flavors that are available for normal primitives. 24 26 */ 25 public static final class Data implements Serializable { 26 private static final long serialVersionUID = -1485089993600213704L; 27 private final Collection<PrimitiveData> primitiveData; 28 29 private Data(Collection<PrimitiveData> primitiveData) { 30 CheckParameterUtil.ensureThat(primitiveData instanceof Serializable, "primitiveData must be instanceof Serializable"); 31 this.primitiveData = primitiveData; 32 } 33 34 /** 35 * Returns the contained {@link PrimitiveData} 36 * @return the contained {@link PrimitiveData} 37 */ 38 public Collection<PrimitiveData> getPrimitiveData() { 39 return primitiveData; 40 } 41 } 27 private static final List<DataFlavor> PRIMITIVE_FLAVORS = Arrays.asList(PrimitiveTransferData.DATA_FLAVOR, 28 TagTransferData.FLAVOR, DataFlavor.stringFlavor); 29 private final PrimitiveTransferData primitives; 30 private OsmDataLayer sourceLayer; 42 31 43 32 /** 44 * Data flavor for {@link PrimitiveData} which is wrapped in {@link Data}. 33 * Constructs a new {@code PrimitiveTransferable}. 34 * @param primitives collection of OSM primitives 45 35 */ 46 public static final DataFlavor PRIMITIVE_DATA = new DataFlavor(Data.class, Data.class.getName()); 47 private final Collection<? extends OsmPrimitive> primitives; 36 public PrimitiveTransferable(PrimitiveTransferData primitives) { 37 this(primitives, null); 38 } 48 39 49 40 /** 50 41 * Constructs a new {@code PrimitiveTransferable}. 51 42 * @param primitives collection of OSM primitives 43 * @param sourceLayer The layer the primitives are copied from. 52 44 */ 53 public PrimitiveTransferable( Collection<? extends OsmPrimitive> primitives) {45 public PrimitiveTransferable(PrimitiveTransferData primitives, OsmDataLayer sourceLayer) { 54 46 this.primitives = primitives; 47 this.sourceLayer = sourceLayer; 55 48 } 56 49 57 50 @Override 58 51 public DataFlavor[] getTransferDataFlavors() { 59 return new DataFlavor[]{PRIMITIVE_DATA, DataFlavor.stringFlavor}; 52 ArrayList<DataFlavor> flavors = new ArrayList<>(PRIMITIVE_FLAVORS); 53 return flavors.toArray(new DataFlavor[flavors.size()]); 60 54 } 61 55 62 56 @Override 63 57 public boolean isDataFlavorSupported(DataFlavor flavor) { 64 return flavor == PRIMITIVE_DATA; 58 DataFlavor[] flavors = getTransferDataFlavors(); 59 for (DataFlavor f : flavors) { 60 if (flavor.equals(f)) { 61 return true; 62 } 63 } 64 return false; 65 65 } 66 66 67 67 @Override 68 68 public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { 69 69 if (DataFlavor.stringFlavor.equals(flavor)) { 70 70 return getStringData(); 71 } else if (PRIMITIVE_DATA.equals(flavor)) { 72 return getPrimitiveData(); 71 } else if (PrimitiveTransferData.DATA_FLAVOR.equals(flavor)) { 72 return primitives; 73 } else if (TagTransferData.FLAVOR.equals(flavor)) { 74 return new TagTransferData(primitives.getDirectlyAdded()); 75 } else { 76 throw new UnsupportedFlavorException(flavor); 73 77 } 74 throw new UnsupportedFlavorException(flavor);75 78 } 76 79 77 80 protected String getStringData() { 78 81 final StringBuilder sb = new StringBuilder(); 79 for ( OsmPrimitive primitive : primitives) {80 sb.append(primitive.getType())81 .append(' ').append(primitive.getUniqueId())82 .append(" # ").append(primitive.getDisplayName(DefaultNameFormatter.getInstance()))83 .append('\n');82 for (PrimitiveData primitive : primitives.getAll()) { 83 if (sb.length() > 0) { 84 sb.append("\n"); 85 } 86 sb.append(OsmPrimitiveType.from(primitive).getAPIName()).append(' ').append(primitive.getId()); 84 87 } 85 88 return sb.toString().replace("\u200E", "").replace("\u200F", ""); 86 89 } 87 88 protected Data getPrimitiveData() {89 final Collection<PrimitiveData> r = new ArrayList<>(primitives.size());90 for (OsmPrimitive primitive : primitives) {91 r.add(primitive.save());92 }93 return new Data(r);94 }95 90 } -
src/org/openstreetmap/josm/gui/datatransfer/RelationMemberTransferable.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/RelationMemberTransferable.java b/src/org/openstreetmap/josm/gui/datatransfer/RelationMemberTransferable.java index 46dc5d2..f7b78c1 100644
a b import java.awt.datatransfer.Transferable; 6 6 import java.awt.datatransfer.UnsupportedFlavorException; 7 7 import java.io.Serializable; 8 8 import java.util.ArrayList; 9 import java.util.Arrays; 9 10 import java.util.Collection; 11 import java.util.Collections; 12 import java.util.HashSet; 10 13 14 import org.openstreetmap.josm.data.osm.OsmPrimitive; 11 15 import org.openstreetmap.josm.data.osm.RelationMember; 12 16 import org.openstreetmap.josm.data.osm.RelationMemberData; 13 17 import org.openstreetmap.josm.gui.DefaultNameFormatter; 18 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 14 19 import org.openstreetmap.josm.tools.CheckParameterUtil; 15 20 16 21 /** … … public class RelationMemberTransferable implements Transferable { 36 41 * @return the contained {@link RelationMemberData} 37 42 */ 38 43 public Collection<RelationMemberData> getRelationMemberData() { 39 return relationMemberDatas; 44 return Collections.unmodifiableCollection(relationMemberDatas); 45 } 46 47 /** 48 * Gets the Data for the given list of members. 49 * @param members The collection. The order is preserved. 50 * @return The data. 51 */ 52 public static Data getData(Collection<RelationMember> members) { 53 final Collection<RelationMemberData> r = new ArrayList<>(members.size()); 54 for (RelationMember member : members) { 55 r.add(new RelationMemberData(member.getRole(), member.getType(), member.getUniqueId())); 56 } 57 return new Data(r); 40 58 } 41 59 } 42 60 43 61 /** 44 62 * Data flavor for {@link RelationMemberData} which is wrapped in {@link Data}. 45 63 */ 46 public static final DataFlavor RELATION_MEMBER_DATA = new DataFlavor(Data.class, Data.class.getName());64 public static final DataFlavor RELATION_MEMBER_DATA = new DataFlavor(Data.class, "Relation member"); 47 65 private final Collection<RelationMember> members; 48 66 49 67 /** … … public class RelationMemberTransferable implements Transferable { 51 69 * @param members list of relation members 52 70 */ 53 71 public RelationMemberTransferable(Collection<RelationMember> members) { 54 this.members = members;72 this.members = new ArrayList<>(members); 55 73 } 56 74 57 75 @Override 58 76 public DataFlavor[] getTransferDataFlavors() { 59 return new DataFlavor[]{RELATION_MEMBER_DATA, DataFlavor.stringFlavor};77 return new DataFlavor[]{RELATION_MEMBER_DATA, PrimitiveTransferData.DATA_FLAVOR, DataFlavor.stringFlavor}; 60 78 } 61 79 62 80 @Override 63 81 public boolean isDataFlavorSupported(DataFlavor flavor) { 64 return flavor == RELATION_MEMBER_DATA;82 return Arrays.asList(getTransferDataFlavors()).contains(flavor); 65 83 } 66 84 67 85 @Override … … public class RelationMemberTransferable implements Transferable { 70 88 return getStringData(); 71 89 } else if (RELATION_MEMBER_DATA.equals(flavor)) { 72 90 return getRelationMemberData(); 91 } else if (PrimitiveTransferData.DATA_FLAVOR.equals(flavor)) { 92 return getPrimitiveData(); 73 93 } 74 94 throw new UnsupportedFlavorException(flavor); 75 95 } 76 96 97 private PrimitiveTransferData getPrimitiveData() { 98 Collection<OsmPrimitive> primitives = new HashSet<>(); 99 for (RelationMember member : members) { 100 primitives.add(member.getMember()); 101 } 102 return PrimitiveTransferData.getData(primitives); 103 } 104 77 105 protected String getStringData() { 78 106 final StringBuilder sb = new StringBuilder(); 79 107 for (RelationMember member : members) { … … public class RelationMemberTransferable implements Transferable { 87 115 } 88 116 89 117 protected Data getRelationMemberData() { 90 final Collection<RelationMemberData> r = new ArrayList<>(members.size()); 91 for (RelationMember member : members) { 92 r.add(new RelationMemberData(member.getRole(), member.getType(), member.getUniqueId())); 93 } 94 return new Data(r); 118 return Data.getData(members); 95 119 } 96 120 } -
new file src/org/openstreetmap/josm/gui/datatransfer/data/PrimitiveTransferData.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/data/PrimitiveTransferData.java b/src/org/openstreetmap/josm/gui/datatransfer/data/PrimitiveTransferData.java new file mode 100644 index 0000000..ff68f09
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.datatransfer.data; 3 4 import java.awt.datatransfer.DataFlavor; 5 import java.io.Serializable; 6 import java.util.ArrayList; 7 import java.util.Collection; 8 import java.util.Collections; 9 import java.util.HashSet; 10 import java.util.LinkedList; 11 import java.util.Queue; 12 13 import org.openstreetmap.josm.data.ProjectionBounds; 14 import org.openstreetmap.josm.data.coor.EastNorth; 15 import org.openstreetmap.josm.data.osm.NodeData; 16 import org.openstreetmap.josm.data.osm.OsmPrimitive; 17 import org.openstreetmap.josm.data.osm.PrimitiveData; 18 import org.openstreetmap.josm.data.osm.Relation; 19 import org.openstreetmap.josm.data.osm.Way; 20 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; 21 22 /** 23 * A list of primitives that are transfered. The list allows you to implicitly add primitives. 24 * It distingluishes between primitives that were directly added and implicitly added ones. 25 * @author Michael Zangl 26 * @since xxx 27 */ 28 public final class PrimitiveTransferData implements Serializable { 29 private static final long serialVersionUID = 1L; 30 31 /** 32 * The data flavor used to represent this class. 33 */ 34 public static final DataFlavor DATA_FLAVOR = new DataFlavor(PrimitiveTransferData.class, "OSM Primitives"); 35 36 private static final class GetReferences implements ReferenceGetter { 37 @Override 38 public Collection<? extends OsmPrimitive> getReferedPrimitives(OsmPrimitive primitive) { 39 if (primitive instanceof Way) { 40 return ((Way) primitive).getNodes(); 41 } else if (primitive instanceof Relation) { 42 return ((Relation) primitive).getMemberPrimitives(); 43 } else { 44 return Collections.emptyList(); 45 } 46 } 47 } 48 49 // TODO: Java8: Replace by Function. 50 private interface ReferenceGetter { 51 Collection<? extends OsmPrimitive> getReferedPrimitives(OsmPrimitive primitive); 52 } 53 54 private final ArrayList<PrimitiveData> direct; 55 private final ArrayList<PrimitiveData> referenced; 56 57 /** 58 * Create the new transfer data. 59 * @param primitives The primitives to transfer 60 * @param referencedGetter A function that allows to get the primitives referenced by the primitives variable. 61 * It will be queried recursively. 62 */ 63 private PrimitiveTransferData(Collection<? extends OsmPrimitive> primitives, ReferenceGetter referencedGetter) { 64 // convert to hash set first to remove dupplicates 65 HashSet<OsmPrimitive> visited = new HashSet<OsmPrimitive>(primitives); 66 this.direct = new ArrayList<>(visited.size()); 67 68 this.referenced = new ArrayList<>(); 69 Queue<OsmPrimitive> toCheck = new LinkedList<>(); 70 for (OsmPrimitive p : visited) { 71 direct.add(p.save()); 72 toCheck.addAll(referencedGetter.getReferedPrimitives(p)); 73 } 74 while (!toCheck.isEmpty()) { 75 OsmPrimitive p = toCheck.poll(); 76 if (visited.add(p)) { 77 referenced.add(p.save()); 78 toCheck.addAll(referencedGetter.getReferedPrimitives(p)); 79 } 80 } 81 } 82 83 /** 84 * Gets all primitives directly added. 85 * @return The primitives 86 */ 87 public Collection<PrimitiveData> getDirectlyAdded() { 88 return Collections.unmodifiableList(direct); 89 } 90 91 /** 92 * Gets all primitives that were added because they were referenced. 93 * @return The primitives 94 */ 95 public Collection<PrimitiveData> getReferenced() { 96 return Collections.unmodifiableList(referenced); 97 } 98 99 /** 100 * Gets a List of all primitives added to this set. 101 * @return That list. 102 */ 103 public Collection<PrimitiveData> getAll() { 104 ArrayList<PrimitiveData> list = new ArrayList<>(); 105 list.addAll(direct); 106 list.addAll(referenced); 107 return list; 108 } 109 110 /** 111 * Creates a new {@link PrimitiveTransferData} object that only contains the primitives. 112 * @param primitives The primitives to contain. 113 * @return That set. 114 */ 115 public static PrimitiveTransferData getData(Collection<? extends OsmPrimitive> primitives) { 116 return new PrimitiveTransferData(primitives, new ReferenceGetter() { 117 @Override 118 public Collection<? extends OsmPrimitive> getReferedPrimitives(OsmPrimitive primitive) { 119 return Collections.emptyList(); 120 } 121 }); 122 } 123 124 125 /** 126 * Creates a new {@link PrimitiveTransferData} object that contains the primitives and all references. 127 * @param primitives The primitives to contain. 128 * @return That set. 129 */ 130 public static PrimitiveTransferData getDataWithReferences(Collection<? extends OsmPrimitive> primitives) { 131 return new PrimitiveTransferData(primitives, new GetReferences()); 132 } 133 134 /** 135 * Compute the center of all nodes. 136 * @return The center or null if this buffer has no location. 137 */ 138 public EastNorth getCenter() { 139 BoundingXYVisitor visitor = new BoundingXYVisitor(); 140 for (PrimitiveData pd : getAll()) { 141 if (pd instanceof NodeData && !pd.isIncomplete()) { 142 visitor.visit(((NodeData) pd).getEastNorth()); 143 } 144 } 145 ProjectionBounds bounds = visitor.getBounds(); 146 if (bounds == null) { 147 return null; 148 } else { 149 return bounds.getCenter(); 150 } 151 } 152 153 /** 154 * Tests wheter this set contains any primitives that have invalid data. 155 * @return <code>true</code> if invalid data is contained in this set. 156 */ 157 public boolean hasIncompleteData() { 158 for (PrimitiveData pd : getAll()) { 159 if (pd.isIncomplete()) { 160 return true; 161 } 162 } 163 return false; 164 } 165 } -
new file src/org/openstreetmap/josm/gui/datatransfer/data/TagTransferData.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/data/TagTransferData.java b/src/org/openstreetmap/josm/gui/datatransfer/data/TagTransferData.java new file mode 100644 index 0000000..531d595
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.datatransfer.data; 3 4 import java.awt.datatransfer.DataFlavor; 5 import java.io.Serializable; 6 import java.util.Collection; 7 import java.util.Collections; 8 import java.util.Map; 9 10 import org.openstreetmap.josm.data.osm.TagMap; 11 import org.openstreetmap.josm.data.osm.Tagged; 12 13 /** 14 * This is a special transfer type that only transfers tag data. 15 * <p> 16 * It currently contains all tags contained in the selection that was copied. 17 * @author Michael Zangl 18 * @since xxx 19 */ 20 public class TagTransferData implements Serializable { 21 22 private static final long serialVersionUID = 1; 23 24 /** 25 * This is a data flavor added 26 */ 27 public static final DataFlavor FLAVOR = new DataFlavor(TagTransferData.class, "OSM Tags"); 28 29 private final TagMap tags = new TagMap(); 30 31 /** 32 * Creates a new {@link TagTransferData} object for the given objects. 33 * @param tagged The tags to transfer. 34 */ 35 public TagTransferData(Collection<? extends Tagged> tagged) { 36 for (Tagged t : tagged) { 37 tags.putAll(t.getKeys()); 38 } 39 } 40 41 /** 42 * Gets all tags contained in this data. 43 * @return The tags. 44 */ 45 public Map<String, String> getTags() { 46 return Collections.unmodifiableMap(tags); 47 } 48 } -
new file src/org/openstreetmap/josm/gui/datatransfer/importers/AbstractOsmDataPaster.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/importers/AbstractOsmDataPaster.java b/src/org/openstreetmap/josm/gui/datatransfer/importers/AbstractOsmDataPaster.java new file mode 100644 index 0000000..d370a39
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.datatransfer.importers; 3 4 import java.awt.datatransfer.DataFlavor; 5 import java.awt.datatransfer.UnsupportedFlavorException; 6 import java.io.IOException; 7 import java.util.Collection; 8 9 import javax.swing.TransferHandler; 10 import javax.swing.TransferHandler.TransferSupport; 11 12 import org.openstreetmap.josm.data.coor.EastNorth; 13 import org.openstreetmap.josm.data.osm.OsmPrimitive; 14 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 15 16 /** 17 * This is an abstract class that helps implementing the transfer support required by swing. 18 * <p> 19 * It implements a mechanism to import a given data flavor into the current OSM data layer. 20 * @author Michael Zangl 21 * @since xxx 22 */ 23 public abstract class AbstractOsmDataPaster { 24 protected final DataFlavor df; 25 26 /** 27 * Create a new {@link AbstractOsmDataPaster} 28 * @param df The data flavor that this support supports. 29 */ 30 protected AbstractOsmDataPaster(DataFlavor df) { 31 this.df = df; 32 } 33 34 /** 35 * Checks if this supports importing the given transfer support. 36 * @param support The support that should be supported. 37 * @return True if we support that transfer. 38 */ 39 public boolean supports(TransferSupport support) { 40 return support.isDataFlavorSupported(df) && isCopy(support); 41 } 42 43 /** 44 * Checks if this supports any of the available flavors. 45 * @param available The flavors that should be supported 46 * @return True if any of them is supported. 47 */ 48 public boolean supports(Collection<DataFlavor> available) { 49 return available.contains(df); 50 } 51 52 private static boolean isCopy(TransferSupport support) { 53 return !support.isDrop() || (TransferHandler.COPY & support.getSourceDropActions()) == TransferHandler.COPY; 54 } 55 56 /** 57 * Attempts to import the given transfer data. 58 * @param support The transfer support to import from. 59 * @param layer The layer to paste at. 60 * @param pasteAt The position to paste at. 61 * @return <code>true</code> if the import was successful. 62 * @throws UnsupportedFlavorException 63 * @throws IOException 64 */ 65 public abstract boolean importData(TransferSupport support, OsmDataLayer layer, EastNorth pasteAt) 66 throws UnsupportedFlavorException, IOException; 67 68 /** 69 * Imports only if this import changes the tags only. Does nothing if more than tags would be changed. 70 * @param support The support 71 * @param selection The primitives to apply on. 72 * @return <code>true</code> if an import was done. 73 * @throws UnsupportedFlavorException 74 * @throws IOException 75 */ 76 public boolean importTagsOn(TransferSupport support, Collection<? extends OsmPrimitive> selection) 77 throws UnsupportedFlavorException, IOException { 78 return false; 79 } 80 } -
new file src/org/openstreetmap/josm/gui/datatransfer/importers/AbstractTagPaster.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/importers/AbstractTagPaster.java b/src/org/openstreetmap/josm/gui/datatransfer/importers/AbstractTagPaster.java new file mode 100644 index 0000000..dfc4cc7
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.datatransfer.importers; 3 4 import java.awt.datatransfer.DataFlavor; 5 import java.awt.datatransfer.UnsupportedFlavorException; 6 import java.io.IOException; 7 import java.util.Collection; 8 import java.util.Map; 9 10 import javax.swing.TransferHandler.TransferSupport; 11 12 import org.openstreetmap.josm.Main; 13 import org.openstreetmap.josm.command.ChangePropertyCommand; 14 import org.openstreetmap.josm.data.coor.EastNorth; 15 import org.openstreetmap.josm.data.osm.OsmPrimitive; 16 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 17 18 /** 19 * This transfer support allows us to transfer tags to the selected primitives 20 * @author Michael Zangl 21 * @since xxx 22 */ 23 public abstract class AbstractTagPaster extends AbstractOsmDataPaster { 24 25 AbstractTagPaster(DataFlavor df) { 26 super(df); 27 } 28 29 @Override 30 public boolean importData(TransferSupport support, OsmDataLayer layer, EastNorth pasteAt) 31 throws UnsupportedFlavorException, IOException { 32 Collection<OsmPrimitive> selection = layer.data.getSelected(); 33 if (selection.isEmpty()) { 34 return false; 35 } 36 37 return importTagsOn(support, selection); 38 } 39 40 @Override 41 public boolean importTagsOn(TransferSupport support, Collection<? extends OsmPrimitive> selection) 42 throws UnsupportedFlavorException, IOException { 43 ChangePropertyCommand command = new ChangePropertyCommand(selection, getTags(support)); 44 Main.main.undoRedo.add(command); 45 return true; 46 } 47 48 /** 49 * Gets the tags that should be pasted. 50 * @param support The TransferSupport to get the tags from. 51 * @return The tags 52 * @throws UnsupportedFlavorException 53 * @throws IOException 54 */ 55 protected abstract Map<String, String> getTags(TransferSupport support) throws UnsupportedFlavorException, IOException; 56 } -
new file src/org/openstreetmap/josm/gui/datatransfer/importers/FilePaster.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/importers/FilePaster.java b/src/org/openstreetmap/josm/gui/datatransfer/importers/FilePaster.java new file mode 100644 index 0000000..80ee372
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.datatransfer.importers; 3 4 import java.awt.datatransfer.DataFlavor; 5 import java.awt.datatransfer.UnsupportedFlavorException; 6 import java.io.File; 7 import java.io.IOException; 8 import java.util.List; 9 10 import javax.swing.TransferHandler.TransferSupport; 11 12 import org.openstreetmap.josm.Main; 13 import org.openstreetmap.josm.actions.OpenFileAction; 14 import org.openstreetmap.josm.data.coor.EastNorth; 15 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 16 17 /** 18 * This transfer support allows us to import a file that is dropped / copied on to the map. 19 * @author Michael Zangl 20 * @since xxx 21 */ 22 public final class FilePaster extends AbstractOsmDataPaster { 23 /** 24 * Create a new {@link FilePaster} 25 */ 26 public FilePaster() { 27 super(DataFlavor.javaFileListFlavor); 28 } 29 30 @Override 31 public boolean importData(TransferSupport support, OsmDataLayer layer, EastNorth pasteAt) 32 throws UnsupportedFlavorException, IOException { 33 @SuppressWarnings("unchecked") 34 List<File> files = (List<File>) support.getTransferable().getTransferData(df); 35 OpenFileAction.OpenFileTask task = new OpenFileAction.OpenFileTask(files, null); 36 task.setRecordHistory(true); 37 Main.worker.submit(task); 38 return true; 39 } 40 41 } -
new file src/org/openstreetmap/josm/gui/datatransfer/importers/PrimitiveDataPaster.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/importers/PrimitiveDataPaster.java b/src/org/openstreetmap/josm/gui/datatransfer/importers/PrimitiveDataPaster.java new file mode 100644 index 0000000..5209c68
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.datatransfer.importers; 3 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 import java.awt.datatransfer.UnsupportedFlavorException; 7 import java.io.IOException; 8 import java.util.ArrayList; 9 import java.util.EnumMap; 10 import java.util.HashMap; 11 import java.util.List; 12 import java.util.Map; 13 14 import javax.swing.TransferHandler.TransferSupport; 15 16 import org.openstreetmap.josm.Main; 17 import org.openstreetmap.josm.command.AddPrimitivesCommand; 18 import org.openstreetmap.josm.data.coor.EastNorth; 19 import org.openstreetmap.josm.data.osm.NodeData; 20 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 21 import org.openstreetmap.josm.data.osm.PrimitiveData; 22 import org.openstreetmap.josm.data.osm.RelationData; 23 import org.openstreetmap.josm.data.osm.RelationMemberData; 24 import org.openstreetmap.josm.data.osm.WayData; 25 import org.openstreetmap.josm.gui.ExtendedDialog; 26 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 27 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 28 29 /** 30 * This transfer support allows us to transfer primitives. This is the default paste action when primitives were copied. 31 * @author Michael Zangl 32 * @since xxx 33 */ 34 public final class PrimitiveDataPaster extends AbstractOsmDataPaster { 35 /** 36 * Create a new {@link PrimitiveDataPaster} 37 */ 38 public PrimitiveDataPaster() { 39 super(PrimitiveTransferData.DATA_FLAVOR); 40 } 41 42 @Override 43 public boolean importData(TransferSupport support, final OsmDataLayer layer, EastNorth pasteAt) 44 throws UnsupportedFlavorException, IOException { 45 PrimitiveTransferData pasteBuffer = (PrimitiveTransferData) support.getTransferable().getTransferData(df); 46 // Allow to cancel paste if there are incomplete primitives 47 if (pasteBuffer.hasIncompleteData() && !confirmDeleteIncomplete()) { 48 return false; 49 } 50 51 EastNorth center = pasteBuffer.getCenter(); 52 EastNorth offset = center == null ? null : pasteAt.subtract(center); 53 54 AddPrimitivesCommand command = createNewPrimitives(pasteBuffer, offset, layer); 55 56 /* Now execute the commands to add the duplicated contents of the paste buffer to the map */ 57 Main.main.undoRedo.add(command); 58 return true; 59 } 60 61 private static AddPrimitivesCommand createNewPrimitives(PrimitiveTransferData pasteBuffer, EastNorth offset, OsmDataLayer layer) { 62 // Make a copy of pasteBuffer and map from old id to copied data id 63 List<PrimitiveData> bufferCopy = new ArrayList<>(); 64 List<PrimitiveData> toSelect = new ArrayList<>(); 65 EnumMap<OsmPrimitiveType, Map<Long, Long>> newIds = generateNewPrimitives(pasteBuffer, bufferCopy, toSelect); 66 67 // Update references in copied buffer 68 for (PrimitiveData data : bufferCopy) { 69 if (data instanceof NodeData) { 70 NodeData nodeData = (NodeData) data; 71 nodeData.setEastNorth(nodeData.getEastNorth().add(offset)); 72 } else if (data instanceof WayData) { 73 updateNodes(newIds.get(OsmPrimitiveType.NODE), data); 74 } else if (data instanceof RelationData) { 75 updateMembers(newIds, data); 76 } 77 } 78 return new AddPrimitivesCommand(bufferCopy, toSelect, layer); 79 } 80 81 private static EnumMap<OsmPrimitiveType, Map<Long, Long>> generateNewPrimitives(PrimitiveTransferData pasteBuffer, 82 List<PrimitiveData> bufferCopy, List<PrimitiveData> toSelect) { 83 EnumMap<OsmPrimitiveType, Map<Long, Long>> newIds = new EnumMap<>(OsmPrimitiveType.class); 84 newIds.put(OsmPrimitiveType.NODE, new HashMap<Long, Long>()); 85 newIds.put(OsmPrimitiveType.WAY, new HashMap<Long, Long>()); 86 newIds.put(OsmPrimitiveType.RELATION, new HashMap<Long, Long>()); 87 88 for (PrimitiveData data : pasteBuffer.getAll()) { 89 if (data.isIncomplete()) { 90 continue; 91 } 92 PrimitiveData copy = data.makeCopy(); 93 // don't know why this is reset, but we need it to not crash on copying incomplete nodes. 94 boolean wasIncomplete = copy.isIncomplete(); 95 copy.clearOsmMetadata(); 96 copy.setIncomplete(wasIncomplete); 97 newIds.get(data.getType()).put(data.getUniqueId(), copy.getUniqueId()); 98 99 bufferCopy.add(copy); 100 if (pasteBuffer.getDirectlyAdded().contains(data)) { 101 toSelect.add(copy); 102 } 103 } 104 return newIds; 105 } 106 107 private static void updateMembers(EnumMap<OsmPrimitiveType, Map<Long, Long>> newIds, PrimitiveData data) { 108 List<RelationMemberData> newMembers = new ArrayList<>(); 109 for (RelationMemberData member : ((RelationData) data).getMembers()) { 110 OsmPrimitiveType memberType = member.getMemberType(); 111 Long newId = newIds.get(memberType).get(member.getMemberId()); 112 if (newId != null) { 113 newMembers.add(new RelationMemberData(member.getRole(), memberType, newId)); 114 } 115 } 116 ((RelationData) data).setMembers(newMembers); 117 } 118 119 private static void updateNodes(Map<Long, Long> newNodeIds, PrimitiveData data) { 120 List<Long> newNodes = new ArrayList<>(); 121 for (Long oldNodeId : ((WayData) data).getNodes()) { 122 Long newNodeId = newNodeIds.get(oldNodeId); 123 if (newNodeId != null) { 124 newNodes.add(newNodeId); 125 } 126 } 127 ((WayData) data).setNodes(newNodes); 128 } 129 130 private static boolean confirmDeleteIncomplete() { 131 ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Delete incomplete members?"), 132 new String[] { tr("Paste without incomplete members"), tr("Cancel") }); 133 ed.setButtonIcons(new String[] { "dialogs/relation/deletemembers", "cancel" }); 134 ed.setContent(tr( 135 "The copied data contains incomplete objects. " + "When pasting the incomplete objects are removed. " 136 + "Do you want to paste the data without the incomplete objects?")); 137 ed.showDialog(); 138 return ed.getValue() == 1; 139 } 140 } -
new file src/org/openstreetmap/josm/gui/datatransfer/importers/TagTransferPaster.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/importers/TagTransferPaster.java b/src/org/openstreetmap/josm/gui/datatransfer/importers/TagTransferPaster.java new file mode 100644 index 0000000..23f9fd7
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.datatransfer.importers; 3 4 import java.awt.datatransfer.UnsupportedFlavorException; 5 import java.io.IOException; 6 import java.util.Map; 7 8 import javax.swing.TransferHandler.TransferSupport; 9 10 import org.openstreetmap.josm.gui.datatransfer.data.TagTransferData; 11 12 /** 13 * This transfer support allows us to transfer tags from the copied primitives on to the selected ones. 14 * @author Michael Zangl 15 * @since xxx 16 */ 17 public final class TagTransferPaster extends AbstractTagPaster { 18 /** 19 * Create a new {@link TagTransferPaster} 20 */ 21 public TagTransferPaster() { 22 super(TagTransferData.FLAVOR); 23 } 24 25 @Override 26 protected Map<String, String> getTags(TransferSupport support) throws UnsupportedFlavorException, IOException { 27 TagTransferData data = (TagTransferData) support.getTransferable().getTransferData(df); 28 return data.getTags(); 29 } 30 } -
new file src/org/openstreetmap/josm/gui/datatransfer/importers/TextTagPaster.java
diff --git a/src/org/openstreetmap/josm/gui/datatransfer/importers/TextTagPaster.java b/src/org/openstreetmap/josm/gui/datatransfer/importers/TextTagPaster.java new file mode 100644 index 0000000..cadc706
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.datatransfer.importers; 3 4 import java.awt.datatransfer.DataFlavor; 5 import java.awt.datatransfer.UnsupportedFlavorException; 6 import java.io.IOException; 7 import java.util.Map; 8 9 import javax.swing.TransferHandler.TransferSupport; 10 11 import org.openstreetmap.josm.Main; 12 import org.openstreetmap.josm.tools.TextTagParser; 13 14 /** 15 * This transfer support allows us to import tags from the text that was copied to the clippboard. 16 * @author Michael Zangl 17 * @since xxx 18 */ 19 public final class TextTagPaster extends AbstractTagPaster { 20 21 /** 22 * Create a new {@link TextTagPaster} 23 */ 24 public TextTagPaster() { 25 super(DataFlavor.stringFlavor); 26 } 27 28 @Override 29 public boolean supports(TransferSupport support) { 30 try { 31 return super.supports(support) && getTags(support) != null; 32 } catch (UnsupportedFlavorException | IOException e) { 33 Main.warn(e); 34 return false; 35 } 36 } 37 38 @Override 39 protected Map<String, String> getTags(TransferSupport support) throws UnsupportedFlavorException, IOException { 40 return TextTagParser.readTagsFromText((String) support.getTransferable().getTransferData(df)); 41 } 42 } -
src/org/openstreetmap/josm/gui/dialogs/OsmIdSelectionDialog.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/OsmIdSelectionDialog.java b/src/org/openstreetmap/josm/gui/dialogs/OsmIdSelectionDialog.java index ea87e40..da11869 100644
a b import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 33 33 import org.openstreetmap.josm.data.osm.PrimitiveId; 34 34 import org.openstreetmap.josm.data.osm.SimplePrimitiveId; 35 35 import org.openstreetmap.josm.gui.ExtendedDialog; 36 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 36 37 import org.openstreetmap.josm.gui.widgets.HistoryComboBox; 37 38 import org.openstreetmap.josm.gui.widgets.HtmlPanel; 38 39 import org.openstreetmap.josm.gui.widgets.JosmTextField; … … public class OsmIdSelectionDialog extends ExtendedDialog implements WindowListen 201 202 } 202 203 203 204 protected void tryToPasteFromClipboard(OsmIdTextField tfId, OsmPrimitiveTypesComboBox cbType) { 204 String buf = Utils.getClipboardContent();205 String buf = ClipboardUtils.getClipboardStringContent(); 205 206 if (buf == null || buf.isEmpty()) return; 206 207 if (buf.length() > Main.pref.getInteger("downloadprimitive.max-autopaste-length", 2000)) return; 207 208 final List<SimplePrimitiveId> ids = SimplePrimitiveId.fuzzyParse(buf); -
src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java b/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java index 3f56870..7935def 100644
a b import org.openstreetmap.josm.gui.OsmPrimitivRenderer; 69 69 import org.openstreetmap.josm.gui.PopupMenuHandler; 70 70 import org.openstreetmap.josm.gui.SideButton; 71 71 import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable; 72 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 72 73 import org.openstreetmap.josm.gui.history.HistoryBrowserDialogManager; 73 74 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent; 74 75 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener; … … public class SelectionListDialog extends ToggleDialog { 880 881 881 882 @Override 882 883 protected Transferable createTransferable(JComponent c) { 883 return new PrimitiveTransferable( getSelectedPrimitives());884 return new PrimitiveTransferable(PrimitiveTransferData.getData(getSelectedPrimitives())); 884 885 } 885 886 } 886 887 } -
src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java b/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java index 4b96ea6..4408f0a 100644
a b import org.openstreetmap.josm.gui.DefaultNameFormatter; 86 86 import org.openstreetmap.josm.gui.ExtendedDialog; 87 87 import org.openstreetmap.josm.gui.PopupMenuHandler; 88 88 import org.openstreetmap.josm.gui.SideButton; 89 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 89 90 import org.openstreetmap.josm.gui.dialogs.ToggleDialog; 90 91 import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor; 91 92 import org.openstreetmap.josm.gui.help.HelpUtil; … … implements SelectionChangedListener, ActiveLayerChangeListener, DataSetListenerA 1264 1265 return; 1265 1266 String key = editHelper.getDataKey(tagTable.getSelectedRow()); 1266 1267 Collection<OsmPrimitive> sel = Main.main.getInProgressSelection(); 1267 String clipboard = Utils.getClipboardContent();1268 String clipboard = ClipboardUtils.getClipboardStringContent(); 1268 1269 if (sel.isEmpty() || clipboard == null) 1269 1270 return; 1270 1271 Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, Utils.strip(clipboard))); … … implements SelectionChangedListener, ActiveLayerChangeListener, DataSetListenerA 1294 1295 } 1295 1296 } 1296 1297 if (!values.isEmpty()) { 1297 Utils.copyToClipboard(Utils.join("\n", values));1298 ClipboardUtils.copyString(Utils.join("\n", values)); 1298 1299 } 1299 1300 } 1300 1301 } -
src/org/openstreetmap/josm/gui/dialogs/properties/TagEditHelper.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/properties/TagEditHelper.java b/src/org/openstreetmap/josm/gui/dialogs/properties/TagEditHelper.java index b00d0ce..a4900a7 100644
a b import org.openstreetmap.josm.data.preferences.EnumProperty; 76 76 import org.openstreetmap.josm.data.preferences.IntegerProperty; 77 77 import org.openstreetmap.josm.data.preferences.StringProperty; 78 78 import org.openstreetmap.josm.gui.ExtendedDialog; 79 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 79 80 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles; 80 81 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingComboBox; 81 82 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionListItem; … … public class TagEditHelper { 583 584 584 585 private void selectACComboBoxSavingUnixBuffer(AutoCompletingComboBox cb) { 585 586 // select combobox with saving unix system selection (middle mouse paste) 586 Clipboard sysSel = GuiHelper.getSystemSelection();587 Clipboard sysSel = ClipboardUtils.getSystemSelection(); 587 588 if (sysSel != null) { 588 Transferable old = Utils.getTransferableContent(sysSel);589 Transferable old = ClipboardUtils.getClipboardContent(sysSel); 589 590 cb.requestFocusInWindow(); 590 591 cb.getEditor().selectAll(); 591 592 if (old != null) { -
src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java b/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java index 47b563a..fd0175d 100644
a b import java.awt.GraphicsEnvironment; 11 11 import java.awt.GridBagConstraints; 12 12 import java.awt.GridBagLayout; 13 13 import java.awt.Window; 14 import java.awt.datatransfer.Clipboard; 15 import java.awt.datatransfer.FlavorListener; 14 16 import java.awt.event.ActionEvent; 15 17 import java.awt.event.FocusAdapter; 16 18 import java.awt.event.FocusEvent; … … import org.openstreetmap.josm.data.osm.Tag; 61 63 import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil; 62 64 import org.openstreetmap.josm.gui.DefaultNameFormatter; 63 65 import org.openstreetmap.josm.gui.MainMenu; 66 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 64 67 import org.openstreetmap.josm.gui.dialogs.relation.actions.AddSelectedAfterSelection; 65 68 import org.openstreetmap.josm.gui.dialogs.relation.actions.AddSelectedAtEndAction; 66 69 import org.openstreetmap.josm.gui.dialogs.relation.actions.AddSelectedAtStartAction; … … public class GenericRelationEditor extends RelationEditor { 152 155 * Action for performing the {@link CancelAction} 153 156 */ 154 157 private final CancelAction cancelAction; 158 /** 159 * A list of listeners that need to be notified on clipboard content changes. 160 */ 161 private final ArrayList<FlavorListener> clipboardListeners = new ArrayList<>(); 155 162 156 163 /** 157 164 * Creates a new relation editor for the given relation. The relation will be saved if the user … … public class GenericRelationEditor extends RelationEditor { 273 280 getRootPane(), memberTable, selectionTable); 274 281 // CHECKSTYLE.ON: LineLength 275 282 276 registerCopyPasteAction(new PasteMembersAction(memberTable Model, getLayer(), this) {283 registerCopyPasteAction(new PasteMembersAction(memberTable, getLayer(), this) { 277 284 @Override 278 285 public void actionPerformed(ActionEvent e) { 279 286 super.actionPerformed(e); … … public class GenericRelationEditor extends RelationEditor { 742 749 tagEditorPanel.initAutoCompletion(getLayer()); 743 750 } 744 751 super.setVisible(visible); 752 Clipboard clipboard = ClipboardUtils.getClipboard(); 745 753 if (visible) { 746 754 leftButtonToolbar.sortBelowButton.setVisible(ExpertToggleAction.isExpert()); 747 755 RelationDialogManager.getRelationDialogManager().positionOnScreen(this); … … public class GenericRelationEditor extends RelationEditor { 749 757 windowMenuItem = addToWindowMenu(this, getLayer().getName()); 750 758 } 751 759 tagEditorPanel.requestFocusInWindow(); 760 761 for (FlavorListener listener : clipboardListeners) { 762 clipboard.addFlavorListener(listener); 763 } 752 764 } else { 753 765 // make sure all registered listeners are unregistered 754 766 // … … public class GenericRelationEditor extends RelationEditor { 760 772 Main.main.menu.windowMenu.remove(windowMenuItem); 761 773 windowMenuItem = null; 762 774 } 775 for (FlavorListener listener : clipboardListeners) { 776 clipboard.removeFlavorListener(listener); 777 } 763 778 dispose(); 764 779 } 765 780 } … … public class GenericRelationEditor extends RelationEditor { 823 838 } 824 839 } 825 840 826 private staticvoid registerCopyPasteAction(AbstractAction action, Object actionName, KeyStroke shortcut,841 private void registerCopyPasteAction(AbstractAction action, Object actionName, KeyStroke shortcut, 827 842 JRootPane rootPane, JTable... tables) { 828 843 int mods = shortcut.getModifiers(); 829 844 int code = shortcut.getKeyCode(); … … public class GenericRelationEditor extends RelationEditor { 840 855 table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(shortcut, actionName); 841 856 table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(shortcut, actionName); 842 857 } 858 if (action instanceof FlavorListener) { 859 clipboardListeners.add((FlavorListener) action); 860 } 843 861 } 844 862 845 863 /** -
src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java b/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java index 324d3ff..f46eb66 100644
a b public class MemberTable extends OsmPrimitivesTable implements IMemberModelListe 85 85 JPopupMenu menu = super.buildPopupMenu(); 86 86 zoomToGap = new ZoomToGapAction(); 87 87 registerListeners(); 88 menu.addSeparator(); 88 89 getSelectionModel().addListSelectionListener(zoomToGap); 89 90 menu.add(zoomToGap); 90 91 menu.addSeparator(); -
src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java b/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java index d72479f..3a84cd0 100644
a b implements TableModelListener, SelectionChangedListener, DataSetListener, OsmPri 479 479 members.add(idx++, member); 480 480 } 481 481 invalidateConnectionType(); 482 final List<Integer> selection = getSelectedIndices();483 482 fireTableRowsInserted(index, idx - 1); 484 setSelectedMembersIdx(selection);485 483 } 486 484 487 485 public void addMembersAtBeginning(List<? extends OsmPrimitive> primitives) { -
src/org/openstreetmap/josm/gui/dialogs/relation/MemberTransferHandler.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTransferHandler.java b/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTransferHandler.java index 99fef5f..7f70cd0 100644
a b import javax.swing.TransferHandler; 16 16 import org.openstreetmap.josm.Main; 17 17 import org.openstreetmap.josm.data.osm.OsmPrimitive; 18 18 import org.openstreetmap.josm.data.osm.PrimitiveData; 19 import org.openstreetmap.josm.data.osm.PrimitiveId; 19 20 import org.openstreetmap.josm.data.osm.RelationMember; 20 21 import org.openstreetmap.josm.data.osm.RelationMemberData; 21 import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable;22 22 import org.openstreetmap.josm.gui.datatransfer.RelationMemberTransferable; 23 import org.openstreetmap.josm. tools.Utils.Function;23 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 24 24 25 class MemberTransferHandler extends TransferHandler { 25 /** 26 * A transfer handler that helps with importing / exporting members for relations. 27 * @author Michael Zangl 28 * @since xxx 29 */ 30 public class MemberTransferHandler extends TransferHandler { 26 31 27 32 @Override 28 33 public int getSourceActions(JComponent c) { … … class MemberTransferHandler extends TransferHandler { 37 42 38 43 @Override 39 44 public boolean canImport(TransferSupport support) { 40 support.setShowDropLocation(true); 45 if (support.isDrop()) { 46 support.setShowDropLocation(true); 47 } 41 48 return support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA) 42 || support.isDataFlavorSupported(PrimitiveTransfer able.PRIMITIVE_DATA);49 || support.isDataFlavorSupported(PrimitiveTransferData.DATA_FLAVOR); 43 50 } 44 51 45 52 @Override 46 53 public boolean importData(TransferSupport support) { 47 final MemberTable destination = (MemberTable) support.getComponent(); 48 final int insertRow = ((JTable.DropLocation) support.getDropLocation()).getRow(); 54 MemberTable destination = (MemberTable) support.getComponent(); 55 int insertRow = computeInsertionRow(support, destination); 56 57 return importDataAt(support, destination, insertRow); 58 59 } 60 61 private int computeInsertionRow(TransferSupport support, MemberTable destination) { 62 final int insertRow; 63 if (support.isDrop()) { 64 insertRow = ((JTable.DropLocation) support.getDropLocation()).getRow(); 65 } else { 66 int selection = destination.getSelectedRow(); 67 if (selection < 0) { 68 // no selection, add at the end. 69 insertRow = destination.getRowCount(); 70 } else { 71 insertRow = selection; 72 } 73 } 74 return insertRow; 75 } 49 76 77 private boolean importDataAt(TransferSupport support, MemberTable destination, int insertRow) { 50 78 try { 51 79 if (support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA)) { 52 80 importRelationMemberData(support, destination, insertRow); 53 } else if (support.isDataFlavorSupported(PrimitiveTransferable.PRIMITIVE_DATA)) { 81 return true; 82 } else if (support.isDataFlavorSupported(PrimitiveTransferData.DATA_FLAVOR)) { 54 83 importPrimitiveData(support, destination, insertRow); 84 return true; 85 } else { 86 return false; 55 87 } 56 88 } catch (IOException | UnsupportedFlavorException e) { 57 89 Main.warn(e); 58 90 return false; 59 91 } 60 61 return true;62 92 } 63 93 64 94 protected void importRelationMemberData(TransferSupport support, final MemberTable destination, int insertRow) 65 95 throws UnsupportedFlavorException, IOException { 66 96 final RelationMemberTransferable.Data memberData = (RelationMemberTransferable.Data) 67 97 support.getTransferable().getTransferData(RelationMemberTransferable.RELATION_MEMBER_DATA); 68 importData(destination, insertRow, memberData.getRelationMemberData(), new Function<RelationMemberData, RelationMember>() {98 importData(destination, insertRow, memberData.getRelationMemberData(), new AbstractRelationMemberConverter<RelationMemberData>() { 69 99 @Override 70 public RelationMember apply(RelationMemberData member) { 71 final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(member.getUniqueId(), member.getType()); 72 if (p == null) { 73 Main.warn(tr("Cannot add {0} since it is not part of dataset", member)); 74 return null; 75 } else { 76 return new RelationMember(member.getRole(), p); 77 } 100 protected RelationMember getMember(MemberTable destination, RelationMemberData data, OsmPrimitive p) { 101 return new RelationMember(data.getRole(), p); 78 102 } 79 103 }); 80 104 } 81 105 82 106 protected void importPrimitiveData(TransferSupport support, final MemberTable destination, int insertRow) 83 107 throws UnsupportedFlavorException, IOException { 84 final PrimitiveTransfer able.Data data = (PrimitiveTransferable.Data)85 support.getTransferable().getTransferData(PrimitiveTransfer able.PRIMITIVE_DATA);86 importData(destination, insertRow, data.get PrimitiveData(), new Function<PrimitiveData, RelationMember>() {108 final PrimitiveTransferData data = (PrimitiveTransferData) 109 support.getTransferable().getTransferData(PrimitiveTransferData.DATA_FLAVOR); 110 importData(destination, insertRow, data.getDirectlyAdded(), new AbstractRelationMemberConverter<PrimitiveData>() { 87 111 @Override 88 public RelationMember apply(PrimitiveData data) { 89 final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(data); 90 if (p == null) { 91 Main.warn(tr("Cannot add {0} since it is not part of dataset", data)); 92 return null; 93 } else { 94 return destination.getMemberTableModel().getRelationMemberForPrimitive(p); 95 } 112 protected RelationMember getMember(MemberTable destination, PrimitiveData data, OsmPrimitive p) { 113 return destination.getMemberTableModel().getRelationMemberForPrimitive(p); 96 114 } 97 115 }); 98 116 } 99 117 100 protected <T > void importData(MemberTable destination, int insertRow,101 Collection<T> memberData, Function<T, RelationMember> toMemberFunction) {118 protected <T extends PrimitiveId> void importData(MemberTable destination, int insertRow, 119 Collection<T> memberData, AbstractRelationMemberConverter<T> toMemberFunction) { 102 120 final Collection<RelationMember> membersToAdd = new ArrayList<>(memberData.size()); 103 for (T i: memberData) {104 final RelationMember member = toMemberFunction. apply(i);121 for (T data : memberData) { 122 final RelationMember member = toMemberFunction.importPrimitive(destination, data); 105 123 if (member != null) { 106 124 membersToAdd.add(member); 107 125 } … … class MemberTransferHandler extends TransferHandler { 119 137 model.remove(source.getSelectedRows()); 120 138 model.selectionChanged(null); 121 139 } 140 141 private abstract static class AbstractRelationMemberConverter<T extends PrimitiveId> { 142 protected RelationMember importPrimitive(MemberTable destination, T data) { 143 final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(data); 144 if (p == null) { 145 Main.warn(tr("Cannot add {0} since it is not part of dataset", data)); 146 return null; 147 } else { 148 return getMember(destination, data, p); 149 } 150 } 151 152 protected abstract RelationMember getMember(MemberTable destination, T data, OsmPrimitive p); 153 } 122 154 } -
src/org/openstreetmap/josm/gui/dialogs/relation/actions/CopyMembersAction.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/CopyMembersAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/CopyMembersAction.java index 952e554..8b8ba36 100644
a b package org.openstreetmap.josm.gui.dialogs.relation.actions; 4 4 import java.awt.event.ActionEvent; 5 5 import java.util.Collection; 6 6 7 import org.openstreetmap.josm.actions.CopyAction; 8 import org.openstreetmap.josm.data.osm.OsmPrimitive; 7 import org.openstreetmap.josm.data.osm.RelationMember; 8 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 9 import org.openstreetmap.josm.gui.datatransfer.RelationMemberTransferable; 9 10 import org.openstreetmap.josm.gui.dialogs.relation.IRelationEditor; 10 11 import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel; 11 12 import org.openstreetmap.josm.gui.layer.OsmDataLayer; … … public class CopyMembersAction extends AddFromSelectionAction { 28 29 29 30 @Override 30 31 public void actionPerformed(ActionEvent e) { 31 final Collection<OsmPrimitive> primitives = memberTableModel.getSelectedChildPrimitives(); 32 if (!primitives.isEmpty()) { 33 CopyAction.copy(layer, primitives); 32 final Collection<RelationMember> members = memberTableModel.getSelectedMembers(); 33 34 if (!members.isEmpty()) { 35 ClipboardUtils.copy(new RelationMemberTransferable(members)); 34 36 } 35 37 } 36 38 -
src/org/openstreetmap/josm/gui/dialogs/relation/actions/PasteMembersAction.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/PasteMembersAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/PasteMembersAction.java index eaa08d2..2cf4c16 100644
a b 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.gui.dialogs.relation.actions; 3 3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 4 import java.awt.datatransfer.FlavorEvent; 5 import java.awt.datatransfer.FlavorListener; 6 6 import java.awt.event.ActionEvent; 7 import java.util.ArrayList;8 import java.util.List;9 7 10 import javax.swing. JOptionPane;8 import javax.swing.TransferHandler.TransferSupport; 11 9 12 import org.openstreetmap.josm.Main; 13 import org.openstreetmap.josm.data.osm.DataSet; 14 import org.openstreetmap.josm.data.osm.OsmPrimitive; 15 import org.openstreetmap.josm.data.osm.PrimitiveData; 16 import org.openstreetmap.josm.gui.dialogs.relation.GenericRelationEditor.AddAbortException; 10 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 17 11 import org.openstreetmap.josm.gui.dialogs.relation.IRelationEditor; 18 import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel; 12 import org.openstreetmap.josm.gui.dialogs.relation.MemberTable; 13 import org.openstreetmap.josm.gui.dialogs.relation.MemberTransferHandler; 19 14 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 20 15 21 16 /** 22 17 * Paste members. 23 18 * @since 9496 24 19 */ 25 public class PasteMembersAction extends AddFromSelectionAction {20 public class PasteMembersAction extends AddFromSelectionAction implements FlavorListener { 26 21 27 22 /** 28 23 * Constructs a new {@code PasteMembersAction}. 29 * @param memberTable Model member table model24 * @param memberTable member table 30 25 * @param layer OSM data layer 31 26 * @param editor relation editor 32 27 */ 33 public PasteMembersAction(MemberTableModel memberTableModel, OsmDataLayer layer, IRelationEditor editor) { 34 super(null, memberTableModel, null, null, null, layer, editor); 28 public PasteMembersAction(MemberTable memberTable, OsmDataLayer layer, IRelationEditor editor) { 29 super(memberTable, null, null, null, null, layer, editor); 30 updateEnabledState(); 35 31 } 36 32 37 33 @Override 38 34 public void actionPerformed(ActionEvent e) { 39 try { 40 List<PrimitiveData> primitives = Main.pasteBuffer.getDirectlyAdded(); 41 DataSet ds = layer.data; 42 List<OsmPrimitive> toAdd = new ArrayList<>(); 43 boolean hasNewInOtherLayer = false; 44 45 for (PrimitiveData primitive: primitives) { 46 OsmPrimitive primitiveInDs = ds.getPrimitiveById(primitive); 47 if (primitiveInDs != null) { 48 toAdd.add(primitiveInDs); 49 } else if (!primitive.isNew()) { 50 OsmPrimitive p = primitive.getType().newInstance(primitive.getUniqueId(), true); 51 ds.addPrimitive(p); 52 toAdd.add(p); 53 } else { 54 hasNewInOtherLayer = true; 55 break; 56 } 57 } 58 59 if (hasNewInOtherLayer) { 60 JOptionPane.showMessageDialog(Main.parent, 61 tr("Members from paste buffer cannot be added because they are not included in current layer")); 62 return; 63 } 64 65 toAdd = filterConfirmedPrimitives(toAdd); 66 int index = memberTableModel.getSelectionModel().getMaxSelectionIndex(); 67 if (index == -1) { 68 index = memberTableModel.getRowCount() - 1; 69 } 70 memberTableModel.addMembersAfterIdx(toAdd, index); 35 new MemberTransferHandler().importData(getSupport()); 36 } 71 37 72 } catch (AddAbortException ex) { 73 Main.trace(ex); 74 } 38 private TransferSupport getSupport() { 39 return new TransferSupport(memberTable, ClipboardUtils.getClipboard().getContents(null)); 75 40 } 76 41 77 42 @Override 78 43 protected void updateEnabledState() { 79 // Do nothing 44 setEnabled(new MemberTransferHandler().canImport(getSupport())); 45 } 46 47 @Override 48 public void flavorsChanged(FlavorEvent e) { 49 updateEnabledState(); 80 50 } 81 51 } -
src/org/openstreetmap/josm/gui/download/DownloadDialog.java
diff --git a/src/org/openstreetmap/josm/gui/download/DownloadDialog.java b/src/org/openstreetmap/josm/gui/download/DownloadDialog.java index c937092..b444bbd 100644
a b import org.openstreetmap.josm.Main; 38 38 import org.openstreetmap.josm.actions.ExpertToggleAction; 39 39 import org.openstreetmap.josm.data.Bounds; 40 40 import org.openstreetmap.josm.gui.MapView; 41 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 41 42 import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction; 42 43 import org.openstreetmap.josm.gui.help.HelpUtil; 43 44 import org.openstreetmap.josm.gui.util.GuiHelper; … … public class DownloadDialog extends JDialog { 242 243 getRootPane().getActionMap().put("checkClipboardContents", new AbstractAction() { 243 244 @Override 244 245 public void actionPerformed(ActionEvent e) { 245 String clip = Utils.getClipboardContent();246 String clip = ClipboardUtils.getClipboardStringContent(); 246 247 if (clip == null) { 247 248 return; 248 249 } -
src/org/openstreetmap/josm/gui/layer/NoteLayer.java
diff --git a/src/org/openstreetmap/josm/gui/layer/NoteLayer.java b/src/org/openstreetmap/josm/gui/layer/NoteLayer.java index 90f65b0..4b9c1a8 100644
a b import org.openstreetmap.josm.data.notes.NoteComment; 30 30 import org.openstreetmap.josm.data.osm.NoteData; 31 31 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; 32 32 import org.openstreetmap.josm.gui.MapView; 33 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 33 34 import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 34 35 import org.openstreetmap.josm.gui.dialogs.LayerListPopup; 35 36 import org.openstreetmap.josm.gui.io.AbstractIOTask; … … import org.openstreetmap.josm.io.OsmApi; 40 41 import org.openstreetmap.josm.io.XmlWriter; 41 42 import org.openstreetmap.josm.tools.ColorHelper; 42 43 import org.openstreetmap.josm.tools.ImageProvider; 43 import org.openstreetmap.josm.tools.Utils;44 44 import org.openstreetmap.josm.tools.date.DateUtils; 45 45 46 46 /** … … public class NoteLayer extends AbstractModifiableLayer implements MouseListener 237 237 public void mouseClicked(MouseEvent e) { 238 238 if (SwingUtilities.isRightMouseButton(e) && noteData.getSelectedNote() != null) { 239 239 final String url = OsmApi.getOsmApi().getBaseUrl() + "notes/" + noteData.getSelectedNote().getId(); 240 Utils.copyToClipboard(url);240 ClipboardUtils.copyString(url); 241 241 return; 242 242 } else if (!SwingUtilities.isLeftMouseButton(e)) { 243 243 return; -
src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java b/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java index 6c58bca..783b9b2 100644
a b import org.openstreetmap.josm.gui.MapFrame.MapModeChangeListener; 52 52 import org.openstreetmap.josm.gui.MapView; 53 53 import org.openstreetmap.josm.gui.NavigatableComponent; 54 54 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 55 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 55 56 import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 56 57 import org.openstreetmap.josm.gui.dialogs.LayerListPopup; 57 58 import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer; … … public class GeoImageLayer extends AbstractModifiableLayer implements PropertyCh 724 725 725 726 public void copyCurrentPhotoPath() { 726 727 if (data != null && !data.isEmpty() && currentPhoto >= 0 && currentPhoto < data.size()) { 727 Utils.copyToClipboard(data.get(currentPhoto).getFile().toString());728 ClipboardUtils.copyString(data.get(currentPhoto).getFile().toString()); 728 729 } 729 730 } 730 731 -
src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java
diff --git a/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java b/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java index 53499d8..90e3efa 100644
a b import java.beans.PropertyChangeListener; 7 7 import java.beans.PropertyChangeSupport; 8 8 import java.util.ArrayList; 9 9 import java.util.Collection; 10 import java.util.Collections; 10 11 import java.util.Comparator; 11 12 import java.util.EnumSet; 12 13 import java.util.HashMap; … … import org.openstreetmap.josm.command.SequenceCommand; 24 25 import org.openstreetmap.josm.data.osm.OsmPrimitive; 25 26 import org.openstreetmap.josm.data.osm.Tag; 26 27 import org.openstreetmap.josm.data.osm.TagCollection; 28 import org.openstreetmap.josm.data.osm.TagMap; 27 29 import org.openstreetmap.josm.data.osm.Tagged; 28 30 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetType; 29 31 import org.openstreetmap.josm.tools.CheckParameterUtil; … … public class TagEditorModel extends AbstractTableModel { 47 49 48 50 private transient OsmPrimitive primitive; 49 51 52 private EndEditListener endEditListener; 53 50 54 /** 51 55 * Creates a new tag editor model. Internally allocates two selection models 52 56 * for row selection and column selection. … … public class TagEditorModel extends AbstractTableModel { 166 170 * removes all tags in the model 167 171 */ 168 172 public void clear() { 173 commitPendingEdit(); 169 174 boolean wasEmpty = tags.isEmpty(); 170 175 tags.clear(); 171 176 if (!wasEmpty) { … … public class TagEditorModel extends AbstractTableModel { 182 187 * @throws IllegalArgumentException if tag is null 183 188 */ 184 189 public void add(TagModel tag) { 190 commitPendingEdit(); 185 191 CheckParameterUtil.ensureParameterNotNull(tag, "tag"); 186 192 tags.add(tag); 187 193 setDirty(true); 188 194 fireTableDataChanged(); 189 195 } 190 196 197 /** 198 * Add a tag at the beginning of the table. 199 * 200 * @param tag The tag to add 201 * 202 * @throws IllegalArgumentException if tag is null 203 * 204 * @see #add(TagModel) 205 */ 191 206 public void prepend(TagModel tag) { 207 commitPendingEdit(); 192 208 CheckParameterUtil.ensureParameterNotNull(tag, "tag"); 193 209 tags.add(0, tag); 194 210 setDirty(true); … … public class TagEditorModel extends AbstractTableModel { 208 224 * @param value the value; converted to "" if null 209 225 */ 210 226 public void add(String name, String value) { 227 commitPendingEdit(); 211 228 String key = (name == null) ? "" : name; 212 229 String val = (value == null) ? "" : value; 213 230 … … public class TagEditorModel extends AbstractTableModel { 258 275 public void deleteTagNames(int[] tagIndices) { 259 276 if (tags == null) 260 277 return; 278 commitPendingEdit(); 261 279 for (int tagIdx : tagIndices) { 262 280 TagModel tag = tags.get(tagIdx); 263 281 if (tag != null) { … … public class TagEditorModel extends AbstractTableModel { 276 294 public void deleteTagValues(int[] tagIndices) { 277 295 if (tags == null) 278 296 return; 297 commitPendingEdit(); 279 298 for (int tagIdx : tagIndices) { 280 299 TagModel tag = tags.get(tagIdx); 281 300 if (tag != null) { … … public class TagEditorModel extends AbstractTableModel { 292 311 * @param name the name. Ignored if null. 293 312 */ 294 313 public void delete(String name) { 314 commitPendingEdit(); 295 315 if (name == null) 296 316 return; 297 317 Iterator<TagModel> it = tags.iterator(); … … public class TagEditorModel extends AbstractTableModel { 317 337 public void deleteTags(int[] tagIndices) { 318 338 if (tags == null) 319 339 return; 340 commitPendingEdit(); 320 341 List<TagModel> toDelete = new ArrayList<>(); 321 342 for (int tagIdx : tagIndices) { 322 343 TagModel tag = tags.get(tagIdx); … … public class TagEditorModel extends AbstractTableModel { 355 376 * @param primitive the OSM primitive 356 377 */ 357 378 public void initFromPrimitive(Tagged primitive) { 379 commitPendingEdit(); 358 380 this.tags.clear(); 359 381 for (String key : primitive.keySet()) { 360 382 String value = primitive.get(key); 361 383 this.tags.add(new TagModel(key, value)); 362 384 } 363 TagModel tag = new TagModel();364 385 sort(); 386 TagModel tag = new TagModel(); 365 387 tags.add(tag); 366 388 setDirty(false); 367 389 fireTableDataChanged(); … … public class TagEditorModel extends AbstractTableModel { 373 395 * @param tags the tags of an OSM primitive 374 396 */ 375 397 public void initFromTags(Map<String, String> tags) { 398 commitPendingEdit(); 376 399 this.tags.clear(); 377 400 for (Entry<String, String> entry : tags.entrySet()) { 378 401 this.tags.add(new TagModel(entry.getKey(), entry.getValue())); … … public class TagEditorModel extends AbstractTableModel { 390 413 * @param tags the tags 391 414 */ 392 415 public void initFromTags(TagCollection tags) { 416 commitPendingEdit(); 393 417 this.tags.clear(); 394 418 if (tags == null) { 395 419 setDirty(false); … … public class TagEditorModel extends AbstractTableModel { 423 447 * @return the map of key/value pairs 424 448 */ 425 449 private Map<String, String> applyToTags(boolean keepEmpty) { 426 Map<String, String> result = new HashMap<>(); 450 // TagMap preserves the order of tags. 451 TagMap result = new TagMap(); 427 452 for (TagModel tag: this.tags) { 428 453 // tag still holds an unchanged list of different values for the same key. 429 454 // no property change command required … … public class TagEditorModel extends AbstractTableModel { 432 457 } 433 458 434 459 // tag name holds an empty key. Don't apply it to the selection. 435 //436 460 if (!keepEmpty && (tag.getName().trim().isEmpty() || tag.getValue().trim().isEmpty())) { 437 461 continue; 438 462 } … … public class TagEditorModel extends AbstractTableModel { 538 562 * sorts the current tags according alphabetical order of names 539 563 */ 540 564 protected void sort() { 541 java.util.Collections.sort(565 Collections.sort( 542 566 tags, 543 567 new Comparator<TagModel>() { 544 568 @Override … … public class TagEditorModel extends AbstractTableModel { 590 614 * @param tags - the list 591 615 */ 592 616 public void updateTags(List<Tag> tags) { 593 617 if (tags.isEmpty()) 594 618 return; 595 619 620 commitPendingEdit(); 596 621 Map<String, TagModel> modelTags = new HashMap<>(); 597 622 for (int i = 0; i < getRowCount(); i++) { 598 623 TagModel tagModel = get(i); … … public class TagEditorModel extends AbstractTableModel { 647 672 return this; 648 673 } 649 674 675 /** 676 * Sets the listener that is notified when an edit should be aborted. 677 * @param endEditListener The listener to be notified when editing should be aborted. 678 */ 679 public void setEndEditListener(EndEditListener endEditListener) { 680 this.endEditListener = endEditListener; 681 } 682 683 private void commitPendingEdit() { 684 if (endEditListener != null) { 685 endEditListener.endCellEditing(); 686 } 687 } 688 650 689 class SelectionStateMemento { 651 690 private final int rowMin; 652 691 private final int rowMax; … … public class TagEditorModel extends AbstractTableModel { 673 712 colSelectionModel.setValueIsAdjusting(false); 674 713 } 675 714 } 715 716 /** 717 * A listener that is called whenever the cells may be updated from outside the editor and the editor should thus be commited. 718 */ 719 public interface EndEditListener { 720 /** 721 * Requests to end the editing of any cells on this model 722 */ 723 public void endCellEditing(); 724 } 676 725 } -
src/org/openstreetmap/josm/gui/tagging/TagTable.java
diff --git a/src/org/openstreetmap/josm/gui/tagging/TagTable.java b/src/org/openstreetmap/josm/gui/tagging/TagTable.java index cea481e..6d2899e 100644
a b 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.gui.tagging; 3 3 4 import static org.openstreetmap.josm.gui.help.HelpUtil.ht;5 4 import static org.openstreetmap.josm.tools.I18n.tr; 6 5 7 6 import java.awt.Component; … … import java.awt.event.ActionEvent; 12 11 import java.awt.event.KeyEvent; 13 12 import java.beans.PropertyChangeEvent; 14 13 import java.beans.PropertyChangeListener; 15 import java.util.ArrayList;16 14 import java.util.Collections; 17 15 import java.util.EventObject; 18 import java.util.List;19 import java.util.Map;20 16 import java.util.concurrent.CopyOnWriteArrayList; 21 17 22 18 import javax.swing.AbstractAction; … … import javax.swing.event.ListSelectionListener; 31 27 import javax.swing.text.JTextComponent; 32 28 33 29 import org.openstreetmap.josm.Main; 34 import org.openstreetmap.josm.actions.CopyAction;35 import org.openstreetmap.josm.actions.PasteTagsAction;36 import org.openstreetmap.josm.data.osm.OsmPrimitive;37 import org.openstreetmap.josm.data.osm.PrimitiveData;38 30 import org.openstreetmap.josm.data.osm.Relation; 39 import org.openstreetmap.josm.data.osm.Tag; 31 import org.openstreetmap.josm.data.osm.TagMap; 32 import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler; 33 import org.openstreetmap.josm.gui.tagging.TagEditorModel.EndEditListener; 40 34 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList; 41 35 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager; 42 36 import org.openstreetmap.josm.gui.widgets.JosmTable; 43 37 import org.openstreetmap.josm.tools.ImageProvider; 44 import org.openstreetmap.josm.tools.TextTagParser;45 import org.openstreetmap.josm.tools.Utils;46 38 47 39 /** 48 40 * This is the tabular editor component for OSM tags. 49 41 * @since 1762 50 42 */ 51 public class TagTable extends JosmTable {43 public class TagTable extends JosmTable implements EndEditListener { 52 44 /** the table cell editor used by this table */ 53 45 private TagCellEditor editor; 54 46 private final TagEditorModel model; … … public class TagTable extends JosmTable { 210 202 default: // Do nothing 211 203 } 212 204 213 if (isEditing()) { 214 CellEditor cEditor = getCellEditor(); 215 if (cEditor != null) { 216 cEditor.cancelCellEditing(); 217 } 218 } 205 endCellEditing(); 219 206 220 207 if (model.getRowCount() == 0) { 221 208 model.ensureOneTag(); … … public class TagTable extends JosmTable { 232 219 } 233 220 234 221 protected final void updateEnabledState() { 235 if (isEditing() && getSelectedColumnCount() == 1 && getSelectedRowCount() == 1) { 236 setEnabled(true); 237 } else if (!isEditing() && getSelectedColumnCount() == 1 && getSelectedRowCount() == 1) { 238 setEnabled(true); 239 } else if (getSelectedColumnCount() > 1 || getSelectedRowCount() > 1) { 222 if (getSelectedColumnCount() >= 1 && getSelectedRowCount() >= 1) { 240 223 setEnabled(true); 241 224 } else { 242 225 setEnabled(false); … … public class TagTable extends JosmTable { 294 277 public void actionPerformed(ActionEvent e) { 295 278 Relation relation = new Relation(); 296 279 model.applyToPrimitive(relation); 297 298 String buf = Utils.getClipboardContent(); 299 if (buf == null || buf.isEmpty() || buf.matches(CopyAction.CLIPBOARD_REGEXP)) { 300 List<PrimitiveData> directlyAdded = Main.pasteBuffer.getDirectlyAdded(); 301 if (directlyAdded == null || directlyAdded.isEmpty()) return; 302 PasteTagsAction.TagPaster tagPaster = new PasteTagsAction.TagPaster(directlyAdded, 303 Collections.<OsmPrimitive>singletonList(relation)); 304 model.updateTags(tagPaster.execute()); 305 } else { 306 // Paste tags from arbitrary text 307 Map<String, String> tags = TextTagParser.readTagsFromText(buf); 308 if (tags == null || tags.isEmpty()) { 309 TextTagParser.showBadBufferMessage(ht("/Action/PasteTags")); 310 } else if (TextTagParser.validateTags(tags)) { 311 List<Tag> newTags = new ArrayList<>(); 312 for (Map.Entry<String, String> entry: tags.entrySet()) { 313 String k = entry.getKey(); 314 String v = entry.getValue(); 315 newTags.add(new Tag(k, v)); 316 } 317 model.updateTags(newTags); 318 } 319 } 280 new OsmTransferHandler().pasteTags(Collections.singleton(relation)); 281 model.updateTags(new TagMap(relation.getKeys()).getTags()); 320 282 } 321 283 322 284 protected final void updateEnabledState() { … … public class TagTable extends JosmTable { 414 376 .setSelectionModel(model.getColumnSelectionModel()).build(), 415 377 model.getRowSelectionModel()); 416 378 this.model = model; 379 model.setEndEditListener(this); 417 380 init(maxCharacters); 418 381 } 419 382 … … public class TagTable extends JosmTable { 487 450 * @param editor tag cell editor 488 451 */ 489 452 public void setTagCellEditor(TagCellEditor editor) { 490 if (isEditing()) { 491 this.editor.cancelCellEditing(); 492 } 453 endCellEditing(); 493 454 this.editor = editor; 494 455 getColumnModel().getColumn(0).setCellEditor(editor); 495 456 getColumnModel().getColumn(1).setCellEditor(editor); … … public class TagTable extends JosmTable { 548 509 } 549 510 550 511 @Override 512 public void endCellEditing() { 513 if (isEditing()) { 514 CellEditor cEditor = getCellEditor(); 515 if (cEditor != null) { 516 // First attempt to commit. If this does not work, cancel. 517 cEditor.stopCellEditing(); 518 cEditor.cancelCellEditing(); 519 } 520 } 521 } 522 523 @Override 551 524 public void removeEditor() { 552 525 // make sure we unregister our custom implementation of CellEditorRemover 553 526 KeyboardFocusManager.getCurrentKeyboardFocusManager(). -
src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingComboBox.java
diff --git a/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingComboBox.java b/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingComboBox.java index c46e863..c98a0df 100644
a b import javax.swing.text.PlainDocument; 23 23 import javax.swing.text.StyleConstants; 24 24 25 25 import org.openstreetmap.josm.Main; 26 import org.openstreetmap.josm.gui. util.GuiHelper;26 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 27 27 import org.openstreetmap.josm.gui.widgets.JosmComboBox; 28 import org.openstreetmap.josm.tools.Utils;29 28 30 29 /** 31 30 * Auto-completing ComboBox. … … public class AutoCompletingComboBox extends JosmComboBox<AutoCompletionListItem> 133 132 } 134 133 final JTextComponent editorComponent = comboBox.getEditorComponent(); 135 134 // save unix system selection (middle mouse paste) 136 Clipboard sysSel = GuiHelper.getSystemSelection();135 Clipboard sysSel = ClipboardUtils.getSystemSelection(); 137 136 if (sysSel != null) { 138 Transferable old = Utils.getTransferableContent(sysSel);137 Transferable old = ClipboardUtils.getClipboardContent(sysSel); 139 138 editorComponent.select(start, end); 140 139 if (old != null) { 141 140 sysSel.setContents(old, null); … … public class AutoCompletingComboBox extends JosmComboBox<AutoCompletionListItem> 200 199 Main.map.keyDetector.setEnabled(false); 201 200 } 202 201 // save unix system selection (middle mouse paste) 203 Clipboard sysSel = GuiHelper.getSystemSelection();202 Clipboard sysSel = ClipboardUtils.getSystemSelection(); 204 203 if (sysSel != null) { 205 Transferable old = Utils.getTransferableContent(sysSel);204 Transferable old = ClipboardUtils.getClipboardContent(sysSel); 206 205 editorComponent.selectAll(); 207 206 if (old != null) { 208 207 sysSel.setContents(old, null); -
src/org/openstreetmap/josm/gui/util/GuiHelper.java
diff --git a/src/org/openstreetmap/josm/gui/util/GuiHelper.java b/src/org/openstreetmap/josm/gui/util/GuiHelper.java index b6612e4..b61c406 100644
a b import java.awt.Image; 20 20 import java.awt.Stroke; 21 21 import java.awt.Toolkit; 22 22 import java.awt.Window; 23 import java.awt.datatransfer.Clipboard;24 23 import java.awt.event.ActionListener; 25 24 import java.awt.event.HierarchyEvent; 26 25 import java.awt.event.HierarchyListener; … … public final class GuiHelper { 496 495 } 497 496 498 497 /** 499 * Gets the singleton instance of the system selection as a <code>Clipboard</code> object.500 * This allows an application to read and modify the current, system-wide selection.501 * @return the system selection as a <code>Clipboard</code>, or <code>null</code> if the native platform does not502 * support a system selection <code>Clipboard</code> or if GraphicsEnvironment.isHeadless() returns true503 * @see Toolkit#getSystemSelection504 * @since 9576505 */506 public static Clipboard getSystemSelection() {507 return GraphicsEnvironment.isHeadless() ? null : Toolkit.getDefaultToolkit().getSystemSelection();508 }509 510 /**511 498 * Returns the first <code>Window</code> ancestor of event source, or 512 499 * {@code null} if event source is not a component contained inside a <code>Window</code>. 513 500 * @param e event object -
src/org/openstreetmap/josm/gui/widgets/AbstractIdTextField.java
diff --git a/src/org/openstreetmap/josm/gui/widgets/AbstractIdTextField.java b/src/org/openstreetmap/josm/gui/widgets/AbstractIdTextField.java index a9d1f33..5a695ed 100644
a b package org.openstreetmap.josm.gui.widgets; 4 4 import javax.swing.text.JTextComponent; 5 5 6 6 import org.openstreetmap.josm.Main; 7 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 7 8 import org.openstreetmap.josm.tools.Utils; 8 9 9 10 /** … … public abstract class AbstractIdTextField<T extends AbstractTextComponentValidat 70 71 * Tries to set text from clipboard (no effect with invalid or empty clipboard) 71 72 */ 72 73 public void tryToPasteFromClipboard() { 73 tryToPasteFrom( Utils.getClipboardContent());74 tryToPasteFrom(ClipboardUtils.getClipboardStringContent()); 74 75 } 75 76 76 77 /** -
src/org/openstreetmap/josm/gui/widgets/UrlLabel.java
diff --git a/src/org/openstreetmap/josm/gui/widgets/UrlLabel.java b/src/org/openstreetmap/josm/gui/widgets/UrlLabel.java index fbb21e4..6a5ac58 100644
a b import java.awt.event.MouseListener; 10 10 import javax.swing.JLabel; 11 11 import javax.swing.SwingUtilities; 12 12 13 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 13 14 import org.openstreetmap.josm.tools.OpenBrowser; 14 import org.openstreetmap.josm.tools.Utils;15 15 16 16 /** 17 17 * Label that contains a clickable link. … … public class UrlLabel extends JLabel implements MouseListener { 111 111 if (SwingUtilities.isLeftMouseButton(e)) { 112 112 OpenBrowser.displayUrl(url); 113 113 } else if (SwingUtilities.isRightMouseButton(e)) { 114 Utils.copyToClipboard(url);114 ClipboardUtils.copyString(url); 115 115 } 116 116 } 117 117 -
src/org/openstreetmap/josm/tools/TextTagParser.java
diff --git a/src/org/openstreetmap/josm/tools/TextTagParser.java b/src/org/openstreetmap/josm/tools/TextTagParser.java index a6aa70b..c28c092 100644
a b import javax.swing.JPanel; 18 18 19 19 import org.openstreetmap.josm.Main; 20 20 import org.openstreetmap.josm.gui.ExtendedDialog; 21 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 21 22 import org.openstreetmap.josm.gui.help.HelpUtil; 22 23 import org.openstreetmap.josm.gui.widgets.UrlLabel; 23 24 import org.openstreetmap.josm.io.XmlWriter; … … public final class TextTagParser { 290 291 int r = ed.getValue(); 291 292 if (r == 0) r = 2; 292 293 // clean clipboard if user asked 293 if (r == 3) Utils.copyToClipboard("");294 if (r == 3) ClipboardUtils.copyString(""); 294 295 return r; 295 296 } 296 297 … … public final class TextTagParser { 325 326 326 327 int r = ed.getValue(); 327 328 // clean clipboard if user asked 328 if (r == 2) Utils.copyToClipboard("");329 if (r == 2) ClipboardUtils.copyString(""); 329 330 } 330 331 } -
src/org/openstreetmap/josm/tools/Utils.java
diff --git a/src/org/openstreetmap/josm/tools/Utils.java b/src/org/openstreetmap/josm/tools/Utils.java index bc151aa..ef320a9 100644
a b import static org.openstreetmap.josm.tools.I18n.trn; 7 7 8 8 import java.awt.Color; 9 9 import java.awt.Font; 10 import java.awt.HeadlessException;11 import java.awt.Toolkit;12 10 import java.awt.datatransfer.Clipboard; 13 import java.awt.datatransfer.ClipboardOwner;14 import java.awt.datatransfer.DataFlavor;15 import java.awt.datatransfer.StringSelection;16 11 import java.awt.datatransfer.Transferable; 17 import java.awt.datatransfer.UnsupportedFlavorException;18 12 import java.awt.font.FontRenderContext; 19 13 import java.awt.font.GlyphVector; 20 14 import java.io.BufferedReader; … … import javax.xml.parsers.SAXParserFactory; 71 65 72 66 import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; 73 67 import org.openstreetmap.josm.Main; 68 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 74 69 import org.w3c.dom.Document; 75 70 import org.xml.sax.InputSource; 76 71 import org.xml.sax.SAXException; … … public final class Utils { 623 618 * Copies the string {@code s} to system clipboard. 624 619 * @param s string to be copied to clipboard. 625 620 * @return true if succeeded, false otherwise. 621 * @deprecated Use {@link ClipboardUtils#copyString(String)}. To be removed end of 2016. 626 622 */ 623 @Deprecated 627 624 public static boolean copyToClipboard(String s) { 628 try { 629 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(s), new ClipboardOwner() { 630 @Override 631 public void lostOwnership(Clipboard clpbrd, Transferable t) { 632 // Do nothing 633 } 634 }); 635 return true; 636 } catch (IllegalStateException | HeadlessException ex) { 637 Main.error(ex); 638 return false; 639 } 625 return ClipboardUtils.copyString(s); 640 626 } 641 627 642 628 /** … … public final class Utils { 644 630 * @param clipboard clipboard from which contents are retrieved 645 631 * @return clipboard contents if available, {@code null} otherwise. 646 632 * @since 8429 633 * @deprecated Use {@link ClipboardUtils#getClipboardContent(Clipboard)} instead. To be removed end of 2016. 647 634 */ 635 @Deprecated 648 636 public static Transferable getTransferableContent(Clipboard clipboard) { 649 Transferable t = null; 650 for (int tries = 0; t == null && tries < 10; tries++) { 651 try { 652 t = clipboard.getContents(null); 653 } catch (IllegalStateException e) { 654 // Clipboard currently unavailable. 655 // On some platforms, the system clipboard is unavailable while it is accessed by another application. 656 try { 657 Thread.sleep(1); 658 } catch (InterruptedException ex) { 659 Main.warn("InterruptedException in "+Utils.class.getSimpleName()+" while getting clipboard content"); 660 } 661 } catch (NullPointerException e) { 662 // JDK-6322854: On Linux/X11, NPE can happen for unknown reasons, on all versions of Java 663 Main.error(e); 664 } 665 } 666 return t; 637 return ClipboardUtils.getClipboardContent(clipboard); 667 638 } 668 639 669 640 /** 670 641 * Extracts clipboard content as string. 671 642 * @return string clipboard contents if available, {@code null} otherwise. 643 * @deprecated Use {@link ClipboardUtils#getClipboardStringContent()}. To be removed end of 2016 672 644 */ 645 @Deprecated 673 646 public static String getClipboardContent() { 674 try { 675 Transferable t = getTransferableContent(Toolkit.getDefaultToolkit().getSystemClipboard()); 676 if (t != null && t.isDataFlavorSupported(DataFlavor.stringFlavor)) { 677 return (String) t.getTransferData(DataFlavor.stringFlavor); 678 } 679 } catch (UnsupportedFlavorException | IOException | HeadlessException ex) { 680 Main.error(ex); 681 return null; 682 } 683 return null; 647 return ClipboardUtils.getClipboardStringContent(); 684 648 } 685 649 686 650 /** -
src/org/openstreetmap/josm/tools/bugreport/DebugTextDisplay.java
diff --git a/src/org/openstreetmap/josm/tools/bugreport/DebugTextDisplay.java b/src/org/openstreetmap/josm/tools/bugreport/DebugTextDisplay.java index 28f88ac..237b952 100644
a b import java.awt.Dimension; 5 5 6 6 import javax.swing.JScrollPane; 7 7 8 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 8 9 import org.openstreetmap.josm.gui.widgets.JosmTextArea; 9 10 import org.openstreetmap.josm.tools.Utils; 10 11 … … public class DebugTextDisplay extends JScrollPane { 34 35 * @return <code>true</code> if copy was successful 35 36 */ 36 37 public boolean copyToClippboard() { 37 return Utils.copyToClipboard(text);38 return ClipboardUtils.copyString(text); 38 39 } 39 40 } -
test/unit/org/openstreetmap/josm/actions/CopyActionTest.java
diff --git a/test/unit/org/openstreetmap/josm/actions/CopyActionTest.java b/test/unit/org/openstreetmap/josm/actions/CopyActionTest.java index 426b4e7..05758b9 100644
a b 2 2 package org.openstreetmap.josm.actions; 3 3 4 4 import static org.junit.Assert.assertEquals; 5 import static org.junit.Assert.assertFalse; 6 import static org.junit.Assert.assertNotNull; 7 import static org.junit.Assert.assertTrue; 8 import static org.junit.Assert.fail; 5 9 10 import java.awt.datatransfer.Clipboard; 11 import java.awt.datatransfer.DataFlavor; 12 import java.awt.datatransfer.StringSelection; 13 import java.awt.datatransfer.UnsupportedFlavorException; 14 import java.io.IOException; 6 15 import java.util.Arrays; 7 import java.util.Collections;8 16 9 import org.junit. BeforeClass;17 import org.junit.Rule; 10 18 import org.junit.Test; 11 import org.openstreetmap.josm.JOSMFixture; 12 import org.openstreetmap.josm.data.osm.Relation; 19 import org.openstreetmap.josm.Main; 20 import org.openstreetmap.josm.data.coor.LatLon; 21 import org.openstreetmap.josm.data.osm.DataSet; 22 import org.openstreetmap.josm.data.osm.Node; 13 23 import org.openstreetmap.josm.data.osm.Way; 24 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 25 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 26 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 27 import org.openstreetmap.josm.testutils.JOSMTestRules; 28 29 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 14 30 15 31 /** 16 32 * Unit tests for class {@link CopyAction}. 17 33 */ 18 34 public class CopyActionTest { 35 private final class CapturingCopyAction extends CopyAction { 36 private boolean warningShown; 37 38 @Override 39 protected void showEmptySelectionWarning() { 40 warningShown = true; 41 } 42 } 19 43 20 44 /** 21 * Setup test.45 * We need prefs for this. 22 46 */ 23 @BeforeClass 24 public static void setUpBeforeClass() { 25 JOSMFixture.createUnitTestFixture().init(); 26 } 47 @Rule 48 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") 49 public JOSMTestRules test = new JOSMTestRules().preferences().platform().fakeAPI(); 27 50 28 51 /** 29 * Test of {@link CopyAction#getCopyString} method for a single way. 52 * Test that copy action copies the selected primitive 53 * @throws IOException 54 * @throws UnsupportedFlavorException 30 55 */ 31 56 @Test 32 public void testCopyStringWay() { 33 final Way way = new Way(123L); 34 assertEquals("way 123", CopyAction.getCopyString(Collections.singleton(way))); 35 } 57 public void testWarnOnEmpty() throws UnsupportedFlavorException, IOException { 58 Clipboard clippboard = ClipboardUtils.getClipboard(); 59 clippboard.setContents(new StringSelection("test"), null); 60 61 CapturingCopyAction action = new CapturingCopyAction(); 62 63 action.updateEnabledState(); 64 assertFalse(action.isEnabled()); 65 action.actionPerformed(null); 66 assertTrue(action.warningShown); 67 68 Main.getLayerManager().addLayer(new OsmDataLayer(new DataSet(), "test", null)); 69 action.warningShown = false; 36 70 71 action.updateEnabledState(); 72 assertFalse(action.isEnabled()); 73 action.actionPerformed(null); 74 assertTrue(action.warningShown); 75 76 assertEquals("test", clippboard.getContents(null).getTransferData(DataFlavor.stringFlavor)); 77 } 37 78 /** 38 * Test of {@link CopyAction#getCopyString} method for a way and a relation. 79 * Test that copy action copies the selected primitive 80 * @throws IOException 81 * @throws UnsupportedFlavorException 39 82 */ 40 83 @Test 41 public void testCopyStringWayRelation() { 42 final Way way = new Way(123L); 43 final Relation relation = new Relation(456); 44 assertEquals("way 123,relation 456", CopyAction.getCopyString(Arrays.asList(way, relation))); 45 assertEquals("relation 456,way 123", CopyAction.getCopyString(Arrays.asList(relation, way))); 84 public void testCopySinglePrimitive() throws UnsupportedFlavorException, IOException { 85 DataSet data = new DataSet(); 86 87 Node node1 = new Node(); 88 node1.setCoor(LatLon.ZERO); 89 data.addPrimitive(node1); 90 91 Node node2 = new Node(); 92 node2.setCoor(LatLon.ZERO); 93 data.addPrimitive(node2); 94 Way way = new Way(); 95 way.setNodes(Arrays.asList(node1, node2)); 96 data.addPrimitive(way); 97 data.setSelected(way); 98 99 Main.getLayerManager().addLayer(new OsmDataLayer(data, "test", null)); 100 101 CopyAction action = new CopyAction() { 102 @Override 103 protected void showEmptySelectionWarning() { 104 fail("Selection is not empty."); 105 } 106 }; 107 action.updateEnabledState(); 108 assertTrue(action.isEnabled()); 109 action.actionPerformed(null); 110 111 Object copied = ClipboardUtils.getClipboard().getContents(null).getTransferData(PrimitiveTransferData.DATA_FLAVOR); 112 assertNotNull(copied); 113 assertTrue(copied instanceof PrimitiveTransferData); 114 PrimitiveTransferData ptd = (PrimitiveTransferData) copied; 115 Object[] direct = ptd.getDirectlyAdded().toArray(); 116 assertEquals(1, direct.length); 117 Object[] referenced = ptd.getReferenced().toArray(); 118 assertEquals(2, referenced.length); 46 119 } 47 120 } -
new file test/unit/org/openstreetmap/josm/gui/datatransfer/ClipboardUtilsTest.java
diff --git a/test/unit/org/openstreetmap/josm/gui/datatransfer/ClipboardUtilsTest.java b/test/unit/org/openstreetmap/josm/gui/datatransfer/ClipboardUtilsTest.java new file mode 100644 index 0000000..fc4be5a
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.datatransfer; 3 4 import static org.junit.Assert.assertEquals; 5 import static org.junit.Assert.assertNotNull; 6 import static org.junit.Assert.assertNull; 7 import static org.junit.Assert.assertSame; 8 import static org.junit.Assert.assertTrue; 9 10 import java.awt.GraphicsEnvironment; 11 import java.awt.datatransfer.Clipboard; 12 import java.awt.datatransfer.DataFlavor; 13 import java.awt.datatransfer.StringSelection; 14 import java.awt.datatransfer.Transferable; 15 import java.awt.datatransfer.UnsupportedFlavorException; 16 import java.io.IOException; 17 18 import org.junit.Rule; 19 import org.junit.Test; 20 import org.openstreetmap.josm.testutils.JOSMTestRules; 21 22 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 23 24 /** 25 * Basic tests for the clipboard utils class. 26 * @author Michael Zangl 27 * @since xxx 28 */ 29 public class ClipboardUtilsTest { 30 private final static class ThrowIllegalStateClipboard extends Clipboard { 31 private int failingAccesses = 3; 32 33 private ThrowIllegalStateClipboard(String name) { 34 super(name); 35 } 36 37 @Override 38 public synchronized Transferable getContents(Object requestor) { 39 if (failingAccesses >= 0) { 40 failingAccesses--; 41 throw new IllegalStateException(); 42 } 43 return super.getContents(requestor); 44 } 45 46 protected synchronized void setFailingAccesses(int failingAccesses) { 47 this.failingAccesses = failingAccesses; 48 } 49 } 50 51 private final static class SupportNothingTransferable implements Transferable { 52 @Override 53 public boolean isDataFlavorSupported(DataFlavor flavor) { 54 return false; 55 } 56 57 @Override 58 public DataFlavor[] getTransferDataFlavors() { 59 return new DataFlavor[0]; 60 } 61 62 @Override 63 public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { 64 throw new UnsupportedFlavorException(flavor); 65 } 66 } 67 68 /** 69 * No dependencies 70 */ 71 @Rule 72 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") 73 public JOSMTestRules test = new JOSMTestRules(); 74 75 /** 76 * Test {@link ClipboardUtils#getClipboard()} 77 */ 78 @Test 79 public void testGetClipboard() { 80 Clipboard c = ClipboardUtils.getClipboard(); 81 assertNotNull(c); 82 assertSame(c, ClipboardUtils.getClipboard()); 83 } 84 85 /** 86 * Test {@link ClipboardUtils#copyString(String)} and {@link ClipboardUtils#getClipboardStringContent()} 87 */ 88 @Test 89 public void testCopyPasteString() { 90 ClipboardUtils.copyString(""); 91 assertEquals("", ClipboardUtils.getClipboardStringContent()); 92 ClipboardUtils.copyString("xxx\nx"); 93 assertEquals("xxx\nx", ClipboardUtils.getClipboardStringContent()); 94 95 ClipboardUtils.copy(new SupportNothingTransferable()); 96 assertEquals(null, ClipboardUtils.getClipboardStringContent()); 97 } 98 99 /** 100 * Test that {@link ClipboardUtils#getClipboardContent(Clipboard)} handles illegal state exceptions 101 */ 102 @Test 103 public void testGetContentIllegalState() { 104 ThrowIllegalStateClipboard throwingClipboard = new ThrowIllegalStateClipboard("test"); 105 106 throwingClipboard.setContents(new StringSelection(""), null); 107 Transferable content = ClipboardUtils.getClipboardContent(throwingClipboard); 108 assertTrue(content.isDataFlavorSupported(DataFlavor.stringFlavor)); 109 110 throwingClipboard.setFailingAccesses(50); 111 content = ClipboardUtils.getClipboardContent(new ThrowIllegalStateClipboard("test")); 112 assertNull(content); 113 } 114 115 /** 116 * Test that {@link ClipboardUtils#getSystemSelection()} works in headless mode. 117 */ 118 @Test 119 public void testSystemSelectionDoesNotFail() { 120 assertTrue(GraphicsEnvironment.isHeadless()); 121 assertNull(ClipboardUtils.getSystemSelection()); 122 } 123 } -
test/unit/org/openstreetmap/josm/gui/datatransfer/PrimitiveTransferableTest.java
diff --git a/test/unit/org/openstreetmap/josm/gui/datatransfer/PrimitiveTransferableTest.java b/test/unit/org/openstreetmap/josm/gui/datatransfer/PrimitiveTransferableTest.java index 69ad859..2c708ca 100644
a b package org.openstreetmap.josm.gui.datatransfer; 4 4 import static org.junit.Assert.assertEquals; 5 5 import static org.junit.Assert.assertFalse; 6 6 import static org.junit.Assert.assertTrue; 7 import static org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable.PRIMITIVE_DATA;8 7 9 8 import java.awt.datatransfer.DataFlavor; 10 9 import java.awt.datatransfer.UnsupportedFlavorException; 10 import java.util.Arrays; 11 11 import java.util.Collection; 12 12 import java.util.Collections; 13 import java.util.List; 13 14 14 import org.junit. BeforeClass;15 import org.junit.Rule; 15 16 import org.junit.Test; 16 import org.openstreetmap.josm.JOSMFixture;17 17 import org.openstreetmap.josm.data.osm.Node; 18 import org.openstreetmap.josm.data.osm.NodeData; 18 19 import org.openstreetmap.josm.data.osm.PrimitiveData; 20 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 21 import org.openstreetmap.josm.gui.datatransfer.data.TagTransferData; 22 import org.openstreetmap.josm.testutils.JOSMTestRules; 23 24 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 19 25 20 26 /** 21 27 * Unit tests of {@link PrimitiveTransferable} class. 22 28 */ 23 29 public class PrimitiveTransferableTest { 24 25 30 /** 26 * Setup tests31 * Prefs to use OSM primitives 27 32 */ 28 @BeforeClass 29 public static void setUpBeforeClass() { 30 JOSMFixture.createUnitTestFixture().init(); 31 } 33 @Rule 34 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") 35 public JOSMTestRules test = new JOSMTestRules().preferences(); 32 36 33 37 /** 34 * Test of {@link PrimitiveTransferable#getTransferDataFlavors()} method .38 * Test of {@link PrimitiveTransferable#getTransferDataFlavors()} method response order 35 39 */ 36 40 @Test 37 41 public void testGetTransferDataFlavors() { 38 DataFlavor[] flavors = new PrimitiveTransferable(null).getTransferDataFlavors(); 39 assertEquals(2, flavors.length); 40 assertEquals(PRIMITIVE_DATA, flavors[0]); 41 assertEquals(DataFlavor.stringFlavor, flavors[1]); 42 List<DataFlavor> flavors = Arrays.asList(new PrimitiveTransferable(null).getTransferDataFlavors()); 43 int ptd = flavors.indexOf(PrimitiveTransferData.DATA_FLAVOR); 44 int tags = flavors.indexOf(TagTransferData.FLAVOR); 45 int string = flavors.indexOf(DataFlavor.stringFlavor); 46 47 assertTrue(ptd >= 0); 48 assertTrue(tags >= 0); 49 assertTrue(string >= 0); 50 51 assertTrue(ptd < tags); 52 assertTrue(tags < string); 42 53 } 43 54 44 55 /** … … public class PrimitiveTransferableTest { 46 57 */ 47 58 @Test 48 59 public void testIsDataFlavorSupported() { 49 assertTrue(new PrimitiveTransferable(null).isDataFlavorSupported(P RIMITIVE_DATA));50 assertFalse(new PrimitiveTransferable(null).isDataFlavorSupported( null));60 assertTrue(new PrimitiveTransferable(null).isDataFlavorSupported(PrimitiveTransferData.DATA_FLAVOR)); 61 assertFalse(new PrimitiveTransferable(null).isDataFlavorSupported(DataFlavor.imageFlavor)); 51 62 } 52 63 53 64 /** … … public class PrimitiveTransferableTest { 56 67 */ 57 68 @Test 58 69 public void testGetTransferDataNominal() throws UnsupportedFlavorException { 59 PrimitiveTransferable pt = new PrimitiveTransferable(Collections.singleton(new Node(1))); 60 assertEquals("node 1 # incomplete\n", pt.getTransferData(DataFlavor.stringFlavor)); 61 Collection<PrimitiveData> td = ((PrimitiveTransferable.Data) pt.getTransferData(PRIMITIVE_DATA)).getPrimitiveData(); 70 PrimitiveTransferData data = PrimitiveTransferData.getData(Collections.singleton(new Node(1))); 71 PrimitiveTransferable pt = new PrimitiveTransferable(data); 72 assertEquals("node 1", pt.getTransferData(DataFlavor.stringFlavor)); 73 Collection<PrimitiveData> td = ((PrimitiveTransferData) pt.getTransferData(PrimitiveTransferData.DATA_FLAVOR)).getAll(); 62 74 assertEquals(1, td.size()); 63 assertTrue(td.iterator().next() instanceof PrimitiveData); 75 assertTrue(td.iterator().next() instanceof NodeData); 76 77 78 data = PrimitiveTransferData.getData(Arrays.asList(new Node(1), new Node(2))); 79 pt = new PrimitiveTransferable(data); 80 assertEquals("node 1\nnode 2", pt.getTransferData(DataFlavor.stringFlavor)); 64 81 } 65 82 66 83 /** … … public class PrimitiveTransferableTest { 69 86 */ 70 87 @Test(expected = UnsupportedFlavorException.class) 71 88 public void testGetTransferDataError() throws UnsupportedFlavorException { 72 new PrimitiveTransferable(Collections.singleton(new Node(1))).getTransferData(null); 89 PrimitiveTransferData data = PrimitiveTransferData.getData(Collections.singleton(new Node(1))); 90 new PrimitiveTransferable(data).getTransferData(DataFlavor.imageFlavor); 73 91 } 74 92 } -
test/unit/org/openstreetmap/josm/gui/datatransfer/RelationMemberTransferableTest.java
diff --git a/test/unit/org/openstreetmap/josm/gui/datatransfer/RelationMemberTransferableTest.java b/test/unit/org/openstreetmap/josm/gui/datatransfer/RelationMemberTransferableTest.java index 477fbf0..1fa90e5 100644
a b public class RelationMemberTransferableTest { 37 37 */ 38 38 @Test 39 39 public void testGetTransferDataFlavors() { 40 DataFlavor[] flavors = new RelationMemberTransferable( null).getTransferDataFlavors();40 DataFlavor[] flavors = new RelationMemberTransferable(Collections.<RelationMember>emptyList()).getTransferDataFlavors(); 41 41 assertEquals(2, flavors.length); 42 42 assertEquals(RELATION_MEMBER_DATA, flavors[0]); 43 43 assertEquals(DataFlavor.stringFlavor, flavors[1]); … … public class RelationMemberTransferableTest { 48 48 */ 49 49 @Test 50 50 public void testIsDataFlavorSupported() { 51 assertTrue(new RelationMemberTransferable(null).isDataFlavorSupported(RELATION_MEMBER_DATA)); 52 assertFalse(new RelationMemberTransferable(null).isDataFlavorSupported(null)); 51 RelationMemberTransferable transferable = new RelationMemberTransferable(Collections.<RelationMember>emptyList()); 52 assertTrue(transferable.isDataFlavorSupported(RELATION_MEMBER_DATA)); 53 assertFalse(transferable.isDataFlavorSupported(null)); 53 54 } 54 55 55 56 /** -
new file test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/AbstractRelationEditorActionTest.java
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/AbstractRelationEditorActionTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/AbstractRelationEditorActionTest.java new file mode 100644 index 0000000..cf48256
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.dialogs.relation.actions; 3 4 import java.util.Collection; 5 import java.util.Collections; 6 import java.util.List; 7 8 import org.junit.Before; 9 import org.junit.Rule; 10 import org.openstreetmap.josm.data.osm.DataSet; 11 import org.openstreetmap.josm.data.osm.OsmPrimitive; 12 import org.openstreetmap.josm.data.osm.Relation; 13 import org.openstreetmap.josm.data.osm.Tag; 14 import org.openstreetmap.josm.gui.dialogs.relation.GenericRelationEditorTest; 15 import org.openstreetmap.josm.gui.dialogs.relation.IRelationEditor; 16 import org.openstreetmap.josm.gui.dialogs.relation.MemberTable; 17 import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel; 18 import org.openstreetmap.josm.gui.dialogs.relation.SelectionTableModel; 19 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 20 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetHandler; 21 import org.openstreetmap.josm.testutils.JOSMTestRules; 22 23 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 24 25 /** 26 * This class provides the basic test environment for relation editor actions. 27 * @author Michael Zangl 28 * @since xxx 29 */ 30 public abstract class AbstractRelationEditorActionTest { 31 /** 32 * Plattform for tooltips. 33 */ 34 @Rule 35 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") 36 public JOSMTestRules test = new JOSMTestRules().preferences().platform(); 37 38 protected SelectionTableModel selectionTableModel; 39 40 protected IRelationEditor editor; 41 42 protected MemberTable memberTable; 43 44 protected OsmDataLayer layer; 45 46 protected MemberTableModel memberTableModel; 47 48 /** 49 * Set up the test data required for common tests using one relation. 50 */ 51 @Before 52 public void setupTestData() { 53 DataSet ds = new DataSet(); 54 final Relation orig = new Relation(1); 55 ds.addPrimitive(orig); 56 layer = new OsmDataLayer(ds, "test", null); 57 memberTableModel = new MemberTableModel(orig, layer, new TaggingPresetHandler() { 58 @Override 59 public void updateTags(List<Tag> tags) { 60 } 61 62 @Override 63 public Collection<OsmPrimitive> getSelection() { 64 return Collections.<OsmPrimitive>singleton(orig); 65 } 66 }); 67 selectionTableModel = new SelectionTableModel(layer); 68 69 editor = GenericRelationEditorTest.newRelationEditor(orig, layer); 70 71 memberTable = new MemberTable(layer, editor.getRelation(), memberTableModel); 72 } 73 } -
new file test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/PasteMembersActionTest.java
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/PasteMembersActionTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/PasteMembersActionTest.java new file mode 100644 index 0000000..40e9156
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.dialogs.relation.actions; 3 4 import static org.junit.Assert.assertEquals; 5 import static org.junit.Assert.assertFalse; 6 import static org.junit.Assert.assertSame; 7 import static org.junit.Assert.assertTrue; 8 9 import java.util.Collections; 10 import java.util.Set; 11 12 import org.junit.Test; 13 import org.openstreetmap.josm.data.osm.Node; 14 import org.openstreetmap.josm.data.osm.Relation; 15 import org.openstreetmap.josm.data.osm.RelationMember; 16 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 17 import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable; 18 import org.openstreetmap.josm.gui.datatransfer.RelationMemberTransferable; 19 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 20 import org.openstreetmap.josm.gui.util.GuiHelper; 21 22 /** 23 * Test for {@link PasteMembersAction} 24 * @author Michael Zangl 25 * @since xxx 26 */ 27 public class PasteMembersActionTest extends AbstractRelationEditorActionTest { 28 /** 29 * Test {@link PasteMembersAction#isEnabled()} 30 */ 31 @Test 32 public void testEnabledState() { 33 copyString(); 34 35 PasteMembersAction action = new PasteMembersAction(memberTable, layer, editor); 36 ClipboardUtils.getClipboard().addFlavorListener(action); 37 38 try { 39 assertFalse(action.isEnabled()); 40 41 Node node = new Node(); 42 copyNode(node); 43 syncListener(); 44 assertTrue(action.isEnabled()); 45 46 copyMember(node); 47 syncListener(); 48 assertTrue(action.isEnabled()); 49 50 copyString(); 51 syncListener(); 52 assertFalse(action.isEnabled()); 53 } finally { 54 ClipboardUtils.getClipboard().removeFlavorListener(action); 55 } 56 } 57 58 private void syncListener() { 59 GuiHelper.runInEDTAndWait(new Runnable() { 60 @Override 61 public void run() { 62 // nop 63 } 64 }); 65 } 66 67 /** 68 * Test that pasting produces the result required 69 */ 70 @Test 71 public void testActionWrongClipboard() { 72 copyString(); 73 PasteMembersAction action = new PasteMembersAction(memberTable, layer, editor); 74 action.actionPerformed(null); 75 76 Relation relation = new Relation(1); 77 memberTableModel.applyToRelation(relation); 78 assertEquals(0, relation.getMembersCount()); 79 } 80 81 /** 82 * Test that pasting produces the result required 83 */ 84 @Test 85 public void testActionForMembers() { 86 Node testNode = new Node(10); 87 layer.data.addPrimitive(testNode); 88 copyMember(testNode); 89 PasteMembersAction action = new PasteMembersAction(memberTable, layer, editor); 90 action.actionPerformed(null); 91 92 Relation relation = new Relation(1); 93 memberTableModel.applyToRelation(relation); 94 assertEquals(1, relation.getMembersCount()); 95 assertEquals("test", relation.getMember(0).getRole()); 96 assertSame(testNode, relation.getMember(0).getMember()); 97 } 98 99 /** 100 * Test that pasting primitvies produces the result required 101 */ 102 @Test 103 public void testActionForPrimitives() { 104 Node testNode = new Node(10); 105 layer.data.addPrimitive(testNode); 106 copyNode(testNode); 107 PasteMembersAction action = new PasteMembersAction(memberTable, layer, editor); 108 action.actionPerformed(null); 109 110 Relation relation = new Relation(1); 111 memberTableModel.applyToRelation(relation); 112 assertEquals(1, relation.getMembersCount()); 113 assertEquals("", relation.getMember(0).getRole()); 114 assertSame(testNode, relation.getMember(0).getMember()); 115 } 116 117 private void copyNode(Node node) { 118 PrimitiveTransferData data = PrimitiveTransferData.getData(Collections.singleton(node)); 119 ClipboardUtils.copy(new PrimitiveTransferable(data)); 120 } 121 122 private void copyMember(Node node) { 123 Set<RelationMember> members = Collections.singleton(new RelationMember("test", node)); 124 ClipboardUtils.copy(new RelationMemberTransferable(members)); 125 } 126 127 private void copyString() { 128 ClipboardUtils.copyString(""); 129 } 130 } -
test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/RelationEditorActionsTest.java
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/RelationEditorActionsTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/RelationEditorActionsTest.java index f44f7fb..bc5a1ab 100644
a b 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.gui.dialogs.relation.actions; 3 3 4 import org.junit. BeforeClass;4 import org.junit.Rule; 5 5 import org.junit.Test; 6 import org.openstreetmap.josm.JOSMFixture;7 6 import org.openstreetmap.josm.data.osm.DataSet; 8 7 import org.openstreetmap.josm.data.osm.Relation; 9 8 import org.openstreetmap.josm.gui.dialogs.relation.GenericRelationEditorTest; … … import org.openstreetmap.josm.gui.dialogs.relation.SelectionTableModel; 14 13 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 15 14 import org.openstreetmap.josm.gui.tagging.TagEditorModel; 16 15 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField; 16 import org.openstreetmap.josm.testutils.JOSMTestRules; 17 18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 17 19 18 20 /** 19 21 * Unit tests for relation editor actions. 20 22 */ 21 23 public class RelationEditorActionsTest { 22 23 24 /** 24 * Setup test.25 * Plattform for tooltips. 25 26 */ 26 @BeforeClass 27 public static void setUpBeforeClass() { 28 JOSMFixture.createUnitTestFixture().init(true); 29 } 27 @Rule 28 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") 29 public JOSMTestRules test = new JOSMTestRules().preferences().platform().commands(); 30 30 31 31 /** 32 * Test all actions with minimal data.32 * Check that all actions do not crash. 33 33 */ 34 34 @Test 35 35 public void testAllActions() { … … public class RelationEditorActionsTest { 57 57 new CancelAction(memberTable, memberTableModel, tagModel, layer, editor, tfRole).actionPerformed(null); 58 58 59 59 new CopyMembersAction(memberTableModel, layer, editor).actionPerformed(null); 60 new PasteMembersAction(memberTable Model, layer, editor).actionPerformed(null);60 new PasteMembersAction(memberTable, layer, editor).actionPerformed(null); 61 61 62 62 new DeleteCurrentRelationAction(layer, editor).actionPerformed(null); 63 63 -
test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
diff --git a/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java b/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java index 9fba4cd..9b8abb7 100644
a b import org.junit.rules.Timeout; 12 12 import org.junit.runner.Description; 13 13 import org.junit.runners.model.InitializationError; 14 14 import org.junit.runners.model.Statement; 15 import org.openstreetmap.josm.JOSMFixture; 15 16 import org.openstreetmap.josm.Main; 16 17 import org.openstreetmap.josm.data.projection.Projections; 17 18 import org.openstreetmap.josm.gui.util.GuiHelper; … … public class JOSMTestRules implements TestRule { 39 40 private String i18n = null; 40 41 private boolean platform; 41 42 private boolean useProjection; 43 private boolean commands; 42 44 43 45 /** 44 46 * Disable the default timeout for this test. Use with care. … … public class JOSMTestRules implements TestRule { 133 135 return this; 134 136 } 135 137 138 /** 139 * Allow the execution of commands using {@link Main#undoRedo} 140 * @return this instance, for easy chaining 141 */ 142 public JOSMTestRules commands() { 143 commands = true; 144 return this; 145 } 146 136 147 @Override 137 148 public Statement apply(final Statement base, Description description) { 138 149 Statement statement = new Statement() { … … public class JOSMTestRules implements TestRule { 160 171 * @throws InitializationError If an error occured while creating the required environment. 161 172 */ 162 173 protected void before() throws InitializationError { 163 cleanUpFromJosmFixture();164 165 174 // Tests are running headless by default. 166 175 System.setProperty("java.awt.headless", "true"); 176 177 cleanUpFromJosmFixture(); 178 167 179 // All tests use the same timezone. 168 180 TimeZone.setDefault(DateUtils.UTC); 169 181 // Set log level to info … … public class JOSMTestRules implements TestRule { 218 230 if (platform) { 219 231 Main.determinePlatformHook(); 220 232 } 233 234 if (commands) { 235 // TODO: Implement a more slective version of this once Main is restructured. 236 JOSMFixture.createUnitTestFixture().init(true); 237 } 221 238 } 222 239 223 240 /**