- Timestamp:
- 2007-10-07T13:20:27+02:00 (17 years ago)
- Location:
- trunk
- Files:
-
- 14 added
- 2 deleted
- 64 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/.classpath
r321 r343 2 2 <classpath> 3 3 <classpathentry kind="src" path="src"/> 4 <classpathentry kind="src" path="test/functional"/>5 <classpathentry kind="src" path="test/unit"/>6 4 <classpathentry excluding="build/|dist/|src/|test/" including="images/" kind="src" path=""/> 7 5 <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> -
trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java
r301 r343 10 10 import java.util.HashMap; 11 11 import java.util.LinkedList; 12 import java.util.List; 13 import java.util.ListIterator; 14 import java.util.ArrayList; 12 15 import java.util.Map; 13 16 import java.util.Set; … … 15 18 import java.util.TreeSet; 16 19 import java.util.Map.Entry; 20 import java.util.HashSet; 17 21 18 22 import javax.swing.Box; … … 31 35 import org.openstreetmap.josm.data.osm.OsmPrimitive; 32 36 import org.openstreetmap.josm.data.osm.Way; 37 import org.openstreetmap.josm.data.osm.Node; 38 import org.openstreetmap.josm.data.osm.NodePair; 33 39 import org.openstreetmap.josm.tools.GBC; 34 40 … … 42 48 public CombineWayAction() { 43 49 super(tr("Combine Way"), "combineway", tr("Combine several ways into one."), KeyEvent.VK_C, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true); 44 DataSet. listeners.add(this);50 DataSet.selListeners.add(this); 45 51 } 46 52 … … 67 73 } 68 74 } 69 70 Way oldWay = selectedWays.poll(); 71 Way newWay = new Way(oldWay); 72 LinkedList<Command> cmds = new LinkedList<Command>(); 73 74 for (Way w : selectedWays) 75 newWay.segments.addAll(w.segments); 75 76 List<Node> nodeList = null; 77 Object firstTry = actuallyCombineWays(selectedWays, false); 78 if (firstTry instanceof List) { 79 nodeList = (List<Node>) firstTry; 80 } else { 81 Object secondTry = actuallyCombineWays(selectedWays, true); 82 if (secondTry instanceof List) { 83 int option = JOptionPane.showConfirmDialog(Main.parent, 84 tr("The ways can not be combined in their current directions. " 85 + "Do you want to reverse some of them?"), tr("Change directions?"), 86 JOptionPane.YES_NO_OPTION); 87 if (option != JOptionPane.YES_OPTION) { 88 return; 89 } 90 nodeList = (List<Node>) secondTry; 91 } else { 92 JOptionPane.showMessageDialog(Main.parent, (String) secondTry); 93 return; 94 } 95 } 96 97 Way newWay = new Way(selectedWays.get(0)); 98 newWay.nodes.clear(); 99 newWay.nodes.addAll(nodeList); 76 100 77 101 // display conflict dialog … … 97 121 } 98 122 99 cmds.add(new DeleteCommand(selectedWays)); 100 cmds.add(new ChangeCommand(oldWay, newWay)); 123 LinkedList<Command> cmds = new LinkedList<Command>(); 124 cmds.add(new DeleteCommand(selectedWays.subList(1, selectedWays.size()))); 125 cmds.add(new ChangeCommand(selectedWays.peek(), newWay)); 101 126 Main.main.undoRedo.add(new SequenceCommand(tr("Combine {0} ways", selectedWays.size()), cmds)); 102 Main.ds.setSelected(oldWay); 127 Main.ds.setSelected(selectedWays.peek()); 128 } 129 130 /** 131 * @return a message if combining failed, else a list of nodes. 132 */ 133 private Object actuallyCombineWays(List<Way> ways, boolean ignoreDirection) { 134 // Battle plan: 135 // 1. Split the ways into small chunks of 2 nodes and weed out 136 // duplicates. 137 // 2. Take a chunk and see if others could be appended or prepended, 138 // if so, do it and remove it from the list of remaining chunks. 139 // Rather, rinse, repeat. 140 // 3. If this algorithm does not produce a single way, 141 // complain to the user. 142 // 4. Profit! 143 144 HashSet<NodePair> chunkSet = new HashSet<NodePair>(); 145 for (Way w : ways) { 146 if (w.nodes.size() == 0) continue; 147 Node lastN = null; 148 for (Node n : w.nodes) { 149 if (lastN == null) { 150 lastN = n; 151 continue; 152 } 153 154 NodePair np = new NodePair(lastN, n); 155 if (ignoreDirection) { 156 np.sort(); 157 } 158 chunkSet.add(np); 159 160 lastN = n; 161 } 162 } 163 LinkedList<NodePair> chunks = new LinkedList<NodePair>(chunkSet); 164 165 if (chunks.isEmpty()) { 166 return tr("All the ways were empty"); 167 } 168 169 List<Node> nodeList = chunks.poll().toArrayList(); 170 while (!chunks.isEmpty()) { 171 ListIterator<NodePair> it = chunks.listIterator(); 172 boolean foundChunk = false; 173 while (it.hasNext()) { 174 NodePair curChunk = it.next(); 175 if (curChunk.a == nodeList.get(nodeList.size() - 1)) { // append 176 nodeList.add(curChunk.b); 177 } else if (curChunk.b == nodeList.get(0)) { // prepend 178 nodeList.add(0, curChunk.a); 179 } else if (ignoreDirection && curChunk.b == nodeList.get(nodeList.size() - 1)) { // append 180 nodeList.add(curChunk.a); 181 } else if (ignoreDirection && curChunk.a == nodeList.get(0)) { // prepend 182 nodeList.add(0, curChunk.b); 183 } else { 184 continue; 185 } 186 187 foundChunk = true; 188 it.remove(); 189 break; 190 } 191 if (!foundChunk) break; 192 } 193 194 if (!chunks.isEmpty()) { 195 return tr("Could not combine ways " 196 + "(They could not be merged into a single string of nodes)"); 197 } else { 198 return nodeList; 199 } 103 200 } 104 201 -
trunk/src/org/openstreetmap/josm/actions/DownloadIncompleteAction.java
r298 r343 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others2 package org.openstreetmap.josm.actions;3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 import static org.openstreetmap.josm.tools.I18n.trn;6 7 import java.awt.event.ActionEvent;8 import java.awt.event.InputEvent;9 import java.awt.event.KeyEvent;10 import java.io.IOException;11 import java.util.Collection;12 import java.util.HashSet;13 14 import javax.swing.JOptionPane;15 16 import org.openstreetmap.josm.Main;17 import org.openstreetmap.josm.data.osm.OsmPrimitive;18 import org.openstreetmap.josm.data.osm.Way;19 import org.openstreetmap.josm.data.osm.visitor.MergeVisitor;20 import org.openstreetmap.josm.gui.PleaseWaitRunnable;21 import org.openstreetmap.josm.io.IncompleteDownloader;22 import org.xml.sax.SAXException;23 24 /**25 * Action that opens a connection to the osm server and download map data.26 *27 * An dialog is displayed asking the user to specify a rectangle to grab.28 * The url and account settings from the preferences are used.29 *30 * @author imi31 */32 public class DownloadIncompleteAction extends JosmAction {33 34 /**35 * Open the download dialog and download the data.36 * Run in the worker thread.37 */38 private final class DownloadTask extends PleaseWaitRunnable {39 private IncompleteDownloader reader;40 41 private DownloadTask(Collection<Way> toDownload) {42 super(trn("Downloading {0} way", "Downloading {0} ways", toDownload.size(), toDownload.size()));43 reader = new IncompleteDownloader(toDownload);44 }45 46 @Override public void realRun() throws IOException, SAXException {47 reader.parse();48 }49 50 @Override protected void finish() {51 MergeVisitor merger = new MergeVisitor(Main.ds, reader.data);52 for (OsmPrimitive osm : reader.data.allPrimitives())53 osm.visit(merger);54 Main.parent.repaint();55 }56 57 @Override protected void cancel() {58 reader.cancel();59 }60 }61 62 public DownloadIncompleteAction() {63 super(tr("Download incomplete objects"), "downloadincomplete", tr("Download all (selected) incomplete ways from the OSM server."), KeyEvent.VK_D, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK | InputEvent.ALT_DOWN_MASK, true);64 }65 66 public void actionPerformed(ActionEvent e) {67 Collection<Way> ways = new HashSet<Way>();68 for (Way w : Main.ds.ways)69 if (w.isIncomplete() && w.selected)70 ways.add(w);71 if (ways.isEmpty()) {72 JOptionPane.showMessageDialog(Main.parent, tr("Please select an incomplete way."));73 return;74 }75 if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog(Main.parent, tr("Download {0} incomplete ways?", ways.size()), tr("Download?"), JOptionPane.YES_NO_OPTION))76 return;77 PleaseWaitRunnable task = new DownloadTask(ways);78 Main.worker.execute(task);79 }80 } -
trunk/src/org/openstreetmap/josm/actions/ReverseSegmentAction.java
r301 r343 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others2 /**3 *4 */5 package org.openstreetmap.josm.actions;6 7 import static org.openstreetmap.josm.tools.I18n.tr;8 9 import java.awt.event.ActionEvent;10 import java.awt.event.KeyEvent;11 import java.util.Collection;12 import java.util.LinkedList;13 14 import javax.swing.JOptionPane;15 16 import org.openstreetmap.josm.Main;17 import org.openstreetmap.josm.command.ChangeCommand;18 import org.openstreetmap.josm.command.Command;19 import org.openstreetmap.josm.command.SequenceCommand;20 import org.openstreetmap.josm.data.osm.Node;21 import org.openstreetmap.josm.data.osm.OsmPrimitive;22 import org.openstreetmap.josm.data.osm.Segment;23 import org.openstreetmap.josm.data.osm.Way;24 import org.openstreetmap.josm.data.osm.visitor.Visitor;25 26 public final class ReverseSegmentAction extends JosmAction {27 28 public ReverseSegmentAction() {29 super(tr("Reverse segments"), "segmentflip", tr("Reverse the direction of all selected Segments."), KeyEvent.VK_R, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true);30 }31 32 public void actionPerformed(ActionEvent e) {33 final Collection<Segment> sel = new LinkedList<Segment>();34 new Visitor(){35 public void visit(Node n) {}36 public void visit(Segment s) {sel.add(s);}37 public void visit(Way w) {sel.addAll(w.segments);}38 public void visitAll() {39 for (OsmPrimitive osm : Main.ds.getSelected())40 osm.visit(this);41 }42 }.visitAll();43 44 if (sel.isEmpty()) {45 JOptionPane.showMessageDialog(Main.parent, tr("Please select at least one segment."));46 return;47 }48 Collection<Command> c = new LinkedList<Command>();49 for (Segment s : sel) {50 Segment snew = new Segment(s);51 Node n = snew.from;52 snew.from = snew.to;53 snew.to = n;54 c.add(new ChangeCommand(s, snew));55 }56 Main.main.undoRedo.add(new SequenceCommand(tr("Reverse Segments"), c));57 Main.map.repaint();58 }59 } -
trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java
r327 r343 126 126 } 127 127 OsmWriter.output(new FileOutputStream(file), new OsmWriter.All(layer.data, false)); 128 if ( tmpFile != null && !Main.pref.getBoolean("save.keepbackup"))128 if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) 129 129 tmpFile.delete(); 130 130 } else if (ExtensionFileFilter.filters[ExtensionFileFilter.CSV].acceptName(file.getPath())) { -
trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java
r301 r343 16 16 import java.util.LinkedList; 17 17 import java.util.List; 18 import java.util.Set; 18 19 import java.util.Map.Entry; 19 20 … … 27 28 import org.openstreetmap.josm.data.SelectionChangedListener; 28 29 import org.openstreetmap.josm.data.osm.DataSet; 30 import org.openstreetmap.josm.data.osm.Relation; 29 31 import org.openstreetmap.josm.data.osm.Node; 30 32 import org.openstreetmap.josm.data.osm.OsmPrimitive; 31 import org.openstreetmap.josm.data.osm.Segment;32 33 import org.openstreetmap.josm.data.osm.Way; 33 34 import org.openstreetmap.josm.data.osm.visitor.NameVisitor; … … 35 36 36 37 /** 37 * Splits a way into multiple ways (all identical except the segments 38 * belonging to the way). 38 * Splits a way into multiple ways (all identical except for their node list). 39 39 * 40 * Various split modes are used depending on what is selected. 41 * 42 * 1. One or more NODES (and, optionally, also one way) selected: 43 * 44 * (All nodes must be part of the same way. If a way is also selected, that way 45 * must contain all selected nodes.) 46 * 47 * Way is split AT the node(s) into contiguous ways. If the original contained 48 * one or more parts that were not reachable from any of the nodes, they form an 49 * extra new way. Examples (numbers are unselected nodes, letters are selected 50 * nodes) 51 * 52 * 1---A---2 becomes 1---A and A---2 53 * 54 * 1---A---2---B---3 becomes 1---A and A---2---B and B---3 55 * 56 * 2 57 * | 58 * 1---A---3 becomes 1---A and 2---A and A---3 59 * 60 * 1---A---2 3---4 becomes 1---A and A---2 and 3---4 61 * 62 * If the selected node(s) do not clearly define the way that is to be split, 63 * then the way must be selected for disambiguation (e.g. you have two ways, 64 * 1---2---3 and 4---2---5, and select node 2, then you must also select the 65 * way you want to split). 66 * 67 * This function will result in at least two ways, unless the selected node is 68 * at the end of the way AND the way is contiguous, which will lead to an error 69 * message. 70 * 71 * After executing the operation, the selection will be cleared. 72 * 73 * 2. One or more SEGMENTS (and, optionally, also one way) selected: 74 * 75 * (All segments must be part of the same way) 76 * 77 * The way is split in a fashion that makes a new way from the selected segments, 78 * i.e. the selected segments are removed from the way to form a new one. 79 * 80 * This function will result in exactly two ways. 81 * 82 * If splitting the segments out of the way makes a non-contiguous part from 83 * something that was contiguous before, the action is aborted and an error 84 * message is shown. 85 * 86 * 3. Exactly one WAY selected 87 * 88 * If the way is contiguous, you will get an error message. If the way is not 89 * contiguous it is split it into 2...n contiguous ways. 40 * Ways are just split at the selected nodes. The nodes remain in their 41 * original order. Selected nodes at the end of a way are ignored. 90 42 */ 91 43 … … 94 46 private Way selectedWay; 95 47 private List<Node> selectedNodes; 96 private List<Segment> selectedSegments;97 48 98 49 /** … … 101 52 public SplitWayAction() { 102 53 super(tr("Split Way"), "splitway", tr("Split a way at the selected node."), KeyEvent.VK_P, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true); 103 DataSet. listeners.add(this);54 DataSet.selListeners.add(this); 104 55 } 105 56 … … 121 72 selectedWay = null; 122 73 selectedNodes = null; 123 selectedSegments = null;124 74 125 75 Visitor splitVisitor = new Visitor(){ … … 129 79 selectedNodes.add(n); 130 80 } 131 public void visit(Segment s) {132 if (selectedSegments == null)133 selectedSegments = new LinkedList<Segment>();134 selectedSegments.add(s);135 }136 81 public void visit(Way w) { 137 82 selectedWay = w; 138 83 } 84 public void visit(Relation e) { 85 // enties are not considered 86 } 139 87 }; 140 88 … … 148 96 for (Node n : selectedNodes) { 149 97 for (Way w : Main.ds.ways) { 150 for ( Segment s : w.segments) {151 if (n.equals( s.from) || n.equals(s.to)) {98 for (Node wn : w.nodes) { 99 if (n.equals(wn)) { 152 100 Integer old = wayOccurenceCounter.get(w); 153 101 wayOccurenceCounter.put(w, (old == null) ? 1 : old+1); … … 183 131 184 132 HashSet<Node> nds = new HashSet<Node>(selectedNodes); 185 for (Segment s : selectedWay.segments) { 186 nds.remove(s.from); 187 nds.remove(s.to); 133 for (Node n : selectedWay.nodes) { 134 nds.remove(n); 188 135 } 189 136 if (!nds.isEmpty()) { … … 193 140 return; 194 141 } 195 196 // If only segments are selected, guess which way to use.197 } else if (selectedWay == null && selectedSegments != null) {198 199 HashMap<Way, Integer> wayOccurenceCounter = new HashMap<Way, Integer>();200 for (Segment s : selectedSegments) {201 for (Way w : Main.ds.ways) {202 if (w.segments.contains(s)) {203 Integer old = wayOccurenceCounter.get(w);204 wayOccurenceCounter.put(w, (old == null) ? 1 : old+1);205 break;206 }207 }208 }209 if (wayOccurenceCounter.isEmpty()) {210 JOptionPane.showMessageDialog(Main.parent,211 trn("The selected segment is not part of any way.",212 "The selected segments are not part of any way.", selectedSegments.size()));213 return;214 }215 216 for (Entry<Way, Integer> entry : wayOccurenceCounter.entrySet()) {217 if (entry.getValue().equals(selectedSegments.size())) {218 if (selectedWay != null) {219 JOptionPane.showMessageDialog(Main.parent,220 trn("There is more than one way using the segment you selected. Please select the way also.",221 "There is more than one way using the segments you selected. Please select the way also.", selectedSegments.size()));222 return;223 }224 selectedWay = entry.getKey();225 }226 }227 228 if (selectedWay == null) {229 JOptionPane.showMessageDialog(Main.parent, tr("The selected segments do not share the same way."));230 return;231 }232 233 // If a way and segments are selected, verify that the segments are part of the way.234 } else if (selectedWay != null && selectedSegments != null) {235 236 if (!selectedWay.segments.containsAll(selectedSegments)) {237 JOptionPane.showMessageDialog(Main.parent,238 trn("The selected way does not contain the selected segment.",239 "The selected way does not contain all the selected segments.", selectedSegments.size()));240 return;241 }242 }243 244 // finally check if the selected way is complete.245 if (selectedWay.isIncomplete()) {246 JOptionPane.showMessageDialog(Main.parent, tr("Warning: This way is incomplete. Try to download it before splitting."));247 return;248 142 } 249 143 … … 261 155 private boolean checkSelection(Collection<? extends OsmPrimitive> selection) { 262 156 boolean way = false; 263 boolean segment = false;264 157 boolean node = false; 265 158 for (OsmPrimitive p : selection) { 266 if (p instanceof Way && !way) 159 if (p instanceof Way && !way) { 267 160 way = true; 268 else if (p instanceof Node && !segment)161 } else if (p instanceof Node) { 269 162 node = true; 270 else if (p instanceof Segment && !node) 271 segment = true; 272 else 163 } else { 273 164 return false; 274 165 } 275 return way || segment || node; 166 } 167 return node; 276 168 } 277 169 … … 279 171 * Split a way into two or more parts, starting at a selected node. 280 172 * 173 * FIXME: what do the following "arguments" refer to? 281 174 * @param way the way to split 282 175 * @param nodes the node(s) to split the way at; must be part of the way. 283 176 */ 284 177 private void splitWay() { 285 286 // The basic idea is to first divide all segments forming this way into 287 // groups, and later form new ways according to the groups. Initally, 288 // all segments are copied into allSegments, and then gradually removed 289 // from there as new groups are built. 290 291 LinkedList<Segment> allSegments = new LinkedList<Segment>(); 292 allSegments.addAll(selectedWay.segments); 293 List<List<Segment>> segmentSets = new ArrayList<List<Segment>>(); 294 295 if (selectedNodes != null) { 296 297 // This is the "split at node" mode. 298 299 boolean split = true; 300 Segment splitSeg = null; 301 while (split) { 302 split = false; 303 304 // Look for a "split segment". A split segment is any segment 305 // that touches one of the split nodes and has not yet been 306 // assigned to one of the segment groups. 307 for (Segment s : allSegments) { 308 for (Node node : selectedNodes) { 309 if (s.from.equals(node) || s.to.equals(node)) { 310 split = true; 311 splitSeg = s; 312 break; 313 } 314 } 315 if (split) 316 break; 178 // We take our way's list of nodes and copy them to a way chunk (a 179 // list of nodes). Whenever we stumble upon a selected node, we start 180 // a new way chunk. 181 182 Set<Node> nodeSet = new HashSet<Node>(selectedNodes); 183 List<List<Node>> wayChunks = new LinkedList<List<Node>>(); 184 List<Node> currentWayChunk = new ArrayList<Node>(); 185 wayChunks.add(currentWayChunk); 186 187 Iterator<Node> it = selectedWay.nodes.iterator(); 188 while (it.hasNext()) { 189 Node currentNode = it.next(); 190 boolean atEndOfWay = currentWayChunk.isEmpty() || !it.hasNext(); 191 currentWayChunk.add(currentNode); 192 if (nodeSet.contains(currentNode) && !atEndOfWay) { 193 currentWayChunk = new ArrayList<Node>(); 194 currentWayChunk.add(currentNode); 195 wayChunks.add(currentWayChunk); 317 196 } 318 319 // If a split segment was found, move this segment and all segments 320 // connected to it into a new segment group, stopping only if we 321 // reach another split node. Segment moving is done recursively by 322 // the moveSegments method. 323 if (split) { 324 LinkedList<Segment> subSegments = new LinkedList<Segment>(); 325 moveSegments(allSegments, subSegments, splitSeg, selectedNodes); 326 segmentSets.add(subSegments); 327 } 328 329 // The loop continues until no more split segments were found. 330 // Nb. not all segments touching a split node are split segments; 331 // e.g. 332 // 333 // 2 4 334 // | | 335 // 1---A---3---C---5 336 // 337 // This way will be split into 5 ways (1---A,2---A,A---3---C,4---C, 338 // C---5). Depending on which is processed first, either A---3 becomes 339 // a split segment and 3---C is moved as a connecting segment, or vice 340 // versa. The result is, of course, the same but this explains why we 341 // cannot simply start a new way for each segment connecting to a split 342 // node. 343 } 344 345 } else if (selectedSegments != null) { 346 347 // This is the "split segments" mode. It is quite easy as the segments to 348 // remove are already explicitly selected, but some restrictions have to 349 // be observed to make sure that no non-contiguous parts are created. 350 351 // first create a "scratch" copy of the full segment list and move all 352 // segments connected to the first selected segment into a temporary list. 353 LinkedList<Segment> copyOfAllSegments = new LinkedList<Segment>(allSegments); 354 LinkedList<Segment> partThatContainsSegments = new LinkedList<Segment>(); 355 moveSegments(copyOfAllSegments, partThatContainsSegments, selectedSegments.get(0), null); 356 357 // this list must now contain ALL selected segments; otherwise, segments 358 // from unconnected parts of the way have been selected and this is not allowed 359 // as it would create a new non-contiguous way. 360 if (!partThatContainsSegments.containsAll(selectedSegments)) { 361 JOptionPane.showMessageDialog(Main.parent, tr("The selected segments are not in the same contiguous part of the way.")); 362 return; 363 } 364 365 // if the contiguous part that contains the segments becomes non-contiguous 366 // after the removal of the segments, that is also an error. 367 partThatContainsSegments.removeAll(selectedSegments); 368 if (!partThatContainsSegments.isEmpty()) { 369 LinkedList<Segment> contiguousSubpart = new LinkedList<Segment>(); 370 moveSegments(partThatContainsSegments, contiguousSubpart, partThatContainsSegments.get(0), null); 371 // if partThatContainsSegments was contiguous before, it will now be empty as all segments 372 // connected to the first segment therein have been moved 373 if (!partThatContainsSegments.isEmpty()) { 374 JOptionPane.showMessageDialog(Main.parent, tr("Removing the selected segments would make a part of the way non-contiguous.")); 375 return; 376 } 377 } 378 379 ArrayList<Segment> subSegments = new ArrayList<Segment>(); 380 subSegments.addAll(selectedSegments); 381 allSegments.removeAll(selectedSegments); 382 segmentSets.add(subSegments); 383 384 } else { 385 386 // This is the "split way into contiguous parts" mode. 387 // We use a similar mechanism to splitting at nodes, but we do not 388 // select split segments. Instead, we randomly grab a segment out 389 // of the way and move all connecting segments to a new group. If 390 // segments remain in the original way, we repeat the procedure. 391 392 while (!allSegments.isEmpty()) { 393 LinkedList<Segment> subSegments = new LinkedList<Segment>(); 394 moveSegments(allSegments, subSegments, allSegments.get(0), null); 395 segmentSets.add(subSegments); 396 } 397 } 398 399 // We now have a number of segment groups. 400 401 // If segments remain in allSegments, this means that they were not reachable 402 // from any of the split nodes, and they will be made into an extra way. 403 if (!allSegments.isEmpty()) { 404 segmentSets.add(allSegments); 405 } 406 407 // If we do not have at least two parts, then the way was circular or the node(s) 408 // were at one end of the way. User error ;-) 409 if (segmentSets.size() < 2) { 410 if (selectedNodes != null) { 411 JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split at the selected node. (Hint: To split circular ways, select two nodes.)")); 412 } else { 413 JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split because it is contiguous. (Hint: To split at a node, select that node.)")); 414 } 197 } 198 199 if (wayChunks.size() < 2) { 200 JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split at the selected nodes. (Hint: Select nodes in the middle of the way.)")); 415 201 return; 416 202 } 417 203 418 // sort the list of segment lists according to their number of elements, so that 419 // the biggest part of the way comes first. That way, we will "change" the largest 420 // part of the way by removing a few segments, and "add" new, smaller ways; looks 421 // nicer. 422 Collections.sort(segmentSets, new Comparator<Collection<Segment>>() { 423 public int compare(Collection<Segment> a, Collection<Segment> b) { 424 if (a.size() < b.size()) 425 return 1; 426 if (b.size() < a.size()) 427 return -1; 428 return 0; 429 } 430 }); 431 432 // build a list of commands, and also a list of ways 433 Collection<Command> commandList = new ArrayList<Command>(segmentSets.size()); 434 Collection<Way> newSelection = new ArrayList<Way>(segmentSets.size()); 435 Iterator<List<Segment>> segsIt = segmentSets.iterator(); 204 // build a list of commands, and also a new selection list 205 Collection<Command> commandList = new ArrayList<Command>(wayChunks.size()); 206 Collection<Way> newSelection = new ArrayList<Way>(wayChunks.size()); 436 207 437 // the first is always a change to the existing way; 208 Iterator<List<Node>> chunkIt = wayChunks.iterator(); 209 210 // First, change the original way 438 211 Way changedWay = new Way(selectedWay); 439 changedWay. segments.clear();440 changedWay. segments.addAll(segsIt.next());212 changedWay.nodes.clear(); 213 changedWay.nodes.addAll(chunkIt.next()); 441 214 commandList.add(new ChangeCommand(selectedWay, changedWay)); 442 215 newSelection.add(selectedWay); 443 216 444 // and commands 1...n are additions of new ways.445 while ( segsIt.hasNext()) {217 // Second, create new ways 218 while (chunkIt.hasNext()) { 446 219 Way wayToAdd = new Way(); 447 220 if (selectedWay.keys != null) 448 221 wayToAdd.keys = new HashMap<String, String>(selectedWay.keys); 449 wayToAdd.segments.clear(); 450 wayToAdd.segments.addAll(segsIt.next()); 222 wayToAdd.nodes.addAll(chunkIt.next()); 451 223 commandList.add(new AddCommand(wayToAdd)); 452 224 newSelection.add(wayToAdd); … … 455 227 NameVisitor v = new NameVisitor(); 456 228 v.visit(selectedWay); 457 Main.main.undoRedo.add(new SequenceCommand(tr("Split way {0} into {1} parts",v.name, segmentSets.size()), commandList)); 229 Main.main.undoRedo.add( 230 new SequenceCommand(tr("Split way {0} into {1} parts", 231 v.name, wayChunks.size()), 232 commandList)); 458 233 Main.ds.setSelected(newSelection); 459 234 } … … 465 240 setEnabled(checkSelection(newSelection)); 466 241 } 467 468 /**469 * Move contiguous segments from one collection to another. The given segment is moved first, and470 * then the procedure is recursively called for all segments that connect to the first segment at471 * either end.472 *473 * @param source the source collection474 * @param destination the destination collection475 * @param start the first segment to be moved476 * @param stopNodes collection of nodes which should be considered end points for moving (may be null).477 */478 private void moveSegments(Collection<Segment> source, LinkedList<Segment> destination, Segment start, Collection<Node> stopNodes) {479 source.remove(start);480 if (destination.isEmpty() || destination.iterator().next().from.equals(start.to))481 destination.addFirst(start);482 else483 destination.addLast(start);484 Segment moveSeg = start;485 while(moveSeg != null) {486 moveSeg = null;487 488 for (Node node : new Node[] { start.from, start.to }) {489 if (stopNodes != null && stopNodes.contains(node))490 continue;491 for (Segment sourceSeg : source) {492 if (sourceSeg.from.equals(node) || sourceSeg.to.equals(node)) {493 moveSeg = sourceSeg;494 break;495 }496 }497 if (moveSeg != null)498 break;499 }500 if (moveSeg != null) {501 moveSegments(source, destination, moveSeg, stopNodes);502 }503 }504 }505 242 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java
r314 r343 24 24 import org.openstreetmap.josm.data.osm.Node; 25 25 import org.openstreetmap.josm.data.osm.OsmPrimitive; 26 import org.openstreetmap.josm.data.osm.Segment;27 26 import org.openstreetmap.josm.data.osm.Way; 27 import org.openstreetmap.josm.data.osm.WaySegment; 28 28 import org.openstreetmap.josm.gui.MapFrame; 29 29 import org.openstreetmap.josm.tools.ImageProvider; … … 33 33 * and there is it. Nothing more, nothing less. 34 34 * 35 * FIXME: "nothing more, nothing less" is a bit out-of-date 36 * 35 37 * Newly created nodes are selected. Shift modifier does not cancel the old 36 38 * selection as usual. … … 41 43 public class AddNodeAction extends MapMode { 42 44 43 enum Mode {node, node segment, autonode}45 enum Mode {node, nodeway, autonode} 44 46 private final Mode mode; 45 47 … … 49 51 putValue("help", "Action/AddNode"); 50 52 actions.add(new AddNodeAction(mf,tr("Add node"), Mode.node, tr("Add a new node to the map"))); 51 actions.add(new AddNodeAction(mf, tr("Add node into segment"), Mode.nodesegment,tr( "Add a node into an existing segment")));52 actions.add(new AddNodeAction(mf, tr("Add node and connect"), Mode.autonode,tr( "Add a node and connect it to the selected node (with CTRL: add node into segment; with SHIFT: re-use existing node)")));53 actions.add(new AddNodeAction(mf, tr("Add node into way"), Mode.nodeway,tr( "Add a node into an existing way"))); 54 actions.add(new AddNodeAction(mf, tr("Add node and connect"), Mode.autonode,tr( "Add a node and connect it to the selected node (with CTRL: add node into way; with SHIFT: re-use existing node)"))); 53 55 setCurrent(0); 54 56 } … … 83 85 * position. 84 86 * 85 * If in nodesegment mode, add the node to the line segment by splitting the 86 * segment. The new created segment will be inserted in every way the segment 87 * was part of. 87 * If in nodeway mode, insert the node into the way. 88 88 */ 89 89 @Override public void mouseClicked(MouseEvent e) { … … 98 98 99 99 Command c = new AddCommand(n); 100 if (mode == Mode.node segment) {101 Segment s = Main.map.mapView.getNearestSegment(e.getPoint());102 if ( s == null)100 if (mode == Mode.nodeway) { 101 WaySegment ws = Main.map.mapView.getNearestWaySegment(e.getPoint()); 102 if (ws == null) 103 103 return; 104 104 105 105 // see if another segment is also near 106 Segment other = Main.map.mapView.getNearestSegment(e.getPoint(), Collections.singleton(s)); 106 WaySegment other = Main.map.mapView.getNearestWaySegment(e.getPoint(), 107 Collections.singleton(ws)); 108 109 Node n1 = ws.way.nodes.get(ws.lowerIndex), 110 n2 = ws.way.nodes.get(ws.lowerIndex + 1); 107 111 108 112 if (other == null && (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) == 0) { 109 113 // moving the new point to the perpendicular point 110 // FIXME: when two segments are split, should move the new point to the114 // FIXME: when two way segments are split, should move the new point to the 111 115 // intersection point! 112 EastNorth A = s.from.eastNorth;113 EastNorth B = s.to.eastNorth;116 EastNorth A = n1.eastNorth; 117 EastNorth B = n2.eastNorth; 114 118 double ab = A.distance(B); 115 119 double nb = n.eastNorth.distance(B); … … 124 128 125 129 // split the first segment 126 split SegmentAtNode(s, n, cmds);130 splitWaySegmentAtNode(ws, n, cmds); 127 131 128 132 // if a second segment was found, split that as well 129 if (other != null) split SegmentAtNode(other, n, cmds);133 if (other != null) splitWaySegmentAtNode(other, n, cmds); 130 134 131 135 c = new SequenceCommand(tr((other == null) ? 132 "Add node into segment" : "Add common node into two segments"), cmds);136 "Add node into way" : "Add common node into two ways"), cmds); 133 137 } 134 138 … … 136 140 if (mode == Mode.autonode) { 137 141 138 Segment insertInto = null;142 WaySegment insertInto = null; 139 143 Node reuseNode = null; 140 144 141 // If CTRL is held, insert the node into a potentially existing segment145 // If CTRL is held, insert the node into a potentially existing way segment 142 146 if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0) { 143 insertInto = Main.map.mapView.getNearestSegment(e.getPoint()); 147 insertInto = Main.map.mapView.getNearestWaySegment(e.getPoint()); 148 if (insertInto == null) System.err.println("Couldn't find nearby way segment"); 144 149 if (insertInto == null) 145 150 return; … … 150 155 // continuation of the "add node and connect" stuff) 151 156 else if ((e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0) { 152 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint() , false);157 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint()); 153 158 if (clicked == null || !(clicked instanceof Node)) 154 159 return; … … 159 164 if (selection.size() == 1 && selection.iterator().next() instanceof Node) { 160 165 Node n1 = (Node)selection.iterator().next(); 166 161 167 Collection<Command> cmds = new LinkedList<Command>(); 162 168 163 169 if (reuseNode != null) { 164 170 // in re-use node mode, n1 must not be identical to clicked node 171 if (n1 == reuseNode) System.err.println("n1 == reuseNode"); 165 172 if (n1 == reuseNode) return; 166 173 // replace newly created node with existing node … … 171 178 } 172 179 173 Segment s = new Segment(n1, n); 174 180 /* Keep track of the way we change, it might be the same into 181 * which we insert the node. 182 */ 183 Way newInsertInto = null; 175 184 if (insertInto != null) 176 splitSegmentAtNode(insertInto, n, cmds); 177 178 cmds.add(new AddCommand(s)); 185 newInsertInto = splitWaySegmentAtNode(insertInto, n, cmds); 179 186 180 187 Way way = getWayForNode(n1); 181 if (way != null) { 182 Way newWay = new Way(way); 183 if (way.segments.get(0).from == n1) { 184 Node tmp = s.from; 185 s.from = s.to; 186 s.to = tmp; 187 newWay.segments.add(0, s); 188 } else 189 newWay.segments.add(s); 190 cmds.add(new ChangeCommand(way, newWay)); 191 } 192 193 c = new SequenceCommand(tr((insertInto == null) ? "Add node and connect" : "Add node into segment and connect"), cmds); 188 if (way == null) { 189 way = new Way(); 190 way.nodes.add(n1); 191 cmds.add(new AddCommand(way)); 192 } else { 193 if (insertInto != null && way == insertInto.way) { 194 way = newInsertInto; 195 } else { 196 Way wnew = new Way(way); 197 cmds.add(new ChangeCommand(way, wnew)); 198 way = wnew; 199 } 200 } 201 202 if (way.nodes.get(way.nodes.size() - 1) == n1) { 203 way.nodes.add(n); 204 } else { 205 way.nodes.add(0, n); 206 } 207 208 c = new SequenceCommand(tr((insertInto == null) ? "Add node and connect" : "Add node into way and connect"), cmds); 194 209 } 195 210 } … … 201 216 202 217 /** 203 * @return If the node is partof exactly one way, return this.218 * @return If the node is the end of exactly one way, return this. 204 219 * <code>null</code> otherwise. 205 220 */ … … 207 222 Way way = null; 208 223 for (Way w : Main.ds.ways) { 209 for (Segment s : w.segments) { 210 if (s.from == n || s.to == n) { 224 int i = w.nodes.indexOf(n); 225 if (i == -1) continue; 226 if (i == 0 || i == w.nodes.size() - 1) { 211 227 if (way != null) 212 228 return null; 213 if (s.from == s.to)214 return null;215 229 way = w; 216 230 } 217 231 } 218 }219 232 return way; 220 233 } 221 234 222 private void splitSegmentAtNode(Segment s, Node n, Collection<Command> cmds) { 223 Segment s1 = new Segment(s); 224 s1.to = n; 225 Segment s2 = new Segment(s.from, s.to); 226 s2.from = n; 227 if (s.keys != null) 228 s2.keys = new HashMap<String, String>(s.keys); 229 230 cmds.add(new ChangeCommand(s, s1)); 231 cmds.add(new AddCommand(s2)); 232 233 // Add the segment to every way 234 for (Way wold : Main.ds.ways) { 235 if (wold.segments.contains(s)) { 236 Way wnew = new Way(wold); 237 Collection<Segment> segs = new ArrayList<Segment>(wnew.segments); 238 wnew.segments.clear(); 239 for (Segment waySeg : segs) { 240 wnew.segments.add(waySeg); 241 if (waySeg == s) 242 wnew.segments.add(s2); 243 } 244 cmds.add(new ChangeCommand(wold, wnew)); 245 } 246 } 235 private Way splitWaySegmentAtNode(WaySegment ws, Node n, Collection<Command> cmds) { 236 Way wnew = new Way(ws.way); 237 wnew.nodes.add(ws.lowerIndex + 1, n); 238 cmds.add(new ChangeCommand(ws.way, wnew)); 239 return wnew; 247 240 } 248 241 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/AddSegmentAction.java
r301 r343 15 15 import org.openstreetmap.josm.Main; 16 16 import org.openstreetmap.josm.command.AddCommand; 17 import org.openstreetmap.josm.command.ChangeCommand; 17 18 import org.openstreetmap.josm.data.osm.Node; 18 19 import org.openstreetmap.josm.data.osm.OsmPrimitive; 19 import org.openstreetmap.josm.data.osm. Segment;20 import org.openstreetmap.josm.data.osm.Way; 20 21 import org.openstreetmap.josm.gui.MapFrame; 21 22 import org.openstreetmap.josm.tools.ImageProvider; … … 51 52 */ 52 53 public AddSegmentAction(MapFrame mapFrame) { 53 super(tr(" Add segment"),54 super(tr("Connect two nodes"), 54 55 "addsegment", 55 tr(" Add a segment between two nodes."),56 tr("Connect two nodes using ways."), 56 57 KeyEvent.VK_G, 57 58 mapFrame, … … 72 73 } 73 74 74 75 /** 76 * Called when user hits space bar while dragging. 77 */ 75 78 @Override public void actionPerformed(ActionEvent e) { 76 79 super.actionPerformed(e); … … 85 88 return; 86 89 87 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint(), true); 88 if (clicked == null || !(clicked instanceof Node)) 89 return; 90 Node clicked = Main.map.mapView.getNearestNode(e.getPoint()); 91 if (clicked == null) return; 90 92 91 93 drawHint(false); 92 first = second = (Node)clicked;94 first = second = clicked; 93 95 } 94 96 … … 101 103 return; 102 104 103 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0); 104 if (clicked == null || clicked == second || !(clicked instanceof Node)) 105 return; 105 Node hovered = Main.map.mapView.getNearestNode(e.getPoint()); 106 if (hovered == second) return; 106 107 107 108 drawHint(false); 108 109 second = (Node)clicked; 109 second = hovered; 110 110 drawHint(true); 111 111 } … … 116 116 @Override public void mouseReleased(MouseEvent e) { 117 117 if (e.getButton() == MouseEvent.BUTTON1) { 118 drawHint(false); 118 119 makeSegment(); 119 first = null; // release segment drawing120 first = null; 120 121 } 122 } 123 124 /** 125 * @return If the node is the end of exactly one way, return this. 126 * <code>null</code> otherwise. 127 */ 128 private Way getWayForNode(Node n) { 129 Way way = null; 130 for (Way w : Main.ds.ways) { 131 int i = w.nodes.indexOf(n); 132 if (i == -1) continue; 133 if (i == 0 || i == w.nodes.size() - 1) { 134 if (way != null) 135 return null; 136 way = w; 137 } 138 } 139 return way; 121 140 } 122 141 … … 126 145 */ 127 146 private void makeSegment() { 128 if (first == null || second == null) { 129 first = null; 130 second = null; 131 return; 132 } 133 134 drawHint(false); 147 Node n1 = first; 148 Node n2 = second; 135 149 136 Node start = first;137 Node end = second;150 // this is to allow continued segment drawing by hitting the space bar 151 // at every intermediate node 138 152 first = second; 139 153 second = null; 154 155 if (n1 == null || n2 == null || n1 == n2) return; 156 157 Way w = getWayForNode(n1); 158 Way wnew; 159 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 140 160 141 if (start != end) { 142 // try to find a segment 143 for (Segment ls : Main.ds.segments) 144 if (!ls.deleted && ((start == ls.from && end == ls.to) || (end == ls.from && start == ls.to))) 145 return; // already a segment here - be happy, do nothing. 146 147 Segment ls = new Segment(start, end); 148 Main.main.undoRedo.add(new AddCommand(ls)); 149 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 150 sel.add(ls); 161 if (w == null) { 162 // create a new way and add it to the current selection. 163 wnew = new Way(); 164 wnew.nodes.add(n1); 165 wnew.nodes.add(n2); 166 Main.main.undoRedo.add(new AddCommand(wnew)); 167 sel.add(wnew); 168 Main.ds.setSelected(sel); 169 } else { 170 // extend an existing way; only add to current selection if 171 // it is not already in there. 172 wnew = new Way(w); 173 if (wnew.nodes.get(wnew.nodes.size() - 1) == n1) { 174 wnew.nodes.add(n2); 175 } else { 176 wnew.nodes.add(0, n2); 177 } 178 Main.main.undoRedo.add(new ChangeCommand(w, wnew)); 179 // do not use wnew below; ChangeCommand only uses wnew as a 180 // message about changes to be done to w but will not replace w! 181 if (!sel.contains(w)) { 182 sel.add(w); 183 } 184 // do not move this into the if block above since it also 185 // fires the selection change event which is desired. 151 186 Main.ds.setSelected(sel); 152 187 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/AddWayAction.java
r301 r343 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others2 package org.openstreetmap.josm.actions.mapmode;3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 import static org.openstreetmap.josm.tools.I18n.trn;6 7 import java.awt.event.KeyEvent;8 import java.awt.event.MouseEvent;9 import java.util.Arrays;10 import java.util.Collection;11 import java.util.HashSet;12 import java.util.LinkedList;13 14 import javax.swing.JOptionPane;15 16 import org.openstreetmap.josm.Main;17 import org.openstreetmap.josm.actions.ReorderAction;18 import org.openstreetmap.josm.command.AddCommand;19 import org.openstreetmap.josm.command.ChangeCommand;20 import org.openstreetmap.josm.command.DeleteCommand;21 import org.openstreetmap.josm.data.SelectionChangedListener;22 import org.openstreetmap.josm.data.osm.DataSet;23 import org.openstreetmap.josm.data.osm.OsmPrimitive;24 import org.openstreetmap.josm.data.osm.Segment;25 import org.openstreetmap.josm.data.osm.Way;26 import org.openstreetmap.josm.gui.MapFrame;27 import org.openstreetmap.josm.tools.ImageProvider;28 29 /**30 * Add a new way. The action is split into the first phase, where a new way get31 * created or selected and the second, where this way is modified.32 *33 * Way creation mode:34 * If there is a selection when the mode is entered, all segments in this35 * selection form a new way. All non-segment objects are deselected. If there36 * were ways selected, the user is asked whether to select all segments of these37 * ways or not, except there is exactly one way selected, which enter the38 * edit ways mode for this way immediatly.39 *40 * If there is no selection on entering, and the user clicks on an segment,41 * the way editing starts the with a new way and this segment. If the user click42 * on a way (not holding Alt down), then this way is edited in the way edit mode.43 *44 * Way editing mode:45 * The user can click on subsequent segments. If the segment belonged to the way46 * it get removed from the way. Elsewhere it get added to the way. JOSM try to add47 * the segment in the correct position. This is done by searching for connections48 * to the segment at its 'to' node which are also in the way. The segemnt is49 * inserted in the way as predecessor of the found segment (or at last segment, if50 * nothing found).51 *52 * @author imi53 */54 public class AddWayAction extends MapMode implements SelectionChangedListener {55 private Way way;56 57 /**58 * Create a new AddWayAction.59 * @param mapFrame The MapFrame this action belongs to.60 * @param followMode The mode to go into when finished creating a way.61 */62 public AddWayAction(MapFrame mapFrame) {63 super(tr("Add Way"), "addway", tr("Add a new way to the data."), KeyEvent.VK_W, mapFrame, ImageProvider.getCursor("normal", "way"));64 DataSet.listeners.add(this);65 }66 67 @Override public void enterMode() {68 super.enterMode();69 way = makeWay();70 Main.ds.setSelected(way);71 Main.map.mapView.addMouseListener(this);72 }73 74 @Override public void exitMode() {75 super.exitMode();76 way = null;77 Main.map.mapView.removeMouseListener(this);78 }79 80 @Override public void mouseClicked(MouseEvent e) {81 if (e.getButton() != MouseEvent.BUTTON1)82 return;83 84 Segment s = Main.map.mapView.getNearestSegment(e.getPoint());85 if (s == null)86 return;87 88 // special case for initial selecting one way89 if (way == null && (e.getModifiers() & MouseEvent.ALT_DOWN_MASK) == 0) {90 Way w = Main.map.mapView.getNearestWay(e.getPoint());91 if (w != null) {92 way = w;93 Main.ds.setSelected(way);94 for (Segment seg : way.segments) {95 if (seg.incomplete) {96 JOptionPane.showMessageDialog(Main.parent,tr("Warning: This way is incomplete. Try to download it before adding segments."));97 return;98 }99 }100 return;101 }102 }103 104 if (way != null && way.segments.contains(s)) {105 Way copy = new Way(way);106 107 copy.segments.remove(s);108 if (copy.segments.isEmpty()) {109 Main.main.undoRedo.add(new DeleteCommand(Arrays.asList(new OsmPrimitive[]{way})));110 way = null;111 } else112 Main.main.undoRedo.add(new ChangeCommand(way, copy));113 } else {114 if (way == null) {115 way = new Way();116 way.segments.add(s);117 Main.main.undoRedo.add(new AddCommand(way));118 } else {119 Way copy = new Way(way);120 int i;121 for (i = 0; i < way.segments.size(); ++i)122 if (way.segments.get(i).from == s.to)123 break;124 copy.segments.add(i, s);125 Main.main.undoRedo.add(new ChangeCommand(way, copy));126 }127 }128 Main.ds.setSelected(way);129 }130 131 /**132 * Form a way, either out of the (one) selected way or by creating a way over the selected133 * line segments.134 */135 private Way makeWay() {136 Collection<OsmPrimitive> selection = Main.ds.getSelected();137 if (selection.isEmpty())138 return null;139 140 if (selection.size() == 1 && selection.iterator().next() instanceof Way) {141 Way way = (Way)selection.iterator().next();142 for (Segment seg : way.segments) {143 if (seg.incomplete) {144 JOptionPane.showMessageDialog(Main.parent, tr("Warning: This way is incomplete. Try to download it before adding segments."));145 break;146 }147 }148 return way;149 }150 151 HashSet<Segment> segmentSet = new HashSet<Segment>();152 int numberOfSelectedWays = 0;153 for (OsmPrimitive osm : selection) {154 if (osm instanceof Way)155 numberOfSelectedWays++;156 else if (osm instanceof Segment)157 segmentSet.add((Segment)osm);158 }159 160 Way wayToAdd = null;161 boolean reordered = false;162 if (numberOfSelectedWays > 0) {163 int answer = JOptionPane.showConfirmDialog(Main.parent,trn("{0} way has been selected.\nDo you wish to select all segments belonging to the way instead?","{0} ways have been selected.\nDo you wish to select all segments belonging to the ways instead?",numberOfSelectedWays,numberOfSelectedWays),tr("Add segments from ways"), JOptionPane.YES_NO_OPTION);164 if (answer == JOptionPane.YES_OPTION) {165 for (OsmPrimitive osm : selection)166 if (osm instanceof Way)167 segmentSet.addAll(((Way)osm).segments);168 } else if (numberOfSelectedWays == 1) {169 answer = JOptionPane.showConfirmDialog(Main.parent,tr("Do you want to add all other selected segments to the one selected way?"),tr("Add segments to way?"), JOptionPane.YES_NO_OPTION);170 if (answer == JOptionPane.YES_OPTION) {171 for (OsmPrimitive osm : selection) {172 if (osm instanceof Way) {173 wayToAdd = (Way)osm;174 answer = JOptionPane.showConfirmDialog(Main.parent,tr("Reorder all line segments?"), tr("Reorder?"), JOptionPane.YES_NO_CANCEL_OPTION);175 if (answer == JOptionPane.CANCEL_OPTION)176 return wayToAdd;177 if (answer == JOptionPane.YES_OPTION) {178 segmentSet.addAll(wayToAdd.segments);179 reordered = true;180 } else181 segmentSet.removeAll(wayToAdd.segments);182 break;183 }184 }185 }186 }187 }188 189 if (segmentSet.isEmpty())190 return null;191 192 LinkedList<Segment> rawSegments = new LinkedList<Segment>(segmentSet);193 LinkedList<Segment> sortedSegments = ReorderAction.sortSegments(rawSegments, true);194 195 if (wayToAdd != null) {196 Way w = new Way(wayToAdd);197 if (reordered)198 w.segments.clear();199 w.segments.addAll(sortedSegments);200 Main.main.undoRedo.add(new ChangeCommand(wayToAdd, w));201 return wayToAdd;202 }203 204 if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog(Main.parent,trn("Create a new way out of {0} segment?","Create a new way out of {0} segments?",sortedSegments.size(),sortedSegments.size()), tr("Create new way"), JOptionPane.YES_NO_OPTION))205 return null;206 207 Way w = new Way();208 w.segments.addAll(sortedSegments);209 Main.main.undoRedo.add(new AddCommand(w));210 return w;211 }212 213 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {214 if (newSelection.size() == 1) {215 OsmPrimitive osm = newSelection.iterator().next();216 way = osm instanceof Way ? (Way)osm : null;217 } else218 way = null;219 }220 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java
r301 r343 24 24 import org.openstreetmap.josm.data.osm.Node; 25 25 import org.openstreetmap.josm.data.osm.OsmPrimitive; 26 import org.openstreetmap.josm.data.osm.Segment;27 26 import org.openstreetmap.josm.data.osm.Way; 28 27 import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor; … … 38 37 * @see #deleteWithReferences(OsmPrimitive) 39 38 * 40 * Pressing Alt will select the way instead of a segment, as usual.41 *42 39 * If the user did not press Ctrl and the object has any references, the user 43 40 * is informed and nothing is deleted. … … 57 54 super(tr("Delete"), 58 55 "delete", 59 tr("Delete nodes , streets or segments."),56 tr("Delete nodes or ways."), 60 57 KeyEvent.VK_D, 61 58 mapFrame, … … 92 89 return; 93 90 94 OsmPrimitive sel = Main.map.mapView.getNearest(e.getPoint() , (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);91 OsmPrimitive sel = Main.map.mapView.getNearest(e.getPoint()); 95 92 if (sel == null) 96 93 return; … … 105 102 106 103 /** 107 * Delete the primitives and everything they reference s.104 * Delete the primitives and everything they reference. 108 105 * 109 * If a node is deleted, the node and all segments, ways and areas106 * If a node is deleted, the node and all ways and relations 110 107 * the node is part of are deleted as well. 111 108 * 112 * If a segment is deleted, all ways the segment is part of 113 * are deleted as well. No nodes are deleted. 109 * If a way is deleted, all relations the way is member of are also deleted. 114 110 * 115 * If a way is deleted, only the way and no segments or nodes are 116 * deleted. 117 * 118 * If an area is deleted, only the area gets deleted. 111 * If a way is deleted, only the way and no nodes are deleted. 119 112 * 120 113 * @param selection The list of all object to be deleted. … … 134 127 * inform the user and do not delete. 135 128 * 136 * If deleting a node which is part of exactly two segments, and both segments 137 * have no conflicting keys, join them and remove the node. 138 * If the two segments are part of the same way, remove the deleted segment 139 * from the way. 129 * If a node is to be deleted which is in the middle of exactly one way, 130 * the node is removed from the way's node list and after that removed 131 * itself. 140 132 * 141 133 * @param selection The objects to delete. … … 149 141 if (!selection.containsAll(v.data)) { 150 142 if (osm instanceof Node && joinIfPossible) { 151 String reason = deleteNodeAndJoin Segment((Node)osm);143 String reason = deleteNodeAndJoinWay((Node)osm); 152 144 if (reason != null && msgBox) { 153 145 JOptionPane.showMessageDialog(Main.parent,tr("Cannot delete node.")+" "+reason); … … 167 159 } 168 160 169 private String deleteNodeAndJoinSegment(Node n) { 170 ArrayList<Segment> segs = new ArrayList<Segment>(2); 171 for (Segment s : Main.ds.segments) { 172 if (!s.deleted && (s.from == n || s.to == n)) { 173 if (segs.size() > 1) 174 return tr("Used by more than two segments."); 175 segs.add(s); 176 } 177 } 178 if (segs.size() != 2) 179 return tr("Used by only one segment."); 180 Segment seg1 = segs.get(0); 181 Segment seg2 = segs.get(1); 182 if (seg1.from == seg2.to) { 183 Segment s = seg1; 184 seg1 = seg2; 185 seg2 = s; 186 } 187 if (seg1.from == seg2.from || seg1.to == seg2.to) 188 return tr("Wrong direction of segments."); 189 for (Entry<String, String> e : seg1.entrySet()) 190 if (seg2.keySet().contains(e.getKey()) && !seg2.get(e.getKey()).equals(e.getValue())) 191 return tr("Conflicting keys"); 192 ArrayList<Way> ways = new ArrayList<Way>(2); 161 private String deleteNodeAndJoinWay(Node n) { 162 ArrayList<Way> ways = new ArrayList<Way>(1); 193 163 for (Way w : Main.ds.ways) { 194 if (w.deleted) 195 continue; 196 if ((w.segments.contains(seg1) && !w.segments.contains(seg2)) || (w.segments.contains(seg2) && !w.segments.contains(seg1))) 197 return tr("Segments are part of different ways."); 198 if (w.segments.contains(seg1) && w.segments.contains(seg2)) 164 if (!w.deleted && w.nodes.contains(n)) { 199 165 ways.add(w); 200 166 } 201 Segment s = new Segment(seg1);202 s.to = seg2.to;203 if (s.keys == null)204 s.keys = seg2.keys;205 else if (seg2.keys != null)206 s.keys.putAll(seg2.keys);207 Collection<Command> cmds = new LinkedList<Command>();208 for (Way w : ways) {209 Way copy = new Way(w);210 copy.segments.remove(seg2);211 cmds.add(new ChangeCommand(w, copy));212 167 } 213 cmds.add(new ChangeCommand(seg1, s)); 214 cmds.add(new DeleteCommand(Arrays.asList(new OsmPrimitive[]{n, seg2}))); 215 Main.main.undoRedo.add(new SequenceCommand(tr("Delete Node"), cmds)); 168 169 if (ways.size() > 1) 170 return tr("Used by more than one way."); 171 172 if (ways.size() == 1) { 173 // node in way 174 Way w = ways.get(0); 175 176 int i = w.nodes.indexOf(n); 177 if (w.nodes.lastIndexOf(n) != i) 178 return tr("Occurs more than once in the same way."); 179 if (i == 0 || i == w.nodes.size() - 1) 180 return tr("Is at the end of a way"); 181 182 Way wnew = new Way(w); 183 wnew.nodes.remove(i); 184 185 Collection<Command> cmds = new LinkedList<Command>(); 186 cmds.add(new ChangeCommand(w, wnew)); 187 cmds.add(new DeleteCommand(Collections.singleton(n))); 188 Main.main.undoRedo.add(new SequenceCommand(tr("Delete Node"), cmds)); 189 } else { 190 // unwayed node 191 Main.main.undoRedo.add(new DeleteCommand(Collections.singleton(n))); 192 } 216 193 return null; 217 194 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java
r298 r343 15 15 /** 16 16 * A class implementing MapMode is able to be selected as an mode for map editing. 17 * As example scrolling the map is a MapMode, connecting Nodes to new Segments17 * As example scrolling the map is a MapMode, connecting Nodes to new Ways 18 18 * is another. 19 19 * -
trunk/src/org/openstreetmap/josm/actions/mapmode/MoveAction.java
r312 r343 162 162 163 163 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 164 OsmPrimitive osm = Main.map.mapView.getNearest(e.getPoint() , (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);164 OsmPrimitive osm = Main.map.mapView.getNearest(e.getPoint()); 165 165 if (osm != null) { 166 166 if (!sel.contains(osm)) -
trunk/src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java
r298 r343 17 17 import org.openstreetmap.josm.data.osm.Node; 18 18 import org.openstreetmap.josm.data.osm.OsmPrimitive; 19 import org.openstreetmap.josm.data.osm.Segment;20 19 import org.openstreetmap.josm.gui.MapFrame; 21 20 import org.openstreetmap.josm.gui.SelectionManager; … … 55 54 * pixel are considered "only click". If that happens, the nearest Node will 56 55 * be selected if there is any within 10 pixel range. If there is no Node within 57 * 10 pixel, the nearest Segment (or Street, if user hold down the Alt-Key)58 * within 10 pixel range is selected. If there is no Segment within 10 pixel59 * and the user clicked in or 10 pixel away from an area, this areais selected.60 * If there is even no area, nothing is selected. Shift and Ctrl key applies to61 * this as usual. For more, @see MapView#getNearest(Point, boolean)56 * 10 pixel, the nearest Way within 10 pixel range is selected. If there is no 57 * Way within 10 pixel and the user clicked in or 10 pixel away from an area, 58 * this area is selected. If there is even no area, nothing is selected. 59 * Shift and Ctrl key applies to this as usual. For more, 60 * @see MapView#getNearest(Point) 62 61 * 63 62 * @author imi … … 65 64 public class SelectionAction extends MapMode implements SelectionEnded { 66 65 67 enum Mode {select, straight}68 private final Mode mode;69 70 66 public static class Group extends GroupAction { 71 67 public Group(MapFrame mf) { 72 68 super(KeyEvent.VK_S,0); 73 69 putValue("help", "Action/Selection"); 74 actions.add(new SelectionAction(mf, tr("Selection"), Mode.select, tr("Select objects by dragging or clicking."))); 75 actions.add(new SelectionAction(mf, tr("Straight line"), Mode.straight, tr("Select objects in a straight line."))); 70 actions.add(new SelectionAction(mf, tr("Selection"), tr("Select objects by dragging or clicking."))); 76 71 setCurrent(0); 77 72 } … … 84 79 private SelectionManager selectionManager; 85 80 86 private Node straightStart = null;87 private Node lastEnd = null;88 private Collection<OsmPrimitive> oldSelection = null;89 90 //TODO: Implement reverse references into data objects and remove this91 private final Map<Node, Collection<Segment>> reverseSegmentMap = new HashMap<Node, Collection<Segment>>();92 93 81 /** 94 82 * Create a new SelectionAction in the given frame. 95 83 * @param mapFrame The frame this action belongs to 96 84 */ 97 public SelectionAction(MapFrame mapFrame, String name, Mode mode, String desc) { 98 super(name, "selection/"+mode, desc, mapFrame, ImageProvider.getCursor("normal", "selection")); 99 this.mode = mode; 100 putValue("help", "Action/Selection/"+Character.toUpperCase(mode.toString().charAt(0))+mode.toString().substring(1)); 85 public SelectionAction(MapFrame mapFrame, String name, String desc) { 86 super(name, "selection/select", desc, mapFrame, ImageProvider.getCursor("normal", "selection")); 87 putValue("help", "Action/Selection"); 101 88 this.selectionManager = new SelectionManager(this, false, mapFrame.mapView); 102 89 } … … 104 91 @Override public void enterMode() { 105 92 super.enterMode(); 106 if (mode == Mode.select)107 93 selectionManager.register(Main.map.mapView); 108 else {109 Main.map.mapView.addMouseMotionListener(this);110 Main.map.mapView.addMouseListener(this);111 for (Segment s : Main.ds.segments) {112 addBackReference(s.from, s);113 addBackReference(s.to, s);114 }115 }116 }117 118 private void addBackReference(Node n, Segment s) {119 Collection<Segment> c = reverseSegmentMap.get(n);120 if (c == null) {121 c = new HashSet<Segment>();122 reverseSegmentMap.put(n, c);123 }124 c.add(s);125 94 } 126 95 127 96 @Override public void exitMode() { 128 97 super.exitMode(); 129 if (mode == Mode.select)130 98 selectionManager.unregister(Main.map.mapView); 131 else {132 Main.map.mapView.removeMouseMotionListener(this);133 Main.map.mapView.removeMouseListener(this);134 reverseSegmentMap.clear();135 }136 99 } 137 100 … … 163 126 Main.map.mapView.repaint(); 164 127 } 165 166 @Override public void mouseDragged(MouseEvent e) {167 Node old = lastEnd;168 lastEnd = Main.map.mapView.getNearestNode(e.getPoint());169 if (straightStart == null)170 straightStart = lastEnd;171 if (straightStart != null && lastEnd != null && straightStart != lastEnd && old != lastEnd) {172 Collection<OsmPrimitive> path = new HashSet<OsmPrimitive>();173 Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>();174 path.add(straightStart);175 calculateShortestPath(path, straightStart, lastEnd);176 if ((e.getModifiers() & MouseEvent.CTRL_MASK) != 0) {177 sel.addAll(oldSelection);178 sel.removeAll(path);179 } else if ((e.getModifiers() & MouseEvent.SHIFT_MASK) != 0) {180 sel = path;181 sel.addAll(oldSelection);182 } else183 sel = path;184 Main.ds.setSelected(sel);185 }186 }187 188 @Override public void mousePressed(MouseEvent e) {189 straightStart = Main.map.mapView.getNearestNode(e.getPoint());190 lastEnd = null;191 oldSelection = Main.ds.getSelected();192 }193 194 @Override public void mouseReleased(MouseEvent e) {195 straightStart = null;196 lastEnd = null;197 oldSelection = null;198 }199 200 /**201 * Get the shortest path by stepping through the node with a common segment with start202 * and nearest to the end (greedy algorithm).203 */204 private void calculateShortestPath(Collection<OsmPrimitive> path, Node start, Node end) {205 for (Node pivot = start; pivot != null;)206 pivot = addNearest(path, pivot, end);207 }208 209 private Node addNearest(Collection<OsmPrimitive> path, Node start, Node end) {210 Collection<Segment> c = reverseSegmentMap.get(start);211 if (c == null)212 return null; // start may be a waypoint without segments213 double min = Double.MAX_VALUE;214 Node next = null;215 Segment seg = null;216 for (Segment s : c) {217 Node other = s.from == start ? s.to : s.from;218 if (other == end) {219 next = other;220 seg = s;221 min = 0;222 break;223 }224 double distance = other.eastNorth.distance(end.eastNorth);225 if (distance < min) {226 min = distance;227 next = other;228 seg = s;229 }230 }231 if (min < start.eastNorth.distance(end.eastNorth) && next != null) {232 path.add(next);233 path.add(seg);234 return next;235 }236 return null;237 }238 128 } -
trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
r319 r343 9 9 import org.openstreetmap.josm.data.osm.Node; 10 10 import org.openstreetmap.josm.data.osm.OsmPrimitive; 11 import org.openstreetmap.josm.data.osm.Segment;12 11 import org.openstreetmap.josm.data.osm.Way; 12 import org.openstreetmap.josm.data.osm.Relation; 13 13 14 14 /** … … 119 119 if (osm instanceof Node) 120 120 return type.equals("node"); 121 if (osm instanceof Segment)122 return type.equals("segment");123 121 if (osm instanceof Way) 124 122 return type.equals("way"); 123 if (osm instanceof Relation) 124 return type.equals("relation"); 125 125 throw new IllegalStateException("unknown class "+osm.getClass()); 126 126 } … … 144 144 private static class Incomplete extends Match { 145 145 @Override public boolean match(OsmPrimitive osm) { 146 return osm instanceof Way && ((Way)osm).isIncomplete(); 146 // return osm instanceof Way && ((Way)osm).isIncomplete(); 147 return false; 147 148 } 148 149 @Override public String toString() {return "incomplete";} -
trunk/src/org/openstreetmap/josm/command/AddCommand.java
r304 r343 12 12 import org.openstreetmap.josm.Main; 13 13 import org.openstreetmap.josm.data.osm.DataSet; 14 import org.openstreetmap.josm.data.osm.Relation; 14 15 import org.openstreetmap.josm.data.osm.OsmPrimitive; 15 16 import org.openstreetmap.josm.data.osm.visitor.AddVisitor; … … 22 23 * A command that adds an osm primitive to a dataset. Keys cannot be added this 23 24 * way. Use ChangeKeyValueCommand instead. 25 * 26 * See ChangeCommand for comments on relation back references. 24 27 * 25 28 * @author imi -
trunk/src/org/openstreetmap/josm/command/ChangeCommand.java
r298 r343 13 13 import org.openstreetmap.josm.data.osm.visitor.NameVisitor; 14 14 15 /** 16 * Command that basically replaces one OSM primitive by another of the 17 * same type. 18 * 19 * @author Imi 20 */ 15 21 public class ChangeCommand extends Command { 16 22 -
trunk/src/org/openstreetmap/josm/command/Command.java
r304 r343 10 10 import javax.swing.tree.MutableTreeNode; 11 11 12 import org.openstreetmap.josm.data.osm.Relation; 12 13 import org.openstreetmap.josm.data.osm.Node; 13 14 import org.openstreetmap.josm.data.osm.OsmPrimitive; 14 import org.openstreetmap.josm.data.osm.Segment;15 15 import org.openstreetmap.josm.data.osm.Way; 16 16 import org.openstreetmap.josm.data.osm.visitor.Visitor; … … 37 37 orig.put(n, new Node(n)); 38 38 } 39 public void visit(Segment s) {40 orig.put(s, new Segment(s));41 }42 39 public void visit(Way w) { 43 40 orig.put(w, new Way(w)); 41 } 42 public void visit(Relation e) { 43 orig.put(e, new Relation(e)); 44 44 } 45 45 } -
trunk/src/org/openstreetmap/josm/command/DeleteCommand.java
r298 r343 11 11 import javax.swing.tree.MutableTreeNode; 12 12 13 import org.openstreetmap.josm.data.osm.Relation; 13 14 import org.openstreetmap.josm.data.osm.OsmPrimitive; 14 15 import org.openstreetmap.josm.data.osm.visitor.NameVisitor; … … 32 33 @Override public void executeCommand() { 33 34 super.executeCommand(); 34 for (OsmPrimitive osm : data) 35 for (OsmPrimitive osm : data) { 35 36 osm.delete(true); 37 } 36 38 } 37 39 38 40 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 39 41 deleted.addAll(data); -
trunk/src/org/openstreetmap/josm/data/Preferences.java
r298 r343 54 54 55 55 /** 56 * Override some values on read. This is intended to be used for technology previews 57 * where we want to temporarily modify things without changing the user's preferences 58 * file. 59 */ 60 protected static final SortedMap<String, String> override = new TreeMap<String, String>(); 61 static { 62 override.put("osm-server.version", "0.5"); 63 override.put("osm-server.additional-versions", ""); 64 override.put("osm-server.url", "http://openstreetmap.gryph.de/api"); 65 override.put("osm-server.username", "fred@remote.org"); 66 override.put("osm-server.password", "fredfred"); 67 override.put("plugins", null); 68 } 69 70 /** 56 71 * Return the location of the user defined preferences file 57 72 */ … … 63 78 64 79 /** 65 * @return A list of all existing directories, where res sources could be stored.80 * @return A list of all existing directories, where resources could be stored. 66 81 */ 67 82 public Collection<String> getAllPossiblePreferenceDirs() { … … 93 108 94 109 synchronized public boolean hasKey(final String key) { 95 return properties.containsKey(key);110 return override.containsKey(key) ? override.get(key) != null : properties.containsKey(key); 96 111 } 97 112 synchronized public String get(final String key) { 113 if (override.containsKey(key)) 114 return override.get(key); 98 115 if (!properties.containsKey(key)) 99 116 return ""; … … 101 118 } 102 119 synchronized public String get(final String key, final String def) { 120 if (override.containsKey(key)) 121 return override.get(key); 103 122 final String prop = properties.get(key); 104 123 if (prop == null || prop.equals("")) … … 111 130 if (e.getKey().startsWith(prefix)) 112 131 all.put(e.getKey(), e.getValue()); 132 for (final Entry<String,String> e : override.entrySet()) 133 if (e.getKey().startsWith(prefix)) 134 if (e.getValue() == null) 135 all.remove(e.getKey()); 136 else 137 all.put(e.getKey(), e.getValue()); 113 138 return all; 114 139 } … … 117 142 } 118 143 synchronized public boolean getBoolean(final String key, final boolean def) { 144 if (override.containsKey(key)) 145 return override.get(key) == null ? def : Boolean.parseBoolean(override.get(key)); 119 146 return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : def; 120 147 } … … 148 175 try { 149 176 final PrintWriter out = new PrintWriter(new FileWriter(getPreferencesDir() + "preferences"), false); 150 for (final Entry<String, String> e : properties.entrySet()) 177 for (final Entry<String, String> e : properties.entrySet()) { 151 178 if (!e.getValue().equals("")) 152 179 out.println(e.getKey() + "=" + e.getValue()); 180 } 153 181 out.close(); 154 182 } catch (final IOException e) { -
trunk/src/org/openstreetmap/josm/data/ServerSidePreferences.java
r298 r343 45 45 public String download() { 46 46 try { 47 System.out.println("reading preference dfrom "+serverUrl);47 System.out.println("reading preferences from "+serverUrl); 48 48 HttpURLConnection con = (HttpURLConnection)serverUrl.openConnection(); 49 49 addAuth(con); -
trunk/src/org/openstreetmap/josm/data/conflict/FromConflict.java
r298 r343 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others2 package org.openstreetmap.josm.data.conflict;3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 6 import org.openstreetmap.josm.data.osm.OsmPrimitive;7 import org.openstreetmap.josm.data.osm.Segment;8 9 public class FromConflict extends ConflictItem {10 11 @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {12 return key instanceof Segment && !((Segment)key).from.equals(((Segment)value).from);13 }14 15 @Override protected String str(OsmPrimitive osm) {16 return osm instanceof Segment ? String.valueOf(((Segment)osm).from.id) : null;17 }18 19 @Override public String key() {20 return "segment|"+tr("from");21 }22 23 @Override public void apply(OsmPrimitive target, OsmPrimitive other) {24 if (target instanceof Segment)25 ((Segment)target).from = ((Segment)other).from;26 }27 } -
trunk/src/org/openstreetmap/josm/data/conflict/SegmentConflict.java
r298 r343 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others2 package org.openstreetmap.josm.data.conflict;3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 6 import org.openstreetmap.josm.data.osm.OsmPrimitive;7 import org.openstreetmap.josm.data.osm.Segment;8 import org.openstreetmap.josm.data.osm.Way;9 10 public class SegmentConflict extends ConflictItem {11 12 @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {13 return key instanceof Way && !((Way)key).segments.equals(((Way)value).segments);14 }15 16 @Override protected String str(OsmPrimitive osm) {17 if (!(osm instanceof Way))18 return null;19 String s = "";20 for (Segment ls : ((Way)osm).segments)21 s += ls.id + ",";22 return s.equals("") ? "<html><i><"+tr("none")+"></i></html>" : s.substring(0, s.length()-1);23 }24 25 @Override public String key() {26 return "way|"+tr("segments");27 }28 29 @Override public void apply(OsmPrimitive target, OsmPrimitive other) {30 if (!(target instanceof Way))31 return;32 ((Way)target).segments.clear();33 ((Way)target).segments.addAll(((Way)other).segments);34 }35 } -
trunk/src/org/openstreetmap/josm/data/conflict/ToConflict.java
r298 r343 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others2 package org.openstreetmap.josm.data.conflict;3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 6 import org.openstreetmap.josm.data.osm.OsmPrimitive;7 import org.openstreetmap.josm.data.osm.Segment;8 9 public class ToConflict extends ConflictItem {10 11 @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {12 return key instanceof Segment && !((Segment)key).to.equals(((Segment)value).to);13 }14 15 @Override protected String str(OsmPrimitive osm) {16 return osm instanceof Segment ? String.valueOf(((Segment)osm).to.id) : null;17 }18 19 @Override public String key() {20 return "segment|"+tr("to");21 }22 23 @Override public void apply(OsmPrimitive target, OsmPrimitive other) {24 if (target instanceof Segment)25 ((Segment)target).to = ((Segment)other).to;26 }27 } -
trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
r298 r343 31 31 32 32 /** 33 * All segments goes here, even when they are in a way. 33 * All ways (Streets etc.) in the DataSet. 34 * 35 * The way nodes are stored only in the way list. 34 36 */ 35 public Collection< Segment> segments = new LinkedList<Segment>();37 public Collection<Way> ways = new LinkedList<Way>(); 36 38 37 39 /** 38 * All ways (Streets etc.) in the DataSet. 39 * 40 * The nodes of the way segments of this way must be objects from 41 * the nodes list, however the way segments are stored only in the 42 * way list. 40 * All relations/relationships 43 41 */ 44 public Collection< Way> ways = new LinkedList<Way>();42 public Collection<Relation> relations = new LinkedList<Relation>(); 45 43 46 44 /** … … 55 53 * selection does only change in the active layer) 56 54 */ 57 public static Collection<SelectionChangedListener> listeners = new LinkedList<SelectionChangedListener>();55 public static Collection<SelectionChangedListener> selListeners = new LinkedList<SelectionChangedListener>(); 58 56 59 57 /** 60 58 * @return A collection containing all primitives of the dataset. The 61 * data is ordered after: first come s nodes, then segments, then ways.59 * data is ordered after: first come nodes, then ways, then relations. 62 60 * Ordering in between the categories is not guaranteed. 63 61 */ … … 65 63 List<OsmPrimitive> o = new LinkedList<OsmPrimitive>(); 66 64 o.addAll(nodes); 67 o.addAll(segments);68 65 o.addAll(ways); 66 o.addAll(relations); 69 67 return o; 70 68 } … … 88 86 public void clearSelection() { 89 87 clearSelection(nodes); 90 clearSelection(segments);91 88 clearSelection(ways); 89 clearSelection(relations); 92 90 Collection<OsmPrimitive> sel = Collections.emptyList(); 93 91 fireSelectionChanged(sel); … … 100 98 public Collection<OsmPrimitive> getSelected() { 101 99 Collection<OsmPrimitive> sel = getSelected(nodes); 102 sel.addAll(getSelected(segments));103 100 sel.addAll(getSelected(ways)); 101 sel.addAll(getSelected(relations)); 104 102 return sel; 105 103 } … … 107 105 public void setSelected(Collection<? extends OsmPrimitive> selection) { 108 106 clearSelection(nodes); 109 clearSelection(segments);110 107 clearSelection(ways); 108 clearSelection(relations); 111 109 for (OsmPrimitive osm : selection) 112 110 osm.selected = true; … … 120 118 } 121 119 clearSelection(nodes); 122 clearSelection(segments);123 120 clearSelection(ways); 121 clearSelection(relations); 124 122 for (OsmPrimitive o : osm) 125 123 if (o != null) … … 158 156 */ 159 157 public static void fireSelectionChanged(Collection<? extends OsmPrimitive> sel) { 160 for (SelectionChangedListener l : listeners)158 for (SelectionChangedListener l : selListeners) 161 159 l.selectionChanged(sel); 162 160 } 163 161 164 162 @Override public DataSet clone() { 165 163 DataSet ds = new DataSet(); 166 164 for (Node n : nodes) 167 165 ds.nodes.add(new Node(n)); 168 for (Segment s : segments)169 ds.segments.add(new Segment(s));170 166 for (Way w : ways) 171 167 ds.ways.add(new Way(w)); 168 for (Relation e : relations) 169 ds.relations.add(new Relation(e)); 172 170 for (DataSource source : dataSources) 173 171 ds.dataSources.add(new DataSource(source.bounds, source.origin)); -
trunk/src/org/openstreetmap/josm/data/osm/Node.java
r298 r343 18 18 public volatile EastNorth eastNorth; 19 19 20 /** 21 * Create an incomplete Node object 22 */ 23 public Node(long id) { 24 this.id = id; 25 incomplete = true; 26 } 27 20 28 /** 21 29 * Create an identical clone of the argument (including the id) -
trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
r298 r343 3 3 4 4 import java.text.SimpleDateFormat; 5 import java.util.ArrayList; 5 6 import java.util.Collection; 6 7 import java.util.Collections; … … 90 91 91 92 /** 93 * If set to true, this object is incomplete, which means only the id 94 * and type is known (type is the objects instance class) 95 */ 96 public boolean incomplete = false; 97 98 /** 92 99 * Implementation of the visitor scheme. Subclases have to call the correct 93 100 * visitor function. … … 125 132 Visitor v = new Visitor(){ 126 133 public void visit(Node n) { ret[0] = 1; } 127 public void visit( Segment s) { ret[0] = 2; }128 public void visit( Way w) { ret[0] = 3; }134 public void visit(Way w) { ret[0] = 2; } 135 public void visit(Relation e) { ret[0] = 3; } 129 136 }; 130 137 visit(v); 131 return id == 0 ? super.hashCode() : (int)(id<< 3)+ret[0];138 return id == 0 ? super.hashCode() : (int)(id<<2)+ret[0]; 132 139 } 133 140 … … 205 212 return timestamp == null ? null : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp); 206 213 } 214 215 207 216 } -
trunk/src/org/openstreetmap/josm/data/osm/Segment.java
r298 r343 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others2 package org.openstreetmap.josm.data.osm;3 4 import org.openstreetmap.josm.data.osm.visitor.Visitor;5 6 7 /**8 * One way segment consisting of a pair of nodes (from/to)9 *10 * @author imi11 */12 public final class Segment extends OsmPrimitive {13 14 /**15 * The starting node of the segment16 */17 public Node from;18 19 /**20 * The ending node of the segment21 */22 public Node to;23 24 /**25 * If set to true, this object is incomplete, which means only the id26 * and type is known (type is the objects instance class)27 */28 public boolean incomplete;29 30 /**31 * Create an identical clone of the argument (including the id)32 */33 public Segment(Segment clone) {34 cloneFrom(clone);35 }36 37 /**38 * Create an segment from the given starting and ending node39 * @param from Starting node of the segment.40 * @param to Ending node of the segment.41 */42 public Segment(Node from, Node to) {43 this.from = from;44 this.to = to;45 incomplete = false;46 }47 48 public Segment(long id) {49 this.id = id;50 incomplete = true;51 }52 53 @Override public void visit(Visitor visitor) {54 visitor.visit(this);55 }56 57 /**58 * @return <code>true</code>, if the <code>ls</code> occupy59 * exactly the same place as <code>this</code>.60 */61 public boolean equalPlace(Segment ls) {62 if (equals(ls))63 return true;64 if (incomplete || ls.incomplete)65 return incomplete == ls.incomplete;66 return ((from.coor.equals(ls.from.coor) && to.coor.equals(ls.to.coor)) ||67 (from.coor.equals(ls.to.coor) && to.coor.equals(ls.from.coor)));68 }69 70 @Override public void cloneFrom(OsmPrimitive osm) {71 super.cloneFrom(osm);72 Segment ls = ((Segment)osm);73 from = ls.from;74 to = ls.to;75 incomplete = ls.incomplete;76 }77 78 @Override public String toString() {79 return "{Segment id="+id+" from="+from+" to="+to+"}";80 }81 82 @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {83 if (!(osm instanceof Segment))84 return super.realEqual(osm, semanticOnly);85 if (incomplete)86 return super.realEqual(osm, semanticOnly) && ((Segment)osm).incomplete;87 return super.realEqual(osm, semanticOnly) && from.equals(((Segment)osm).from) && to.equals(((Segment)osm).to);88 }89 90 public int compareTo(OsmPrimitive o) {91 return o instanceof Segment ? Long.valueOf(id).compareTo(o.id) : (o instanceof Node ? -1 : 1);92 }93 } -
trunk/src/org/openstreetmap/josm/data/osm/Way.java
r298 r343 9 9 10 10 /** 11 * One full way, consisting of several way segments chained together.11 * One full way, consisting of a list of way nodes. 12 12 * 13 13 * @author imi … … 16 16 17 17 /** 18 * All way segments in this way18 * All way nodes in this way 19 19 */ 20 public final List< Segment> segments = new ArrayList<Segment>();20 public final List<Node> nodes = new ArrayList<Node>(); 21 21 22 22 @Override public void visit(Visitor visitor) { … … 31 31 } 32 32 33 /** 34 * Create an empty way without id. Use this only if you set meaningful 35 * values yourself. 36 */ 33 37 public Way() { 38 } 39 40 /** 41 * Create an incomplete Way. 42 */ 43 public Way(long id) { 44 this.id = id; 45 incomplete = true; 34 46 } 35 47 36 48 @Override public void cloneFrom(OsmPrimitive osm) { 37 49 super.cloneFrom(osm); 38 segments.clear();39 segments.addAll(((Way)osm).segments);50 nodes.clear(); 51 nodes.addAll(((Way)osm).nodes); 40 52 } 41 53 42 54 @Override public String toString() { 43 return "{Way id="+id+" segments="+Arrays.toString(segments.toArray())+"}";55 return "{Way id="+id+" nodes="+Arrays.toString(nodes.toArray())+"}"; 44 56 } 45 57 46 58 @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) { 47 return osm instanceof Way ? super.realEqual(osm, semanticOnly) && segments.equals(((Way)osm).segments) : false;59 return osm instanceof Way ? super.realEqual(osm, semanticOnly) && nodes.equals(((Way)osm).nodes) : false; 48 60 } 49 61 … … 52 64 } 53 65 66 @Deprecated 54 67 public boolean isIncomplete() { 55 for (Segment s : segments)56 if (s.incomplete)57 return true;58 68 return false; 59 69 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/AddVisitor.java
r298 r343 1 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others 2 /**3 */4 2 package org.openstreetmap.josm.data.osm.visitor; 5 3 6 4 import org.openstreetmap.josm.data.osm.DataSet; 7 import org.openstreetmap.josm.data.osm. Segment;5 import org.openstreetmap.josm.data.osm.Relation; 8 6 import org.openstreetmap.josm.data.osm.Node; 9 7 import org.openstreetmap.josm.data.osm.Way; … … 27 25 ds.nodes.add(n); 28 26 } 29 public void visit(Segment s) {30 ds.segments.add(s);31 }32 27 public void visit(Way w) { 33 28 ds.ways.add(w); 34 29 } 30 public void visit(Relation e) { 31 ds.relations.add(e); 32 } 35 33 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/AllNodesVisitor.java
r298 r343 5 5 import java.util.HashSet; 6 6 7 import org.openstreetmap.josm.data.osm.Segment; 7 import org.openstreetmap.josm.data.osm.Relation; 8 import org.openstreetmap.josm.data.osm.RelationMember; 8 9 import org.openstreetmap.josm.data.osm.Node; 9 10 import org.openstreetmap.josm.data.osm.OsmPrimitive; … … 30 31 31 32 /** 32 * Line segments have exactly two nodes: from and to.33 * Ways have their way nodes. 33 34 */ 34 public void visit(Segment ls) { 35 if (!ls.incomplete) { 36 visit(ls.from); 37 visit(ls.to); 38 } 35 public void visit(Way w) { 36 for (Node n : w.nodes) 37 visit(n); 39 38 } 40 39 41 40 /** 42 * Ways have all nodes from their segments. 41 * Relations may have any number of nodes. 42 * FIXME: do we want to collect nodes from segs/ways that are relation members? 43 * if so, use AutomatchVisitor! 43 44 */ 44 public void visit( Way w) {45 for ( Segment ls : w.segments)46 visit(ls);45 public void visit(Relation e) { 46 for (RelationMember m : e.members) 47 if (m.member instanceof Node) visit((Node)m.member); 47 48 } 48 49 49 /** 50 50 * @return All nodes the given primitive has. -
trunk/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java
r298 r343 5 5 import org.openstreetmap.josm.data.Bounds; 6 6 import org.openstreetmap.josm.data.coor.EastNorth; 7 import org.openstreetmap.josm.data.osm. Segment;7 import org.openstreetmap.josm.data.osm.Relation; 8 8 import org.openstreetmap.josm.data.osm.Node; 9 9 import org.openstreetmap.josm.data.osm.Way; … … 22 22 } 23 23 24 public void visit(Segment ls) { 25 if (!ls.incomplete) { 26 visit(ls.from); 27 visit(ls.to); 28 } 24 public void visit(Way w) { 25 for (Node n : w.nodes) 26 visit(n); 29 27 } 30 28 31 public void visit(Way w) { 32 for (Segment ls : w.segments) 33 visit(ls); 29 public void visit(Relation e) { 30 // relations have no bounding box. 34 31 } 35 32 -
trunk/src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java
r298 r343 6 6 7 7 import org.openstreetmap.josm.data.osm.DataSet; 8 import org.openstreetmap.josm.data.osm.Segment; 8 import org.openstreetmap.josm.data.osm.Relation; 9 import org.openstreetmap.josm.data.osm.RelationMember; 9 10 import org.openstreetmap.josm.data.osm.Node; 10 11 import org.openstreetmap.josm.data.osm.OsmPrimitive; … … 12 13 13 14 /** 14 * Helper that collect all segments a node is part of, all ways 15 * a node or segment is part of and all areas a node is part of. 15 * Helper that collect all ways a node is part of. 16 16 * 17 17 * Deleted objects are not collected. … … 41 41 if (w.deleted) 42 42 continue; 43 for (Segment ls : w.segments) { 44 if (ls.incomplete) 45 continue; 46 if (ls.from == n || ls.to == n) { 43 for (Node n2 : w.nodes) { 44 if (n == n2) { 47 45 data.add(w); 46 } 47 } 48 } 49 checkRelationMembership(n); 50 } 51 52 public void visit(Way w) { 53 checkRelationMembership(w); 54 } 55 56 public void visit(Relation r) { 57 checkRelationMembership(r); 58 } 59 60 private void checkRelationMembership(OsmPrimitive p) { 61 // FIXME - this might be a candidate for optimisation 62 // if OSM primitives are made to hold a list of back 63 // references. 64 for (Relation r : ds.relations) { 65 for (RelationMember m : r.members) { 66 if (m.member == p) { 67 data.add(r); 68 // move up the tree (there might be relations 69 // referring to this relation) 70 checkRelationMembership(r); 48 71 break; 49 72 } 50 73 } 51 74 } 52 for (Segment ls : ds.segments) {53 if (ls.deleted || ls.incomplete)54 continue;55 if (ls.from == n || ls.to == n)56 data.add(ls);57 }58 75 } 59 public void visit(Segment ls) {60 for (Way w : ds.ways) {61 if (w.deleted)62 continue;63 if (w.segments.contains(ls))64 data.add(w);65 }66 }67 public void visit(Way w) {}68 76 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/DeleteVisitor.java
r298 r343 1 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others 2 /**3 */4 2 package org.openstreetmap.josm.data.osm.visitor; 5 3 6 4 import org.openstreetmap.josm.data.osm.DataSet; 7 import org.openstreetmap.josm.data.osm. Segment;5 import org.openstreetmap.josm.data.osm.Relation; 8 6 import org.openstreetmap.josm.data.osm.Node; 9 7 import org.openstreetmap.josm.data.osm.Way; … … 27 25 ds.nodes.remove(n); 28 26 } 29 public void visit(Segment ls) {30 ds.segments.remove(ls);31 }32 27 public void visit(Way w) { 33 28 ds.ways.remove(w); 34 29 } 30 public void visit(Relation e) { 31 ds.relations.remove(e); 32 } 35 33 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java
r298 r343 10 10 11 11 import org.openstreetmap.josm.data.osm.DataSet; 12 import org.openstreetmap.josm.data.osm.Relation; 13 import org.openstreetmap.josm.data.osm.RelationMember; 12 14 import org.openstreetmap.josm.data.osm.Node; 13 15 import org.openstreetmap.josm.data.osm.OsmPrimitive; 14 import org.openstreetmap.josm.data.osm.Segment;15 16 import org.openstreetmap.josm.data.osm.Way; 16 17 … … 25 26 /** 26 27 * Map from primitives in the database to visited primitives. (Attention: The other way 27 * round than mergedNodes and mergedSegments)28 * round than mergedNodes) 28 29 */ 29 30 public Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>(); … … 38 39 */ 39 40 private final Map<Node, Node> mergedNodes = new HashMap<Node, Node>(); 40 /**41 * A list of all segments that got replaced with others.42 * Key is the segment in the other's dataset and the value is the one that is now43 * in ds.segments.44 */45 private final Map<Segment, Segment> mergedSegments = new HashMap<Segment, Segment>();46 41 47 42 public MergeVisitor(DataSet ds, DataSet mergeds) { … … 81 76 82 77 /** 83 * Merge the segment if id matches or if both nodes are the same (and the 84 * id is zero of either segment). Nodes are the "same" when they @see match 85 */ 86 public void visit(Segment other) { 87 if (mergeAfterId(mergedSegments, ds.segments, other)) 88 return; 89 90 Segment my = null; 91 for (Segment ls : ds.segments) { 92 if (match(other, ls) && ((mergeds == null) || (!mergeds.segments.contains(ls)))) { 93 my = ls; 94 break; 95 } 96 } 97 98 if (my == null) 99 ds.segments.add(other); 100 else if (my.incomplete && !other.incomplete) { 101 mergedSegments.put(other, my); 102 my.cloneFrom(other); 103 } else if (!other.incomplete) { 104 mergedSegments.put(other, my); 105 mergeCommon(my, other); 106 if (my.modified && !other.modified) 107 return; 108 if (!match(my.from, other.from)) { 109 my.from = other.from; 110 my.modified = other.modified; 111 } 112 if (!match(my.to, other.to)) { 113 my.to = other.to; 114 my.modified = other.modified; 115 } 116 } 117 } 118 78 * Simply calls cloneFrom() for now. 79 * Might be useful to keep around to facilitate merge with the relations 80 * branch. 81 */ 119 82 private <T extends OsmPrimitive> void cloneFromExceptIncomplete(T myOsm, T otherOsm) { 120 if (!(myOsm instanceof Way)) 121 myOsm.cloneFrom(otherOsm); 122 else { 123 Way my = (Way)myOsm; 124 Way other = (Way)otherOsm; 125 HashMap<Long, Segment> copy = new HashMap<Long, Segment>(); 126 for (Segment s : my.segments) 127 copy.put(s.id, s); 128 my.cloneFrom(other); 129 my.segments.clear(); 130 for (Segment s : other.segments) { 131 Segment myS = copy.get(s.id); 132 if (s.incomplete && myS != null && !myS.incomplete) { 133 mergedSegments.put(s, myS); 134 my.segments.add(myS); 135 } else 136 my.segments.add(s); 137 } 138 } 83 myOsm.cloneFrom(otherOsm); 139 84 } 140 85 141 86 /** 142 * Merge the way if id matches or if all segments matchesand the87 * Merge the way if id matches or if all nodes match and the 143 88 * id is zero of either way. 144 89 */ … … 155 100 } 156 101 if (my == null) { 157 // Add the way and replace any incomplete segments that we already have158 102 ds.ways.add(other); 159 for (Segment s : other.segments) { 160 if (s.incomplete) { 103 } else { 104 mergeCommon(my, other); 105 if (my.modified && !other.modified) 106 return; 107 boolean same = true; 108 Iterator<Node> it = other.nodes.iterator(); 109 for (Node n : my.nodes) { 110 if (!match(n, it.next())) 111 same = false; 112 } 113 if (!same) { 114 my.nodes.clear(); 115 my.nodes.addAll(other.nodes); 116 my.modified = other.modified; 117 } 118 } 119 } 120 121 /** 122 * Merge the relation if id matches or if all members match and the 123 * id of either relation is zero. 124 */ 125 public void visit(Relation other) { 126 if (mergeAfterId(null, ds.relations, other)) 127 return; 128 129 Relation my = null; 130 for (Relation e : ds.relations) { 131 if (match(other, e) && ((mergeds == null) || (!mergeds.relations.contains(e)))) { 132 my = e; 133 break; 134 } 135 } 136 137 if (my == null) { 138 // Add the relation and replace any incomplete segments that we already have 139 ds.relations.add(other); 140 // FIXME unclear! 141 /* 142 for (RelationMember em : other.getMembers()) { 143 if (em.member.incomplete) { 161 144 for (Segment ourSegment : ds.segments) { 162 145 if (ourSegment.id == s.id) { … … 166 149 } 167 150 } 168 } 151 }*/ 169 152 } else { 170 153 mergeCommon(my, other); … … 172 155 return; 173 156 boolean same = true; 174 Iterator<Segment> it = other.segments.iterator(); 175 for (Segment ls : my.segments) { 176 if (!match(ls, it.next())) 157 if (other.members.size() != my.members.size()) { 177 158 same = false; 178 } 159 } else { 160 for (RelationMember em : my.members) { 161 if (!other.members.contains(em)) { 162 same = false; 163 break; 164 } 165 } 166 } 167 // FIXME Unclear 168 /* 179 169 if (!same) { 180 170 HashMap<Long, Segment> copy = new HashMap<Long, Segment>(); … … 192 182 my.modified = other.modified; 193 183 } 184 */ 194 185 } 195 186 } … … 200 191 */ 201 192 public void fixReferences() { 202 for (Segment s : ds.segments)203 fixSegment(s);204 for (OsmPrimitive osm : conflicts.values())205 if (osm instanceof Segment)206 fixSegment((Segment)osm);207 193 for (Way w : ds.ways) 208 194 fixWay(w); … … 214 200 private void fixWay(Way w) { 215 201 boolean replacedSomething = false; 216 LinkedList< Segment> newSegments = new LinkedList<Segment>();217 for ( Segment ls : w.segments) {218 Segment otherLs = mergedSegments.get(ls);219 new Segments.add(otherLs == null ? ls : otherLs);220 if (other Ls!= null)202 LinkedList<Node> newNodes = new LinkedList<Node>(); 203 for (Node n : w.nodes) { 204 Node otherN = mergedNodes.get(n); 205 newNodes.add(otherN == null ? n : otherN); 206 if (otherN != null) 221 207 replacedSomething = true; 222 208 } 223 209 if (replacedSomething) { 224 w.segments.clear(); 225 w.segments.addAll(newSegments); 226 } 227 for (Segment ls : w.segments) 228 fixSegment(ls); 210 w.nodes.clear(); 211 w.nodes.addAll(newNodes); 229 212 } 230 231 private void fixSegment(Segment ls) {232 233 if (mergedNodes.containsKey(ls.from))234 ls.from = mergedNodes.get(ls.from);235 236 if (mergedNodes.containsKey(ls.to))237 ls.to = mergedNodes.get(ls.to);238 239 213 } 240 214 241 215 /** 242 * @return Whether the nodes match es(in sense of "be mergable").216 * @return Whether the nodes match (in sense of "be mergable"). 243 217 */ 244 218 private boolean match(Node n1, Node n2) { … … 249 223 250 224 /** 251 * @return Whether the segments matches (in sense of "be mergable"). 252 */ 253 private boolean match(Segment ls1, Segment ls2) { 254 if (ls1.id == ls2.id && ls1.id != 0) 255 return true; 256 //if (ls1.id != 0 && ls2.id != 0) 257 // return false; 258 if (ls1.incomplete || ls2.incomplete) 259 return false; 260 return match(ls1.from, ls2.from) && match(ls1.to, ls2.to); 261 } 262 263 /** 264 * @return Whether the ways matches (in sense of "be mergable"). 225 * @return Whether the ways match (in sense of "be mergable"). 265 226 */ 266 227 private boolean match(Way w1, Way w2) { 267 228 if (w1.id == 0 || w2.id == 0) { 268 if (w1. segments.size() != w2.segments.size())269 270 Iterator< Segment> it = w1.segments.iterator();271 for ( Segment ls : w2.segments)272 if (!match( ls, it.next()))229 if (w1.nodes.size() != w2.nodes.size()) 230 return false; 231 Iterator<Node> it = w1.nodes.iterator(); 232 for (Node n : w2.nodes) 233 if (!match(n, it.next())) 273 234 return false; 274 235 return true; … … 276 237 return w1.id == w2.id; 277 238 } 239 /** 240 * @return Whether the relations match (in sense of "be mergable"). 241 */ 242 private boolean match(Relation w1, Relation w2) { 243 // FIXME this is not perfect yet... 244 if (w1.id == 0 || w2.id == 0) { 245 if (w1.members.size() != w2.members.size()) 246 return false; 247 for (RelationMember em : w1.members) { 248 if (!w2.members.contains(em)) { 249 return false; 250 } 251 } 252 return true; 253 } 254 return w1.id == w2.id; 255 } 256 278 257 279 258 /** … … 327 306 } 328 307 if (my.id == other.id && my.id != 0) { 329 if (my instanceof Segment && ((Segment)my).incomplete)330 return false; // merge always over an incomplete331 308 if (my.modified && other.modified) { 332 309 conflicts.put(my, other); -
trunk/src/org/openstreetmap/josm/data/osm/visitor/NameVisitor.java
r298 r343 1 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others 2 3 2 package org.openstreetmap.josm.data.osm.visitor; 4 3 … … 13 12 14 13 import org.openstreetmap.josm.Main; 14 import org.openstreetmap.josm.data.osm.Relation; 15 15 import org.openstreetmap.josm.data.osm.Node; 16 16 import org.openstreetmap.josm.data.osm.OsmPrimitive; 17 import org.openstreetmap.josm.data.osm.Segment;18 17 import org.openstreetmap.josm.data.osm.Way; 19 18 import org.openstreetmap.josm.tools.ImageProvider; … … 41 40 42 41 /** 43 * If the segment has a key named "name", its value is displayed.44 * Otherwise, if it has "id", this is used. If none of these available,45 * "(x1,y1) -> (x2,y2)" is displayed with the nodes coordinates.46 */47 public void visit(Segment ls) {48 name = ls.get("name");49 if (name == null) {50 if (ls.incomplete)51 name = ls.id == 0 ? tr("new") : ls.id+" ("+tr("unknown")+")";52 else53 name = (ls.id==0?"":ls.id+" ")+"("+ls.from.coor.lat()+","+ls.from.coor.lon()+") -> ("+ls.to.coor.lat()+","+ls.to.coor.lon()+")";54 }55 addId(ls);56 icon = ImageProvider.get("data", "segment");57 trn("segment", "segments", 0); // no marktrn available58 className = "segment";59 }60 61 /**62 42 * If the node has a name-key or id-key, this is displayed. If not, (lat,lon) 63 43 * is displayed. … … 81 61 if (name == null) name = w.get("ref"); 82 62 if (name == null) { 83 AllNodesVisitor.getAllNodes(w.segments);84 Set<Node> nodes = new HashSet<Node>();85 for (Segment ls : w.segments) {86 if (!ls.incomplete) {87 nodes.add(ls.from);88 nodes.add(ls.to);89 }90 }91 63 String what = (w.get("highway") != null) ? "highway " : (w.get("railway") != null) ? "railway " : (w.get("waterway") != null) ? "waterway " : ""; 92 name = what + trn("{0} node", "{0} nodes", nodes.size(),nodes.size());64 name = what + trn("{0} node", "{0} nodes", w.nodes.size(), w.nodes.size()); 93 65 } 94 if (w.isIncomplete())95 name += " ("+tr("incomplete")+")";96 66 addId(w); 97 67 icon = ImageProvider.get("data", "way"); 98 68 trn("way", "ways", 0); // no marktrn available 99 69 className = "way"; 70 } 71 72 /** 73 */ 74 public void visit(Relation e) { 75 name = e.get("type"); 76 // FIXME add names of members 77 if (name == null) 78 name = "relation"; 79 addId(e); 80 icon = ImageProvider.get("data", "relation"); 81 trn("relation", "relations", 0); // no marktrn available 82 className = "relation"; 100 83 } 101 84 -
trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java
r319 r343 12 12 import org.openstreetmap.josm.Main; 13 13 import org.openstreetmap.josm.data.osm.DataSet; 14 import org.openstreetmap.josm.data.osm.Relation; 14 15 import org.openstreetmap.josm.data.osm.Node; 15 16 import org.openstreetmap.josm.data.osm.OsmPrimitive; 16 import org.openstreetmap.josm.data.osm.Segment;17 17 import org.openstreetmap.josm.data.osm.Way; 18 18 import org.openstreetmap.josm.gui.NavigatableComponent; … … 30 30 public final static Color darkblue = new Color(0,0,128); 31 31 public final static Color darkgreen = new Color(0,128,0); 32 32 33 33 /** 34 34 * The environment to paint to. … … 41 41 42 42 public boolean inactive; 43 43 44 44 protected static final double PHI = Math.toRadians(20); 45 45 46 46 /** 47 47 * Preferences 48 48 */ 49 49 protected Color inactiveColor; 50 50 protected Color selectedColor; 51 51 protected Color nodeColor; 52 protected Color segmentColor;53 52 protected Color dfltWayColor; 54 53 protected Color incompleteColor; … … 61 60 */ 62 61 protected Color currentColor = null; 63 protected GeneralPath curr rentPath = new GeneralPath();64 62 protected GeneralPath currentPath = new GeneralPath(); 63 65 64 public void visitAll(DataSet data) { 65 66 66 inactiveColor = getPreferencesColor("inactive", Color.DARK_GRAY); 67 67 selectedColor = getPreferencesColor("selected", Color.WHITE); 68 68 nodeColor = getPreferencesColor("node", Color.RED); 69 segmentColor = getPreferencesColor("segment", darkgreen);70 69 dfltWayColor = getPreferencesColor("way", darkblue); 71 70 incompleteColor = getPreferencesColor("incomplete way", darkerblue); … … 74 73 showOrderNumber = Main.pref.getBoolean("draw.segment.order_number"); 75 74 76 for (final OsmPrimitive osm : data.segments)77 if (!osm.deleted && !osm.selected)78 osm.visit(this);79 75 for (final OsmPrimitive osm : data.ways) 80 76 if (!osm.deleted && !osm.selected) 81 77 osm.visit(this); 82 displaySegments(null); // Flush segment cache before nodes78 displaySegments(null); 83 79 for (final OsmPrimitive osm : data.nodes) 84 80 if (!osm.deleted && !osm.selected) … … 108 104 109 105 /** 110 * Draw just a line between the points.111 * White if selected (as always) or green otherwise.112 */113 public void visit(Segment ls) {114 Color color;115 if (inactive)116 color = inactiveColor;117 else if (ls.selected)118 color = selectedColor;119 else120 color = segmentColor;121 drawSegment(ls, color, showDirectionArrow);122 }123 124 /**125 106 * Draw a darkblue line for all segments. 126 107 * @param w The way to draw. … … 132 113 else { 133 114 wayColor = dfltWayColor; 134 for (Segment ls : w.segments) { 135 if (ls.incomplete) { 136 wayColor = incompleteColor; 137 break; 138 } 115 } 116 117 int orderNumber = 0; 118 Node lastN = null; 119 for (Node n : w.nodes) { 120 if (lastN == null) { 121 lastN = n; 122 continue; 139 123 } 140 }141 142 int orderNumber = 0;143 for (Segment ls : w.segments) {144 124 orderNumber++; 145 if (!ls.selected) // selected already in good color 146 drawSegment(ls, w.selected && !inactive ? selectedColor : wayColor, showDirectionArrow); 147 if (!ls.incomplete && showOrderNumber) 148 drawOrderNumber(ls, orderNumber); 149 } 150 } 151 152 /** 153 * Draw an number of the order of the segment within the parents way 154 */ 155 protected void drawOrderNumber(Segment ls, int orderNumber) { 125 drawSegment(lastN, n, w.selected && !inactive ? selectedColor : wayColor, showDirectionArrow); 126 if (showOrderNumber) 127 drawOrderNumber(lastN, n, orderNumber); 128 lastN = n; 129 } 130 } 131 132 public void visit(Relation e) { 133 // relations are not (yet?) drawn. 134 } 135 136 /** 137 * Draw an number of the order of the two consecutive nodes within the 138 * parents way 139 */ 140 protected void drawOrderNumber(Node n1, Node n2, int orderNumber) { 156 141 int strlen = (""+orderNumber).length(); 157 Point p1 = nc.getPoint( ls.from.eastNorth);158 Point p2 = nc.getPoint( ls.to.eastNorth);142 Point p1 = nc.getPoint(n1.eastNorth); 143 Point p2 = nc.getPoint(n2.eastNorth); 159 144 int x = (p1.x+p2.x)/2 - 4*strlen; 160 145 int y = (p1.y+p2.y)/2 + 4; … … 181 166 Rectangle screen = g.getClipBounds(); 182 167 183 if ( screen.contains(p.x, p.y))168 if (screen.contains(p.x, p.y)) 184 169 g.drawRect(p.x-1, p.y-1, 2, 2); 185 170 } … … 188 173 * Draw a line with the given color. 189 174 */ 190 protected void drawSegment(Segment ls, Color col, boolean showDirection) { 191 if (ls.incomplete) 192 return; 175 protected void drawSegment(Node n1, Node n2, Color col, boolean showDirection) { 176 193 177 if (col != currentColor) { 194 178 displaySegments(col); 195 179 } 196 180 197 Point p1 = nc.getPoint( ls.from.eastNorth);198 Point p2 = nc.getPoint( ls.to.eastNorth);199 200 Rectangle screen = g.getClipBounds(); 181 Point p1 = nc.getPoint(n1.eastNorth); 182 Point p2 = nc.getPoint(n2.eastNorth); 183 184 Rectangle screen = g.getClipBounds(); 201 185 Line2D line = new Line2D.Double(p1.x, p1.y, p2.x, p2.y); 202 186 if (screen.contains(p1.x, p1.y, p2.x, p2.y) || screen.intersectsLine(line)) 203 187 { 204 curr rentPath.moveTo(p1.x, p1.y);205 curr rentPath.lineTo(p2.x, p2.y);206 188 currentPath.moveTo(p1.x, p1.y); 189 currentPath.lineTo(p2.x, p2.y); 190 207 191 if (showDirection) { 208 192 double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI; 209 currrentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI))); 210 currrentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI))); 211 currrentPath.lineTo(p2.x, p2.y); } 212 } 213 } 214 215 protected void displaySegments(Color newColor) { 216 if (currrentPath != null) { 217 g.setColor(currentColor); 218 ((Graphics2D) g).draw(currrentPath); 219 currrentPath = new GeneralPath(); 220 currentColor = newColor; 193 currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI))); 194 currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI))); 195 currentPath.lineTo(p2.x, p2.y); 196 } 221 197 } 222 198 } … … 230 206 return ColorHelper.html2color(colStr); 231 207 } 232 233 208 234 209 public void setGraphics(Graphics g) { 235 210 this.g = g; … … 239 214 this.nc = nc; 240 215 } 216 217 protected void displaySegments(Color newColor) { 218 if (currentPath != null) { 219 g.setColor(currentColor); 220 ((Graphics2D) g).draw(currentPath); 221 currentPath = new GeneralPath(); 222 currentColor = newColor; 223 } 224 } 241 225 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/Visitor.java
r298 r343 2 2 package org.openstreetmap.josm.data.osm.visitor; 3 3 4 import org.openstreetmap.josm.data.osm.Relation; 4 5 import org.openstreetmap.josm.data.osm.Node; 5 import org.openstreetmap.josm.data.osm.Segment;6 6 import org.openstreetmap.josm.data.osm.Way; 7 7 … … 14 14 public interface Visitor { 15 15 void visit(Node n); 16 void visit(Segment s);17 16 void visit(Way w); 17 void visit(Relation e); 18 18 } -
trunk/src/org/openstreetmap/josm/gui/ConflictResolver.java
r339 r343 38 38 import org.openstreetmap.josm.data.conflict.ConflictItem; 39 39 import org.openstreetmap.josm.data.conflict.DeleteConflict; 40 import org.openstreetmap.josm.data.conflict.FromConflict;41 40 import org.openstreetmap.josm.data.conflict.PositionConflict; 42 41 import org.openstreetmap.josm.data.conflict.PropertyConflict; 43 import org.openstreetmap.josm.data.conflict.SegmentConflict;44 import org.openstreetmap.josm.data.conflict.ToConflict;45 42 import org.openstreetmap.josm.data.osm.OsmPrimitive; 46 43 import org.openstreetmap.josm.tools.GBC; … … 140 137 possibleConflicts.add(new DeleteConflict()); 141 138 possibleConflicts.add(new PositionConflict()); 142 possibleConflicts.add(new FromConflict());143 possibleConflicts.add(new ToConflict());144 possibleConflicts.add(new SegmentConflict());145 139 TreeSet<String> allkeys = new TreeSet<String>(); 146 140 for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) { -
trunk/src/org/openstreetmap/josm/gui/GettingStarted.java
r312 r343 48 48 panel = new JPanel(new GridBagLayout()); 49 49 50 panel.add(new JLabel("<html><h2>You are running a technology preview with support for <i>API 0.5</i>.</h2>" + 51 "<h3>API 0.5 supports object relationships, and segments have been removed.</h3>" + 52 "<h3>This version is hard-coded to use the API 0.5 running on <i>openstreetmap.gryph.de</i> which has data from a recent planet file."+ 53 "<br>Please be gentle with that machine and request only moderate bounding boxes.<br>" + 54 "<br>Username and password are also hardcoded, so your real username and password are not transmitted.<br>" + 55 "</h3>"), GBC.eol()); 56 57 addLine("wiki", "Read the [Wiki page on API 0.5]"); 50 58 addGettingStarted(); 51 59 addGettingHelp(); … … 86 94 else if (e.getActionCommand().equals("help")) 87 95 Main.main.menu.help.actionPerformed(e); 96 else if (e.getActionCommand().equals("wiki")) 97 OpenBrowser.displayUrl("http://wiki.openstreetmap.org/index.php?title=OSM_Protocol_Version_0.5"); 88 98 else if (e.getActionCommand().equals("tutorial")) 89 99 OpenBrowser.displayUrl("http://josm.openstreetmap.de/wiki/TutorialVideos"); -
trunk/src/org/openstreetmap/josm/gui/MainMenu.java
r298 r343 18 18 import org.openstreetmap.josm.actions.CombineWayAction; 19 19 import org.openstreetmap.josm.actions.DownloadAction; 20 import org.openstreetmap.josm.actions.DownloadIncompleteAction;21 20 import org.openstreetmap.josm.actions.ExitAction; 22 21 import org.openstreetmap.josm.actions.GpxExportAction; … … 26 25 import org.openstreetmap.josm.actions.PreferencesAction; 27 26 import org.openstreetmap.josm.actions.RedoAction; 28 import org.openstreetmap.josm.actions.ReorderAction; 29 import org.openstreetmap.josm.actions.ReverseSegmentAction; 27 import org.openstreetmap.josm.actions.ReverseWayAction; 30 28 import org.openstreetmap.josm.actions.SaveAction; 31 29 import org.openstreetmap.josm.actions.SaveAsAction; … … 56 54 public final OpenAction open = new OpenAction(); 57 55 public final DownloadAction download = new DownloadAction(); 58 public final Action reverse Segment = new ReverseSegmentAction();56 public final Action reverseWay = new ReverseWayAction(); 59 57 public final Action splitWay = new SplitWayAction(); 60 58 public final Action combineWay = new CombineWayAction(); 61 59 public final Action alignInCircle = new AlignInCircleAction(); 62 60 public final Action alignInLine = new AlignInLineAction(); 63 public final Action reorder = new ReorderAction();64 61 public final Action upload = new UploadAction(); 65 62 public final Action save = new SaveAction(null); … … 70 67 public final HelpAction help = new HelpAction(); 71 68 public final Action about = new AboutAction(); 72 public final DownloadIncompleteAction downloadIncomplete = new DownloadIncompleteAction();73 69 74 70 public final JMenu layerMenu = new JMenu(tr("Layer")); … … 117 113 toolsMenu.add(alignInLine); 118 114 toolsMenu.addSeparator(); 119 toolsMenu.add(reverseSegment); 120 toolsMenu.add(reorder); 115 toolsMenu.add(reverseWay); 121 116 toolsMenu.addSeparator(); 122 117 toolsMenu.add(splitWay); … … 126 121 connectionMenu.setMnemonic('C'); 127 122 connectionMenu.add(download); 128 connectionMenu.add(downloadIncomplete);129 123 connectionMenu.add(upload); 130 124 add(connectionMenu); -
trunk/src/org/openstreetmap/josm/gui/MapFrame.java
r312 r343 15 15 import org.openstreetmap.josm.Main; 16 16 import org.openstreetmap.josm.actions.mapmode.AddSegmentAction; 17 import org.openstreetmap.josm.actions.mapmode.AddWayAction;18 17 import org.openstreetmap.josm.actions.mapmode.DeleteAction; 19 18 import org.openstreetmap.josm.actions.mapmode.MapMode; … … 24 23 import org.openstreetmap.josm.gui.dialogs.CommandStackDialog; 25 24 import org.openstreetmap.josm.gui.dialogs.ConflictDialog; 25 import org.openstreetmap.josm.gui.dialogs.RelationListDialog; 26 26 import org.openstreetmap.josm.gui.dialogs.HistoryDialog; 27 27 import org.openstreetmap.josm.gui.dialogs.LayerListDialog; … … 85 85 toolBarActions.add(new IconToggleButton(new AddNodeGroup(this))); 86 86 toolBarActions.add(new IconToggleButton(new AddSegmentAction(this))); 87 toolBarActions.add(new IconToggleButton(new AddWayAction(this)));88 87 toolBarActions.add(new IconToggleButton(new DeleteAction(this))); 89 88 … … 104 103 addToggleDialog(conflictDialog = new ConflictDialog()); 105 104 addToggleDialog(new CommandStackDialog(this)); 105 addToggleDialog(new RelationListDialog()); 106 106 107 107 // status line below the map -
trunk/src/org/openstreetmap/josm/gui/MapStatus.java
r298 r343 126 126 OsmPrimitive osmNearest = null; 127 127 // Set the text label in the bottom status bar 128 osmNearest = mv.getNearest(ms.mousePos , (ms.modifiers & MouseEvent.ALT_DOWN_MASK) != 0);128 osmNearest = mv.getNearest(ms.mousePos); 129 129 if (osmNearest != null) { 130 130 NameVisitor visitor = new NameVisitor(); -
trunk/src/org/openstreetmap/josm/gui/MapView.java
r304 r343 85 85 86 86 // listend to selection changes to redraw the map 87 DataSet. listeners.add(new SelectionChangedListener(){87 DataSet.selListeners.add(new SelectionChangedListener(){ 88 88 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 89 89 repaint(); -
trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java
r306 r343 4 4 import java.awt.Point; 5 5 import java.util.Collection; 6 import java.util.Collections;7 6 import java.util.HashSet; 8 import java.util.List;9 7 10 8 import javax.swing.JComponent; … … 16 14 import org.openstreetmap.josm.data.osm.Node; 17 15 import org.openstreetmap.josm.data.osm.OsmPrimitive; 18 import org.openstreetmap.josm.data.osm.Segment;19 16 import org.openstreetmap.josm.data.osm.Way; 17 import org.openstreetmap.josm.data.osm.WaySegment; 20 18 import org.openstreetmap.josm.data.projection.Projection; 21 19 … … 147 145 148 146 /** 149 * @return the nearest way to the screen point given. 150 */ 151 public final Way getNearestWay(Point p) { 147 * @return the nearest way segment to the screen point given that is not 148 * in ignore. 149 * 150 * @param p the point for which to search the nearest segment. 151 * @param ignore a collection of segments which are not to be returned. 152 * May be null. 153 */ 154 public final WaySegment getNearestWaySegment(Point p, Collection<WaySegment> ignore) { 152 155 Way minPrimitive = null; 156 int minI = 0; 153 157 double minDistanceSq = Double.MAX_VALUE; 154 158 for (Way w : Main.ds.ways) { 155 159 if (w.deleted) 156 160 continue; 157 for (Segment ls : w.segments) { 158 if (ls.deleted || ls.incomplete) 161 Node lastN = null; 162 int i = -2; 163 for (Node n : w.nodes) { 164 i++; 165 if (n.deleted) continue; 166 if (lastN == null) { 167 lastN = n; 159 168 continue; 160 Point A = getPoint(ls.from.eastNorth); 161 Point B = getPoint(ls.to.eastNorth); 169 } 170 if (ignore == null || !ignore.contains(new WaySegment(w, i))) { 171 Point A = getPoint(lastN.eastNorth); 172 Point B = getPoint(n.eastNorth); 173 double c = A.distanceSq(B); 174 double a = p.distanceSq(B); 175 double b = p.distanceSq(A); 176 double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared 177 if (perDist < 100 && minDistanceSq > perDist && a < c+100 && b < c+100) { 178 minDistanceSq = perDist; 179 minPrimitive = w; 180 minI = i; 181 } 182 } 183 lastN = n; 184 } 185 } 186 return minPrimitive == null ? null : new WaySegment(minPrimitive, minI); 187 } 188 189 /** 190 * @return the nearest way segment to the screen point given. 191 */ 192 public final WaySegment getNearestWaySegment(Point p) { 193 return getNearestWaySegment(p, null); 194 } 195 196 /** 197 * @return the nearest way to the screen point given. 198 */ 199 public final Way getNearestWay(Point p) { 200 WaySegment nearestWaySeg = getNearestWaySegment(p); 201 return nearestWaySeg == null ? null : nearestWaySeg.way; 202 } 203 204 /** 205 * Return the object, that is nearest to the given screen point. 206 * 207 * First, a node will be searched. If a node within 10 pixel is found, the 208 * nearest node is returned. 209 * 210 * If no node is found, search for near ways. 211 * 212 * If nothing is found, return <code>null</code>. 213 * 214 * @param p The point on screen. 215 * @return The primitive, that is nearest to the point p. 216 */ 217 public OsmPrimitive getNearest(Point p) { 218 OsmPrimitive osm = getNearestNode(p); 219 if (osm == null) 220 osm = getNearestWay(p); 221 return osm; 222 } 223 224 @Deprecated 225 public OsmPrimitive getNearest(Point p, boolean segmentInsteadWay) { 226 return getNearest(p); 227 } 228 229 /** 230 * @return A list of all objects that are nearest to 231 * the mouse. Does a simple sequential scan on all the data. 232 * 233 * @return A collection of all items or <code>null</code> 234 * if no item under or near the point. The returned 235 * list is never empty. 236 */ 237 public Collection<OsmPrimitive> getAllNearest(Point p) { 238 Collection<OsmPrimitive> nearest = new HashSet<OsmPrimitive>(); 239 for (Way w : Main.ds.ways) { 240 if (w.deleted) continue; 241 Node lastN = null; 242 for (Node n : w.nodes) { 243 if (n.deleted) continue; 244 if (lastN == null) { 245 lastN = n; 246 continue; 247 } 248 Point A = getPoint(lastN.eastNorth); 249 Point B = getPoint(n.eastNorth); 162 250 double c = A.distanceSq(B); 163 251 double a = p.distanceSq(B); 164 252 double b = p.distanceSq(A); 165 253 double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared 166 if (perDist < 100 && minDistanceSq > perDist && a < c+100 && b < c+100) { 167 minDistanceSq = perDist; 168 minPrimitive = w; 169 } 170 } 171 } 172 return minPrimitive; 173 } 174 175 /** 176 * @return the nearest segment to the screen point given 177 * 178 * @param p the point for which to search the nearest segment. 179 */ 180 public final Segment getNearestSegment(Point p) { 181 List<Segment> e = Collections.emptyList(); 182 return getNearestSegment(p, e); 183 } 184 185 /** 186 * @return the nearest segment to the screen point given that is not 187 * in ignoreThis. 188 * 189 * @param p the point for which to search the nearest segment. 190 * @param ignore a collection of segments which are not to be returned. Must not be null. 191 */ 192 public final Segment getNearestSegment(Point p, Collection<Segment> ignore) { 193 Segment minPrimitive = null; 194 double minDistanceSq = Double.MAX_VALUE; 195 // segments 196 for (Segment ls : Main.ds.segments) { 197 if (ls.deleted || ls.incomplete || ignore.contains(ls)) 198 continue; 199 Point A = getPoint(ls.from.eastNorth); 200 Point B = getPoint(ls.to.eastNorth); 201 double c = A.distanceSq(B); 202 double a = p.distanceSq(B); 203 double b = p.distanceSq(A); 204 double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared 205 if (perDist < 100 && minDistanceSq > perDist && a < c+100 && b < c+100) { 206 minDistanceSq = perDist; 207 minPrimitive = ls; 208 } 209 } 210 return minPrimitive; 211 } 212 213 /** 214 * Return the object, that is nearest to the given screen point. 215 * 216 * First, a node will be searched. If a node within 10 pixel is found, the 217 * nearest node is returned. 218 * 219 * If no node is found, search for pending segments. 220 * 221 * If no such segment is found, and a non-pending segment is 222 * within 10 pixel to p, this segment is returned, except when 223 * <code>wholeWay</code> is <code>true</code>, in which case the 224 * corresponding Way is returned. 225 * 226 * If no segment is found and the point is within an area, return that 227 * area. 228 * 229 * If no area is found, return <code>null</code>. 230 * 231 * @param p The point on screen. 232 * @param segmentInsteadWay Whether the segment (true) or only the whole 233 * way should be returned. 234 * @return The primitive, that is nearest to the point p. 235 */ 236 public OsmPrimitive getNearest(Point p, boolean segmentInsteadWay) { 237 OsmPrimitive osm = getNearestNode(p); 238 if (osm == null && !segmentInsteadWay) 239 osm = getNearestWay(p); 240 if (osm == null) 241 osm = getNearestSegment(p); 242 return osm; 243 } 244 245 /** 246 * @return A list of all objects that are nearest to 247 * the mouse. To do this, first the nearest object is 248 * determined. 249 * 250 * If its a node, return all segments and 251 * streets the node is part of, as well as all nodes 252 * (with their segments and ways) with the same 253 * location. 254 * 255 * If its a segment, return all ways this segment 256 * belongs to as well as all segments that are between 257 * the same nodes (in both direction) with all their ways. 258 * 259 * @return A collection of all items or <code>null</code> 260 * if no item under or near the point. The returned 261 * list is never empty. 262 */ 263 public Collection<OsmPrimitive> getAllNearest(Point p) { 264 OsmPrimitive osm = getNearest(p, true); 265 if (osm == null) 266 return null; 267 Collection<OsmPrimitive> c = new HashSet<OsmPrimitive>(); 268 c.add(osm); 269 if (osm instanceof Node) { 270 Node node = (Node)osm; 271 for (Node n : Main.ds.nodes) 272 if (!n.deleted && n.coor.equals(node.coor)) 273 c.add(n); 274 for (Segment ls : Main.ds.segments) 275 // segments never match nodes, so they are skipped by contains 276 if (!ls.deleted && !ls.incomplete && (c.contains(ls.from) || c.contains(ls.to))) 277 c.add(ls); 278 } 279 if (osm instanceof Segment) { 280 Segment line = (Segment)osm; 281 for (Segment ls : Main.ds.segments) 282 if (!ls.deleted && ls.equalPlace(line)) 283 c.add(ls); 284 } 285 if (osm instanceof Node || osm instanceof Segment) { 286 for (Way w : Main.ds.ways) { 287 if (w.deleted) 288 continue; 289 for (Segment ls : w.segments) { 290 if (!ls.deleted && !ls.incomplete && c.contains(ls)) { 291 c.add(w); 254 if (perDist < 100 && a < c+100 && b < c+100) { 255 nearest.add(w); 292 256 break; 293 257 } 294 } 258 lastN = n; 259 } 260 } 261 for (Node n : Main.ds.nodes) { 262 if (!n.deleted && getPoint(n.eastNorth).distanceSq(p) < 100) { 263 nearest.add(n); 295 264 } 296 265 } 297 return c;266 return nearest.isEmpty() ? null : nearest; 298 267 } 299 268 -
trunk/src/org/openstreetmap/josm/gui/OsmPrimitivRenderer.java
r298 r343 5 5 6 6 import javax.swing.DefaultListCellRenderer; 7 import javax.swing.JLabel; 7 8 import javax.swing.JList; 9 import javax.swing.JTable; 10 import javax.swing.ListCellRenderer; 11 import javax.swing.table.DefaultTableCellRenderer; 12 import javax.swing.table.TableCellRenderer; 8 13 9 14 import org.openstreetmap.josm.data.osm.OsmPrimitive; … … 12 17 /** 13 18 * Renderer that renders the objects from an OsmPrimitive as data. 19 * 20 * Can be used in lists and tables. 21 * 14 22 * @author imi 23 * @author Frederik Ramm <frederik@remote.org> 15 24 */ 16 public class OsmPrimitivRenderer extends DefaultListCellRenderer {25 public class OsmPrimitivRenderer implements ListCellRenderer, TableCellRenderer { 17 26 27 /** 28 * NameVisitor provides proper names and icons for OsmPrimitives 29 */ 18 30 private NameVisitor visitor = new NameVisitor(); 19 31 20 @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 21 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 22 if (value != null) { 32 /** 33 * Default list cell renderer - delegate for ListCellRenderer operation 34 */ 35 private DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer(); 36 37 /** 38 * Default table cell renderer - delegate for TableCellRenderer operation 39 */ 40 private DefaultTableCellRenderer defaultTableCellRenderer = new DefaultTableCellRenderer(); 41 42 /** 43 * Adapter method supporting the ListCellRenderer interface. 44 */ 45 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 46 Component def = defaultListCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 47 return renderer(def, (OsmPrimitive) value); 48 } 49 50 /** 51 * Adapter method supporting the TableCellRenderer interface. 52 */ 53 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 54 Component def = defaultTableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 55 return renderer(def, (OsmPrimitive) value); 56 } 57 58 /** 59 * Internal method that stuffs information into the rendering component 60 * provided that it's a kind of JLabel. 61 * @param def the rendering component 62 * @param value the OsmPrimtive to render 63 * @return the modified rendering component 64 */ 65 private Component renderer(Component def, OsmPrimitive value) { 66 if (def != null && value != null && def instanceof JLabel) { 23 67 ((OsmPrimitive)value).visit(visitor); 24 setText(visitor.name);25 setIcon(visitor.icon);68 ((JLabel)def).setText(visitor.name); 69 ((JLabel)def).setIcon(visitor.icon); 26 70 } 27 return this;71 return def; 28 72 } 73 29 74 } -
trunk/src/org/openstreetmap/josm/gui/SelectionManager.java
r298 r343 25 25 import org.openstreetmap.josm.data.osm.Node; 26 26 import org.openstreetmap.josm.data.osm.OsmPrimitive; 27 import org.openstreetmap.josm.data.osm.Segment;28 27 import org.openstreetmap.josm.data.osm.Way; 29 28 … … 282 281 * modifier. 283 282 * @param alt Whether the alt key was pressed, which means select all objects 284 * that are touched, instead those which are completly covered. Also 285 * select whole ways instead of segments. 283 * that are touched, instead those which are completly covered. 286 284 */ 287 285 public Collection<OsmPrimitive> getObjectsInRectangle(Rectangle r, boolean alt) { … … 293 291 294 292 if (clicked) { 295 OsmPrimitive osm = nc.getNearest(center , alt);293 OsmPrimitive osm = nc.getNearest(center); 296 294 if (osm != null) 297 295 selection.add(osm); … … 303 301 } 304 302 305 // pending segments306 for (Segment s : Main.ds.segments)307 if (!s.deleted && rectangleContainSegment(r, alt, s))308 selection.add(s);309 310 303 // ways 311 304 for (Way w : Main.ds.ways) { 312 if (w.deleted) 313 continue; 314 boolean someSelectableSegment = false; 315 boolean wholeWaySelected = true; 316 for (Segment s : w.segments) { 317 if (s.incomplete) 305 if (w.deleted || w.nodes.isEmpty()) 318 306 continue; 319 someSelectableSegment = true; 320 if (!rectangleContainSegment(r, alt, s)) { 321 wholeWaySelected = false; 307 if (alt) { 308 for (Node n : w.nodes) { 309 if (r.contains(nc.getPoint(n.eastNorth))) { 310 selection.add(w); 322 311 break; 323 312 } 324 313 } 325 if (someSelectableSegment && wholeWaySelected) 326 selection.add(w); 314 } else { 315 boolean allIn = true; 316 for (Node n : w.nodes) { 317 if (!r.contains(nc.getPoint(n.eastNorth))) { 318 allIn = false; 319 break; 327 320 } 328 321 } 322 if (allIn) selection.add(w); 323 } 324 } 325 } 329 326 return selection; 330 }331 332 /**333 * Decide whether the segment is in the rectangle Return334 * <code>true</code>, if it is in or false if not.335 *336 * @param r The rectangle, in which the segment has to be.337 * @param alt Whether user pressed the Alt key338 * @param ls The segment.339 * @return <code>true</code>, if the Segment was added to the selection.340 */341 private boolean rectangleContainSegment(Rectangle r, boolean alt, Segment ls) {342 if (ls.incomplete)343 return false;344 if (alt) {345 Point p1 = nc.getPoint(ls.from.eastNorth);346 Point p2 = nc.getPoint(ls.to.eastNorth);347 if (r.intersectsLine(p1.x, p1.y, p2.x, p2.y))348 return true;349 } else {350 if (r.contains(nc.getPoint(ls.from.eastNorth))351 && r.contains(nc.getPoint(ls.to.eastNorth)))352 return true;353 }354 return false;355 327 } 356 328 -
trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java
r301 r343 33 33 import org.openstreetmap.josm.data.SelectionChangedListener; 34 34 import org.openstreetmap.josm.data.osm.DataSet; 35 import org.openstreetmap.josm.data.osm.Relation; 36 import org.openstreetmap.josm.data.osm.RelationMember; 35 37 import org.openstreetmap.josm.data.osm.Node; 36 38 import org.openstreetmap.josm.data.osm.OsmPrimitive; 37 import org.openstreetmap.josm.data.osm.Segment;38 39 import org.openstreetmap.josm.data.osm.Way; 39 40 import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor; … … 88 89 add(buttonPanel, BorderLayout.SOUTH); 89 90 90 DataSet. listeners.add(new SelectionChangedListener(){91 DataSet.selListeners.add(new SelectionChangedListener(){ 91 92 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 92 93 displaylist.clearSelection(); … … 130 131 model.addElement(osm); 131 132 for (OsmPrimitive osm : this.conflicts.keySet()) 132 if (osm instanceof Segment)133 model.addElement(osm);134 for (OsmPrimitive osm : this.conflicts.keySet())135 133 if (osm instanceof Way) 136 134 model.addElement(osm); … … 155 153 g.drawRect(p.x-1, p.y-1, 2, 2); 156 154 } 157 public void visit(Segment ls) { 158 if (ls.incomplete) 159 return; 160 Point p1 = nc.getPoint(ls.from.eastNorth); 161 Point p2 = nc.getPoint(ls.to.eastNorth); 155 public void visit(Node n1, Node n2) { 156 Point p1 = nc.getPoint(n1.eastNorth); 157 Point p2 = nc.getPoint(n2.eastNorth); 162 158 g.drawLine(p1.x, p1.y, p2.x, p2.y); 163 159 } 164 160 public void visit(Way w) { 165 for (Segment ls : w.segments) 166 visit(ls); 161 Node lastN = null; 162 for (Node n : w.nodes) { 163 if (lastN == null) { 164 lastN = n; 165 continue; 166 } 167 visit(lastN, n); 168 lastN = n; 169 } 170 } 171 public void visit(Relation e) { 172 for (RelationMember em : e.members) 173 em.member.visit(this); 167 174 } 168 175 }; -
trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java
r298 r343 144 144 revertButton.putClientProperty("help", "Dialog/History/Revert"); 145 145 146 DataSet. listeners.add(this);146 DataSet.selListeners.add(this); 147 147 } 148 148 -
trunk/src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java
r301 r343 48 48 import org.openstreetmap.josm.data.osm.DataSet; 49 49 import org.openstreetmap.josm.data.osm.OsmPrimitive; 50 import org.openstreetmap.josm.data.osm.Relation; 51 import org.openstreetmap.josm.data.osm.RelationMember; 52 import org.openstreetmap.josm.data.osm.visitor.NameVisitor; 50 53 import org.openstreetmap.josm.gui.MapFrame; 51 54 import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference; 55 import org.openstreetmap.josm.gui.tagging.ForwardActionListener; 52 56 import org.openstreetmap.josm.gui.tagging.TaggingCellRenderer; 53 import org.openstreetmap.josm.gui.tagging.ForwardActionListener;54 57 import org.openstreetmap.josm.gui.tagging.TaggingPreset; 55 58 import org.openstreetmap.josm.tools.AutoCompleteComboBox; … … 77 80 78 81 /** 82 * Used to display relation names in the membership table 83 */ 84 private NameVisitor nameVisitor = new NameVisitor(); 85 86 /** 79 87 * Watches for double clicks and from editing or new property, depending on the 80 88 * location, the click was. … … 85 93 if (e.getClickCount() < 2) 86 94 return; 87 if (e.getSource() instanceof JScrollPane)88 add();89 else{95 96 if (e.getSource() == propertyTable) 97 { 90 98 int row = propertyTable.rowAtPoint(e.getPoint()); 91 edit(row); 92 } 93 } 94 } 95 96 /** 97 * Edit the value in the table row 98 * @param row The row of the table, from which the value is edited. 99 */ 100 void edit(int row) { 101 String key = data.getValueAt(row, 0).toString(); 99 if (row > -1) { 100 propertyEdit(row); 101 return; 102 } 103 } else if (e.getSource() == membershipTable) { 104 int row = membershipTable.rowAtPoint(e.getPoint()); 105 if (row > -1) { 106 membershipEdit(row); 107 return; 108 } 109 } 110 add(); 111 } 112 } 113 114 /** 115 * Edit the value in the properties table row 116 * @param row The row of the table from which the value is edited. 117 */ 118 void propertyEdit(int row) { 119 String key = propertyData.getValueAt(row, 0).toString(); 102 120 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 103 121 if (sel.isEmpty()) { … … 118 136 p.add(keyField, GBC.eol().fill(GBC.HORIZONTAL)); 119 137 120 final J ComboBox combo = (JComboBox)data.getValueAt(row, 1);138 final JTextField valueField = new JTextField((String)propertyData.getValueAt(row, 1)); 121 139 p.add(new JLabel(tr("Value")), GBC.std()); 122 140 p.add(Box.createHorizontalStrut(10), GBC.std()); 123 p.add( combo, GBC.eol().fill(GBC.HORIZONTAL));141 p.add(valueField, GBC.eol().fill(GBC.HORIZONTAL)); 124 142 125 143 final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION){ 126 144 @Override public void selectInitialValue() { 127 combo.requestFocusInWindow();128 combo.getEditor().selectAll();145 valueField.requestFocusInWindow(); 146 valueField.selectAll(); 129 147 } 130 148 }; 131 149 final JDialog dlg = optionPane.createDialog(Main.parent, tr("Change values?")); 132 combo.getEditor().addActionListener(new ActionListener(){150 valueField.addActionListener(new ActionListener(){ 133 151 public void actionPerformed(ActionEvent e) { 134 152 optionPane.setValue(JOptionPane.OK_OPTION); … … 136 154 } 137 155 }); 138 String oldComboEntry = combo.getEditor().getItem().toString();139 156 dlg.setVisible(true); 140 157 … … 142 159 if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE || 143 160 (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) { 144 combo.getEditor().setItem(oldComboEntry); 145 return; 146 } 147 148 String value = combo.getEditor().getItem().toString(); 161 return; 162 } 163 164 String value = valueField.getText(); 149 165 if (value.equals(tr("<different>"))) 150 166 return; … … 164 180 } 165 181 166 if (!key.equals(newkey) || value == null)167 182 selectionChanged(sel); // update whole table 168 169 183 Main.parent.repaint(); // repaint all - drawing could have been changed 184 } 185 186 /** 187 * This simply fires up an relation editor for the relation shown; everything else 188 * is the editor's business. 189 * 190 * @param row 191 */ 192 void membershipEdit(int row) { 193 final RelationEditor editor = new RelationEditor((Relation)membershipData.getValueAt(row, 0)); 194 editor.setVisible(true); 170 195 } 171 196 … … 197 222 } 198 223 } 199 for (int i = 0; i < data.getRowCount(); ++i)200 allData.remove( data.getValueAt(i, 0));224 for (int i = 0; i < propertyData.getRowCount(); ++i) 225 allData.remove(propertyData.getValueAt(i, 0)); 201 226 final AutoCompleteComboBox keys = new AutoCompleteComboBox(); 202 227 keys.setPossibleItems(allData.keySet()); … … 249 274 */ 250 275 private void delete(int row) { 251 String key = data.getValueAt(row, 0).toString();276 String key = propertyData.getValueAt(row, 0).toString(); 252 277 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 253 278 Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, null)); … … 258 283 * The property data. 259 284 */ 260 private final DefaultTableModel data = new DefaultTableModel(){285 private final DefaultTableModel propertyData = new DefaultTableModel() { 261 286 @Override public boolean isCellEditable(int row, int column) { 262 287 return false; 263 288 } 264 289 @Override public Class<?> getColumnClass(int columnIndex) { 265 return columnIndex == 1 ? JComboBox.class :String.class;290 return String.class; 266 291 } 267 292 }; 293 294 /** 295 * The membership data. 296 */ 297 private final DefaultTableModel membershipData = new DefaultTableModel() { 298 @Override public boolean isCellEditable(int row, int column) { 299 return false; 300 } 301 @Override public Class<?> getColumnClass(int columnIndex) { 302 return columnIndex == 1 ? Relation.class : String.class; 303 } 304 }; 305 268 306 /** 269 307 * The properties list. 270 308 */ 271 private final JTable propertyTable = new JTable(data); 309 private final JTable propertyTable = new JTable(propertyData); 310 private final JTable membershipTable = new JTable(membershipData); 311 272 312 public JComboBox taggingPresets = new JComboBox(); 273 313 … … 277 317 */ 278 318 public PropertiesDialog(MapFrame mapFrame) { 279 super(tr("Properties "), "propertiesdialog", tr("Properties for selected objects."), KeyEvent.VK_P, 150);319 super(tr("Properties/Memberships"), "propertiesdialog", tr("Properties for selected objects."), KeyEvent.VK_P, 150); 280 320 281 321 if (TaggingPresetPreference.taggingPresets.size() > 0) { … … 300 340 taggingPresets.setRenderer(new TaggingCellRenderer()); 301 341 302 data.setColumnIdentifiers(new String[]{tr("Key"),tr("Value")}); 342 // setting up the properties table 343 344 propertyData.setColumnIdentifiers(new String[]{tr("Key"),tr("Value")}); 303 345 propertyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 304 propertyTable.setDefaultRenderer(JComboBox.class, new DefaultTableCellRenderer(){ 346 347 propertyTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer(){ 305 348 @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 306 349 Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column); 307 350 if (c instanceof JLabel) { 308 String str = ( (JComboBox)value).getEditor().getItem().toString();351 String str = (String) value; 309 352 ((JLabel)c).setText(str); 310 353 if (str.equals(tr("<different>"))) … … 314 357 } 315 358 }); 316 propertyTable.setDefaultRenderer(String.class, new DefaultTableCellRenderer(){ 359 360 // setting up the membership table 361 362 membershipData.setColumnIdentifiers(new String[]{tr("Member Of"),tr("Role")}); 363 membershipTable.setRowSelectionAllowed(false); 364 365 membershipTable.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() { 317 366 @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 318 return super.getTableCellRendererComponent(table, value, isSelected, false, row, column); 367 Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column); 368 if (c instanceof JLabel) { 369 nameVisitor.visit((Relation)value); 370 ((JLabel)c).setText(nameVisitor.name); 371 } 372 return c; 319 373 } 320 374 }); 375 376 // combine both tables and wrap them in a scrollPane 377 JPanel bothTables = new JPanel(); 378 bothTables.setLayout(new GridBagLayout()); 379 bothTables.add(propertyTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL)); 380 bothTables.add(propertyTable, GBC.eol().fill(GBC.BOTH)); 381 bothTables.add(membershipTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL)); 382 bothTables.add(membershipTable, GBC.eol().fill(GBC.BOTH)); 383 321 384 DblClickWatch dblClickWatch = new DblClickWatch(); 322 385 propertyTable.addMouseListener(dblClickWatch); 323 JScrollPane scrollPane = new JScrollPane(propertyTable); 386 membershipTable.addMouseListener(dblClickWatch); 387 JScrollPane scrollPane = new JScrollPane(bothTables); 324 388 scrollPane.addMouseListener(dblClickWatch); 325 389 add(scrollPane, BorderLayout.CENTER); … … 335 399 JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to edit.")); 336 400 else 337 edit(sel);401 propertyEdit(sel); 338 402 } else if (e.getActionCommand().equals("Delete")) { 339 403 if (sel == -1) … … 344 408 } 345 409 }; 410 346 411 buttonPanel.add(createButton(marktr("Add"),tr("Add a new key/value pair to all objects"), KeyEvent.VK_A, buttonAction)); 347 412 buttonPanel.add(createButton(marktr("Edit"),tr( "Edit the value of the selected key for all objects"), KeyEvent.VK_E, buttonAction)); … … 349 414 add(buttonPanel, BorderLayout.SOUTH); 350 415 351 DataSet. listeners.add(this);416 DataSet.selListeners.add(this); 352 417 } 353 418 … … 375 440 if (propertyTable.getCellEditor() != null) 376 441 propertyTable.getCellEditor().cancelCellEditing(); 377 data.setRowCount(0); 442 443 // re-load property data 444 445 propertyData.setRowCount(0); 378 446 379 447 Map<String, Integer> valueCount = new HashMap<String, Integer>(); … … 391 459 } 392 460 for (Entry<String, Collection<String>> e : props.entrySet()) { 393 JComboBox value = new JComboBox(e.getValue().toArray()); 394 value.setEditable(true); 395 value.getEditor().setItem(e.getValue().size() > 1 || valueCount.get(e.getKey()) != newSelection.size() ? tr("<different>") : e.getValue().iterator().next()); 396 data.addRow(new Object[]{e.getKey(), value}); 461 String value=(e.getValue().size() > 1 || valueCount.get(e.getKey()) != newSelection.size() ? tr("<different>") : e.getValue().iterator().next()); 462 propertyData.addRow(new Object[]{e.getKey(), value}); 463 } 464 465 // re-load membership data 466 // this is rather expensive since we have to walk through all members of all existing relationships. 467 // could use back references here for speed if necessary. 468 469 membershipData.setRowCount(0); 470 471 Map<Relation, Integer> valueCountM = new HashMap<Relation, Integer>(); 472 TreeMap<Relation, Collection<String>> roles = new TreeMap<Relation, Collection<String>>(); 473 for (Relation r : Main.ds.relations) { 474 for (RelationMember m : r.members) { 475 if (newSelection.contains(m.member)) { 476 Collection<String> value = roles.get(r); 477 if (value == null) { 478 value = new TreeSet<String>(); 479 roles.put(r, value); 480 } 481 value.add(m.role); 482 valueCountM.put(r, valueCount.containsKey(r) ? valueCount.get(r)+1 : 1); 483 } 484 } 485 } 486 487 for (Entry<Relation, Collection<String>> e : roles.entrySet()) { 488 //JComboBox value = new JComboBox(e.getValue().toArray()); 489 //value.setEditable(true); 490 //value.getEditor().setItem(e.getValue().size() > 1 || valueCount.get(e.getKey()) != newSelection.size() ? tr("<different>") : e.getValue().iterator().next()); 491 String value = e.getValue().size() > 1 || valueCountM.get(e.getKey()) != newSelection.size() ? tr("<different>") : e.getValue().iterator().next(); 492 membershipData.addRow(new Object[]{e.getKey(), value}); 397 493 } 398 494 } -
trunk/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java
r298 r343 80 80 selectionChanged(Main.ds.getSelected()); 81 81 82 DataSet. listeners.add(this);82 DataSet.selListeners.add(this); 83 83 } 84 84 -
trunk/src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java
r298 r343 54 54 selectionChanged(Main.ds.getSelected()); 55 55 56 DataSet. listeners.add(this);56 DataSet.selListeners.add(this); 57 57 } 58 58 -
trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
r312 r343 34 34 import org.openstreetmap.josm.data.osm.DataSet; 35 35 import org.openstreetmap.josm.data.osm.DataSource; 36 import org.openstreetmap.josm.data.osm.Relation; 36 37 import org.openstreetmap.josm.data.osm.Node; 37 38 import org.openstreetmap.josm.data.osm.OsmPrimitive; 38 import org.openstreetmap.josm.data.osm.Segment;39 39 import org.openstreetmap.josm.data.osm.Way; 40 40 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; … … 60 60 public final int[] normal = new int[3]; 61 61 public final int[] deleted = new int[3]; 62 public final String[] names = {"node", " segment", "way"};62 public final String[] names = {"node", "way", "relation"}; 63 63 64 64 private void inc(final OsmPrimitive osm, final int i) { … … 72 72 } 73 73 74 public void visit(final Segment ls) {75 inc(ls, 1);76 }77 78 74 public void visit(final Way w) { 75 inc(w, 1); 76 } 77 public void visit(final Relation w) { 79 78 inc(w, 2); 80 79 } … … 133 132 * Draw all primitives in this layer but do not draw modified ones (they 134 133 * are drawn by the edit layer). 135 * Draw nodes last to overlap the segments they belong to.134 * Draw nodes last to overlap the ways they belong to. 136 135 */ 137 136 @Override public void paint(final Graphics g, final MapView mv) { … … 163 162 String tool = ""; 164 163 tool += undeletedSize(data.nodes)+" "+trn("node", "nodes", undeletedSize(data.nodes))+", "; 165 tool += undeletedSize(data.segments)+" "+trn("segment", "segments", undeletedSize(data.segments))+", ";166 164 tool += undeletedSize(data.ways)+" "+trn("way", "ways", undeletedSize(data.ways)); 167 165 if (associatedFile != null) … … 222 220 for (final Iterator<Node> it = data.nodes.iterator(); it.hasNext();) 223 221 cleanIterator(it, processedSet); 224 for (final Iterator<Segment> it = data.segments.iterator(); it.hasNext();)225 cleanIterator(it, processedSet);226 222 for (final Iterator<Way> it = data.ways.iterator(); it.hasNext();) 227 223 cleanIterator(it, processedSet); -
trunk/src/org/openstreetmap/josm/gui/layer/RawGpsLayer.java
r298 r343 38 38 import org.openstreetmap.josm.data.osm.DataSet; 39 39 import org.openstreetmap.josm.data.osm.Node; 40 import org.openstreetmap.josm.data.osm.Segment;41 40 import org.openstreetmap.josm.data.osm.Way; 42 41 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; … … 71 70 for (Collection<GpsPoint> c : data) { 72 71 Way w = new Way(); 73 Node start = null;74 72 for (GpsPoint p : c) { 75 Node end = new Node(p.latlon); 76 ds.nodes.add(end); 77 if (start != null) { 78 Segment segment = new Segment(start,end); 79 w.segments.add(segment); 80 ds.segments.add(segment); 81 } 82 start = end; 73 Node n = new Node(p.latlon); 74 ds.nodes.add(n); 75 w.nodes.add(n); 83 76 } 84 77 ds.ways.add(w); -
trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java
r302 r343 13 13 import java.util.Arrays; 14 14 import java.util.Collection; 15 import java.util.Collections; 15 16 import java.util.Comparator; 16 17 import java.util.HashMap; … … 194 195 pluginMap = new HashMap<PluginDescription, Boolean>(); 195 196 pluginPanel.removeAll(); 196 Collection<String> enabledPlugins = Arrays.asList(Main.pref.get("plugins").split(",")); 197 198 // the following could probably be done more elegantly? 199 Collection<String> enabledPlugins = null; 200 String enabledProp = Main.pref.get("plugins"); 201 if ((enabledProp == null) || ("".equals(enabledProp))) { 202 enabledPlugins = Collections.EMPTY_SET; 203 } 204 else 205 { 206 enabledPlugins = Arrays.asList(enabledProp.split(",")); 207 } 208 197 209 for (final PluginDescription plugin : availablePlugins) { 198 210 boolean enabled = enabledPlugins.contains(plugin.name); -
trunk/src/org/openstreetmap/josm/io/BoundingBoxDownloader.java
r298 r343 103 103 Main.pleaseWaitDlg.currentAction.setText(tr("Downloading OSM data...")); 104 104 final DataSet data = OsmReader.parseDataSet(in, null, Main.pleaseWaitDlg); 105 String origin = Main.pref.get("osm-server.url")+"/"+Main.pref.get("osm-server.version", "0. 4");105 String origin = Main.pref.get("osm-server.url")+"/"+Main.pref.get("osm-server.version", "0.5"); 106 106 Bounds bounds = new Bounds(new LatLon(lat1, lon1), new LatLon(lat2, lon2)); 107 107 DataSource src = new DataSource(bounds, origin); -
trunk/src/org/openstreetmap/josm/io/GpxWriter.java
r298 r343 11 11 import org.openstreetmap.josm.data.osm.Node; 12 12 import org.openstreetmap.josm.data.osm.OsmPrimitive; 13 import org.openstreetmap.josm.data.osm.Segment;14 13 import org.openstreetmap.josm.data.osm.Way; 15 14 import org.openstreetmap.josm.gui.layer.RawGpsLayer.GpsPoint; … … 32 31 33 32 /** 34 * Export the dataset to gpx. Only the physical segment structure is 35 * exported. To do this, the list of ways is processed. If a way span a 36 * sequence of segments, this is added as one trkseg. 37 * Then, all remaining segments are added in one extra trk. Finally, 38 * all remaining nodes are added as wpt. 33 * Export the dataset to gpx. The ways are converted to trksegs, each in 34 * a seperate trk. Finally, all remaining nodes are added as wpt. 39 35 */ 40 36 public static final class All implements XmlWriter.OsmWriterInterface { … … 106 102 continue; 107 103 out.println(" <trk>"); 108 Segment oldLs = null;109 for (Segment ls : w.segments) {110 if (ls.incomplete)111 continue;112 // end old segemnt, if no longer match a chain113 if (oldLs != null && !oldLs.to.coor.equals(ls.from.coor)) {114 out.println(" </trkseg>");115 writer.outputNode(oldLs.to, false);116 all.remove(oldLs.to);117 oldLs = null;118 }119 // start new segment if necessary120 if (oldLs == null)121 104 out.println(" <trkseg>"); 122 writer.outputNode(ls.from, false); 123 all.remove(ls.from); 124 oldLs = ls; 125 all.remove(ls); 126 } 127 // write last node if there 128 if (oldLs != null) { 129 writer.outputNode(oldLs.to, false); 130 all.remove(oldLs.to); 105 for (Node n : w.nodes) { 106 writer.outputNode(n, false); 107 all.remove(n); 108 } 131 109 out.println(" </trkseg>"); 132 }133 110 out.println(" </trk>"); 134 111 all.remove(w); 135 }136 137 // add remaining segments138 Collection<Segment> segments = new LinkedList<Segment>();139 for (OsmPrimitive osm : all)140 if (osm instanceof Segment && !((Segment)osm).incomplete)141 segments.add((Segment)osm);142 if (!segments.isEmpty()) {143 out.println(" <trk>");144 for (Segment ls : segments) {145 out.println(" <trkseg>");146 writer.outputNode(ls.from, false);147 all.remove(ls.from);148 writer.outputNode(ls.to, false);149 all.remove(ls.to);150 out.println(" </trkseg>");151 all.remove(ls);152 }153 out.println(" </trk>");154 112 } 155 113 -
trunk/src/org/openstreetmap/josm/io/OsmIdReader.java
r319 r343 31 31 32 32 @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 33 if (qName.equals("node") || qName.equals(" segment") || qName.equals("way")) {33 if (qName.equals("node") || qName.equals("way")) { 34 34 try { 35 35 entries.put(Long.valueOf(atts.getValue("id")), qName); -
trunk/src/org/openstreetmap/josm/io/OsmReader.java
r319 r343 24 24 import org.openstreetmap.josm.data.osm.DataSet; 25 25 import org.openstreetmap.josm.data.osm.DataSource; 26 import org.openstreetmap.josm.data.osm.Relation; 27 import org.openstreetmap.josm.data.osm.RelationMember; 26 28 import org.openstreetmap.josm.data.osm.Node; 27 29 import org.openstreetmap.josm.data.osm.OsmPrimitive; 28 import org.openstreetmap.josm.data.osm.Segment;29 30 import org.openstreetmap.josm.data.osm.User; 30 31 import org.openstreetmap.josm.data.osm.Way; … … 44 45 * all nodes are read and stored. Other information than nodes are stored in a raw list 45 46 * 46 * The second phase reads from the raw list all segments and create Segment objects. 47 * 48 * The third phase read all ways out of the remaining objects in the raw list. 47 * The second phase read all ways out of the remaining objects in the raw list. 49 48 * 50 49 * @author Imi … … 91 90 92 91 /** 93 * Data structure for the remaining segment objects 94 * Maps the raw attributes to key/value pairs. 95 */ 96 private Map<OsmPrimitiveData, long[]> segs = new HashMap<OsmPrimitiveData, long[]>(); 92 * Used as a temporary storage for relation members, before they 93 * are resolved into pointers to real objects. 94 */ 95 private static class RelationMemberData { 96 public String type; 97 public long id; 98 public RelationMember relationMember; 99 } 97 100 98 101 /** … … 100 103 */ 101 104 private Map<OsmPrimitiveData, Collection<Long>> ways = new HashMap<OsmPrimitiveData, Collection<Long>>(); 105 106 /** 107 * Data structure for relation objects 108 */ 109 private Map<OsmPrimitiveData, Collection<RelationMemberData>> relations = new HashMap<OsmPrimitiveData, Collection<RelationMemberData>>(); 102 110 103 111 /** … … 132 140 ds.dataSources.add(src); 133 141 } 142 143 // ---- PARSING NODES AND WAYS ---- 144 134 145 } else if (qName.equals("node")) { 135 146 current = new Node(new LatLon(getDouble(atts, "lat"), getDouble(atts, "lon"))); 136 147 readCommon(atts, current); 137 148 nodes.put(current.id, (Node)current); 138 } else if (qName.equals("segment")) {139 current = new OsmPrimitiveData();140 readCommon(atts, current);141 segs.put((OsmPrimitiveData)current, new long[]{getLong(atts, "from"), getLong(atts, "to")});142 149 } else if (qName.equals("way")) { 143 150 current = new OsmPrimitiveData(); 144 151 readCommon(atts, current); 145 152 ways.put((OsmPrimitiveData)current, new LinkedList<Long>()); 146 } else if (qName.equals(" seg")) {153 } else if (qName.equals("nd")) { 147 154 Collection<Long> list = ways.get(current); 148 155 if (list == null) 149 throw new SAXException(tr("Found < seg> tag on non-way."));150 long id = getLong(atts, " id");156 throw new SAXException(tr("Found <nd> element in non-way.")); 157 long id = getLong(atts, "ref"); 151 158 if (id == 0) 152 throw new SAXException(tr(" Incomplete segment with id=0"));159 throw new SAXException(tr("<nd> has zero ref")); 153 160 list.add(id); 154 } else if (qName.equals("tag")) 161 162 // ---- PARSING RELATIONS ---- 163 164 } else if (qName.equals("relation")) { 165 current = new OsmPrimitiveData(); 166 readCommon(atts, current); 167 relations.put((OsmPrimitiveData)current, new LinkedList<RelationMemberData>()); 168 } else if (qName.equals("member")) { 169 Collection<RelationMemberData> list = relations.get(current); 170 if (list == null) 171 throw new SAXException(tr("Found <member> tag on non-relation.")); 172 RelationMemberData emd = new RelationMemberData(); 173 emd.relationMember = new RelationMember(); 174 emd.id = getLong(atts, "ref"); 175 emd.type=atts.getValue("type"); 176 emd.relationMember.role = atts.getValue("role"); 177 178 if (emd.id == 0) 179 throw new SAXException(tr("Incomplete <member> specification with ref=0")); 180 181 list.add(emd); 182 183 // ---- PARSING TAGS (applicable to all objects) ---- 184 185 } else if (qName.equals("tag")) { 155 186 current.put(atts.getValue("k"), atts.getValue("v")); 187 } 156 188 } catch (NumberFormatException x) { 157 189 x.printStackTrace(); // SAXException does not chain correctly … … 173 205 public OsmReader() { 174 206 // first add the main server version 175 allowedVersions.add(Main.pref.get("osm-server.version", "0. 4"));207 allowedVersions.add(Main.pref.get("osm-server.version", "0.5")); 176 208 // now also add all compatible versions 177 209 String[] additionalVersions = 178 Main.pref.get("osm-server.additional-versions", "0.3").split("/,/"); 210 Main.pref.get("osm-server.additional-versions", "").split("/,/"); 211 if (additionalVersions.length == 1 && additionalVersions[0].length() == 0) 212 additionalVersions = new String[] {}; 179 213 allowedVersions.addAll(Arrays.asList(additionalVersions)); 180 214 } … … 224 258 throw new SAXException(tr("Missing required attribute \"{0}\".",value)); 225 259 return Long.parseLong(s); 226 }227 228 private void createSegments() {229 for (Entry<OsmPrimitiveData, long[]> e : segs.entrySet()) {230 Node from = findNode(e.getValue()[0]);231 Node to = findNode(e.getValue()[1]);232 if (from == null || to == null)233 continue; //TODO: implement support for incomplete nodes.234 Segment s = new Segment(from, to);235 e.getKey().copyTo(s);236 segments.put(s.id, s);237 adder.visit(s);238 }239 260 } 240 261 … … 253 274 } 254 275 255 private Segment findSegment(long id) {256 Segment s = segments.get(id);257 if (s != null)258 return s;259 for (Segment seg : references.segments)260 if (seg.id == id)261 return seg;262 // TODO: This has to be changed to support multiple layers.263 for (Segment seg : Main.ds.segments)264 if (seg.id == id)265 return new Segment(seg);266 return null;267 }268 269 276 private void createWays() { 270 277 for (Entry<OsmPrimitiveData, Collection<Long>> e : ways.entrySet()) { 271 278 Way w = new Way(); 279 boolean failed = false; 272 280 for (long id : e.getValue()) { 273 Segment s = findSegment(id);274 if ( s== null) {275 s = new Segment(id); // incomplete line segment276 adder.visit(s);281 Node n = findNode(id); 282 if (n == null) { 283 failed = true; 284 break; 277 285 } 278 w. segments.add(s);286 w.nodes.add(n); 279 287 } 288 if (failed) continue; 280 289 e.getKey().copyTo(w); 281 290 adder.visit(w); … … 284 293 285 294 /** 286 * All read segments after phase 2. 287 */ 288 private Map<Long, Segment> segments = new HashMap<Long, Segment>(); 295 * Return the Way object with the given id, or null if it doesn't 296 * exist yet. This method only looks at ways stored in the data set. 297 * 298 * @param id 299 * @return way object or null 300 */ 301 private Way findWay(long id) { 302 for (Way wy : ds.ways) 303 if (wy.id == id) 304 return wy; 305 for (Way wy : Main.ds.ways) 306 if (wy.id == id) 307 return wy; 308 return null; 309 } 310 311 /** 312 * Return the Relation object with the given id, or null if it doesn't 313 * exist yet. This method only looks at relations stored in the data set. 314 * 315 * @param id 316 * @return relation object or null 317 */ 318 private Relation findRelation(long id) { 319 for (Relation e : ds.relations) 320 if (e.id == id) 321 return e; 322 for (Relation e : Main.ds.relations) 323 if (e.id == id) 324 return e; 325 return null; 326 } 327 328 /** 329 * Create relations. This is slightly different than n/s/w because 330 * unlike other objects, relations may reference other relations; it 331 * is not guaranteed that a referenced relation will have been created 332 * before it is referenced. So we have to create all relations first, 333 * and populate them later. 334 */ 335 private void createRelations() { 336 337 // pass 1 - create all relations 338 for (Entry<OsmPrimitiveData, Collection<RelationMemberData>> e : relations.entrySet()) { 339 Relation en = new Relation(); 340 e.getKey().copyTo(en); 341 adder.visit(en); 342 } 343 344 // pass 2 - sort out members 345 for (Entry<OsmPrimitiveData, Collection<RelationMemberData>> e : relations.entrySet()) { 346 Relation en = findRelation(e.getKey().id); 347 if (en == null) throw new Error("Failed to create relation " + e.getKey().id); 348 349 for (RelationMemberData emd : e.getValue()) { 350 RelationMember em = emd.relationMember; 351 if (emd.type.equals("node")) { 352 em.member = findNode(emd.id); 353 if (em.member == null) { 354 em.member = new Node(emd.id); 355 adder.visit((Node)em.member); 356 } 357 } else if (emd.type.equals("way")) { 358 em.member = findWay(emd.id); 359 if (em.member == null) { 360 em.member = new Way(emd.id); 361 adder.visit((Way)em.member); 362 } 363 } else if (emd.type.equals("relation")) { 364 em.member = findRelation(emd.id); 365 if (em.member == null) { 366 em.member = new Relation(emd.id); 367 adder.visit((Relation)em.member); 368 } 369 } else { 370 // this is an error. 371 } 372 en.members.add(em); 373 } 374 } 375 } 289 376 290 377 /** … … 298 385 osm.references = ref == null ? new DataSet() : ref; 299 386 300 // phase 1: Parse nodes and read in raw segments andways387 // phase 1: Parse nodes and read in raw ways 301 388 InputSource inputSource = new InputSource(new InputStreamReader(source, "UTF-8")); 302 389 try { … … 314 401 315 402 try { 316 osm.createSegments();317 403 osm.createWays(); 404 osm.createRelations(); 318 405 } catch (NumberFormatException e) { 319 406 e.printStackTrace(); -
trunk/src/org/openstreetmap/josm/io/OsmServerReader.java
r298 r343 30 30 */ 31 31 protected InputStream getInputStream(String urlStr, PleaseWaitDialog pleaseWaitDlg) throws IOException { 32 String version = Main.pref.get("osm-server.version", "0. 4");32 String version = Main.pref.get("osm-server.version", "0.5"); 33 33 urlStr = Main.pref.get("osm-server.url")+"/"+version+"/" + urlStr; 34 34 System.out.println("download: "+urlStr); -
trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java
r298 r343 17 17 18 18 import org.openstreetmap.josm.Main; 19 import org.openstreetmap.josm.data.osm.Relation;