Changeset 1169 in josm
- Timestamp:
- 2008-12-23T15:07:05+01:00 (16 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 256 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/Main.java
r1163 r1169 182 182 183 183 /** 184 * Remove the specified layer from the map. If it is the last layer, 184 * Remove the specified layer from the map. If it is the last layer, 185 185 * remove the map as well. 186 186 */ … … 219 219 220 220 /** 221 * Load all plugins specified in preferences. If the parameter is 221 * Load all plugins specified in preferences. If the parameter is 222 222 * <code>true</code>, all early plugins are loaded (before constructor). 223 223 */ … … 281 281 Main.pref.put("pluginmanager.lastupdate",Long.toString(tim)); 282 282 } else if (d > maxTime) { 283 JOptionPane.showMessageDialog(Main.parent, 284 "<html>" + 283 JOptionPane.showMessageDialog(Main.parent, 284 "<html>" + 285 285 tr("Last plugin update more than {0} days ago.", d) + 286 "<br><em>" + 286 "<br><em>" + 287 287 tr("(You can change the number of days after which this warning appears<br>by setting the config option 'pluginmanager.warntime'.)") + 288 288 "</html>"); … … 512 512 } else if (os.toLowerCase().startsWith("windows")) { 513 513 platform = new PlatformHookWindows(); 514 } else if (os.equals("Linux") || os.equals("Solaris") || 515 os.equals("SunOS") || os.equals("AIX") || 514 } else if (os.equals("Linux") || os.equals("Solaris") || 515 os.equals("SunOS") || os.equals("AIX") || 516 516 os.equals("FreeBSD") || os.equals("NetBSD") || os.equals("OpenBSD")) { 517 517 platform = new PlatformHookUnixoid(); -
trunk/src/org/openstreetmap/josm/actions/AboutAction.java
r1138 r1169 51 51 public class AboutAction extends JosmAction { 52 52 53 54 55 56 53 private static final String version; 54 55 private final static JTextArea revision; 56 private static String time; 57 57 58 58 static { … … 60 60 if(u == null) { 61 61 try { 62 u = new URL("jar:" + Main.class.getProtectionDomain().getCodeSource().getLocation().toString() 62 u = new URL("jar:" + Main.class.getProtectionDomain().getCodeSource().getLocation().toString() 63 63 + "!/META-INF/MANIFEST.MF"); 64 64 } catch (MalformedURLException e) { … … 66 66 } 67 67 } 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 68 revision = loadFile(u); 69 70 Pattern versionPattern = Pattern.compile(".*?(?:Revision|Main-Version): ([0-9]*(?: SVN)?).*", Pattern.CASE_INSENSITIVE|Pattern.DOTALL); 71 Matcher match = versionPattern.matcher(revision.getText()); 72 version = match.matches() ? match.group(1) : tr("UNKNOWN"); 73 74 Pattern timePattern = Pattern.compile(".*?(?:Last Changed Date|Main-Date): ([^\n]*).*", Pattern.CASE_INSENSITIVE|Pattern.DOTALL); 75 match = timePattern.matcher(revision.getText()); 76 time = match.matches() ? match.group(1) : tr("UNKNOWN"); 77 } 78 79 /** 80 * Return string describing version. 81 * Note that the strinc contains the version number plus an optional suffix of " SVN" to indicate an unofficial development build. 82 * @return version string 83 */ 84 static public String getVersionString() { 85 return version; 86 } 87 87 88 88 /** … … 99 99 return myVersion; 100 100 } 101 101 102 102 /** 103 103 * check whether the version is a development build out of SVN. … … 107 107 return version.endsWith(" SVN"); 108 108 } 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 *of problems (e.g. no internet connection).183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 109 110 public AboutAction() { 111 super(tr("About"), "about", tr("Display the about screen."), Shortcut.registerShortcut("system:about", tr("About"), KeyEvent.VK_F1, Shortcut.GROUP_DIRECT, Shortcut.SHIFT_DEFAULT), true); 112 } 113 114 public void actionPerformed(ActionEvent e) { 115 JTabbedPane about = new JTabbedPane(); 116 117 JTextArea readme = loadFile(Main.class.getResource("/README")); 118 JTextArea contribution = loadFile(Main.class.getResource("/CONTRIBUTION")); 119 120 JPanel info = new JPanel(new GridBagLayout()); 121 info.add(new JLabel(tr("Java OpenStreetMap Editor Version {0}",version)), GBC.eol().fill(GBC.HORIZONTAL)); 122 info.add(new JLabel(tr("last change at {0}",time)), GBC.eol().fill(GBC.HORIZONTAL)); 123 info.add(new JLabel(tr("Java Version {0}",System.getProperty("java.version"))), GBC.eol().fill(GBC.HORIZONTAL)); 124 info.add(GBC.glue(0,10), GBC.eol()); 125 info.add(new JLabel(tr("Homepage")), GBC.std().insets(0,0,10,0)); 126 info.add(new UrlLabel("http://josm.openstreetmap.de"), GBC.eol().fill(GBC.HORIZONTAL)); 127 info.add(new JLabel(tr("Bug Reports")), GBC.std().insets(0,0,10,0)); 128 info.add(new UrlLabel("http://josm.openstreetmap.de/newticket"), GBC.eol().fill(GBC.HORIZONTAL)); 129 info.add(new JLabel(tr("News about JOSM")), GBC.std().insets(0,0,10,0)); 130 info.add(new UrlLabel("http://www.opengeodata.org/?cat=17"), GBC.eol().fill(GBC.HORIZONTAL)); 131 132 about.addTab(tr("Info"), info); 133 about.addTab(tr("Readme"), createScrollPane(readme)); 134 about.addTab(tr("Revision"), createScrollPane(revision)); 135 about.addTab(tr("Contribution"), createScrollPane(contribution)); 136 137 JPanel pluginTab = new JPanel(new GridBagLayout()); 138 for (final PluginProxy p : Main.plugins) { 139 String name = p.info.name + (p.info.version != null && !p.info.version.equals("") ? " Version: "+p.info.version : ""); 140 pluginTab.add(new JLabel(name), GBC.std()); 141 pluginTab.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL)); 142 pluginTab.add(new JButton(new AbstractAction(tr("Information")){ 143 public void actionPerformed(ActionEvent event) { 144 StringBuilder b = new StringBuilder(); 145 for (Entry<String,String> e : p.info.attr.entrySet()) { 146 b.append(e.getKey()); 147 b.append(": "); 148 b.append(e.getValue()); 149 b.append("\n"); 150 } 151 JTextArea a = new JTextArea(10,40); 152 a.setEditable(false); 153 a.setText(b.toString()); 154 JOptionPane.showMessageDialog(Main.parent, new JScrollPane(a)); 155 } 156 }), GBC.eol()); 157 JLabel label = new JLabel("<html><i>"+(p.info.description==null?tr("no description available"):p.info.description)+"</i></html>"); 158 label.setBorder(BorderFactory.createEmptyBorder(0,20,0,0)); 159 label.setMaximumSize(new Dimension(450,1000)); 160 pluginTab.add(label, GBC.eop().fill(GBC.HORIZONTAL)); 161 } 162 about.addTab(tr("Plugins"), new JScrollPane(pluginTab)); 163 164 about.setPreferredSize(new Dimension(500,300)); 165 166 JOptionPane.showMessageDialog(Main.parent, about, tr("About JOSM..."), 167 JOptionPane.INFORMATION_MESSAGE, ImageProvider.get("logo")); 168 } 169 170 private JScrollPane createScrollPane(JTextArea area) { 171 area.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 172 area.setOpaque(false); 173 JScrollPane sp = new JScrollPane(area); 174 sp.setBorder(null); 175 sp.setOpaque(false); 176 return sp; 177 } 178 179 /** 180 * Retrieve the latest JOSM version from the JOSM homepage. 181 * @return An string with the latest version or "UNKNOWN" in case 182 * of problems (e.g. no internet connection). 183 */ 184 public static String checkLatestVersion() { 185 String latest; 186 try { 187 InputStream s = new URL("http://josm.openstreetmap.de/current").openStream(); 188 latest = new BufferedReader(new InputStreamReader(s)).readLine(); 189 s.close(); 190 } catch (IOException x) { 191 x.printStackTrace(); 192 return tr("UNKNOWN"); 193 } 194 return latest; 195 } 196 197 /** 198 * Load the specified resource into an TextArea and return it. 199 * @param resource The resource url to load 200 * @return An read-only text area with the content of "resource" 201 */ 202 private static JTextArea loadFile(URL resource) { 203 JTextArea area = new JTextArea(tr("File could not be found.")); 204 area.setEditable(false); 205 Font font = Font.getFont("monospaced"); 206 if (font != null) 207 area.setFont(font); 208 if (resource == null) 209 return area; 210 BufferedReader in; 211 try { 212 in = new BufferedReader(new InputStreamReader(resource.openStream())); 213 StringBuilder sb = new StringBuilder(); 214 for (String line = in.readLine(); line != null; line = in.readLine()) { 215 sb.append(line); 216 sb.append('\n'); 217 } 218 area.setText(sb.toString()); 219 area.setCaretPosition(0); 220 } catch (IOException e) { 221 e.printStackTrace(); 222 } 223 return area; 224 } 225 225 } -
trunk/src/org/openstreetmap/josm/actions/AddNodeAction.java
r1138 r1169 41 41 42 42 /** 43 * This action displays a dialog where the user can enter a latitude and longitude, 43 * This action displays a dialog where the user can enter a latitude and longitude, 44 44 * and when ok is pressed, a new node is created at the specified position. 45 45 */ … … 47 47 48 48 public AddNodeAction() { 49 50 51 49 super(tr("Add Node"), "addnode", tr("Add a node by entering latitude and longitude."), 50 Shortcut.registerShortcut("addnode", tr("Edit: {0}", tr("Add Node")), KeyEvent.VK_D, Shortcut.GROUP_EDIT, 51 Shortcut.SHIFT_DEFAULT), true); 52 52 } 53 53 54 54 public void actionPerformed(ActionEvent e) { 55 55 JPanel p = new JPanel(new GridBagLayout()); 56 56 p.add(new JLabel("<html>"+ 57 tr("Enter the coordinates for the new node.") + 58 "<br>" + tr("Use decimal degrees.") + 59 "<br>" + tr("Negative values denote Western/Southern hemisphere.")), 57 tr("Enter the coordinates for the new node.") + 58 "<br>" + tr("Use decimal degrees.") + 59 "<br>" + tr("Negative values denote Western/Southern hemisphere.")), 60 60 GBC.eol()); 61 61 62 62 p.add(new JLabel(tr("Latitude")), GBC.std().insets(0,10,5,0)); 63 63 final JTextField lat = new JTextField(12); … … 65 65 p.add(new JLabel(tr("Longitude")), GBC.std().insets(0,0,5,10)); 66 66 final JTextField lon = new JTextField(12); 67 p.add(lon, GBC.eol().insets(0,0,0,10)); 68 67 p.add(lon, GBC.eol().insets(0,0,0,10)); 68 69 69 Node nnew = null; 70 70 … … 79 79 } catch (Exception ex) { } 80 80 } 81 82 83 84 85 86 81 82 /* Now execute the commands to add the dupicated contents of the paste buffer to the map */ 83 84 Main.main.undoRedo.add(new AddCommand(nnew)); 85 Main.ds.setSelected(nnew); 86 Main.map.mapView.repaint(); 87 87 } 88 88 } -
trunk/src/org/openstreetmap/josm/actions/AlignInCircleAction.java
r1160 r1169 24 24 /** 25 25 * Aligns all selected nodes within a circle. (Useful for roundabouts) 26 * 26 * 27 27 * @author Matthew Newton 28 28 * @author Petr Dlouhý … … 31 31 32 32 public AlignInCircleAction() { 33 super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."), 34 Shortcut.registerShortcut("tools:aligncircle", tr("Tool: {0}", tr("Align Nodes in Circle")), 33 super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."), 34 Shortcut.registerShortcut("tools:aligncircle", tr("Tool: {0}", tr("Align Nodes in Circle")), 35 35 KeyEvent.VK_O, Shortcut.GROUP_EDIT), true); 36 36 } -
trunk/src/org/openstreetmap/josm/actions/AlignInLineAction.java
r1084 r1169 29 29 public final class AlignInLineAction extends JosmAction { 30 30 31 32 33 34 31 public AlignInLineAction() { 32 super(tr("Align Nodes in Line"), "alignline", tr("Move the selected nodes onto a line."), 33 Shortcut.registerShortcut("tools:alignline", tr("Tool: {0}", tr("Align Nodes in Line")), KeyEvent.VK_L, Shortcut.GROUP_EDIT), true); 34 } 35 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 36 /** 37 * The general algorithm here is to find the two selected nodes 38 * that are furthest apart, and then to align all other selected 39 * nodes onto the straight line between these nodes. 40 */ 41 public void actionPerformed(ActionEvent e) { 42 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 43 Collection<Node> nodes = new LinkedList<Node>(); 44 Collection<Node> itnodes = new LinkedList<Node>(); 45 for (OsmPrimitive osm : sel) 46 if (osm instanceof Node) { 47 nodes.add((Node)osm); 48 itnodes.add((Node)osm); 49 } 50 // special case if no single nodes are selected and exactly one way is: 51 // then use the way's nodes 52 if ((nodes.size() == 0) && (sel.size() == 1)) 53 for (OsmPrimitive osm : sel) 54 if (osm instanceof Way) { 55 nodes.addAll(((Way)osm).nodes); 56 itnodes.addAll(((Way)osm).nodes); 57 } 58 if (nodes.size() < 3) { 59 JOptionPane.showMessageDialog(Main.parent, tr("Please select at least three nodes.")); 60 return; 61 } 62 62 63 64 65 63 // Find from the selected nodes two that are the furthest apart. 64 // Let's call them A and B. 65 double distance = 0; 66 66 67 68 67 Node nodea = null; 68 Node nodeb = null; 69 69 70 71 72 73 74 75 76 77 78 79 80 70 for (Node n : nodes) { 71 itnodes.remove(n); 72 for (Node m : itnodes) { 73 double dist = Math.sqrt(n.eastNorth.distance(m.eastNorth)); 74 if (dist > distance) { 75 nodea = n; 76 nodeb = m; 77 distance = dist; 78 } 79 } 80 } 81 81 82 83 84 82 // Remove the nodes A and B from the list of nodes to move 83 nodes.remove(nodea); 84 nodes.remove(nodeb); 85 85 86 87 88 89 90 86 // Find out co-ords of A and B 87 double ax = nodea.eastNorth.east(); 88 double ay = nodea.eastNorth.north(); 89 double bx = nodeb.eastNorth.east(); 90 double by = nodeb.eastNorth.north(); 91 91 92 93 92 // A list of commands to do 93 Collection<Command> cmds = new LinkedList<Command>(); 94 94 95 96 97 98 99 95 // OK, for each node to move, work out where to move it! 96 for (Node n : nodes) { 97 // Get existing co-ords of node to move 98 double nx = n.eastNorth.east(); 99 double ny = n.eastNorth.north(); 100 100 101 102 103 104 105 106 107 108 109 110 111 112 101 if (ax == bx) { 102 // Special case if AB is vertical... 103 nx = ax; 104 } else if (ay == by) { 105 // ...or horizontal 106 ny = ay; 107 } else { 108 // Otherwise calculate position by solving y=mx+c 109 double m1 = (by - ay) / (bx - ax); 110 double c1 = ay - (ax * m1); 111 double m2 = (-1) / m1; 112 double c2 = n.eastNorth.north() - (n.eastNorth.east() * m2); 113 113 114 115 116 114 nx = (c2 - c1) / (m1 - m2); 115 ny = (m1 * nx) + c1; 116 } 117 117 118 119 120 118 // Add the command to move the node to its new position. 119 cmds.add(new MoveCommand(n, nx - n.eastNorth.east(), ny - n.eastNorth.north() )); 120 } 121 121 122 123 124 125 122 // Do it! 123 Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds)); 124 Main.map.repaint(); 125 } 126 126 } -
trunk/src/org/openstreetmap/josm/actions/AutoScaleAction.java
r1084 r1169 47 47 public AutoScaleAction(String mode) { 48 48 super(tr("Zoom to {0}", tr(mode)), "dialogs/autoscale/" + mode, tr("Zoom the view to {0}.", tr(mode)), 49 49 Shortcut.registerShortcut("view:zoom"+mode, tr("View: {0}", tr("Zoom to {0}", tr(mode))), getModeShortcut(mode), Shortcut.GROUP_EDIT), true); 50 50 String modeHelp = Character.toUpperCase(mode.charAt(0)) + mode.substring(1); 51 51 putValue("help", "Action/AutoScale/" + modeHelp); -
trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java
r1084 r1169 49 49 public class CombineWayAction extends JosmAction implements SelectionChangedListener { 50 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 //duplicates.236 237 //if so, do it and remove it from the list of remaining chunks.238 //Rather, rinse, repeat.239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 51 public CombineWayAction() { 52 super(tr("Combine Way"), "combineway", tr("Combine several ways into one."), 53 Shortcut.registerShortcut("tools:combineway", tr("Tool: {0}", tr("Combine Way")), KeyEvent.VK_C, Shortcut.GROUP_EDIT), true); 54 DataSet.selListeners.add(this); 55 } 56 57 public void actionPerformed(ActionEvent event) { 58 Collection<OsmPrimitive> selection = Main.ds.getSelected(); 59 LinkedList<Way> selectedWays = new LinkedList<Way>(); 60 61 for (OsmPrimitive osm : selection) 62 if (osm instanceof Way) 63 selectedWays.add((Way)osm); 64 65 if (selectedWays.size() < 2) { 66 JOptionPane.showMessageDialog(Main.parent, tr("Please select at least two ways to combine.")); 67 return; 68 } 69 70 // Check whether all ways have identical relationship membership. More 71 // specifically: If one of the selected ways is a member of relation X 72 // in role Y, then all selected ways must be members of X in role Y. 73 74 // FIXME: In a later revision, we should display some sort of conflict 75 // dialog like we do for tags, to let the user choose which relations 76 // should be kept. 77 78 // Step 1, iterate over all relations and figure out which of our 79 // selected ways are members of a relation. 80 HashMap<Pair<Relation,String>, HashSet<Way>> backlinks = 81 new HashMap<Pair<Relation,String>, HashSet<Way>>(); 82 HashSet<Relation> relationsUsingWays = new HashSet<Relation>(); 83 for (Relation r : Main.ds.relations) { 84 if (r.deleted || r.incomplete) continue; 85 for (RelationMember rm : r.members) { 86 if (rm.member instanceof Way) { 87 for(Way w : selectedWays) { 88 if (rm.member == w) { 89 Pair<Relation,String> pair = new Pair<Relation,String>(r, rm.role); 90 HashSet<Way> waylinks = new HashSet<Way>(); 91 if (backlinks.containsKey(pair)) { 92 waylinks = backlinks.get(pair); 93 } else { 94 waylinks = new HashSet<Way>(); 95 backlinks.put(pair, waylinks); 96 } 97 waylinks.add(w); 98 99 // this is just a cache for later use 100 relationsUsingWays.add(r); 101 } 102 } 103 } 104 } 105 } 106 107 // Complain to the user if the ways don't have equal memberships. 108 for (HashSet<Way> waylinks : backlinks.values()) { 109 if (!waylinks.containsAll(selectedWays)) { 110 int option = JOptionPane.showConfirmDialog(Main.parent, 111 tr("The selected ways have differing relation memberships. " 112 + "Do you still want to combine them?"), 113 tr("Combine ways with different memberships?"), 114 JOptionPane.YES_NO_OPTION); 115 if (option == JOptionPane.YES_OPTION) 116 break; 117 return; 118 } 119 } 120 121 // collect properties for later conflict resolving 122 Map<String, Set<String>> props = new TreeMap<String, Set<String>>(); 123 for (Way w : selectedWays) { 124 for (Entry<String,String> e : w.entrySet()) { 125 if (!props.containsKey(e.getKey())) 126 props.put(e.getKey(), new TreeSet<String>()); 127 props.get(e.getKey()).add(e.getValue()); 128 } 129 } 130 131 List<Node> nodeList = null; 132 Object firstTry = actuallyCombineWays(selectedWays, false); 133 if (firstTry instanceof List) { 134 nodeList = (List<Node>) firstTry; 135 } else { 136 Object secondTry = actuallyCombineWays(selectedWays, true); 137 if (secondTry instanceof List) { 138 int option = JOptionPane.showConfirmDialog(Main.parent, 139 tr("The ways can not be combined in their current directions. " 140 + "Do you want to reverse some of them?"), tr("Change directions?"), 141 JOptionPane.YES_NO_OPTION); 142 if (option != JOptionPane.YES_OPTION) { 143 return; 144 } 145 nodeList = (List<Node>) secondTry; 146 } else { 147 JOptionPane.showMessageDialog(Main.parent, secondTry); 148 return; 149 } 150 } 151 152 // Find the most appropriate way to modify. 153 154 // Eventually this might want to be the way with the longest 155 // history or the longest selected way but for now just attempt 156 // to reuse an existing id. 157 Way modifyWay = selectedWays.peek(); 158 for (Way w : selectedWays) { 159 modifyWay = w; 160 if (w.id != 0) break; 161 } 162 Way newWay = new Way(modifyWay); 163 164 newWay.nodes.clear(); 165 newWay.nodes.addAll(nodeList); 166 167 // display conflict dialog 168 Map<String, JComboBox> components = new HashMap<String, JComboBox>(); 169 JPanel p = new JPanel(new GridBagLayout()); 170 for (Entry<String, Set<String>> e : props.entrySet()) { 171 if (TigerUtils.isTigerTag(e.getKey())) { 172 String combined = TigerUtils.combineTags(e.getKey(), e.getValue()); 173 newWay.put(e.getKey(), combined); 174 } else if (e.getValue().size() > 1) { 175 if("created_by".equals(e.getKey())) 176 { 177 newWay.put("created_by", "JOSM"); 178 } 179 else 180 { 181 JComboBox c = new JComboBox(e.getValue().toArray()); 182 c.setEditable(true); 183 p.add(new JLabel(e.getKey()), GBC.std()); 184 p.add(Box.createHorizontalStrut(10), GBC.std()); 185 p.add(c, GBC.eol()); 186 components.put(e.getKey(), c); 187 } 188 } else 189 newWay.put(e.getKey(), e.getValue().iterator().next()); 190 } 191 192 if (!components.isEmpty()) { 193 int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter values for all conflicts."), JOptionPane.OK_CANCEL_OPTION); 194 if (answer != JOptionPane.OK_OPTION) 195 return; 196 for (Entry<String, JComboBox> e : components.entrySet()) 197 newWay.put(e.getKey(), e.getValue().getEditor().getItem().toString()); 198 } 199 200 LinkedList<Command> cmds = new LinkedList<Command>(); 201 LinkedList<Way> deletedWays = new LinkedList<Way>(selectedWays); 202 deletedWays.remove(modifyWay); 203 cmds.add(new DeleteCommand(deletedWays)); 204 cmds.add(new ChangeCommand(modifyWay, newWay)); 205 206 // modify all relations containing the now-deleted ways 207 for (Relation r : relationsUsingWays) { 208 Relation newRel = new Relation(r); 209 newRel.members.clear(); 210 HashSet<String> rolesToReAdd = new HashSet<String>(); 211 for (RelationMember rm : r.members) { 212 // Don't copy the member if it to one of our ways, just keep a 213 // note to re-add it later on. 214 if (selectedWays.contains(rm.member)) { 215 rolesToReAdd.add(rm.role); 216 } else { 217 newRel.members.add(rm); 218 } 219 } 220 for (String role : rolesToReAdd) { 221 newRel.members.add(new RelationMember(role, modifyWay)); 222 } 223 cmds.add(new ChangeCommand(r, newRel)); 224 } 225 Main.main.undoRedo.add(new SequenceCommand(tr("Combine {0} ways", selectedWays.size()), cmds)); 226 Main.ds.setSelected(modifyWay); 227 } 228 229 /** 230 * @return a message if combining failed, else a list of nodes. 231 */ 232 private Object actuallyCombineWays(List<Way> ways, boolean ignoreDirection) { 233 // Battle plan: 234 // 1. Split the ways into small chunks of 2 nodes and weed out 235 // duplicates. 236 // 2. Take a chunk and see if others could be appended or prepended, 237 // if so, do it and remove it from the list of remaining chunks. 238 // Rather, rinse, repeat. 239 // 3. If this algorithm does not produce a single way, 240 // complain to the user. 241 // 4. Profit! 242 243 HashSet<Pair<Node,Node>> chunkSet = new HashSet<Pair<Node,Node>>(); 244 for (Way w : ways) 245 chunkSet.addAll(w.getNodePairs(ignoreDirection)); 246 247 LinkedList<Pair<Node,Node>> chunks = new LinkedList<Pair<Node,Node>>(chunkSet); 248 249 if (chunks.isEmpty()) { 250 return tr("All the ways were empty"); 251 } 252 253 List<Node> nodeList = Pair.toArrayList(chunks.poll()); 254 while (!chunks.isEmpty()) { 255 ListIterator<Pair<Node,Node>> it = chunks.listIterator(); 256 boolean foundChunk = false; 257 while (it.hasNext()) { 258 Pair<Node,Node> curChunk = it.next(); 259 if (curChunk.a == nodeList.get(nodeList.size() - 1)) { // append 260 nodeList.add(curChunk.b); 261 } else if (curChunk.b == nodeList.get(0)) { // prepend 262 nodeList.add(0, curChunk.a); 263 } else if (ignoreDirection && curChunk.b == nodeList.get(nodeList.size() - 1)) { // append 264 nodeList.add(curChunk.a); 265 } else if (ignoreDirection && curChunk.a == nodeList.get(0)) { // prepend 266 nodeList.add(0, curChunk.b); 267 } else { 268 continue; 269 } 270 271 foundChunk = true; 272 it.remove(); 273 break; 274 } 275 if (!foundChunk) break; 276 } 277 278 if (!chunks.isEmpty()) { 279 return tr("Could not combine ways " 280 + "(They could not be merged into a single string of nodes)"); 281 } 282 283 return nodeList; 284 } 285 286 /** 287 * Enable the "Combine way" menu option if more then one way is selected 288 */ 289 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 290 boolean first = false; 291 for (OsmPrimitive osm : newSelection) { 292 if (osm instanceof Way) { 293 if (first) { 294 setEnabled(true); 295 return; 296 } 297 first = true; 298 } 299 } 300 setEnabled(false); 301 } 302 302 } -
trunk/src/org/openstreetmap/josm/actions/CopyAction.java
r1084 r1169 28 28 public final class CopyAction extends JosmAction implements SelectionChangedListener { 29 29 30 30 private LinkedList<JosmAction> listeners; 31 31 32 33 34 35 36 37 38 39 32 public CopyAction() { 33 super(tr("Copy"), "copy", 34 tr("Copy selected objects to paste buffer."), 35 Shortcut.registerShortcut("system:copy", tr("Edit: {0}", tr("Copy")), KeyEvent.VK_C, Shortcut.GROUP_MENU), true); 36 setEnabled(false); 37 DataSet.selListeners.add(this); 38 listeners = new LinkedList<JosmAction>(); 39 } 40 40 41 42 43 41 @Override public void addListener(JosmAction a) { 42 listeners.add(a); 43 } 44 44 45 46 47 48 49 50 51 45 public void actionPerformed(ActionEvent e) { 46 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 47 if (sel.isEmpty()) { 48 JOptionPane.showMessageDialog(Main.parent, 49 tr("Please select something to copy.")); 50 return; 51 } 52 52 53 54 55 56 53 /* New pasteBuffer - will be assigned to the global one at the end */ 54 final DataSet pasteBuffer = new DataSet(); 55 final HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>(); 56 /* temporarily maps old nodes to new so we can do a true deep copy */ 57 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 58 /* scan the selected objects, mapping them to copies; when copying a way or relation, 59 * the copy references the copies of their child objects */ 60 new Visitor(){ 61 public void visit(Node n) { 62 /* check if already in pasteBuffer - e.g. two ways are selected which share a node; 63 * or a way and a node in that way is selected, we'll see it twice, once via the 64 * way and once directly; and so on. */ 65 if (map.containsKey(n)) { return; } 66 Node nnew = new Node(n); 67 map.put(n, nnew); 68 pasteBuffer.addPrimitive(nnew); 69 } 70 public void visit(Way w) { 71 /* check if already in pasteBuffer - could have come from a relation, and directly etc. */ 72 if (map.containsKey(w)) { return; } 73 Way wnew = new Way(); 74 wnew.cloneFrom(w); 75 wnew.nodes.clear(); 76 List<Node> nodes = new ArrayList<Node>(); 77 for (Node n : w.nodes) { 78 if (! map.containsKey(n)) { 79 n.visit(this); 80 } 81 nodes.add((Node)map.get(n)); 82 } 83 wnew.nodes.clear(); 84 wnew.nodes.addAll(nodes); 85 pasteBuffer.addPrimitive(wnew); 86 } 87 public void visit(Relation e) { 88 if (map.containsKey(e)) { return; } 89 Relation enew = new Relation(e); 90 List<RelationMember> members = new ArrayList<RelationMember>(); 91 for (RelationMember m : e.members) { 92 if (! map.containsKey(m.member)) { 93 m.member.visit(this); 94 } 95 RelationMember mnew = new RelationMember(m); 96 mnew.member = map.get(m.member); 97 members.add(mnew); 98 } 99 enew.members.addAll(members); 100 pasteBuffer.addPrimitive(enew); 101 } 102 public void visitAll() { 103 for (OsmPrimitive osm : Main.ds.getSelected()) 104 osm.visit(this); 105 } 106 }.visitAll(); 107 107 108 109 108 Main.pasteBuffer = pasteBuffer; 109 Main.main.menu.paste.setEnabled(true); /* now we have a paste buffer we can make paste available */ 110 110 111 112 113 114 111 for(JosmAction a : listeners) { 112 a.pasteBufferChanged(Main.pasteBuffer); 113 } 114 } 115 115 116 117 118 116 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 117 setEnabled(! newSelection.isEmpty()); 118 } 119 119 } -
trunk/src/org/openstreetmap/josm/actions/CreateCircleAction.java
r1084 r1169 34 34 public final class CreateCircleAction extends JosmAction { 35 35 36 37 38 39 36 public CreateCircleAction() { 37 super(tr("Create Circle"), "createcircle", tr("Create a circle from three selected nodes."), 38 Shortcut.registerShortcut("tools:createcircle", tr("Tool: {0}", tr("Create Circle")), KeyEvent.VK_O, Shortcut.GROUP_EDIT, Shortcut.SHIFT_DEFAULT), true); 39 } 40 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 41 private double calcang(double xc, double yc, double x, double y) { 42 // calculate the angle from xc|yc to x|y 43 if (xc == x && yc == y) { 44 return 0; // actually invalid, but we won't have this case in this context 45 } 46 double yd = Math.abs(y - yc); 47 if (yd == 0 && xc < x) { 48 return 0; 49 } 50 if (yd == 0 && xc > x) { 51 return Math.PI; 52 } 53 double xd = Math.abs(x - xc); 54 double a = Math.atan2(xd, yd); 55 if (y > yc) { 56 a = Math.PI - a; 57 } 58 if (x < xc) { 59 a = -a; 60 } 61 a = 1.5*Math.PI + a; 62 if (a < 0) { 63 a += 2*Math.PI; 64 } 65 if (a >= 2*Math.PI) { 66 a -= 2*Math.PI; 67 } 68 return a; 69 } 70 70 71 72 73 74 75 76 77 71 public void actionPerformed(ActionEvent e) { 72 int numberOfNodesInCircle = Integer.parseInt(Main.pref.get("createcircle.nodecount", "8")); 73 if (numberOfNodesInCircle < 1) { 74 numberOfNodesInCircle = 1; 75 } else if (numberOfNodesInCircle > 100) { 76 numberOfNodesInCircle = 100; 77 } 78 78 79 80 81 79 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 80 Collection<Node> nodes = new LinkedList<Node>(); 81 Way existingWay = null; 82 82 83 84 85 83 for (OsmPrimitive osm : sel) 84 if (osm instanceof Node) 85 nodes.add((Node)osm); 86 86 87 88 89 90 91 92 93 94 95 96 97 98 87 // special case if no single nodes are selected and exactly one way is: 88 // then use the way's nodes 89 if ((nodes.size() == 0) && (sel.size() == 1)) 90 for (OsmPrimitive osm : sel) 91 if (osm instanceof Way) { 92 existingWay = ((Way)osm); 93 for (Node n : ((Way)osm).nodes) 94 { 95 if(!nodes.contains(n)) 96 nodes.add(n); 97 } 98 } 99 99 100 101 102 103 100 if (nodes.size() != 3) { 101 JOptionPane.showMessageDialog(Main.parent, tr("Please select exactly three nodes or one way with exactly three nodes.")); 102 return; 103 } 104 104 105 106 107 108 109 110 111 112 113 114 105 // let's get some shorter names 106 Node n1 = ((Node)nodes.toArray()[0]); 107 double x1 = n1.eastNorth.east(); 108 double y1 = n1.eastNorth.north(); 109 Node n2 = ((Node)nodes.toArray()[1]); 110 double x2 = n2.eastNorth.east(); 111 double y2 = n2.eastNorth.north(); 112 Node n3 = ((Node)nodes.toArray()[2]); 113 double x3 = n3.eastNorth.east(); 114 double y3 = n3.eastNorth.north(); 115 115 116 117 118 116 // calculate the center (xc/yc) 117 double s = 0.5*((x2 - x3)*(x1 - x3) - (y2 - y3)*(y3 - y1)); 118 double sUnder = (x1 - x2)*(y3 - y1) - (y2 - y1)*(x1 - x3); 119 119 120 121 122 123 120 if (sUnder == 0) { 121 JOptionPane.showMessageDialog(Main.parent, tr("Those nodes are not in a circle.")); 122 return; 123 } 124 124 125 125 s /= sUnder; 126 126 127 128 127 double xc = 0.5*(x1 + x2) + s*(y2 - y1); 128 double yc = 0.5*(y1 + y2) + s*(x1 - x2); 129 129 130 131 130 // calculate the radius (r) 131 double r = Math.sqrt(Math.pow(xc-x1,2) + Math.pow(yc-y1,2)); 132 132 133 134 135 136 137 138 139 133 // find where to put the existing nodes 134 double a1 = calcang(xc, yc, x1, y1); 135 double a2 = calcang(xc, yc, x2, y2); 136 double a3 = calcang(xc, yc, x3, y3); 137 if (a1 < a2) { double at = a1; Node nt = n1; a1 = a2; n1 = n2; a2 = at; n2 = nt; } 138 if (a2 < a3) { double at = a2; Node nt = n2; a2 = a3; n2 = n3; a3 = at; n3 = nt; } 139 if (a1 < a2) { double at = a1; Node nt = n1; a1 = a2; n1 = n2; a2 = at; n2 = nt; } 140 140 141 142 141 // now we can start doing thigs to OSM data 142 Collection<Command> cmds = new LinkedList<Command>(); 143 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 144 // build a way for the circle 145 Way wayToAdd; 146 if (existingWay == null) { 147 wayToAdd = new Way(); 148 } else { 149 // re-use existing way if it was selected 150 wayToAdd = new Way(existingWay); 151 wayToAdd.nodes.clear(); 152 } 153 for (int i = 1; i <= numberOfNodesInCircle; i++) { 154 double a = 2*Math.PI*(1.0 - i/(double)numberOfNodesInCircle); // "1-" to get it clock-wise 155 // insert existing nodes if they fit before this new node (999 means "already added this node") 156 if (a1 < 999 && a1 > a) { 157 wayToAdd.nodes.add(n1); 158 a1 = 999; 159 } 160 if (a2 < 999 && a2 > a) { 161 wayToAdd.nodes.add(n2); 162 a2 = 999; 163 } 164 if (a3 < 999 && a3 > a) { 165 wayToAdd.nodes.add(n3); 166 a3 = 999; 167 } 168 // get the position of the new node and insert it 169 double x = xc + r*Math.cos(a); 170 double y = yc + r*Math.sin(a); 171 Node n = new Node(Main.proj.eastNorth2latlon(new EastNorth(x,y))); 172 wayToAdd.nodes.add(n); 173 cmds.add(new AddCommand(n)); 174 } 175 wayToAdd.nodes.add(wayToAdd.nodes.get(0)); // close the circle 176 if (existingWay == null) { 177 cmds.add(new AddCommand(wayToAdd)); 178 } else { 179 cmds.add(new ChangeCommand(existingWay, wayToAdd)); 180 } 181 181 182 183 184 182 Main.main.undoRedo.add(new SequenceCommand(tr("Create Circle"), cmds)); 183 Main.map.repaint(); 184 } 185 185 } -
trunk/src/org/openstreetmap/josm/actions/DeleteAction.java
r1087 r1169 17 17 public final class DeleteAction extends JosmAction implements SelectionChangedListener { 18 18 19 20 21 19 public DeleteAction() { 20 super(tr("Delete"), "dialogs/delete", tr("Delete selected objects."), 21 Shortcut.registerShortcut("system:delete", tr("Edit: {0}", tr("Delete")), KeyEvent.VK_DELETE, Shortcut.GROUP_DIRECT), true); 22 22 DataSet.selListeners.add(this); 23 24 23 setEnabled(false); 24 } 25 25 26 27 28 29 26 public void actionPerformed(ActionEvent e) { 27 new org.openstreetmap.josm.actions.mapmode.DeleteAction(Main.map) 28 .doActionPerformed(e); 29 } 30 30 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 31 31 setEnabled(! newSelection.isEmpty()); -
trunk/src/org/openstreetmap/josm/actions/DiskAccessAction.java
r1084 r1169 17 17 abstract public class DiskAccessAction extends JosmAction { 18 18 19 20 21 19 public DiskAccessAction(String name, String iconName, String tooltip, Shortcut shortcut) { 20 super(name, iconName, tooltip, shortcut, true); 21 } 22 22 23 24 25 26 23 @Deprecated 24 public DiskAccessAction(String name, String iconName, String tooltip, int shortcut, int modifiers) { 25 super(name, iconName, tooltip, shortcut, modifiers, true); 26 } 27 27 28 29 30 31 32 33 34 28 protected static JFileChooser createAndOpenFileChooser(boolean open, boolean multiple, String title) { 29 String curDir = Main.pref.get("lastDirectory"); 30 if (curDir.equals("")) 31 curDir = "."; 32 JFileChooser fc = new JFileChooser(new File(curDir)); 33 if(title != null) 34 fc.setDialogTitle(title); 35 35 36 37 38 39 36 fc.setMultiSelectionEnabled(multiple); 37 for (int i = 0; i < ExtensionFileFilter.filters.length; ++i) 38 fc.addChoosableFileFilter(ExtensionFileFilter.filters[i]); 39 fc.setAcceptAllFileFilterUsed(true); 40 40 41 42 43 41 int answer = open ? fc.showOpenDialog(Main.parent) : fc.showSaveDialog(Main.parent); 42 if (answer != JFileChooser.APPROVE_OPTION) 43 return null; 44 44 45 46 45 if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) 46 Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath()); 47 47 48 49 50 51 52 53 48 if (!open) { 49 File file = fc.getSelectedFile(); 50 if (file == null || (file.exists() && JOptionPane.YES_OPTION != 51 JOptionPane.showConfirmDialog(Main.parent, tr("File exists. Overwrite?"), tr("Overwrite"), JOptionPane.YES_NO_OPTION))) 52 return null; 53 } 54 54 55 56 55 return fc; 56 } 57 57 } -
trunk/src/org/openstreetmap/josm/actions/DownloadAction.java
r1084 r1169 28 28 public class DownloadAction extends JosmAction { 29 29 30 30 public DownloadDialog dialog; 31 31 32 33 34 35 32 public DownloadAction() { 33 super(tr("Download from OSM ..."), "download", tr("Download map data from the OSM server."), 34 Shortcut.registerShortcut("file:download", tr("File: {0}", tr("Download from OSM ...")), KeyEvent.VK_D, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true); 35 } 36 36 37 38 37 public void actionPerformed(ActionEvent e) { 38 dialog = new DownloadDialog(); 39 39 40 41 40 JPanel downPanel = new JPanel(new GridBagLayout()); 41 downPanel.add(dialog, GBC.eol().fill(GBC.BOTH)); 42 42 43 44 45 46 43 JOptionPane pane = new JOptionPane(downPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION); 44 JDialog dlg = pane.createDialog(Main.parent, tr("Download")); 45 dlg.setResizable(true); 46 dialog.setOptionPane(pane); 47 47 48 49 50 51 48 if (dlg.getWidth() > 1000) 49 dlg.setSize(1000, dlg.getHeight()); 50 if (dlg.getHeight() > 600) 51 dlg.setSize(dlg.getWidth(),600); 52 52 53 53 boolean finish = false; 54 54 while (!finish) { 55 55 dlg.setVisible(true); 56 56 Main.pref.put("download.newlayer", dialog.newLayer.isSelected()); 57 58 59 60 61 62 63 64 65 66 67 68 69 57 if (pane.getValue() instanceof Integer && (Integer)pane.getValue() == JOptionPane.OK_OPTION) { 58 Main.pref.put("download.tab", Integer.toString(dialog.getSelectedTab())); 59 for (DownloadTask task : dialog.downloadTasks) { 60 Main.pref.put("download."+task.getPreferencesSuffix(), task.getCheckBox().isSelected()); 61 if (task.getCheckBox().isSelected()) { 62 task.download(this, dialog.minlat, dialog.minlon, dialog.maxlat, dialog.maxlon); 63 finish = true; 64 } 65 } 66 } else 67 finish = true; 68 if (!finish) 69 JOptionPane.showMessageDialog(Main.parent, tr("Please select at least one task to download")); 70 70 } 71 71 72 72 dialog = null; 73 74 73 dlg.dispose(); 74 } 75 75 } -
trunk/src/org/openstreetmap/josm/actions/DuplicateAction.java
r1084 r1169 18 18 19 19 public DuplicateAction() { 20 21 22 23 24 20 super(tr("Duplicate"), "duplicate", 21 tr("Duplicate selection by copy and immediate paste."), 22 Shortcut.registerShortcut("system:duplicate", tr("Edit: {0}", tr("Duplicate")), KeyEvent.VK_D, Shortcut.GROUP_MENU), true); 23 setEnabled(false); 24 DataSet.selListeners.add(this); 25 25 } 26 26 27 28 29 27 public void actionPerformed(ActionEvent e) { 28 Main.main.menu.copy.actionPerformed(e); 29 Main.main.menu.paste.actionPerformed(e); 30 30 } 31 31 32 33 34 32 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 33 setEnabled(! newSelection.isEmpty()); 34 } 35 35 } -
trunk/src/org/openstreetmap/josm/actions/ExitAction.java
r1084 r1169 16 16 */ 17 17 public class ExitAction extends JosmAction { 18 19 20 21 22 23 24 18 /** 19 * Construct the action with "Exit" as label 20 */ 21 public ExitAction() { 22 super(tr("Exit"), "exit", tr("Exit the application."), 23 Shortcut.registerShortcut("system:menuexit", tr("Exit"), KeyEvent.VK_Q, Shortcut.GROUP_MENU), true); 24 } 25 25 26 27 28 29 26 public void actionPerformed(ActionEvent e) { 27 if (!Main.breakBecauseUnsavedChanges()) 28 System.exit(0); 29 } 30 30 } -
trunk/src/org/openstreetmap/josm/actions/ExtensionFileFilter.java
r929 r1169 9 9 10 10 /** 11 * A file filter that filters after the extension. Also includes a list of file 11 * A file filter that filters after the extension. Also includes a list of file 12 12 * filters used in JOSM. 13 * 13 * 14 14 * @author imi 15 15 */ 16 16 public class ExtensionFileFilter extends FileFilter { 17 18 19 17 private final String extension; 18 private final String description; 19 public final String defaultExtension; 20 20 21 public static final int OSM = 0; 22 public static final int GPX = 1; 23 public static final int NMEA = 2; 24 25 public static ExtensionFileFilter[] filters = { 26 new ExtensionFileFilter("osm,xml", "osm", tr("OSM Server Files (*.osm *.xml)")), 27 new ExtensionFileFilter("gpx,gpx.gz", "gpx", tr("GPX Files (*.gpx *.gpx.gz)")), 28 new ExtensionFileFilter("nmea,txt", "nmea", tr("NMEA-0183 Files (*.nmea *.txt)")), 29 }; 21 public static final int OSM = 0; 22 public static final int GPX = 1; 23 public static final int NMEA = 2; 30 24 31 /** 32 * Construct an extension file filter by giving the extension to check after. 33 * 34 */ 35 public ExtensionFileFilter(String extension, String defExt, String description) { 36 this.extension = extension; 37 defaultExtension = defExt; 38 this.description = description; 39 } 25 public static ExtensionFileFilter[] filters = { 26 new ExtensionFileFilter("osm,xml", "osm", tr("OSM Server Files (*.osm *.xml)")), 27 new ExtensionFileFilter("gpx,gpx.gz", "gpx", tr("GPX Files (*.gpx *.gpx.gz)")), 28 new ExtensionFileFilter("nmea,txt", "nmea", tr("NMEA-0183 Files (*.nmea *.txt)")), 29 }; 40 30 41 public boolean acceptName(String filename) { 42 String name = filename.toLowerCase(); 43 for (String ext : extension.split(",")) 44 if (name.endsWith("."+ext)) 45 return true; 46 return false; 47 } 31 /** 32 * Construct an extension file filter by giving the extension to check after. 33 * 34 */ 35 public ExtensionFileFilter(String extension, String defExt, String description) { 36 this.extension = extension; 37 defaultExtension = defExt; 38 this.description = description; 39 } 48 40 49 @Override public boolean accept(File pathname) { 50 if (pathname.isDirectory()) 51 return true; 52 return acceptName(pathname.getName()); 53 } 41 public boolean acceptName(String filename) { 42 String name = filename.toLowerCase(); 43 for (String ext : extension.split(",")) 44 if (name.endsWith("."+ext)) 45 return true; 46 return false; 47 } 54 48 55 @Override public String getDescription() { 56 return description; 57 } 49 @Override public boolean accept(File pathname) { 50 if (pathname.isDirectory()) 51 return true; 52 return acceptName(pathname.getName()); 53 } 54 55 @Override public String getDescription() { 56 return description; 57 } 58 58 } -
trunk/src/org/openstreetmap/josm/actions/GpxExportAction.java
r1084 r1169 40 40 public class GpxExportAction extends DiskAccessAction { 41 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 42 private final static String warningGpl = "<html><font color='red' size='-2'>"+tr("Note: GPL is not compatible with the OSM license. Do not upload GPL licensed tracks.")+"</html>"; 43 44 private final Layer layer; 45 46 public GpxExportAction(Layer layer) { 47 super(tr("Export to GPX ..."), "exportgpx", tr("Export the data to GPX file."), 48 Shortcut.registerShortcut("file:exportgpx", tr("Export to GPX ..."), KeyEvent.VK_E, Shortcut.GROUP_MENU)); 49 this.layer = layer; 50 } 51 52 public void actionPerformed(ActionEvent e) { 53 if (layer == null && Main.map == null) { 54 JOptionPane.showMessageDialog(Main.parent, tr("Nothing to export. Get some data first.")); 55 return; 56 } 57 58 JFileChooser fc = createAndOpenFileChooser(false, false, null); 59 if (fc == null) 60 return; 61 File file = fc.getSelectedFile(); 62 if (file == null) 63 return; 64 65 exportGpx(file, this.layer == null ? Main.main.editLayer() : this.layer); 66 } 67 68 public static void exportGpx(File file, Layer layer) { 69 String fn = file.getPath(); 70 if (fn.indexOf('.') == -1) { 71 fn += ".gpx"; 72 file = new File(fn); 73 } 74 75 // open the dialog asking for options 76 JPanel p = new JPanel(new GridBagLayout()); 77 78 p.add(new JLabel(tr("gps track description")), GBC.eol()); 79 JTextArea desc = new JTextArea(3,40); 80 desc.setWrapStyleWord(true); 81 desc.setLineWrap(true); 82 p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH)); 83 84 JCheckBox author = new JCheckBox(tr("Add author information"), Main.pref.getBoolean("lastAddAuthor", true)); 85 author.setSelected(true); 86 p.add(author, GBC.eol()); 87 JLabel nameLabel = new JLabel(tr("Real name")); 88 p.add(nameLabel, GBC.std().insets(10,0,5,0)); 89 JTextField authorName = new JTextField(Main.pref.get("lastAuthorName")); 90 p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL)); 91 JLabel emailLabel = new JLabel(tr("Email")); 92 p.add(emailLabel, GBC.std().insets(10,0,5,0)); 93 JTextField email = new JTextField(Main.pref.get("osm-server.username")); 94 p.add(email, GBC.eol().fill(GBC.HORIZONTAL)); 95 JLabel copyrightLabel = new JLabel(tr("Copyright (URL)")); 96 p.add(copyrightLabel, GBC.std().insets(10,0,5,0)); 97 JTextField copyright = new JTextField(); 98 p.add(copyright, GBC.std().fill(GBC.HORIZONTAL)); 99 JButton predefined = new JButton(tr("Predefined")); 100 p.add(predefined, GBC.eol().insets(5,0,0,0)); 101 JLabel copyrightYearLabel = new JLabel(tr("Copyright year")); 102 p.add(copyrightYearLabel, GBC.std().insets(10,0,5,5)); 103 JTextField copyrightYear = new JTextField(""); 104 p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL)); 105 JLabel warning = new JLabel("<html><font size='-2'> </html"); 106 p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15,0,0,0)); 107 addDependencies(author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel, copyrightLabel, copyrightYearLabel, warning); 108 109 p.add(new JLabel(tr("Keywords")), GBC.eol()); 110 JTextField keywords = new JTextField(); 111 p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL)); 112 113 int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Export options"), JOptionPane.OK_CANCEL_OPTION); 114 if (answer != JOptionPane.OK_OPTION) 115 return; 116 117 Main.pref.put("lastAddAuthor", author.isSelected()); 118 if (authorName.getText().length() != 0) 119 Main.pref.put("lastAuthorName", authorName.getText()); 120 if (copyright.getText().length() != 0) 121 Main.pref.put("lastCopyright", copyright.getText()); 122 123 GpxData gpxData; 124 if (layer instanceof OsmDataLayer) 125 gpxData = ((OsmDataLayer)layer).toGpxData(); 126 else if (layer instanceof GpxLayer) 127 gpxData = ((GpxLayer)layer).data; 128 else 129 gpxData = OsmDataLayer.toGpxData(Main.ds); 130 // TODO: add copyright, etc. 131 try { 132 FileOutputStream fo = new FileOutputStream(file); 133 new GpxWriter(fo).write(gpxData); 134 fo.flush(); 135 fo.close(); 136 } catch (IOException x) { 137 x.printStackTrace(); 138 JOptionPane.showMessageDialog(Main.parent, tr("Error while exporting {0}", fn)+":\n"+x.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE); 139 } 140 } 141 142 /** 143 * Add all those listeners to handle the enable state of the fields. 144 * @param copyrightYearLabel 145 * @param copyrightLabel 146 * @param emailLabel 147 * @param nameLabel 148 * @param warning 149 */ 150 private static void addDependencies( 151 final JCheckBox author, 152 final JTextField authorName, 153 final JTextField email, 154 final JTextField copyright, 155 final JButton predefined, 156 final JTextField copyrightYear, 157 final JLabel nameLabel, 158 final JLabel emailLabel, 159 final JLabel copyrightLabel, 160 final JLabel copyrightYearLabel, 161 final JLabel warning) { 162 163 ActionListener authorActionListener = new ActionListener(){ 164 public void actionPerformed(ActionEvent e) { 165 boolean b = author.isSelected(); 166 authorName.setEnabled(b); 167 email.setEnabled(b); 168 nameLabel.setEnabled(b); 169 emailLabel.setEnabled(b); 170 authorName.setText(b ? Main.pref.get("lastAuthorName") : ""); 171 email.setText(b ? Main.pref.get("osm-server.username") : ""); 172 173 boolean authorSet = authorName.getText().length() != 0; 174 enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b && authorSet); 175 } 176 }; 177 author.addActionListener(authorActionListener); 178 179 KeyAdapter authorNameListener = new KeyAdapter(){ 180 @Override public void keyReleased(KeyEvent e) { 181 boolean b = authorName.getText().length()!=0 && author.isSelected(); 182 enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b); 183 } 184 }; 185 authorName.addKeyListener(authorNameListener); 186 187 predefined.addActionListener(new ActionListener(){ 188 public void actionPerformed(ActionEvent e) { 189 JList l = new JList(new String[]{"Creative Commons By-SA", "public domain", "GNU Lesser Public License (LGPL)", "BSD License (MIT/X11)"}); 190 l.setVisibleRowCount(4); 191 l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 192 int answer = JOptionPane.showConfirmDialog(Main.parent, new JScrollPane(l),tr("Choose a predefined license"), JOptionPane.OK_CANCEL_OPTION); 193 if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1) 194 return; 195 final String[] urls = { 196 "http://creativecommons.org/licenses/by-sa/2.5", 197 "public domain", 198 "http://www.gnu.org/copyleft/lesser.html", 199 "http://www.opensource.org/licenses/bsd-license.php"}; 200 String license = ""; 201 for (int i : l.getSelectedIndices()) { 202 if (i == 1) { 203 license = "public domain"; 204 break; 205 } 206 license += license.length()==0 ? urls[i] : ", "+urls[i]; 207 } 208 copyright.setText(license); 209 copyright.setCaretPosition(0); 210 } 211 }); 212 213 authorActionListener.actionPerformed(null); 214 authorNameListener.keyReleased(null); 215 } 216 217 private static void enableCopyright(final JTextField copyright, final JButton predefined, final JTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel, final JLabel warning, boolean enable) { 218 copyright.setEnabled(enable); 219 predefined.setEnabled(enable); 220 copyrightYear.setEnabled(enable); 221 copyrightLabel.setEnabled(enable); 222 copyrightYearLabel.setEnabled(enable); 223 warning.setText(enable ? warningGpl : "<html><font size='-2'> </html"); 224 225 if (enable && copyrightYear.getText().length()==0) { 226 copyrightYear.setText(enable ? Integer.toString(Calendar.getInstance().get(Calendar.YEAR)) : ""); 227 } else if (!enable) 228 copyrightYear.setText(""); 229 230 if (enable && copyright.getText().length()==0) { 231 copyright.setText(enable ? Main.pref.get("lastCopyright", "http://creativecommons.org/licenses/by-sa/2.5") : ""); 232 copyright.setCaretPosition(0); 233 } else if (!enable) 234 copyright.setText(""); 235 } 236 236 } -
trunk/src/org/openstreetmap/josm/actions/HelpAction.java
r1163 r1169 42 42 public class HelpAction extends AbstractAction { 43 43 44 45 44 public interface Helpful { 45 String helpTopic(); 46 46 } 47 47 48 48 private String languageCode = Main.getLanguageCodeU(); 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 49 private JFrame helpBrowser = new JFrame(tr("JOSM Online Help")); 50 private String baseurl = Main.pref.get("help.baseurl", "http://josm.openstreetmap.de"); 51 private JEditorPane help = new JEditorPane(); 52 private WikiReader reader = new WikiReader(baseurl); 53 private String url; 54 55 public HelpAction() { 56 super(tr("Help"), ImageProvider.get("help")); 57 help.setEditable(false); 58 help.addHyperlinkListener(new HyperlinkListener(){ 59 public void hyperlinkUpdate(HyperlinkEvent e) { 60 if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) 61 return; 62 if (e.getURL() == null) 63 help.setText("<html>404 not found</html>"); 64 else if (e.getURL().toString().startsWith(WikiReader.JOSM_EXTERN)) 65 OpenBrowser.displayUrl("http://"+e.getURL().toString().substring(WikiReader.JOSM_EXTERN.length())+"?action=edit"); 66 else 67 setHelpUrl(e.getURL().toString()); 68 } 69 }); 70 help.setContentType("text/html"); 71 72 JPanel p = new JPanel(new BorderLayout()); 73 helpBrowser.setContentPane(p); 74 75 p.add(new JScrollPane(help), BorderLayout.CENTER); 76 String[] bounds = Main.pref.get("help.window.bounds", "0,0,800,600").split(","); 77 helpBrowser.setBounds( 78 Integer.parseInt(bounds[0]), 79 Integer.parseInt(bounds[1]), 80 Integer.parseInt(bounds[2]), 81 Integer.parseInt(bounds[3])); 82 83 JPanel buttons = new JPanel(); 84 p.add(buttons, BorderLayout.SOUTH); 85 createButton(buttons, tr("Open in Browser")); 86 createButton(buttons, tr("Edit")); 87 createButton(buttons, tr("Reload")); 88 89 helpBrowser.addWindowListener(new WindowAdapter(){ 90 @Override public void windowClosing(WindowEvent e) { 91 closeHelp(); 92 } 93 }); 94 94 95 95 help.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Close"); 96 96 help.getActionMap().put("Close", new AbstractAction(){ 97 98 97 public void actionPerformed(ActionEvent e) { 98 closeHelp(); 99 99 } 100 100 }); 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 } 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 101 } 102 103 public void actionPerformed(ActionEvent e) { 104 if (tr("Open in Browser").equals(e.getActionCommand())) { 105 OpenBrowser.displayUrl(url); 106 } else if (tr("Edit").equals(e.getActionCommand())) { 107 if (!url.startsWith(baseurl)) { 108 JOptionPane.showMessageDialog(Main.parent, tr("Can only edit help pages from JOSM Online Help")); 109 return; 110 } 111 OpenBrowser.displayUrl(url+"?action=edit"); 112 } else if (tr("Reload").equals(e.getActionCommand())) { 113 setHelpUrl(url); 114 } else if (e.getActionCommand() == null) { 115 String topic = null; 116 Point mouse = Main.parent.getMousePosition(); 117 if (mouse != null) 118 topic = contextSensitiveHelp(SwingUtilities.getDeepestComponentAt(Main.parent, mouse.x, mouse.y)); 119 if (topic == null) { 120 helpBrowser.setVisible(false); 121 setHelpUrl(baseurl+"/wiki/Help"); 122 } else 123 help(topic); 124 } else { 125 helpBrowser.setVisible(false); 126 setHelpUrl(baseurl+"/wiki/Help"); 127 } 128 } 129 130 /** 131 * @return The topic of the help. <code>null</code> for "don't know" 132 */ 133 private String contextSensitiveHelp(Object c) { 134 if (c instanceof Helpful) 135 return ((Helpful)c).helpTopic(); 136 if (c instanceof JMenu) 137 return "Menu/"+((JMenu)c).getText(); 138 if (c instanceof AbstractButton) { 139 AbstractButton b = (AbstractButton)c; 140 if (b.getClientProperty("help") != null) 141 return (String)b.getClientProperty("help"); 142 return contextSensitiveHelp(((AbstractButton)c).getAction()); 143 } 144 if (c instanceof Action) 145 return (String)((Action)c).getValue("help"); 146 if (c instanceof Component) 147 return contextSensitiveHelp(((Component)c).getParent()); 148 return null; 149 } 150 151 /** 152 * Displays the help (or browse on the already open help) on the online page 153 * with the given help topic. Use this for larger help descriptions. 154 */ 155 public void help(String topic) { 156 helpBrowser.setVisible(false); 157 setHelpUrl(baseurl+"/wiki/Help/"+topic); 158 } 159 160 /** 161 * Set the content of the help window to a specific text (in html format) 162 * @param url The url this content is the representation of 163 */ 164 public void setHelpUrl(String url) { 165 int i = url.lastIndexOf("/")+1; 166 String title = url.substring(i); 167 if(!title.startsWith(languageCode)) 168 title = languageCode + title; 169 String langurl = url.substring(0, i) + title; 170 if(langurl.equals(this.url) || langurl.equals(url)) 171 { 172 this.url = url; 173 try { 174 help.read(new StringReader(reader.read(url)), help.getEditorKit().createDefaultDocument()); 175 } catch (IOException ex) { 176 help.setText(tr("Error while loading page {0}",url)); 177 } 178 } 179 else 180 { 181 try { 182 help.read(new StringReader(reader.read(langurl)), help.getEditorKit().createDefaultDocument()); 183 String message = help.getText(); 184 String le = "http://josm-extern." + langurl.substring(7); 185 if(message.indexOf("Describe "") >= 0 && message.indexOf(le) >= 0) 186 throw new IOException(); 187 this.url = langurl; 188 } catch (IOException e) { 189 this.url = url; 190 try { 191 help.read(new StringReader(reader.read(url)), help.getEditorKit().createDefaultDocument()); 192 } catch (IOException ex) { 193 help.setText(tr("Error while loading page {0}",url)); 194 } 195 } 196 } 197 helpBrowser.setVisible(true); 198 } 199 200 /** 201 * Closes the help window 202 */ 203 public void closeHelp() { 204 String bounds = helpBrowser.getX()+","+helpBrowser.getY()+","+helpBrowser.getWidth()+","+helpBrowser.getHeight(); 205 Main.pref.put("help.window.bounds", bounds); 206 helpBrowser.setVisible(false); 207 } 208 209 private void createButton(JPanel buttons, String name) { 210 JButton b = new JButton(tr(name)); 211 b.setActionCommand(name); 212 b.addActionListener(this); 213 buttons.add(b); 214 } 215 215 } -
trunk/src/org/openstreetmap/josm/actions/HistoryInfoAction.java
r1084 r1169 18 18 public class HistoryInfoAction extends JosmAction { 19 19 20 21 22 23 20 public HistoryInfoAction() { 21 super(tr("OSM History Information"), "about",tr("Display history information about OSM ways or nodes."), 22 Shortcut.registerShortcut("core:history", tr("OSM History Information"), KeyEvent.VK_H, Shortcut.GROUP_HOTKEY), true); 23 } 24 24 25 25 public void actionPerformed(ActionEvent e) { 26 26 new Visitor() { 27 27 public void visit(Node n) { 28 29 28 OpenBrowser.displayUrl("http://www.openstreetmap.org/browse/node/" + n.id + "/history"); 29 } 30 30 31 31 public void visit(Way w) { … … 43 43 }.visitAll(); 44 44 45 45 } 46 46 47 47 } -
trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java
r1084 r1169 26 26 27 27 public class JoinNodeWayAction extends JosmAction { 28 29 30 31 28 public JoinNodeWayAction() { 29 super(tr("Join node to way"), "joinnodeway", tr("Join a node into the nearest way segments"), 30 Shortcut.registerShortcut("tools:joinnodeway", tr("Tool: {0}", tr("Join node to way")), KeyEvent.VK_J, Shortcut.GROUP_EDIT), true); 31 } 32 32 33 34 35 36 33 public void actionPerformed(ActionEvent e) { 34 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 35 if (sel.size() != 1 || !(sel.iterator().next() instanceof Node)) return; 36 Node node = (Node) sel.iterator().next(); 37 37 38 39 40 41 42 43 44 45 46 47 48 38 List<WaySegment> wss = Main.map.mapView.getNearestWaySegments( 39 Main.map.mapView.getPoint(node.eastNorth)); 40 HashMap<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>(); 41 for (WaySegment ws : wss) { 42 List<Integer> is; 43 if (insertPoints.containsKey(ws.way)) { 44 is = insertPoints.get(ws.way); 45 } else { 46 is = new ArrayList<Integer>(); 47 insertPoints.put(ws.way, is); 48 } 49 49 50 51 52 53 54 50 if (ws.way.nodes.get(ws.lowerIndex) != node 51 && ws.way.nodes.get(ws.lowerIndex+1) != node) { 52 is.add(ws.lowerIndex); 53 } 54 } 55 55 56 57 58 59 60 61 62 63 64 56 Collection<Command> cmds = new LinkedList<Command>(); 57 for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) { 58 Way w = insertPoint.getKey(); 59 Way wnew = new Way(w); 60 List<Integer> is = insertPoint.getValue(); 61 pruneSuccsAndReverse(is); 62 for (int i : is) wnew.nodes.add(i+1, node); 63 cmds.add(new ChangeCommand(w, wnew)); 64 } 65 65 66 67 68 66 Main.main.undoRedo.add(new SequenceCommand(tr("Join Node and Line"), cmds)); 67 Main.map.repaint(); 68 } 69 69 70 71 70 private static void pruneSuccsAndReverse(List<Integer> is) { 71 //if (is.size() < 2) return; 72 72 73 74 75 76 77 78 79 80 81 82 83 73 HashSet<Integer> is2 = new HashSet<Integer>(); 74 for (int i : is) { 75 if (!is2.contains(i - 1) && !is2.contains(i + 1)) { 76 is2.add(i); 77 } 78 } 79 is.clear(); 80 is.addAll(is2); 81 Collections.sort(is); 82 Collections.reverse(is); 83 } 84 84 } -
trunk/src/org/openstreetmap/josm/actions/JosmAction.java
r1084 r1169 25 25 abstract public class JosmAction extends AbstractAction implements Destroyable { 26 26 27 28 29 27 @Deprecated 28 public KeyStroke shortcut; 29 protected Shortcut sc; 30 30 31 32 33 34 35 36 37 38 31 public Shortcut getShortcut() { 32 if (sc == null) { 33 sc = Shortcut.registerShortcut("core:none", "No Shortcut", 0, Shortcut.GROUP_NONE); 34 sc.setAutomatic(); // as this shortcut is shared by all action that don't want to have a shortcut, 35 // we shouldn't allow the user to change it... 36 } 37 return sc; 38 } 39 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 40 @Deprecated 41 public JosmAction(String name, String iconName, String tooltip, int shortcut, int modifier, boolean register) { 42 super(name, iconName == null ? null : ImageProvider.get(iconName)); 43 setHelpId(); 44 if (shortcut != 0) { 45 int group = Shortcut.GROUP_LAYER; //GROUP_NONE; 46 if (((modifier & InputEvent.CTRL_MASK) != 0) || ((modifier & InputEvent.CTRL_DOWN_MASK) != 0)) { 47 group = Shortcut.GROUP_MENU; 48 } else if (modifier == 0) { 49 group = Shortcut.GROUP_EDIT; 50 } 51 sc = Shortcut.registerShortcut("auto:"+name, name, shortcut, group); 52 this.shortcut = sc.getKeyStroke(); 53 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name); 54 Main.contentPane.getActionMap().put(name, this); 55 } 56 putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc)); 57 putValue("toolbar", iconName); 58 58 if (register) 59 60 59 Main.toolbar.register(this); 60 } 61 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 62 /** 63 * The new super for all actions. 64 * 65 * Use this super constructor to setup your action. It takes 5 parameters: 66 * 67 * name - the action's text as displayed on the menu (if it is added to a menu) 68 * iconName - the filename of the icon to use 69 * tooltip - a longer description of the action that will be displayed in the tooltip. Please note 70 * that html is not supported for menu action on some platforms 71 * shortcut - a ready-created shortcut object or null if you don't want a shortcut. But you always 72 * do want a shortcut, remember you can alway register it with group=none, so you 73 * won't be assigned a shurtcut unless the user configures one. If you pass null here, 74 * the user CANNOT configure a shortcut for your action. 75 * register - register this action for the toolbar preferences? 76 */ 77 public JosmAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean register) { 78 super(name, iconName == null ? null : ImageProvider.get(iconName)); 79 setHelpId(); 80 sc = shortcut; 81 if (sc != null) { 82 this.shortcut = sc.getKeyStroke(); 83 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name); 84 Main.contentPane.getActionMap().put(name, this); 85 } 86 putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc)); 87 putValue("toolbar", iconName); 88 88 if (register) 89 90 89 Main.toolbar.register(this); 90 } 91 91 92 93 94 95 96 97 92 public void destroy() { 93 if (shortcut != null) { 94 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(sc.getKeyStroke()); 95 Main.contentPane.getActionMap().remove(sc.getKeyStroke()); 96 } 97 } 98 98 99 100 101 99 public JosmAction() { 100 setHelpId(); 101 } 102 102 103 104 105 106 107 108 103 /** 104 * needs to be overridden to be useful 105 */ 106 public void pasteBufferChanged(DataSet newPasteBuffer) { 107 return; 108 } 109 109 110 111 112 113 114 115 110 /** 111 * needs to be overridden to be useful 112 */ 113 public void addListener(JosmAction a) { 114 return; 115 } 116 116 117 118 119 120 121 122 117 private void setHelpId() { 118 String helpId = "Action/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1); 119 if (helpId.endsWith("Action")) 120 helpId = helpId.substring(0, helpId.length()-6); 121 putValue("help", helpId); 122 } 123 123 } -
trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java
r1084 r1169 52 52 public class MergeNodesAction extends JosmAction implements SelectionChangedListener { 53 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 54 public MergeNodesAction() { 55 super(tr("Merge Nodes"), "mergenodes", tr("Merge nodes into the oldest one."), 56 Shortcut.registerShortcut("tools:mergenodes", tr("Tool: {0}", tr("Merge Nodes")), KeyEvent.VK_M, Shortcut.GROUP_EDIT), true); 57 DataSet.selListeners.add(this); 58 } 59 60 public void actionPerformed(ActionEvent event) { 61 Collection<OsmPrimitive> selection = Main.ds.getSelected(); 62 LinkedList<Node> selectedNodes = new LinkedList<Node>(); 63 64 // the selection check should stop this procedure starting if 65 // nothing but node are selected - otherwise we don't care 66 // anyway as long as we have at least two nodes 67 for (OsmPrimitive osm : selection) 68 if (osm instanceof Node) 69 selectedNodes.add((Node)osm); 70 71 if (selectedNodes.size() < 2) { 72 JOptionPane.showMessageDialog(Main.parent, tr("Please select at least two nodes to merge.")); 73 return; 74 } 75 76 // Find which node to merge into (i.e. which one will be left) 77 // - this should be combined from two things: 78 // 1. It will be the first node in the list that has a 79 // positive ID number, OR the first node. 80 // 2. It will be at the position of the first node in the 81 // list. 82 // 83 // *However* - there is the problem that the selection list is 84 // _not_ in the order that the nodes were clicked on, meaning 85 // that the user doesn't know which node will be chosen (so 86 // (2) is not implemented yet.) :-( 87 Node useNode = null; 88 for (Node n: selectedNodes) { 89 if (n.id > 0) { 90 useNode = n; 91 break; 92 } 93 } 94 if (useNode == null) 95 useNode = selectedNodes.iterator().next(); 96 97 mergeNodes(selectedNodes, useNode); 98 } 99 100 /** 101 * really do the merging - returns the node that is left 102 */ 103 public static Node mergeNodes(LinkedList<Node> allNodes, Node dest) { 104 Node newNode = new Node(dest); 105 106 // Check whether all ways have identical relationship membership. More 107 // specifically: If one of the selected ways is a member of relation X 108 // in role Y, then all selected ways must be members of X in role Y. 109 110 // FIXME: In a later revision, we should display some sort of conflict 111 // dialog like we do for tags, to let the user choose which relations 112 // should be kept. 113 114 // Step 1, iterate over all relations and figure out which of our 115 // selected ways are members of a relation. 116 HashMap<Pair<Relation,String>, HashSet<Node>> backlinks = 117 new HashMap<Pair<Relation,String>, HashSet<Node>>(); 118 HashSet<Relation> relationsUsingNodes = new HashSet<Relation>(); 119 for (Relation r : Main.ds.relations) { 120 if (r.deleted || r.incomplete) continue; 121 for (RelationMember rm : r.members) { 122 if (rm.member instanceof Node) { 123 for (Node n : allNodes) { 124 if (rm.member == n) { 125 Pair<Relation,String> pair = new Pair<Relation,String>(r, rm.role); 126 HashSet<Node> nodelinks = new HashSet<Node>(); 127 if (backlinks.containsKey(pair)) { 128 nodelinks = backlinks.get(pair); 129 } else { 130 nodelinks = new HashSet<Node>(); 131 backlinks.put(pair, nodelinks); 132 } 133 nodelinks.add(n); 134 135 // this is just a cache for later use 136 relationsUsingNodes.add(r); 137 } 138 } 139 } 140 } 141 } 142 143 // Complain to the user if the ways don't have equal memberships. 144 for (HashSet<Node> nodelinks : backlinks.values()) { 145 if (!nodelinks.containsAll(allNodes)) { 146 int option = JOptionPane.showConfirmDialog(Main.parent, 147 tr("The selected nodes have differing relation memberships. " 148 + "Do you still want to merge them?"), 149 tr("Merge nodes with different memberships?"), 150 JOptionPane.YES_NO_OPTION); 151 if (option == JOptionPane.YES_OPTION) 152 break; 153 return null; 154 } 155 } 156 157 // collect properties for later conflict resolving 158 Map<String, Set<String>> props = new TreeMap<String, Set<String>>(); 159 for (Node n : allNodes) { 160 for (Entry<String,String> e : n.entrySet()) { 161 if (!props.containsKey(e.getKey())) 162 props.put(e.getKey(), new TreeSet<String>()); 163 props.get(e.getKey()).add(e.getValue()); 164 } 165 } 166 167 // display conflict dialog 168 Map<String, JComboBox> components = new HashMap<String, JComboBox>(); 169 JPanel p = new JPanel(new GridBagLayout()); 170 for (Entry<String, Set<String>> e : props.entrySet()) { 171 if (TigerUtils.isTigerTag(e.getKey())) { 172 String combined = TigerUtils.combineTags(e.getKey(), e.getValue()); 173 newNode.put(e.getKey(), combined); 174 } else if (e.getValue().size() > 1) { 175 if("created_by".equals(e.getKey())) 176 { 177 newNode.put("created_by", "JOSM"); 178 } 179 else 180 { 181 JComboBox c = new JComboBox(e.getValue().toArray()); 182 c.setEditable(true); 183 p.add(new JLabel(e.getKey()), GBC.std()); 184 p.add(Box.createHorizontalStrut(10), GBC.std()); 185 p.add(c, GBC.eol()); 186 components.put(e.getKey(), c); 187 } 188 } else 189 newNode.put(e.getKey(), e.getValue().iterator().next()); 190 } 191 192 if (!components.isEmpty()) { 193 int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter values for all conflicts."), JOptionPane.OK_CANCEL_OPTION); 194 if (answer != JOptionPane.OK_OPTION) 195 return null; 196 for (Entry<String, JComboBox> e : components.entrySet()) 197 newNode.put(e.getKey(), e.getValue().getEditor().getItem().toString()); 198 } 199 200 LinkedList<Command> cmds = new LinkedList<Command>(); 201 cmds.add(new ChangeCommand(dest, newNode)); 202 203 Collection<OsmPrimitive> del = new HashSet<OsmPrimitive>(); 204 205 for (Way w : Main.ds.ways) { 206 if (w.deleted || w.incomplete || w.nodes.size() < 1) continue; 207 boolean modify = false; 208 for (Node sn : allNodes) { 209 if (sn == dest) continue; 210 if (w.nodes.contains(sn)) { 211 modify = true; 212 } 213 } 214 if (!modify) continue; 215 // OK - this way contains one or more nodes to change 216 ArrayList<Node> nn = new ArrayList<Node>(); 217 Node lastNode = null; 218 for (int i = 0; i < w.nodes.size(); i++) { 219 Node pushNode = w.nodes.get(i); 220 if (allNodes.contains(pushNode)) { 221 pushNode = dest; 222 } 223 if (pushNode != lastNode) { 224 nn.add(pushNode); 225 } 226 lastNode = pushNode; 227 } 228 if (nn.size() < 2) { 229 CollectBackReferencesVisitor backRefs = 230 new CollectBackReferencesVisitor(Main.ds, false); 231 w.visit(backRefs); 232 if (!backRefs.data.isEmpty()) { 233 JOptionPane.showMessageDialog(Main.parent, 234 tr("Cannot merge nodes: " + 235 "Would have to delete a way that is still used.")); 236 return null; 237 } 238 del.add(w); 239 } else { 240 Way newWay = new Way(w); 241 newWay.nodes.clear(); 242 newWay.nodes.addAll(nn); 243 cmds.add(new ChangeCommand(w, newWay)); 244 } 245 } 246 247 // delete any merged nodes 248 del.addAll(allNodes); 249 del.remove(dest); 250 if (!del.isEmpty()) cmds.add(new DeleteCommand(del)); 251 252 // modify all relations containing the now-deleted nodes 253 for (Relation r : relationsUsingNodes) { 254 Relation newRel = new Relation(r); 255 newRel.members.clear(); 256 HashSet<String> rolesToReAdd = new HashSet<String>(); 257 for (RelationMember rm : r.members) { 258 // Don't copy the member if it points to one of our nodes, 259 // just keep a note to re-add it later on. 260 if (allNodes.contains(rm.member)) { 261 rolesToReAdd.add(rm.role); 262 } else { 263 newRel.members.add(rm); 264 } 265 } 266 for (String role : rolesToReAdd) { 267 newRel.members.add(new RelationMember(role, dest)); 268 } 269 cmds.add(new ChangeCommand(r, newRel)); 270 } 271 272 Main.main.undoRedo.add(new SequenceCommand(tr("Merge {0} nodes", allNodes.size()), cmds)); 273 Main.ds.setSelected(dest); 274 275 return dest; 276 } 277 278 279 /** 280 * Enable the "Merge Nodes" menu option if more then one node is selected 281 */ 282 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 283 boolean ok = true; 284 if (newSelection.size() < 2) { 285 setEnabled(false); 286 return; 287 } 288 for (OsmPrimitive osm : newSelection) { 289 if (!(osm instanceof Node)) { 290 ok = false; 291 break; 292 } 293 } 294 setEnabled(ok); 295 } 296 296 } -
trunk/src/org/openstreetmap/josm/actions/MoveAction.java
r1084 r1169 26 26 public class MoveAction extends JosmAction { 27 27 28 29 28 public enum Direction { UP, LEFT, RIGHT, DOWN } 29 private Direction myDirection; 30 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 31 // any better idea? 32 private static Object calltosupermustbefirststatementinconstructor(Direction dir, boolean text) { 33 Shortcut sc; 34 String directiontext; 35 if (dir == Direction.UP) { 36 directiontext = tr("up"); 37 sc = Shortcut.registerShortcut("core:moveup", tr("Move objects {0}", directiontext), KeyEvent.VK_UP, Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT); 38 } else if (dir == Direction.DOWN) { 39 directiontext = tr("down"); 40 sc = Shortcut.registerShortcut("core:movedown", tr("Move objects {0}", directiontext), KeyEvent.VK_DOWN, Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT); 41 } else if (dir == Direction.LEFT) { 42 directiontext = tr("left"); 43 sc = Shortcut.registerShortcut("core:moveleft", tr("Move objects {0}", directiontext), KeyEvent.VK_LEFT, Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT); 44 } else { //dir == Direction.RIGHT) { 45 directiontext = tr("right"); 46 sc = Shortcut.registerShortcut("core:moveright", tr("Move objects {0}", directiontext), KeyEvent.VK_RIGHT, Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT); 47 } 48 if (text) { 49 return directiontext; 50 } else { 51 return sc; 52 } 53 } 54 54 55 56 57 58 59 60 55 public MoveAction(Direction dir) { 56 super(tr("Move {0}", calltosupermustbefirststatementinconstructor(dir, true)), null, 57 tr("Moves Objects {0}", calltosupermustbefirststatementinconstructor(dir, true)), 58 (Shortcut)calltosupermustbefirststatementinconstructor(dir, false), true); 59 myDirection = dir; 60 } 61 61 62 62 public void actionPerformed(ActionEvent event) { 63 63 64 65 64 // find out how many "real" units the objects have to be moved in order to 65 // achive an 1-pixel movement 66 66 67 68 67 EastNorth en1 = Main.map.mapView.getEastNorth(100, 100); 68 EastNorth en2 = Main.map.mapView.getEastNorth(101, 101); 69 69 70 71 70 double distx = en2.east() - en1.east(); 71 double disty = en2.north() - en1.north(); 72 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 73 switch (myDirection) { 74 case UP: 75 distx = 0; 76 disty = -disty; 77 break; 78 case DOWN: 79 distx = 0; 80 break; 81 case LEFT: 82 disty = 0; 83 distx = -distx; 84 default: 85 disty = 0; 86 } 87 87 88 89 88 Collection<OsmPrimitive> selection = Main.ds.getSelected(); 89 Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(selection); 90 90 91 92 91 Command c = !Main.main.undoRedo.commands.isEmpty() 92 ? Main.main.undoRedo.commands.getLast() : null; 93 93 94 95 96 97 98 94 if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).objects)) 95 ((MoveCommand)c).moveAgain(distx, disty); 96 else 97 Main.main.undoRedo.add( 98 c = new MoveCommand(selection, distx, disty)); 99 99 100 101 102 103 104 105 106 107 108 100 for (Node n : affectedNodes) { 101 if (n.coor.isOutSideWorld()) { 102 // Revert move 103 ((MoveCommand) c).moveAgain(-distx, -disty); 104 JOptionPane.showMessageDialog(Main.parent, 105 tr("Cannot move objects outside of the world.")); 106 return; 107 } 108 } 109 109 110 111 110 Main.map.mapView.repaint(); 111 } 112 112 } -
trunk/src/org/openstreetmap/josm/actions/NewAction.java
r1084 r1169 14 14 public class NewAction extends JosmAction { 15 15 16 17 18 19 16 public NewAction() { 17 super(tr("New"), "new", tr("Create a new map."), 18 Shortcut.registerShortcut("system:new", tr("File: {0}", tr("New")), KeyEvent.VK_N, Shortcut.GROUP_MENU), true); 19 } 20 20 21 22 23 21 public void actionPerformed(ActionEvent e) { 22 Main.main.addLayer(new OsmDataLayer(new DataSet(), tr("unnamed"), null)); 23 } 24 24 } -
trunk/src/org/openstreetmap/josm/actions/OpenFileAction.java
r1167 r1169 35 35 public class OpenFileAction extends DiskAccessAction { 36 36 37 /** 38 * Create an open action. The name is "Open a file". 39 */ 40 public OpenFileAction() { 41 super(tr("Open ..."), "open", tr("Open a file."), 42 Shortcut.registerShortcut("system:open", tr("File: {0}", tr("Open ...")), KeyEvent.VK_O, Shortcut.GROUP_MENU)); 43 } 44 45 public void actionPerformed(ActionEvent e) { 46 JFileChooser fc = createAndOpenFileChooser(true, true, null); 47 if (fc == null) 48 return; 49 File[] files = fc.getSelectedFiles(); 50 for (int i = files.length; i > 0; --i) 51 openFile(files[i-1]); 52 } 53 54 /** 55 * Open the given file. 56 */ 57 public void openFile(File file) { 58 try { 59 if (asGpxData(file.getName())) 60 openFileAsGpx(file); 61 else if (asNmeaData(file.getName())) 62 openFileAsNmea(file); 63 else 64 openAsData(file); 65 } catch (SAXException x) { 66 x.printStackTrace(); 67 JOptionPane.showMessageDialog(Main.parent, tr("Error while parsing {0}",file.getName())+": "+x.getMessage()); 68 } catch (IOException x) { 69 x.printStackTrace(); 70 JOptionPane.showMessageDialog(Main.parent, tr("Could not read \"{0}\"",file.getName())+"\n"+x.getMessage()); 71 } 72 } 73 74 private void openAsData(File file) throws SAXException, IOException, FileNotFoundException { 75 String fn = file.getName(); 76 if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(fn)) { 77 DataSet dataSet = OsmReader.parseDataSet(new FileInputStream(file), null, Main.pleaseWaitDlg); 78 OsmDataLayer layer = new OsmDataLayer(dataSet, file.getName(), file); 79 Main.main.addLayer(layer); 80 layer.fireDataChange(); 81 } 82 else 83 JOptionPane.showMessageDialog(Main.parent, fn+": "+tr("Unknown file extension: {0}", fn.substring(file.getName().lastIndexOf('.')+1))); 84 } 85 86 private void openFileAsGpx(File file) throws SAXException, IOException, FileNotFoundException { 87 String fn = file.getName(); 88 if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn)) { 89 GpxReader r = null; 90 InputStream is; 91 if (file.getName().endsWith(".gpx.gz")) { 92 is = new GZIPInputStream(new FileInputStream(file)); 93 } else { 94 is = new FileInputStream(file); 95 } 96 // Workaround for SAX BOM bug 97 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6206835 98 if(!((is.read()==0xef)&&(is.read()==0xbb)&&(is.read()==0xbf))) { 99 is.close(); 100 if (file.getName().endsWith(".gpx.gz")) { 101 is = new GZIPInputStream(new FileInputStream(file)); 102 } else { 103 is = new FileInputStream(file); 104 } 105 } 106 r = new GpxReader(is,file.getAbsoluteFile().getParentFile()); 107 r.data.storageFile = file; 108 GpxLayer gpxLayer = new GpxLayer(r.data, fn); 109 Main.main.addLayer(gpxLayer); 110 if (Main.pref.getBoolean("marker.makeautomarkers", true)) { 111 MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer); 112 if (ml.data.size() > 0) { 113 Main.main.addLayer(ml); 114 } 115 } 116 117 } else { 118 throw new IllegalStateException(); 119 } 120 } 121 122 private void showNmeaInfobox(boolean success, NmeaReader r) { 123 String msg = tr("Coordinates imported: ") + r.getNumberOfCoordinates() + "\n" + 124 tr("Malformed sentences: ") + r.getParserMalformed() + "\n" + 125 tr("Checksum errors: ") + r.getParserChecksumErrors() + "\n"; 126 if(!success) // don't scare the user unneccessarily 127 msg += tr("Unknown sentences: ") + r.getParserUnknown() + "\n"; 128 msg += tr("Zero coordinates: ") + r.getParserZeroCoordinates(); 129 if(success) { 130 JOptionPane.showMessageDialog( 131 Main.parent, msg, 132 tr("NMEA import success"),JOptionPane.INFORMATION_MESSAGE); 133 } else { 134 JOptionPane.showMessageDialog( 135 Main.parent, msg, 136 tr("NMEA import faliure!"),JOptionPane.ERROR_MESSAGE); 137 } 138 } 139 140 private void openFileAsNmea(File file) throws IOException, FileNotFoundException { 141 String fn = file.getName(); 142 if (ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn)) { 143 NmeaReader r = new NmeaReader(new FileInputStream(file), file.getAbsoluteFile().getParentFile()); 144 if(r.getNumberOfCoordinates()>0) { 145 r.data.storageFile = file; 146 GpxLayer gpxLayer = new GpxLayer(r.data, fn); 147 Main.main.addLayer(gpxLayer); 148 if (Main.pref.getBoolean("marker.makeautomarkers", true)) { 149 MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer); 150 if (ml.data.size() > 0) { 151 Main.main.addLayer(ml); 152 } 153 } 154 } 155 showNmeaInfobox(r.getNumberOfCoordinates()>0, r); 156 } else { 157 throw new IllegalStateException(); 158 } 37 /** 38 * Create an open action. The name is "Open a file". 39 */ 40 public OpenFileAction() { 41 super(tr("Open ..."), "open", tr("Open a file."), 42 Shortcut.registerShortcut("system:open", tr("File: {0}", tr("Open ...")), KeyEvent.VK_O, Shortcut.GROUP_MENU)); 159 43 } 160 44 161 private boolean asGpxData(String fn) { 162 return ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn); 163 } 45 public void actionPerformed(ActionEvent e) { 46 JFileChooser fc = createAndOpenFileChooser(true, true, null); 47 if (fc == null) 48 return; 49 File[] files = fc.getSelectedFiles(); 50 for (int i = files.length; i > 0; --i) 51 openFile(files[i-1]); 52 } 164 53 165 private boolean asNmeaData(String fn) { 166 return ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn); 167 } 54 /** 55 * Open the given file. 56 */ 57 public void openFile(File file) { 58 try { 59 if (asGpxData(file.getName())) 60 openFileAsGpx(file); 61 else if (asNmeaData(file.getName())) 62 openFileAsNmea(file); 63 else 64 openAsData(file); 65 } catch (SAXException x) { 66 x.printStackTrace(); 67 JOptionPane.showMessageDialog(Main.parent, tr("Error while parsing {0}",file.getName())+": "+x.getMessage()); 68 } catch (IOException x) { 69 x.printStackTrace(); 70 JOptionPane.showMessageDialog(Main.parent, tr("Could not read \"{0}\"",file.getName())+"\n"+x.getMessage()); 71 } 72 } 73 74 private void openAsData(File file) throws SAXException, IOException, FileNotFoundException { 75 String fn = file.getName(); 76 if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(fn)) { 77 DataSet dataSet = OsmReader.parseDataSet(new FileInputStream(file), null, Main.pleaseWaitDlg); 78 OsmDataLayer layer = new OsmDataLayer(dataSet, file.getName(), file); 79 Main.main.addLayer(layer); 80 layer.fireDataChange(); 81 } 82 else 83 JOptionPane.showMessageDialog(Main.parent, fn+": "+tr("Unknown file extension: {0}", fn.substring(file.getName().lastIndexOf('.')+1))); 84 } 85 86 private void openFileAsGpx(File file) throws SAXException, IOException, FileNotFoundException { 87 String fn = file.getName(); 88 if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn)) { 89 GpxReader r = null; 90 InputStream is; 91 if (file.getName().endsWith(".gpx.gz")) { 92 is = new GZIPInputStream(new FileInputStream(file)); 93 } else { 94 is = new FileInputStream(file); 95 } 96 // Workaround for SAX BOM bug 97 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6206835 98 if(!((is.read()==0xef)&&(is.read()==0xbb)&&(is.read()==0xbf))) { 99 is.close(); 100 if (file.getName().endsWith(".gpx.gz")) { 101 is = new GZIPInputStream(new FileInputStream(file)); 102 } else { 103 is = new FileInputStream(file); 104 } 105 } 106 r = new GpxReader(is,file.getAbsoluteFile().getParentFile()); 107 r.data.storageFile = file; 108 GpxLayer gpxLayer = new GpxLayer(r.data, fn); 109 Main.main.addLayer(gpxLayer); 110 if (Main.pref.getBoolean("marker.makeautomarkers", true)) { 111 MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer); 112 if (ml.data.size() > 0) { 113 Main.main.addLayer(ml); 114 } 115 } 116 117 } else { 118 throw new IllegalStateException(); 119 } 120 } 121 122 private void showNmeaInfobox(boolean success, NmeaReader r) { 123 String msg = tr("Coordinates imported: ") + r.getNumberOfCoordinates() + "\n" + 124 tr("Malformed sentences: ") + r.getParserMalformed() + "\n" + 125 tr("Checksum errors: ") + r.getParserChecksumErrors() + "\n"; 126 if(!success) // don't scare the user unneccessarily 127 msg += tr("Unknown sentences: ") + r.getParserUnknown() + "\n"; 128 msg += tr("Zero coordinates: ") + r.getParserZeroCoordinates(); 129 if(success) { 130 JOptionPane.showMessageDialog( 131 Main.parent, msg, 132 tr("NMEA import success"),JOptionPane.INFORMATION_MESSAGE); 133 } else { 134 JOptionPane.showMessageDialog( 135 Main.parent, msg, 136 tr("NMEA import faliure!"),JOptionPane.ERROR_MESSAGE); 137 } 138 } 139 140 private void openFileAsNmea(File file) throws IOException, FileNotFoundException { 141 String fn = file.getName(); 142 if (ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn)) { 143 NmeaReader r = new NmeaReader(new FileInputStream(file), file.getAbsoluteFile().getParentFile()); 144 if(r.getNumberOfCoordinates()>0) { 145 r.data.storageFile = file; 146 GpxLayer gpxLayer = new GpxLayer(r.data, fn); 147 Main.main.addLayer(gpxLayer); 148 if (Main.pref.getBoolean("marker.makeautomarkers", true)) { 149 MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer); 150 if (ml.data.size() > 0) { 151 Main.main.addLayer(ml); 152 } 153 } 154 } 155 showNmeaInfobox(r.getNumberOfCoordinates()>0, r); 156 } else { 157 throw new IllegalStateException(); 158 } 159 } 160 161 private boolean asGpxData(String fn) { 162 return ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn); 163 } 164 165 private boolean asNmeaData(String fn) { 166 return ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn); 167 } 168 168 169 169 -
trunk/src/org/openstreetmap/josm/actions/OpenLocationAction.java
r1148 r1169 42 42 public class OpenLocationAction extends JosmAction { 43 43 44 45 46 47 48 49 50 44 /** 45 * Create an open action. The name is "Open a file". 46 */ 47 public OpenLocationAction() { 48 super(tr("Open Location..."), "openlocation", tr("Open a URL."), 49 Shortcut.registerShortcut("system:open_location", tr("File: {0}", tr("Open Location...")), KeyEvent.VK_L, Shortcut.GROUP_MENU), true); 50 } 51 51 52 52 public void actionPerformed(ActionEvent e) { 53 53 54 55 56 57 58 59 60 61 62 63 64 65 54 JCheckBox layer = new JCheckBox(tr("Separate Layer")); 55 layer.setSelected(Main.pref.getBoolean("download.newlayer")); 56 JPanel all = new JPanel(new GridBagLayout()); 57 all.add(new JLabel("Enter URL to download:"), GBC.eol()); 58 JTextField urltext = new JTextField(40); 59 all.add(urltext, GBC.eol()); 60 all.add(layer, GBC.eol()); 61 int answer = JOptionPane.showConfirmDialog(Main.parent, all, tr("Download Location"), JOptionPane.OK_CANCEL_OPTION); 62 if (answer != JOptionPane.OK_OPTION) 63 return; 64 openUrl(layer.isSelected(), urltext.getText()); 65 } 66 66 67 68 69 70 71 72 67 /** 68 * Open the given file. 69 */ 70 public void openUrl(boolean new_layer, String url) { 71 new DownloadOsmTask().loadUrl(new_layer, url); 72 } 73 73 74 74 } -
trunk/src/org/openstreetmap/josm/actions/OrthogonalizeAction.java
r1090 r1169 28 28 29 29 /** 30 * Align edges of a way so all angles are right angles. 31 * 30 * Align edges of a way so all angles are right angles. 31 * 32 32 * 1. Find orientation of all edges 33 33 * 2. Compute main orientation, weighted by length of edge, normalized to angles between 0 and pi/2 … … 38 38 public final class OrthogonalizeAction extends JosmAction { 39 39 40 41 super(tr("Orthogonalize shape"), 42 "ortho", 40 public OrthogonalizeAction() { 41 super(tr("Orthogonalize shape"), 42 "ortho", 43 43 tr("Move nodes so all angles are 90 or 270deg"), 44 Shortcut.registerShortcut("tools:orthogonalize", tr("Tool: {0}", tr("Orthogonalize")), 45 KeyEvent.VK_Q, 44 Shortcut.registerShortcut("tools:orthogonalize", tr("Tool: {0}", tr("Orthogonalize")), 45 KeyEvent.VK_Q, 46 46 Shortcut.GROUP_EDIT), true); 47 47 } 48 48 49 49 public void actionPerformed(ActionEvent e) { … … 60 60 JOptionPane.showMessageDialog(Main.parent, tr("Only two nodes allowed")); 61 61 return; 62 } 62 } 63 63 dirnodes.add((Node) osm); 64 64 continue; … … 68 68 JOptionPane.showMessageDialog(Main.parent, tr("Selection must consist only of ways.")); 69 69 return; 70 } 70 } 71 71 72 72 // Check if every way is made of at least four segments and closed … … 78 78 79 79 // Check if every edge in the way is a definite edge of at least 45 degrees of direction change 80 // Otherwise, two segments could be turned into same direction and intersection would fail. 80 // Otherwise, two segments could be turned into same direction and intersection would fail. 81 81 // Or changes of shape would be too serious. 82 82 for (int i1=0; i1 < way.nodes.size()-1; i1++) { … … 116 116 boolean use_dirnodes = false; 117 117 118 if (dirnodes.size() == 2) { 119 // When selection contains two nodes, use the nodes to compute a direction 118 if (dirnodes.size() == 2) { 119 // When selection contains two nodes, use the nodes to compute a direction 120 120 // to align all ways to 121 121 align_to_heading = normalize_angle(dirnodes.get(0).eastNorth.heading(dirnodes.get(1).eastNorth)); … … 124 124 125 125 for (OsmPrimitive osm : sel) { 126 if(!(osm instanceof Way)) 126 if(!(osm instanceof Way)) 127 127 continue; 128 128 … … 164 164 165 165 if (angle_diff_max > Math.PI/3) { 166 // rearrange headings: everything < 0 gets PI/2-rotated 166 // rearrange headings: everything < 0 gets PI/2-rotated 167 167 for (int i=0; i < sides; i++) { 168 if (headings[i] < 0) 168 if (headings[i] < 0) 169 169 headings[i] += Math.PI/2; 170 170 } … … 183 183 sum_weights += weights[i]; 184 184 } 185 align_to_heading = normalize_angle(sum_weighted_headings/sum_weights); 185 align_to_heading = normalize_angle(sum_weighted_headings/sum_weights); 186 186 } 187 187 188 188 189 189 for (int i=0; i < sides; i++) { 190 // Compute handy indices of three nodes to be used in one loop iteration. 191 // We use segments (i1,i2) and (i2,i3), align them and compute the new 190 // Compute handy indices of three nodes to be used in one loop iteration. 191 // We use segments (i1,i2) and (i2,i3), align them and compute the new 192 192 // position of the i2-node as the intersection of the realigned (i1,i2), (i2,i3) segments 193 193 // Not the most efficient algorithm, but we don't handle millions of nodes... … … 212 212 213 213 // compute intersection of segments 214 double u=det(B.east() - A.east(), B.north() - A.north(), 214 double u=det(B.east() - A.east(), B.north() - A.north(), 215 215 C.east() - D.east(), C.north() - D.north()); 216 216 217 217 // Check for parallel segments and do nothing if they are 218 // In practice this will probably only happen when a way has 218 // In practice this will probably only happen when a way has 219 219 // been duplicated 220 220 … … 225 225 // if the segment is scaled to length 1 226 226 227 double q = det(B.north() - C.north(), B.east() - C.east(), 227 double q = det(B.north() - C.north(), B.east() - C.east(), 228 228 D.north() - C.north(), D.east() - C.east()) / u; 229 229 EastNorth intersection = new EastNorth( … … 239 239 cmds.add(new MoveCommand(n, dx, dy)); 240 240 } 241 } 241 } 242 242 } 243 243 -
trunk/src/org/openstreetmap/josm/actions/PasteAction.java
r1084 r1169 29 29 30 30 public PasteAction() { 31 32 33 31 super(tr("Paste"), "paste", tr("Paste contents of paste buffer."), 32 Shortcut.registerShortcut("system:paste", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_V, Shortcut.GROUP_MENU), true); 33 setEnabled(false); 34 34 } 35 35 36 37 36 public void actionPerformed(ActionEvent e) { 37 DataSet pasteBuffer = Main.pasteBuffer; 38 38 39 40 41 42 43 44 45 46 47 48 39 /* Find the middle of the pasteBuffer area */ 40 double maxEast = -1E100, minEast = 1E100, maxNorth = -1E100, minNorth = 1E100; 41 for (Node n : pasteBuffer.nodes) { 42 double east = n.eastNorth.east(); 43 double north = n.eastNorth.north(); 44 if (east > maxEast) { maxEast = east; } 45 if (east < minEast) { minEast = east; } 46 if (north > maxNorth) { maxNorth = north; } 47 if (north < minNorth) { minNorth = north; } 48 } 49 49 50 51 52 53 54 55 50 EastNorth mPosition; 51 if((e.getModifiers() & ActionEvent.CTRL_MASK) ==0){ 52 mPosition = Main.map.mapView.getCenter(); 53 } else { 54 mPosition = Main.map.mapView.getEastNorth(Main.map.mapView.lastMEvent.getX(), Main.map.mapView.lastMEvent.getY()); 55 } 56 56 57 58 57 double offsetEast = mPosition.east() - (maxEast + minEast)/2.0; 58 double offsetNorth = mPosition.north() - (maxNorth + minNorth)/2.0; 59 59 60 61 60 HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>(); 61 /* temporarily maps old nodes to new so we can do a true deep copy */ 62 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 63 /* do the deep copy of the paste buffer contents, leaving the pasteBuffer unchanged */ 64 for (Node n : pasteBuffer.nodes) { 65 Node nnew = new Node(n); 66 nnew.id = 0; 67 /* adjust the coordinates to the middle of the visible map area */ 68 nnew.eastNorth = new EastNorth(nnew.eastNorth.east() + offsetEast, nnew.eastNorth.north() + offsetNorth); 69 nnew.coor = Main.proj.eastNorth2latlon(nnew.eastNorth); 70 map.put(n, nnew); 71 } 72 for (Way w : pasteBuffer.ways) { 73 Way wnew = new Way(); 74 wnew.cloneFrom(w); 75 wnew.id = 0; 76 /* make sure we reference the new nodes corresponding to the old ones */ 77 List<Node> nodes = new ArrayList<Node>(); 78 for (Node n : w.nodes) { 79 nodes.add((Node)map.get(n)); 80 } 81 wnew.nodes.clear(); 82 wnew.nodes.addAll(nodes); 83 map.put(w, wnew); 84 } 85 for (Relation r : pasteBuffer.relations) { 86 Relation rnew = new Relation(r); 87 rnew.id = 0; 88 List<RelationMember> members = new ArrayList<RelationMember>(); 89 for (RelationMember m : r.members) { 90 RelationMember mnew = new RelationMember(m); 91 mnew.member = map.get(m.member); 92 members.add(mnew); 93 } 94 rnew.members.clear(); 95 rnew.members.addAll(members); 96 map.put(r, rnew); 97 } 98 98 99 100 101 102 103 104 99 /* Now execute the commands to add the dupicated contents of the paste buffer to the map */ 100 Collection<OsmPrimitive> osms = map.values(); 101 Collection<Command> clist = new LinkedList<Command>(); 102 for (OsmPrimitive osm : osms) { 103 clist.add(new AddCommand(osm)); 104 } 105 105 106 107 108 106 Main.main.undoRedo.add(new SequenceCommand(tr("Paste"), clist)); 107 Main.ds.setSelected(osms); 108 Main.map.mapView.repaint(); 109 109 } 110 110 } -
trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java
r1084 r1169 24 24 public final class PasteTagsAction extends JosmAction implements SelectionChangedListener { 25 25 26 27 28 29 30 31 32 33 26 public PasteTagsAction(JosmAction copyAction) { 27 super(tr("Paste Tags"), "pastetags", 28 tr("Apply tags of contents of paste buffer to all selected items."), 29 Shortcut.registerShortcut("system:pastestyle", tr("Edit: {0}", tr("Paste Tags")), KeyEvent.VK_V, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), true); 30 DataSet.selListeners.add(this); 31 copyAction.addListener(this); 32 setEnabled(false); 33 } 34 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 35 private void pasteKeys(Collection<Command> clist, Collection<? extends OsmPrimitive> pasteBufferSubset, Collection<OsmPrimitive> selectionSubset) { 36 /* scan the paste buffer, and add tags to each of the selected objects. 37 * If a tag already exists, it is overwritten */ 38 if (selectionSubset != null && ! selectionSubset.isEmpty()) { 39 for (Iterator<? extends OsmPrimitive> it = pasteBufferSubset.iterator(); it.hasNext();) { 40 OsmPrimitive osm = it.next(); 41 Map<String, String> m = osm.keys; 42 if(m != null) 43 { 44 for (String key : m.keySet()) { 45 if (! key.equals("created_by")) 46 clist.add(new ChangePropertyCommand(selectionSubset, key, osm.keys.get(key))); 47 } 48 } 49 } 50 } 51 } 52 52 53 54 55 56 57 58 59 60 61 53 public void actionPerformed(ActionEvent e) { 54 Collection<Command> clist = new LinkedList<Command>(); 55 pasteKeys(clist, Main.pasteBuffer.nodes, Main.ds.getSelectedNodes()); 56 pasteKeys(clist, Main.pasteBuffer.ways, Main.ds.getSelectedWays()); 57 pasteKeys(clist, Main.pasteBuffer.relations, Main.ds.getSelectedRelations()); 58 Main.main.undoRedo.add(new SequenceCommand(tr("Paste Tags"), clist)); 59 Main.ds.setSelected(Main.ds.getSelected()); // to force selection listeners, in particular the tag panel, to update 60 Main.map.mapView.repaint(); 61 } 62 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 63 private boolean containsSameKeysWithDifferentValues(Collection<? extends OsmPrimitive> osms) { 64 Map<String,String> kvSeen = new HashMap<String,String>(); 65 for (Iterator<? extends OsmPrimitive> it = osms.iterator(); it.hasNext();) { 66 OsmPrimitive osm = it.next(); 67 if (osm.keys == null || osm.keys.isEmpty()) 68 continue; 69 for (String key : osm.keys.keySet()) { 70 if (key.equals("created_by")) // we ignore created_by 71 continue; 72 String value = osm.keys.get(key); 73 if (! kvSeen.containsKey(key)) 74 kvSeen.put(key, value); 75 else if (! kvSeen.get(key).equals(value)) 76 return true; 77 } 78 } 79 return false; 80 } 81 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 82 /** 83 * Determines whether to enable the widget depending on the contents of the paste 84 * buffer and current selection 85 * @param pasteBuffer 86 */ 87 private void possiblyEnable(Collection<? extends OsmPrimitive> selection, DataSet pasteBuffer) { 88 /* only enable if there is something selected to paste into and 89 if we don't have conflicting keys in the pastebuffer */ 90 setEnabled(selection != null && 91 ! selection.isEmpty() && 92 ! pasteBuffer.allPrimitives().isEmpty() && 93 (Main.ds.getSelectedNodes().isEmpty() || 94 ! containsSameKeysWithDifferentValues(pasteBuffer.nodes)) && 95 (Main.ds.getSelectedWays().isEmpty() || 96 ! containsSameKeysWithDifferentValues(pasteBuffer.ways)) && 97 (Main.ds.getSelectedRelations().isEmpty() || 98 ! containsSameKeysWithDifferentValues(pasteBuffer.relations))); 99 } 100 100 101 102 103 101 @Override public void pasteBufferChanged(DataSet newPasteBuffer) { 102 possiblyEnable(Main.ds.getSelected(), newPasteBuffer); 103 } 104 104 105 106 107 105 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 106 possiblyEnable(newSelection, Main.pasteBuffer); 107 } 108 108 } -
trunk/src/org/openstreetmap/josm/actions/PreferencesAction.java
r1084 r1169 25 25 public class PreferencesAction extends JosmAction { 26 26 27 28 29 30 31 32 33 27 /** 28 * Create the preference action with "&Preferences" as label. 29 */ 30 public PreferencesAction() { 31 super(tr("Preferences ..."), "preference", tr("Open a preferences page for global settings."), 32 Shortcut.registerShortcut("system:preferences", tr("Preferences"), KeyEvent.VK_F12, Shortcut.GROUP_DIRECT), true); 33 } 34 34 35 36 37 38 39 40 41 42 35 /** 36 * Launch the preferences dialog. 37 */ 38 public void actionPerformed(ActionEvent e) { 39 PreferenceDialog prefDlg = new PreferenceDialog(); 40 prefDlg.setMinimumSize(new Dimension(400,300)); 41 JPanel prefPanel = new JPanel(new GridBagLayout()); 42 prefPanel.add(prefDlg, GBC.eol().fill(GBC.BOTH)); 43 43 44 45 46 47 44 JOptionPane pane = new JOptionPane(prefPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION); 45 JDialog dlg = pane.createDialog(Main.parent, tr("Preferences")); 46 dlg.setResizable(true); 47 dlg.setMinimumSize(new Dimension(500,400)); 48 48 49 // 50 // 51 // 52 // 49 // if (dlg.getWidth() > 600) 50 // dlg.setSize(600, dlg.getHeight()); 51 // if (dlg.getHeight() > 600) 52 // dlg.setSize(dlg.getWidth(),600); 53 53 54 55 54 int JOSMWidth = Main.parent.getWidth(); 55 int JOSMHeight = Main.parent.getHeight(); 56 56 57 58 59 57 if (JOSMWidth > 2000 && JOSMWidth > JOSMHeight * 2) 58 // don't center on horizontal span monitor configurations (yes, can be selfish sometimes) 59 JOSMWidth /= 2; 60 60 61 62 63 64 65 66 61 int targetWidth = JOSMWidth / 2; 62 if (targetWidth < 600) targetWidth = 600; 63 if (targetWidth > 1200) targetWidth = 1200; 64 int targetHeight = (JOSMHeight * 3) / 4; 65 if (targetHeight < 600) targetHeight = 600; 66 if (targetHeight > 1200) targetHeight = 1200; 67 67 68 69 68 int targetX = Main.parent.getX() + JOSMWidth / 2 - targetWidth / 2; 69 int targetY = Main.parent.getY() + JOSMHeight / 2 - targetHeight / 2; 70 70 71 71 dlg.setBounds(targetX, targetY, targetWidth, targetHeight); 72 72 73 74 75 76 73 dlg.setVisible(true); 74 if (pane.getValue() instanceof Integer && (Integer)pane.getValue() == JOptionPane.OK_OPTION) 75 prefDlg.ok(); 76 } 77 77 } -
trunk/src/org/openstreetmap/josm/actions/RedoAction.java
r1084 r1169 17 17 public class RedoAction extends JosmAction { 18 18 19 20 21 22 23 24 25 26 19 /** 20 * Construct the action with "Redo" as label. 21 */ 22 public RedoAction() { 23 super(tr("Redo"), "redo", tr("Redo the last undone action."), 24 Shortcut.registerShortcut("system:redo", tr("Edit: {0}", tr("Redo")), KeyEvent.VK_Y, Shortcut.GROUP_MENU), true); 25 setEnabled(false); 26 } 27 27 28 29 30 31 32 33 28 public void actionPerformed(ActionEvent e) { 29 if (Main.map == null) 30 return; 31 Main.map.repaint(); 32 Main.main.undoRedo.redo(); 33 } 34 34 } -
trunk/src/org/openstreetmap/josm/actions/RenameLayerAction.java
r655 r1169 21 21 * Action to rename an specific layer. Provides the option to rename the 22 22 * file, this layer was loaded from as well (if it was loaded from a file). 23 * 23 * 24 24 * @author Imi 25 25 */ 26 26 public class RenameLayerAction extends AbstractAction { 27 27 28 29 28 private File file; 29 private Layer layer; 30 30 31 32 33 *If null, no possibility to "rename the file as well" is provided.34 35 36 37 38 39 40 31 /** 32 * @param file The file of the original location of this layer. 33 * If null, no possibility to "rename the file as well" is provided. 34 */ 35 public RenameLayerAction(File file, Layer layer) { 36 super(tr("Rename layer"), ImageProvider.get("dialogs", "edit")); 37 this.file = file; 38 this.layer = layer; 39 this.putValue("help", "Action/LayerRename"); 40 } 41 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 42 public void actionPerformed(ActionEvent e) { 43 Box panel = Box.createVerticalBox(); 44 final JTextField name = new JTextField(layer.name); 45 panel.add(name); 46 JCheckBox filerename = new JCheckBox(tr("Also rename the file")); 47 if (Main.applet) { 48 filerename.setEnabled(false); 49 filerename.setSelected(false); 50 } else { 51 panel.add(filerename); 52 filerename.setEnabled(file != null); 53 } 54 if (filerename.isEnabled()) 55 filerename.setSelected(Main.pref.getBoolean("layer.rename-file", true)); 56 56 57 58 59 60 61 62 63 64 57 final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION){ 58 @Override public void selectInitialValue() { 59 name.requestFocusInWindow(); 60 name.selectAll(); 61 } 62 }; 63 final JDialog dlg = optionPane.createDialog(Main.parent, tr("Rename layer")); 64 dlg.setVisible(true); 65 65 66 67 68 69 70 66 Object answer = optionPane.getValue(); 67 if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE || 68 (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) { 69 return; 70 } 71 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 72 String nameText = name.getText(); 73 if (filerename.isEnabled()) { 74 Main.pref.put("layer.rename-file", filerename.isSelected()); 75 if (filerename.isSelected()) { 76 String newname = nameText; 77 if (newname.indexOf("/") == -1 && newname.indexOf("\\") == -1) 78 newname = file.getParent() + File.separator + newname; 79 String oldname = file.getName(); 80 if (name.getText().indexOf('.') == -1 && oldname.indexOf('.') >= 0) 81 newname += oldname.substring(oldname.lastIndexOf('.')); 82 File newFile = new File(newname); 83 if (file.renameTo(newFile)) { 84 layer.associatedFile = newFile; 85 nameText = newFile.getName(); 86 } else { 87 JOptionPane.showMessageDialog(Main.parent, tr("Could not rename the file \"{0}\".", file.getPath())); 88 return; 89 } 90 } 91 } 92 layer.name = nameText; 93 Main.parent.repaint(); 94 } 95 95 } -
trunk/src/org/openstreetmap/josm/actions/ReverseWayAction.java
r1084 r1169 28 28 public final class ReverseWayAction extends JosmAction { 29 29 30 31 32 33 30 public ReverseWayAction() { 31 super(tr("Reverse ways"), "wayflip", tr("Reverse the direction of all selected ways."), 32 Shortcut.registerShortcut("tools:reverse", tr("Tool: {0}", tr("Reverse ways")), KeyEvent.VK_R, Shortcut.GROUP_EDIT), true); 33 } 34 34 35 36 37 38 39 35 public void actionPerformed(ActionEvent e) { 36 final Collection<Way> sel = new LinkedList<Way>(); 37 new Visitor() { 38 public void visit(Node n) { 39 } 40 40 41 42 43 41 public void visit(Way w) { 42 sel.add(w); 43 } 44 44 45 46 45 public void visit(Relation e) { 46 } 47 47 48 49 50 51 52 48 public void visitAll() { 49 for (OsmPrimitive osm : Main.ds.getSelected()) 50 osm.visit(this); 51 } 52 }.visitAll(); 53 53 54 55 56 57 58 54 if (sel.isEmpty()) { 55 JOptionPane.showMessageDialog(Main.parent, 56 tr("Please select at least one way.")); 57 return; 58 } 59 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 60 boolean propertiesUpdated = false; 61 ReverseWayTagCorrector reverseWayTagCorrector = new ReverseWayTagCorrector(); 62 Collection<Command> c = new LinkedList<Command>(); 63 for (Way w : sel) { 64 Way wnew = new Way(w); 65 Collections.reverse(wnew.nodes); 66 if (Main.pref.getBoolean("tag-correction.reverse-way", true)) { 67 try 68 { 69 final Collection<Command> changePropertyCommands = reverseWayTagCorrector.execute(wnew); 70 propertiesUpdated = propertiesUpdated 71 || (changePropertyCommands != null && !changePropertyCommands.isEmpty()); 72 c.addAll(changePropertyCommands); 73 } 74 catch(UserCancelException ex) 75 { 76 return; 77 } 78 } 79 c.add(new ChangeCommand(w, wnew)); 80 } 81 Main.main.undoRedo.add(new SequenceCommand(tr("Reverse ways"), c)); 82 if (propertiesUpdated) 83 DataSet.fireSelectionChanged(Main.ds.getSelected()); 84 Main.map.repaint(); 85 } 86 86 } -
trunk/src/org/openstreetmap/josm/actions/SaveAction.java
r1084 r1169 19 19 public class SaveAction extends SaveActionBase { 20 20 21 22 23 24 25 26 27 28 21 /** 22 * Construct the action with "Save" as label. 23 * @param layer Save this layer. 24 */ 25 public SaveAction(Layer layer) { 26 super(tr("Save"), "save", tr("Save the current data."), 27 Shortcut.registerShortcut("system:save", tr("File: {0}", tr("Save")), KeyEvent.VK_S, Shortcut.GROUP_MENU), layer); 28 } 29 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 30 @Override public File getFile(Layer layer) { 31 if (layer instanceof OsmDataLayer) { 32 File f = ((OsmDataLayer)layer).associatedFile; 33 if (f != null) { 34 return f; 35 } 36 } 37 if (layer instanceof GpxLayer) { 38 File f = ((GpxLayer)layer).data.storageFile; 39 if (f != null) { 40 return f; 41 } 42 } 43 return openFileDialog(layer); 44 } 45 45 } -
trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java
r1084 r1169 26 26 public abstract class SaveActionBase extends DiskAccessAction { 27 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 28 private Layer layer; 29 30 public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut, Layer layer) { 31 super(name, iconName, tooltip, shortcut); 32 this.layer = layer; 33 } 34 35 @Deprecated 36 public SaveActionBase(String name, String iconName, String tooltip, int shortcut, int modifiers, Layer layer) { 37 super(name, iconName, tooltip, shortcut, modifiers); 38 this.layer = layer; 39 } 40 41 public void actionPerformed(ActionEvent e) { 42 Layer layer = this.layer; 43 if (layer == null && Main.map != null && (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer 44 || Main.map.mapView.getActiveLayer() instanceof GpxLayer)) 45 layer = Main.map.mapView.getActiveLayer(); 46 if (layer == null) 47 layer = Main.main.editLayer(); 48 49 if (!checkSaveConditions(layer)) 50 return; 51 52 53 File file = getFile(layer); 54 if (file == null) 55 return; 56 57 save(file, layer); 58 59 layer.name = file.getName(); 60 layer.associatedFile = file; 61 Main.parent.repaint(); 62 } 63 64 protected abstract File getFile(Layer layer); 65 66 /** 67 * Checks whether it is ok to launch a save (whether we have data, 68 * there is no conflict etc.) 69 * @return <code>true</code>, if it is safe to save. 70 */ 71 public boolean checkSaveConditions(Layer layer) { 72 if (layer == null) { 73 JOptionPane.showMessageDialog(Main.parent, tr("Internal Error: cannot check conditions for no layer. Please report this as a bug.")); 74 return false; 75 } 76 if (Main.map == null) { 77 JOptionPane.showMessageDialog(Main.parent, tr("No document open so nothing to save.")); 78 return false; 79 } 80 81 if (layer instanceof OsmDataLayer && isDataSetEmpty((OsmDataLayer)layer) && JOptionPane.NO_OPTION == JOptionPane.showConfirmDialog(Main.parent,tr("The document contains no data. Save anyway?"), tr("Empty document"), JOptionPane.YES_NO_OPTION)) { 82 return false; 83 } 84 if (layer instanceof GpxLayer && ((GpxLayer)layer).data == null) { 85 return false; 86 } 87 if (!Main.map.conflictDialog.conflicts.isEmpty()) { 88 int answer = JOptionPane.showConfirmDialog(Main.parent, 89 tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"),tr("Conflicts"), JOptionPane.YES_NO_OPTION); 90 if (answer != JOptionPane.YES_OPTION) 91 return false; 92 } 93 return true; 94 } 95 96 public static File openFileDialog(Layer layer) { 97 JFileChooser fc = createAndOpenFileChooser(false, false, layer instanceof GpxLayer ? tr("Save GPX file") : tr("Save OSM file")); 98 if (fc == null) 99 return null; 100 101 File file = fc.getSelectedFile(); 102 103 String fn = file.getPath(); 104 if (fn.indexOf('.') == -1) { 105 FileFilter ff = fc.getFileFilter(); 106 if (ff instanceof ExtensionFileFilter) 107 fn += "." + ((ExtensionFileFilter)ff).defaultExtension; 108 else if (layer instanceof GpxLayer) 109 fn += ".gpx"; 110 else 111 fn += ".osm"; 112 file = new File(fn); 113 } 114 return file; 115 } 116 117 private static void copy(File src, File dst) throws IOException { 118 FileInputStream srcStream; 119 FileOutputStream dstStream; 120 try { 121 srcStream = new FileInputStream(src); 122 dstStream = new FileOutputStream(dst); 123 } catch (FileNotFoundException e) { 124 JOptionPane.showMessageDialog(Main.parent, tr("Could not back up file.")+"\n"+e.getMessage()); 125 return; 126 } 127 byte buf[] = new byte[1<<16]; 128 int len; 129 while ((len = srcStream.read(buf)) != -1) { 130 dstStream.write(buf, 0, len); 131 } 132 srcStream.close(); 133 dstStream.close(); 134 } 135 136 public static void save(File file, Layer layer) { 137 if (layer instanceof GpxLayer) { 138 save(file, (GpxLayer)layer); 139 ((GpxLayer)layer).data.storageFile = file; 140 } else if (layer instanceof OsmDataLayer) { 141 save(file, (OsmDataLayer)layer); 142 } 143 } 144 145 public static void save(File file, OsmDataLayer layer) { 146 File tmpFile = null; 147 try { 148 if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) { 149 GpxExportAction.exportGpx(file, layer); 150 } else if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(file.getPath())) { 151 // use a tmp file because if something errors out in the 152 // process of writing the file, we might just end up with 153 // a truncated file. That can destroy lots of work. 154 if (file.exists()) { 155 tmpFile = new File(file.getPath() + "~"); 156 copy(file, tmpFile); 157 } 158 OsmWriter.output(new FileOutputStream(file), new OsmWriter.All(layer.data, false)); 159 if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) 160 tmpFile.delete(); 161 } else { 162 JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension.")); 163 return; 164 } 165 layer.cleanData(null, false); 166 } catch (IOException e) { 167 e.printStackTrace(); 168 JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage()); 169 170 try { 171 // if the file save failed, then the tempfile will not 172 // be deleted. So, restore the backup if we made one. 173 if (tmpFile != null && tmpFile.exists()) { 174 copy(tmpFile, file); 175 } 176 } catch (IOException e2) { 177 e2.printStackTrace(); 178 JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e2.getMessage()); 179 } 180 } 181 } 182 183 public static void save(File file, GpxLayer layer) { 184 File tmpFile = null; 185 try { 186 if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) { 187 188 // use a tmp file because if something errors out in the 189 // process of writing the file, we might just end up with 190 // a truncated file. That can destroy lots of work. 191 if (file.exists()) { 192 tmpFile = new File(file.getPath() + "~"); 193 copy(file, tmpFile); 194 } 195 FileOutputStream fo = new FileOutputStream(file); 196 new GpxWriter(fo).write(layer.data); 197 fo.flush(); 198 fo.close(); 199 200 if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) { 201 tmpFile.delete(); 202 } 203 } else { 204 JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension.")); 205 return; 206 } 207 } catch (IOException e) { 208 e.printStackTrace(); 209 JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage()); 210 } 211 try { 212 // if the file save failed, then the tempfile will not 213 // be deleted. So, restore the backup if we made one. 214 if (tmpFile != null && tmpFile.exists()) { 215 copy(tmpFile, file); 216 } 217 } catch (IOException e) { 218 e.printStackTrace(); 219 JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e.getMessage()); 220 } 221 } 222 223 /** 224 * Check the data set if it would be empty on save. It is empty, if it contains 225 * no objects (after all objects that are created and deleted without being 226 * transfered to the server have been removed). 227 * 228 * @return <code>true</code>, if a save result in an empty data set. 229 */ 230 private boolean isDataSetEmpty(OsmDataLayer layer) { 231 for (OsmPrimitive osm : layer.data.allNonDeletedPrimitives()) 232 if (!osm.deleted || osm.id > 0) 233 return false; 234 return true; 235 } 236 236 } -
trunk/src/org/openstreetmap/josm/actions/SaveAsAction.java
r1084 r1169 17 17 public class SaveAsAction extends SaveActionBase { 18 18 19 20 21 22 23 24 25 26 19 /** 20 * Construct the action with "Save" as label. 21 * @param layer Save this layer. 22 */ 23 public SaveAsAction(Layer layer) { 24 super(tr("Save as ..."), "save_as", tr("Save the current data to a new file."), 25 Shortcut.registerShortcut("system:saveas", tr("File: {0}", tr("Save as ...")), KeyEvent.VK_S, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), layer); 26 } 27 27 28 29 30 28 @Override protected File getFile(Layer layer) { 29 return openFileDialog(layer); 30 } 31 31 } -
trunk/src/org/openstreetmap/josm/actions/SelectAllAction.java
r1084 r1169 12 12 public class SelectAllAction extends JosmAction { 13 13 14 15 16 17 14 public SelectAllAction() { 15 super(tr("Select All"),"selectall", tr("Select all undeleted objects in the data layer. This selects incomplete objects too."), 16 Shortcut.registerShortcut("system:selectall", tr("Edit: {0}", tr("Select All")), KeyEvent.VK_A, Shortcut.GROUP_MENU), true); 17 } 18 18 19 20 21 19 public void actionPerformed(ActionEvent e) { 20 Main.ds.setSelected(Main.ds.allNonDeletedPhysicalPrimitives()); 21 } 22 22 } -
trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java
r1084 r1169 44 44 public class SplitWayAction extends JosmAction implements SelectionChangedListener { 45 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 } 82 83 84 } 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 46 private Way selectedWay; 47 private List<Node> selectedNodes; 48 49 /** 50 * Create a new SplitWayAction. 51 */ 52 public SplitWayAction() { 53 super(tr("Split Way"), "splitway", tr("Split a way at the selected node."), 54 Shortcut.registerShortcut("tools:splitway", tr("Tool: {0}", tr("Split Way")), KeyEvent.VK_P, Shortcut.GROUP_EDIT), true); 55 DataSet.selListeners.add(this); 56 } 57 58 /** 59 * Called when the action is executed. 60 * 61 * This method performs an expensive check whether the selection clearly defines one 62 * of the split actions outlined above, and if yes, calls the splitWay method. 63 */ 64 public void actionPerformed(ActionEvent e) { 65 66 Collection<OsmPrimitive> selection = Main.ds.getSelected(); 67 68 if (!checkSelection(selection)) { 69 JOptionPane.showMessageDialog(Main.parent, tr("The current selection cannot be used for splitting.")); 70 return; 71 } 72 73 selectedWay = null; 74 selectedNodes = null; 75 76 Visitor splitVisitor = new Visitor(){ 77 public void visit(Node n) { 78 if (selectedNodes == null) 79 selectedNodes = new LinkedList<Node>(); 80 selectedNodes.add(n); 81 } 82 public void visit(Way w) { 83 selectedWay = w; 84 } 85 public void visit(Relation e) { 86 // enties are not considered 87 } 88 }; 89 90 for (OsmPrimitive p : selection) 91 p.visit(splitVisitor); 92 93 // If only nodes are selected, try to guess which way to split. This works if there 94 // is exactly one way that all nodes are part of. 95 if (selectedWay == null && selectedNodes != null) { 96 HashMap<Way, Integer> wayOccurenceCounter = new HashMap<Way, Integer>(); 97 for (Node n : selectedNodes) { 98 for (Way w : Main.ds.ways) { 99 if (w.deleted || w.incomplete) continue; 100 int last = w.nodes.size()-1; 101 if(last <= 0) continue; // zero or one node ways 102 Boolean circular = w.nodes.get(0).equals(w.nodes.get(last)); 103 int i = 0; 104 for (Node wn : w.nodes) { 105 if ((circular || (i > 0 && i < last)) && n.equals(wn)) { 106 Integer old = wayOccurenceCounter.get(w); 107 wayOccurenceCounter.put(w, (old == null) ? 1 : old+1); 108 break; 109 } 110 i++; 111 } 112 } 113 } 114 if (wayOccurenceCounter.isEmpty()) { 115 JOptionPane.showMessageDialog(Main.parent, 116 trn("The selected node is no inner part of any way.", 117 "The selected nodes are no inner part of any way.", selectedNodes.size())); 118 return; 119 } 120 121 for (Entry<Way, Integer> entry : wayOccurenceCounter.entrySet()) { 122 if (entry.getValue().equals(selectedNodes.size())) { 123 if (selectedWay != null) { 124 JOptionPane.showMessageDialog(Main.parent, tr("There is more than one way using the node(s) you selected. Please select the way also.")); 125 return; 126 } 127 selectedWay = entry.getKey(); 128 } 129 } 130 131 if (selectedWay == null) { 132 JOptionPane.showMessageDialog(Main.parent, tr("The selected nodes do not share the same way.")); 133 return; 134 } 135 136 // If a way and nodes are selected, verify that the nodes are part of the way. 137 } else if (selectedWay != null && selectedNodes != null) { 138 139 HashSet<Node> nds = new HashSet<Node>(selectedNodes); 140 for (Node n : selectedWay.nodes) { 141 nds.remove(n); 142 } 143 if (!nds.isEmpty()) { 144 JOptionPane.showMessageDialog(Main.parent, 145 trn("The selected way does not contain the selected node.", 146 "The selected way does not contain all the selected nodes.", selectedNodes.size())); 147 return; 148 } 149 } 150 151 // and then do the work. 152 splitWay(); 153 } 154 155 /** 156 * Checks if the selection consists of something we can work with. 157 * Checks only if the number and type of items selected looks good; 158 * does not check whether the selected items are really a valid 159 * input for splitting (this would be too expensive to be carried 160 * out from the selectionChanged listener). 161 */ 162 private boolean checkSelection(Collection<? extends OsmPrimitive> selection) { 163 boolean way = false; 164 boolean node = false; 165 for (OsmPrimitive p : selection) { 166 if (p instanceof Way && !way) { 167 way = true; 168 } else if (p instanceof Node) { 169 node = true; 170 } else { 171 return false; 172 } 173 } 174 return node; 175 } 176 177 /** 178 * Split a way into two or more parts, starting at a selected node. 179 */ 180 private void splitWay() { 181 // We take our way's list of nodes and copy them to a way chunk (a 182 // list of nodes). Whenever we stumble upon a selected node, we start 183 // a new way chunk. 184 185 Set<Node> nodeSet = new HashSet<Node>(selectedNodes); 186 List<List<Node>> wayChunks = new LinkedList<List<Node>>(); 187 List<Node> currentWayChunk = new ArrayList<Node>(); 188 wayChunks.add(currentWayChunk); 189 190 Iterator<Node> it = selectedWay.nodes.iterator(); 191 while (it.hasNext()) { 192 Node currentNode = it.next(); 193 boolean atEndOfWay = currentWayChunk.isEmpty() || !it.hasNext(); 194 currentWayChunk.add(currentNode); 195 if (nodeSet.contains(currentNode) && !atEndOfWay) { 196 currentWayChunk = new ArrayList<Node>(); 197 currentWayChunk.add(currentNode); 198 wayChunks.add(currentWayChunk); 199 } 200 } 201 202 // Handle circular ways specially. 203 // If you split at a circular way at two nodes, you just want to split 204 // it at these points, not also at the former endpoint. 205 // So if the last node is the same first node, join the last and the 206 // first way chunk. 207 List<Node> lastWayChunk = wayChunks.get(wayChunks.size() - 1); 208 if (wayChunks.size() >= 2 209 && wayChunks.get(0).get(0) == lastWayChunk.get(lastWayChunk.size() - 1) 210 && !nodeSet.contains(wayChunks.get(0).get(0))) { 211 if (wayChunks.size() == 2) { 212 JOptionPane.showMessageDialog(Main.parent, tr("You must select two or more nodes to split a circular way.")); 213 return; 214 } 215 lastWayChunk.remove(lastWayChunk.size() - 1); 216 lastWayChunk.addAll(wayChunks.get(0)); 217 wayChunks.remove(wayChunks.size() - 1); 218 wayChunks.set(0, lastWayChunk); 219 } 220 221 if (wayChunks.size() < 2) { 222 if(wayChunks.get(0).get(0) == wayChunks.get(0).get(wayChunks.get(0).size()-1)) 223 JOptionPane.showMessageDialog(Main.parent, tr("You must select two or more nodes to split a circular way.")); 224 else 225 JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split at the selected nodes. (Hint: Select nodes in the middle of the way.)")); 226 return; 227 } 228 //Main.debug("wayChunks.size(): " + wayChunks.size()); 229 //Main.debug("way id: " + selectedWay.id); 230 231 // build a list of commands, and also a new selection list 232 Collection<Command> commandList = new ArrayList<Command>(wayChunks.size()); 233 Collection<Way> newSelection = new ArrayList<Way>(wayChunks.size()); 234 235 Iterator<List<Node>> chunkIt = wayChunks.iterator(); 236 237 // First, change the original way 238 Way changedWay = new Way(selectedWay); 239 changedWay.nodes.clear(); 240 changedWay.nodes.addAll(chunkIt.next()); 241 commandList.add(new ChangeCommand(selectedWay, changedWay)); 242 newSelection.add(selectedWay); 243 244 Collection<Way> newWays = new ArrayList<Way>(); 245 // Second, create new ways 246 while (chunkIt.hasNext()) { 247 Way wayToAdd = new Way(); 248 if (selectedWay.keys != null) { 249 wayToAdd.keys = new HashMap<String, String>(selectedWay.keys); 250 wayToAdd.checkTagged(); 251 251 wayToAdd.checkDirectionTagged(); 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 252 } 253 newWays.add(wayToAdd); 254 wayToAdd.nodes.addAll(chunkIt.next()); 255 commandList.add(new AddCommand(wayToAdd)); 256 //Main.debug("wayToAdd: " + wayToAdd); 257 newSelection.add(wayToAdd); 258 259 } 260 Boolean warnme=false; 261 // now copy all relations to new way also 262 for (Relation r : Main.ds.relations) { 263 if (r.deleted || r.incomplete) continue; 264 for (RelationMember rm : r.members) { 265 if (rm.member instanceof Way) { 266 if (rm.member == selectedWay) 267 { 268 Relation c = new Relation(r); 269 for(Way wayToAdd : newWays) 270 { 271 RelationMember em = new RelationMember(); 272 em.member = wayToAdd; 273 em.role = rm.role; 274 if(em.role.length() > 0) 275 warnme = true; 276 c.members.add(em); 277 } 278 commandList.add(new ChangeCommand(r, c)); 279 break; 280 } 281 } 282 } 283 } 284 if(warnme) 285 JOptionPane.showMessageDialog(Main.parent, tr("A role based relation membership was copied to all new ways.\nYou should verify this and correct it when necessary.")); 286 287 NameVisitor v = new NameVisitor(); 288 v.visit(selectedWay); 289 Main.main.undoRedo.add( 290 new SequenceCommand(tr("Split way {0} into {1} parts", 291 v.name, wayChunks.size()), 292 commandList)); 293 Main.ds.setSelected(newSelection); 294 } 295 296 /** 297 * Enable the "split way" menu option if the selection looks like we could use it. 298 */ 299 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 300 setEnabled(checkSelection(newSelection)); 301 } 302 302 } -
trunk/src/org/openstreetmap/josm/actions/ToggleGPXLinesAction.java
r1138 r1169 12 12 public class ToggleGPXLinesAction extends JosmAction { 13 13 14 15 16 17 14 public ToggleGPXLinesAction() { 15 super(tr("Toggle GPX Lines"), "gps-lines", tr("Toggles the global setting ''{0}''.", tr("Draw lines between raw gps points.")), 16 Shortcut.registerShortcut("view:gpxlines", tr("View: {0}", tr("Toggle GPX Lines")), KeyEvent.VK_X, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), true); 17 } 18 18 19 20 21 22 19 public void actionPerformed(ActionEvent e) { 20 Main.pref.put("draw.rawgps.lines", !Main.pref.getBoolean("draw.rawgps.lines")); 21 Main.map.mapView.repaint(); 22 } 23 23 } -
trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java
r1084 r1169 36 36 public class UnGlueAction extends JosmAction { //implements SelectionChangedListener { 37 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 38 private Node selectedNode; 39 private Way selectedWay; 40 private ArrayList<Node> selectedNodes; 41 42 /** 43 * Create a new UnGlueAction. 44 */ 45 public UnGlueAction() { 46 super(tr("UnGlue Ways"), "unglueways", tr("Duplicate nodes that are used by multiple ways."), 47 Shortcut.registerShortcut("tools:unglue", tr("Tool: {0}", tr("UnGlue Ways")), KeyEvent.VK_G, Shortcut.GROUP_EDIT), true); 48 //DataSet.selListeners.add(this); 49 } 50 51 /** 52 * Called when the action is executed. 53 * 54 * This method does some checking on the selection and calls the matching unGlueWay method. 55 */ 56 public void actionPerformed(ActionEvent e) { 57 58 Collection<OsmPrimitive> selection = Main.ds.getSelected(); 59 60 if (checkSelection(selection)) { 61 int count = 0; 62 for (Way w : Main.ds.ways) { 63 if (w.deleted || w.incomplete || w.nodes.size() < 1) continue; 64 if (!w.nodes.contains(selectedNode)) continue; 65 count++; 66 } 67 if (count < 2) { 68 JOptionPane.showMessageDialog(Main.parent, tr("This node is not glued to anything else.")); 69 } else { 70 // and then do the work. 71 unglueWays(); 72 } 73 } else if (checkSelection2(selection)) { 74 ArrayList<Node> tmpNodes = new ArrayList<Node>(); 75 for (Node n : selectedNodes) { 76 int count = 0; 77 for (Way w : Main.ds.ways) { 78 if (w.deleted || w.incomplete || w.nodes.size() < 1) continue; 79 if (!w.nodes.contains(n)) continue; 80 count++; 81 } 82 if (count >= 2) { 83 tmpNodes.add(n); 84 } 85 } 86 if (tmpNodes.size() < 1) { 87 if (selection.size() > 1) { 88 JOptionPane.showMessageDialog(Main.parent, tr("None of these nodes is glued to anything else.")); 89 } else { 90 JOptionPane.showMessageDialog(Main.parent, tr("None of this way's nodes is glued to anything else.")); 91 } 92 } else { 93 // and then do the work. 94 selectedNodes = tmpNodes; 95 unglueWays2(); 96 } 97 } else { 98 JOptionPane.showMessageDialog(Main.parent, 99 tr("The current selection cannot be used for unglueing.")+"\n"+ 100 "\n"+ 101 tr("Select either:")+"\n"+ 102 tr("* One node that is used by more than one way, or")+"\n"+ 103 tr("* One node that is used by more than one way and one of those ways, or")+"\n"+ 104 tr("* One way that has one or more nodes that are used by more than one way, or")+"\n"+ 105 tr("* One way and one or more of its nodes that are used by more than one way.")+"\n"+ 106 "\n"+ 107 tr("Note: If a way is selected, this way will get fresh copies of the unglued\n"+ 108 "nodes and the new nodes will be selected. Otherwise, all ways will get their\n"+ 109 "own copy and all nodes will be selected.") 110 ); 111 } 112 selectedNode = null; 113 selectedWay = null; 114 selectedNodes = null; 115 } 116 117 /** 118 * Checks if the selection consists of something we can work with. 119 * Checks only if the number and type of items selected looks good; 120 * does not check whether the selected items are really a valid 121 * input for splitting (this would be too expensive to be carried 122 * out from the selectionChanged listener). 123 * 124 * If this method returns "true", selectedNode and selectedWay will 125 * be set. 126 * 127 * Returns true if either one node is selected or one node and one 128 * way are selected and the node is part of the way. 129 * 130 * The way will be put into the object variable "selectedWay", the 131 * node into "selectedNode". 132 */ 133 private boolean checkSelection(Collection<? extends OsmPrimitive> selection) { 134 135 int size = selection.size(); 136 if (size < 1 || size > 2) 137 return false; 138 139 selectedNode = null; 140 selectedWay = null; 141 142 for (OsmPrimitive p : selection) { 143 if (p instanceof Node) { 144 selectedNode = (Node) p; 145 if (size == 1 || selectedWay != null) 146 return size == 1 || selectedWay.nodes.contains(selectedNode); 147 } else if (p instanceof Way) { 148 selectedWay = (Way) p; 149 if (size == 2 && selectedNode != null) 150 return selectedWay.nodes.contains(selectedNode); 151 } 152 } 153 154 return false; 155 } 156 157 /** 158 * Checks if the selection consists of something we can work with. 159 * Checks only if the number and type of items selected looks good; 160 * does not check whether the selected items are really a valid 161 * input for splitting (this would be too expensive to be carried 162 * out from the selectionChanged listener). 163 * 164 * Returns true if one way and any number of nodes that are part of 165 * that way are selected. Note: "any" can be none, then all nodes of 166 * the way are used. 167 * 168 * The way will be put into the object variable "selectedWay", the 169 * nodes into "selectedNodes". 170 */ 171 private boolean checkSelection2(Collection<? extends OsmPrimitive> selection) { 172 if (selection.size() < 1) 173 return false; 174 175 selectedWay = null; 176 for (OsmPrimitive p : selection) { 177 if (p instanceof Way) { 178 if (selectedWay != null) { 179 return false; 180 } 181 selectedWay = (Way) p; 182 } 183 } 184 if (selectedWay == null) { 185 return false; 186 } 187 188 selectedNodes = new ArrayList<Node>(); 189 for (OsmPrimitive p : selection) { 190 if (p instanceof Node) { 191 Node n = (Node) p; 192 if (!selectedWay.nodes.contains(n)) { 193 return false; 194 } 195 selectedNodes.add(n); 196 } 197 } 198 199 if (selectedNodes.size() < 1) { 200 selectedNodes.addAll(selectedWay.nodes); 201 } 202 203 return true; 204 } 205 206 /** 207 * dupe the given node of the given way 208 * 209 * -> the new node will be put into the parameter newNodes. 210 * -> the add-node command will be put into the parameter cmds. 211 * -> the changed way will be returned and must be put into cmds by the caller! 212 */ 213 private Way modifyWay(Node originalNode, Way w, List<Command> cmds, List<Node> newNodes) { 214 ArrayList<Node> nn = new ArrayList<Node>(); 215 for (Node pushNode : w.nodes) { 216 if (originalNode == pushNode) { 217 // clone the node for all other ways 218 pushNode = new Node(pushNode); 219 pushNode.id = 0; 220 newNodes.add(pushNode); 221 cmds.add(new AddCommand(pushNode)); 222 } 223 nn.add(pushNode); 224 } 225 Way newWay = new Way(w); 226 newWay.nodes.clear(); 227 newWay.nodes.addAll(nn); 228 229 return newWay; 230 } 231 232 /** 233 * put all newNodes into the same relation(s) that originalNode is in 234 */ 235 private void fixRelations(Node originalNode, List<Command> cmds, List<Node> newNodes) { 236 // modify all relations containing the node 237 Relation newRel = null; 238 HashSet<String> rolesToReAdd = null; 239 for (Relation r : Main.ds.relations) { 240 if (r.deleted || r.incomplete) continue; 241 newRel = null; 242 rolesToReAdd = null; 243 for (RelationMember rm : r.members) { 244 if (rm.member instanceof Node) { 245 if (rm.member == originalNode) { 246 if (newRel == null) { 247 newRel = new Relation(r); 248 newRel.members.clear(); 249 rolesToReAdd = new HashSet<String>(); 250 } 251 rolesToReAdd.add(rm.role); 252 } 253 } 254 } 255 if (newRel != null) { 256 for (RelationMember rm : r.members) { 257 //if (rm.member != selectedNode) { 258 newRel.members.add(rm); 259 //} 260 } 261 for (Node n : newNodes) { 262 for (String role : rolesToReAdd) { 263 newRel.members.add(new RelationMember(role, n)); 264 } 265 } 266 cmds.add(new ChangeCommand(r, newRel)); 267 } 268 } 269 } 270 271 272 /** 273 * dupe a single node into as many nodes as there are ways using it, OR 274 * 275 * dupe a single node once, and put the copy on the selected way 276 */ 277 private void unglueWays() { 278 LinkedList<Command> cmds = new LinkedList<Command>(); 279 List<Node> newNodes = new LinkedList<Node>(); 280 281 if (selectedWay == null) { 282 boolean firstway = true; 283 // modify all ways containing the nodes 284 for (Way w : Main.ds.ways) { 285 if (w.deleted || w.incomplete || w.nodes.size() < 1) continue; 286 if (!w.nodes.contains(selectedNode)) continue; 287 if (!firstway) cmds.add(new ChangeCommand(w, modifyWay(selectedNode, w, cmds, newNodes))); 288 firstway = false; 289 } 290 } else { 291 cmds.add(new ChangeCommand(selectedWay, modifyWay(selectedNode, selectedWay, cmds, newNodes))); 292 } 293 294 fixRelations(selectedNode, cmds, newNodes); 295 296 Main.main.undoRedo.add(new SequenceCommand(tr("Dupe into {0} nodes", newNodes.size()+1), cmds)); 297 if (selectedWay == null) { // if a node has been selected, new selection is ALL nodes 298 newNodes.add(selectedNode); 299 } // if a node and a way has been selected, new selection is only the new node that was added to the selected way 300 Main.ds.setSelected(newNodes); 301 } 302 303 /** 304 * dupe all nodes that are selected, and put the copies on the selected way 305 * 306 */ 307 private void unglueWays2() { 308 LinkedList<Command> cmds = new LinkedList<Command>(); 309 List<Node> allNewNodes = new LinkedList<Node>(); 310 Way tmpWay = selectedWay; 311 312 for (Node n : selectedNodes) { 313 List<Node> newNodes = new LinkedList<Node>(); 314 tmpWay = modifyWay(n, tmpWay, cmds, newNodes); 315 fixRelations(n, cmds, newNodes); 316 allNewNodes.addAll(newNodes); 317 } 318 cmds.add(new ChangeCommand(selectedWay, tmpWay)); // only one changeCommand for a way, else garbage will happen 319 320 Main.main.undoRedo.add(new SequenceCommand(tr("Dupe {0} nodes into {1} nodes", selectedNodes.size(), selectedNodes.size()+allNewNodes.size()), cmds)); 321 Main.ds.setSelected(allNewNodes); 322 } 323 323 324 324 // Disabled because we have such a nice help text that would not be shown otherwise. 325 325 // 326 // 327 // 328 // 329 // 330 // 331 // 332 // 333 // 334 // 326 // /** 327 // * Enable the menu option if the selection looks like we could use it. 328 // */ 329 // public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 330 // setEnabled(checkSelection(newSelection) || checkSelection2(newSelection)); 331 // selectedNode = null; 332 // selectedWay = null; 333 // selectedNodes = null; 334 // } 335 335 } -
trunk/src/org/openstreetmap/josm/actions/UndoAction.java
r1084 r1169 17 17 public class UndoAction extends JosmAction { 18 18 19 20 21 22 23 24 25 26 19 /** 20 * Construct the action with "Undo" as label. 21 */ 22 public UndoAction() { 23 super(tr("Undo"), "undo", tr("Undo the last action."), 24 Shortcut.registerShortcut("system:undo", tr("Edit: {0}", tr("Undo")), KeyEvent.VK_Z, Shortcut.GROUP_MENU), true); 25 setEnabled(false); 26 } 27 27 28 29 30 31 32 33 28 public void actionPerformed(ActionEvent e) { 29 if (Main.map == null) 30 return; 31 Main.map.repaint(); 32 Main.main.undoRedo.undo(); 33 } 34 34 } -
trunk/src/org/openstreetmap/josm/actions/UnselectAllAction.java
r1084 r1169 13 13 public class UnselectAllAction extends JosmAction { 14 14 15 16 17 18 19 15 public UnselectAllAction() { 16 super(tr("Unselect All"), "unselectall", tr("Unselect all objects."), 17 Shortcut.registerShortcut("edit:unselectall", tr("Edit: {0}", tr("Unselect All")), KeyEvent.VK_U, Shortcut.GROUP_EDIT), true); 18 // this is not really GROUP_EDIT, but users really would complain if the yhad to reconfigure because we put 19 // the correct group in 20 20 21 22 23 24 25 21 // Add extra shortcut C-S-a 22 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 23 Shortcut.registerShortcut("edit:unselectallfocus", tr("Edit: {0}", tr("Unselect All (Focus)")), 24 KeyEvent.VK_A, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT).getKeyStroke(), 25 tr("Unselect All")); 26 26 27 28 29 30 31 32 33 34 35 36 37 27 // Add extra shortcut ESCAPE 28 /* 29 * FIXME: this isn't optimal. In a better world the mapmode actions 30 * would be able to capture keyboard events and react accordingly. But 31 * for now this is a reasonable approximation. 32 */ 33 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 34 Shortcut.registerShortcut("edit:unselectallescape", tr("Edit: {0}", tr("Unselect All (Escape)")), 35 KeyEvent.VK_ESCAPE, Shortcut.GROUP_DIRECT).getKeyStroke(), 36 tr("Unselect All")); 37 } 38 38 39 40 41 39 public void actionPerformed(ActionEvent e) { 40 Main.ds.setSelected(); 41 } 42 42 } -
trunk/src/org/openstreetmap/josm/actions/UploadAction.java
r1084 r1169 35 35 public class UploadAction extends JosmAction { 36 36 37 38 39 40 41 42 43 44 45 46 47 37 /** Upload Hook */ 38 public interface UploadHook { 39 /** 40 * Checks the upload. 41 * @param add The added primitives 42 * @param update The updated primitives 43 * @param delete The deleted primitives 44 * @return true, if the upload can continue 45 */ 46 public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete); 47 } 48 48 49 50 51 52 53 54 55 56 57 58 59 49 /** 50 * The list of upload hooks. These hooks will be called one after the other 51 * when the user wants to upload data. Plugins can insert their own hooks here 52 * if they want to be able to veto an upload. 53 * 54 * Be default, the standard upload dialog is the only element in the list. 55 * Plugins should normally insert their code before that, so that the upload 56 * dialog is the last thing shown before upload really starts; on occasion 57 * however, a plugin might also want to insert something after that. 58 */ 59 public final LinkedList<UploadHook> uploadHooks = new LinkedList<UploadHook>(); 60 60 61 62 63 61 public UploadAction() { 62 super(tr("Upload to OSM ..."), "upload", tr("Upload all changes to the OSM server."), 63 Shortcut.registerShortcut("file:upload", tr("File: {0}", tr("Upload to OSM ...")), KeyEvent.VK_U, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true); 64 64 65 66 67 68 69 70 65 /** 66 * Displays a screen where the actions that would be taken are displayed and 67 * give the user the possibility to cancel the upload. 68 */ 69 uploadHooks.add(new UploadHook() { 70 public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete) { 71 71 72 72 JPanel p = new JPanel(new GridBagLayout()); 73 73 74 74 OsmPrimitivRenderer renderer = new OsmPrimitivRenderer(); 75 75 76 77 78 79 80 81 82 76 if (!add.isEmpty()) { 77 p.add(new JLabel(tr("Objects to add:")), GBC.eol()); 78 JList l = new JList(add.toArray()); 79 l.setCellRenderer(renderer); 80 l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10); 81 p.add(new JScrollPane(l), GBC.eol().fill()); 82 } 83 83 84 85 86 87 88 89 90 84 if (!update.isEmpty()) { 85 p.add(new JLabel(tr("Objects to modify:")), GBC.eol()); 86 JList l = new JList(update.toArray()); 87 l.setCellRenderer(renderer); 88 l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10); 89 p.add(new JScrollPane(l), GBC.eol().fill()); 90 } 91 91 92 93 94 95 96 97 98 92 if (!delete.isEmpty()) { 93 p.add(new JLabel(tr("Objects to delete:")), GBC.eol()); 94 JList l = new JList(delete.toArray()); 95 l.setCellRenderer(renderer); 96 l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10); 97 p.add(new JScrollPane(l), GBC.eol().fill()); 98 } 99 99 100 101 102 103 104 100 return JOptionPane.showConfirmDialog(Main.parent, p, tr("Upload these changes?"), 101 JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION; 102 } 103 }); 104 } 105 105 106 107 108 109 110 106 public void actionPerformed(ActionEvent e) { 107 if (Main.map == null) { 108 JOptionPane.showMessageDialog(Main.parent,tr("Nothing to upload. Get some data first.")); 109 return; 110 } 111 111 112 113 114 115 116 117 112 if (!Main.map.conflictDialog.conflicts.isEmpty()) { 113 JOptionPane.showMessageDialog(Main.parent,tr("There are unresolved conflicts. You have to resolve these first.")); 114 Main.map.conflictDialog.action.button.setSelected(true); 115 Main.map.conflictDialog.action.actionPerformed(null); 116 return; 117 } 118 118 119 120 121 122 123 124 125 126 127 128 129 130 131 119 final LinkedList<OsmPrimitive> add = new LinkedList<OsmPrimitive>(); 120 final LinkedList<OsmPrimitive> update = new LinkedList<OsmPrimitive>(); 121 final LinkedList<OsmPrimitive> delete = new LinkedList<OsmPrimitive>(); 122 for (OsmPrimitive osm : Main.ds.allPrimitives()) { 123 if (osm.get("josm/ignore") != null) 124 continue; 125 if (osm.id == 0 && !osm.deleted) 126 add.addLast(osm); 127 else if (osm.modified && !osm.deleted) 128 update.addLast(osm); 129 else if (osm.deleted && osm.id != 0) 130 delete.addFirst(osm); 131 } 132 132 133 134 135 136 133 if (add.isEmpty() && update.isEmpty() && delete.isEmpty()) { 134 JOptionPane.showMessageDialog(Main.parent,tr("No changes to upload.")); 135 return; 136 } 137 137 138 139 140 141 142 138 // Call all upload hooks in sequence. The upload confirmation dialog 139 // is one of these. 140 for(UploadHook hook : uploadHooks) 141 if(!hook.checkUpload(add, update, delete)) 142 return; 143 143 144 145 146 147 148 144 final OsmServerWriter server = new OsmServerWriter(); 145 final Collection<OsmPrimitive> all = new LinkedList<OsmPrimitive>(); 146 all.addAll(add); 147 all.addAll(update); 148 all.addAll(delete); 149 149 150 151 152 153 154 155 156 157 158 159 160 161 162 150 PleaseWaitRunnable uploadTask = new PleaseWaitRunnable(tr("Uploading data")){ 151 @Override protected void realRun() throws SAXException { 152 server.uploadOsm(all); 153 } 154 @Override protected void finish() { 155 Main.main.editLayer().cleanData(server.processed, !add.isEmpty()); 156 } 157 @Override protected void cancel() { 158 server.cancel(); 159 } 160 }; 161 Main.worker.execute(uploadTask); 162 } 163 163 } -
trunk/src/org/openstreetmap/josm/actions/ZoomInAction.java
r1087 r1169 12 12 public final class ZoomInAction extends JosmAction { 13 13 14 15 16 17 18 14 public ZoomInAction() { 15 super(tr("Zoom in"), "dialogs/zoomin", tr("Zoom in"), 16 Shortcut.registerShortcut("view:zoomin", tr("View: {0}", tr("Zoom in")), KeyEvent.VK_PLUS, Shortcut.GROUP_DIRECT), true); 17 setEnabled(true); 18 } 19 19 20 20 public void actionPerformed(ActionEvent e) { 21 21 if (Main.map == null) return; 22 23 24 22 double zoom = Main.map.mapView.getScale(); 23 Main.map.mapView.zoomTo(Main.map.mapView.getCenter(), zoom * .9); 24 } 25 25 } -
trunk/src/org/openstreetmap/josm/actions/ZoomOutAction.java
r1087 r1169 12 12 public final class ZoomOutAction extends JosmAction { 13 13 14 15 16 17 18 14 public ZoomOutAction() { 15 super(tr("Zoom out"), "dialogs/zoomout", tr("Zoom out"), 16 Shortcut.registerShortcut("view:zoomout", tr("View: {0}", tr("Zoom out")), KeyEvent.VK_MINUS, Shortcut.GROUP_DIRECT), true); 17 setEnabled(true); 18 } 19 19 20 20 public void actionPerformed(ActionEvent e) { 21 21 if (Main.map == null) return; 22 23 24 22 double zoom = Main.map.mapView.getScale(); 23 Main.map.mapView.zoomTo(Main.map.mapView.getCenter(), zoom /.9); 24 } 25 25 } -
trunk/src/org/openstreetmap/josm/actions/audio/AudioBackAction.java
r1084 r1169 15 15 public class AudioBackAction extends JosmAction { 16 16 17 17 private double amount; // note, normally negative, i.e. jump backwards in time 18 18 19 20 21 22 23 24 25 26 27 28 19 public AudioBackAction() { 20 super(tr("Back"), "audio-back", tr("Jump back."), 21 Shortcut.registerShortcut("audio:back", tr("Audio: {0}", tr("Back")), KeyEvent.VK_F6, Shortcut.GROUP_DIRECT), true); 22 try { 23 amount = - Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0")); 24 } catch (NumberFormatException e) { 25 amount = 10.0; 26 } 27 this.putValue("help", "Action/Back"); 28 } 29 29 30 31 32 33 34 35 36 37 38 39 30 public void actionPerformed(ActionEvent e) { 31 try { 32 if (AudioPlayer.playing() || AudioPlayer.paused()) 33 AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position() + amount); 34 else 35 MarkerLayer.playAudio(); 36 } catch (Exception ex) { 37 AudioPlayer.audioMalfunction(ex); 38 } 39 } 40 40 } -
trunk/src/org/openstreetmap/josm/actions/audio/AudioFastSlowAction.java
r1084 r1169 11 11 abstract public class AudioFastSlowAction extends JosmAction { 12 12 13 13 private double multiplier; 14 14 15 16 17 18 19 20 21 22 23 24 15 public AudioFastSlowAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean fast) { 16 super(name, iconName, tooltip, shortcut, true); 17 try { 18 multiplier = Double.parseDouble(Main.pref.get("audio.fastfwdmultiplier","1.3")); 19 } catch (NumberFormatException e) { 20 multiplier = 1.3; 21 } 22 if (! fast) 23 multiplier = 1.0 / multiplier; 24 } 25 25 26 27 28 29 30 31 32 33 34 35 36 26 @Deprecated 27 public AudioFastSlowAction(String name, String iconName, String tooltip, int shortcut, int modifier, boolean fast) { 28 super(name, iconName, tooltip, shortcut, modifier, true); 29 try { 30 multiplier = Double.parseDouble(Main.pref.get("audio.fastfwdmultiplier","1.3")); 31 } catch (NumberFormatException e) { 32 multiplier = 1.3; 33 } 34 if (! fast) 35 multiplier = 1.0 / multiplier; 36 } 37 37 38 39 40 41 42 43 44 45 46 47 48 38 public void actionPerformed(ActionEvent e) { 39 double speed = AudioPlayer.speed(); 40 if (speed * multiplier <= 0.1) 41 return; 42 try { 43 if (AudioPlayer.playing() || AudioPlayer.paused()) 44 AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position(), speed * multiplier); 45 } catch (Exception ex) { 46 AudioPlayer.audioMalfunction(ex); 47 } 48 } 49 49 } -
trunk/src/org/openstreetmap/josm/actions/audio/AudioFasterAction.java
r1084 r1169 9 9 public class AudioFasterAction extends AudioFastSlowAction { 10 10 11 12 13 14 11 public AudioFasterAction() { 12 super(tr("Faster"), "audio-faster", tr("Faster Forward"), 13 Shortcut.registerShortcut("audio:faster", tr("Audio: {0}", tr("Faster")), KeyEvent.VK_F9, Shortcut.GROUP_DIRECT), true); 14 } 15 15 } -
trunk/src/org/openstreetmap/josm/actions/audio/AudioFwdAction.java
r1084 r1169 15 15 public class AudioFwdAction extends JosmAction { 16 16 17 17 private double amount; 18 18 19 20 21 22 23 24 25 26 27 19 public AudioFwdAction() { 20 super(tr("Forward"), "audio-fwd", tr("Jump forward"), 21 Shortcut.registerShortcut("audio:forward", tr("Audio: {0}", tr("Forward")), KeyEvent.VK_F7, Shortcut.GROUP_DIRECT), true); 22 try { 23 amount = Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0")); 24 } catch (NumberFormatException e) { 25 amount = 10.0; 26 } 27 } 28 28 29 30 31 32 33 34 35 36 37 38 29 public void actionPerformed(ActionEvent e) { 30 try { 31 if (AudioPlayer.playing() || AudioPlayer.paused()) 32 AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position() + amount); 33 else 34 MarkerLayer.playAudio(); 35 } catch (Exception ex) { 36 AudioPlayer.audioMalfunction(ex); 37 } 38 } 39 39 } -
trunk/src/org/openstreetmap/josm/actions/audio/AudioNextAction.java
r1084 r1169 13 13 public class AudioNextAction extends JosmAction { 14 14 15 16 17 18 15 public AudioNextAction() { 16 super(tr("Next Marker"), "audio-next", tr("Play next marker."), 17 Shortcut.registerShortcut("audio:next", tr("Audio: {0}", tr("Next Marker")), KeyEvent.VK_F8, Shortcut.GROUP_DIRECT), true); 18 } 19 19 20 21 22 20 public void actionPerformed(ActionEvent e) { 21 MarkerLayer.playNextMarker(); 22 } 23 23 } -
trunk/src/org/openstreetmap/josm/actions/audio/AudioPlayPauseAction.java
r1084 r1169 15 15 public class AudioPlayPauseAction extends JosmAction { 16 16 17 18 19 20 17 public AudioPlayPauseAction() { 18 super(tr("Play/pause"), "audio-playpause", tr("Play/pause audio."), 19 Shortcut.registerShortcut("audio:pause", tr("Audio: {0}", tr("Play/pause")), KeyEvent.VK_PERIOD, Shortcut.GROUP_DIRECT), true); 20 } 21 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 22 public void actionPerformed(ActionEvent e) { 23 URL url = AudioPlayer.url(); 24 try { 25 if (AudioPlayer.paused() && url != null) { 26 AudioPlayer.play(url); 27 } else if (AudioPlayer.playing()){ 28 if (AudioPlayer.speed() != 1.0) 29 AudioPlayer.play(url, AudioPlayer.position()); 30 else 31 AudioPlayer.pause(); 32 } else { 33 // find first audio marker to play 34 MarkerLayer.playAudio(); 35 } 36 } catch (Exception ex) { 37 AudioPlayer.audioMalfunction(ex); 38 } 39 } 40 40 } -
trunk/src/org/openstreetmap/josm/actions/audio/AudioPrevAction.java
r1084 r1169 13 13 public class AudioPrevAction extends JosmAction { 14 14 15 16 17 18 15 public AudioPrevAction() { 16 super(tr("Previous Marker"), "audio-prev", tr("Play previous marker."), 17 Shortcut.registerShortcut("audio:prev", tr("Audio: {0}", tr("Previous Marker")), KeyEvent.VK_F5, Shortcut.GROUP_DIRECT), true); 18 } 19 19 20 21 22 20 public void actionPerformed(ActionEvent e) { 21 MarkerLayer.playPreviousMarker(); 22 } 23 23 } -
trunk/src/org/openstreetmap/josm/actions/audio/AudioSlowerAction.java
r1084 r1169 9 9 public class AudioSlowerAction extends AudioFastSlowAction { 10 10 11 12 13 14 11 public AudioSlowerAction() { 12 super(tr("Slower"), "audio-slower", tr("Slower Forward"), 13 Shortcut.registerShortcut("audio:slower", tr("Audio: {0}", tr("Slower")), KeyEvent.VK_F4, Shortcut.GROUP_DIRECT), true); 14 } 15 15 } -
trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java
r1148 r1169 21 21 public class DownloadGpsTask implements DownloadTask { 22 22 23 24 25 26 23 private static class Task extends PleaseWaitRunnable { 24 private BoundingBoxDownloader reader; 25 private GpxData rawData; 26 private final boolean newLayer; 27 27 28 29 30 31 32 28 public Task(boolean newLayer, BoundingBoxDownloader reader) { 29 super(tr("Downloading GPS data")); 30 this.reader = reader; 31 this.newLayer = newLayer; 32 } 33 33 34 35 36 34 @Override public void realRun() throws IOException, SAXException { 35 rawData = reader.parseRawGps(); 36 } 37 37 38 39 40 38 @Override protected void finish() { 39 if (rawData == null) 40 return; 41 41 rawData.recalculateBounds(); 42 42 Bounds b = rawData.bounds; 43 String name = b.min.lat() + " " + b.min.lon() + " x " + b.max.lat() + " " + b.max.lon(); 44 GpxLayer layer = new GpxLayer(rawData, name); 45 if (newLayer || findMergeLayer() == null) 46 Main.main.addLayer(layer); 47 else 48 findMergeLayer().mergeFrom(layer); 49 } 50 51 private Layer findMergeLayer() { 52 if (Main.map == null) 53 return null; 54 Layer active = Main.map.mapView.getActiveLayer(); 55 if (active != null && active instanceof GpxLayer) 56 return active; 57 for (Layer l : Main.map.mapView.getAllLayers()) 58 if (l instanceof GpxLayer) 59 return l; 60 return null; 43 String name = b.min.lat() + " " + b.min.lon() + " x " + b.max.lat() + " " + b.max.lon(); 44 GpxLayer layer = new GpxLayer(rawData, name); 45 if (newLayer || findMergeLayer() == null) 46 Main.main.addLayer(layer); 47 else 48 findMergeLayer().mergeFrom(layer); 61 49 } 62 50 63 @Override protected void cancel() { 64 if (reader != null) 65 reader.cancel(); 66 } 67 } 51 private Layer findMergeLayer() { 52 if (Main.map == null) 53 return null; 54 Layer active = Main.map.mapView.getActiveLayer(); 55 if (active != null && active instanceof GpxLayer) 56 return active; 57 for (Layer l : Main.map.mapView.getAllLayers()) 58 if (l instanceof GpxLayer) 59 return l; 60 return null; 61 } 68 62 69 private JCheckBox checkBox = new JCheckBox(tr("Raw GPS data")); 70 71 public void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon) { 72 Task task = new Task(action.dialog.newLayer.isSelected(), new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon)); 73 Main.worker.execute(task); 74 } 75 76 public JCheckBox getCheckBox() { 77 return checkBox; 63 @Override protected void cancel() { 64 if (reader != null) 65 reader.cancel(); 66 } 78 67 } 79 68 80 public String getPreferencesSuffix() { 81 return "gps"; 69 private JCheckBox checkBox = new JCheckBox(tr("Raw GPS data")); 70 71 public void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon) { 72 Task task = new Task(action.dialog.newLayer.isSelected(), new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon)); 73 Main.worker.execute(task); 82 74 } 83 75 84 public void loadUrl(boolean a,java.lang.String b) { 76 public JCheckBox getCheckBox() { 77 return checkBox; 78 } 79 80 public String getPreferencesSuffix() { 81 return "gps"; 82 } 83 84 public void loadUrl(boolean a,java.lang.String b) { 85 85 // FIXME this is not currently used 86 86 } -
trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java
r1146 r1169 31 31 private static Bounds currentBounds; 32 32 33 34 35 36 33 private static class Task extends PleaseWaitRunnable { 34 private OsmServerReader reader; 35 private DataSet dataSet; 36 private boolean newLayer; 37 37 38 39 40 41 42 38 public Task(boolean newLayer, OsmServerReader reader) { 39 super(tr("Downloading data")); 40 this.reader = reader; 41 this.newLayer = newLayer; 42 } 43 43 44 45 46 44 @Override public void realRun() throws IOException, SAXException { 45 dataSet = reader.parseOsm(); 46 } 47 47 48 49 50 51 52 48 @Override protected void finish() { 49 if (dataSet == null) 50 return; // user cancelled download or error occoured 51 if (dataSet.allPrimitives().isEmpty()) { 52 errorMessage = tr("No data imported."); 53 53 // need to synthesize a download bounds lest the visual indication of downloaded 54 54 // area doesn't work … … 56 56 } 57 57 58 59 60 61 62 63 58 OsmDataLayer layer = new OsmDataLayer(dataSet, tr("Data Layer"), null); 59 if (newLayer) 60 Main.main.addLayer(layer); 61 else 62 Main.main.editLayer().mergeFrom(layer); 63 } 64 64 65 66 67 68 69 70 65 @Override protected void cancel() { 66 if (reader != null) 67 reader.cancel(); 68 } 69 } 70 private JCheckBox checkBox = new JCheckBox(tr("OpenStreetMap data"), true); 71 71 72 73 74 75 76 77 78 79 80 81 82 83 72 public void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon) { 73 // Swap min and max if user has specified them the wrong way round 74 // (easy to do if you are crossing 0, for example) 75 // FIXME should perhaps be done in download dialog? 76 if (minlat > maxlat) { 77 double t = minlat; minlat = maxlat; maxlat = t; 78 } 79 if (minlon > maxlon) { 80 double t = minlon; minlon = maxlon; maxlon = t; 81 } 82 83 Task task = new Task(action != null && (action.dialog == null || action.dialog.newLayer.isSelected()), new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon)); 84 84 currentBounds = new Bounds(new LatLon(minlat, minlon), new LatLon(maxlat, maxlon)); 85 85 Main.worker.execute(task); 86 86 } 87 87 88 88 public void loadUrl(boolean new_layer, String url) { 89 89 Task task = new Task(new_layer, new OsmServerLocationReader(url)); 90 90 Main.worker.execute(task); 91 91 } 92 93 94 95 92 96 public JCheckBox getCheckBox() { 97 return checkBox; 93 94 95 96 public JCheckBox getCheckBox() { 97 return checkBox; 98 98 } 99 99 100 101 100 public String getPreferencesSuffix() { 101 return "osm"; 102 102 } 103 103 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java
r1150 r1169 36 36 public class DeleteAction extends MapMode { 37 37 38 39 40 41 42 43 44 45 46 47 48 49 38 /** 39 * Construct a new DeleteAction. Mnemonic is the delete - key. 40 * @param mapFrame The frame this action belongs to. 41 */ 42 public DeleteAction(MapFrame mapFrame) { 43 super(tr("Delete Mode"), 44 "delete", 45 tr("Delete nodes or ways."), 46 Shortcut.registerShortcut("mapmode:delete", tr("Mode: {0}",tr("Delete")), KeyEvent.VK_D, Shortcut.GROUP_EDIT), 47 mapFrame, 48 ImageProvider.getCursor("normal", "delete")); 49 } 50 50 51 52 53 54 51 @Override public void enterMode() { 52 super.enterMode(); 53 Main.map.mapView.addMouseListener(this); 54 } 55 55 56 57 58 59 56 @Override public void exitMode() { 57 super.exitMode(); 58 Main.map.mapView.removeMouseListener(this); 59 } 60 60 61 61 62 63 64 65 66 67 62 @Override public void actionPerformed(ActionEvent e) { 63 super.actionPerformed(e); 64 if(!Main.map.mapView.isDrawableLayer()) 65 return; 66 doActionPerformed(e); 67 } 68 68 69 70 71 72 73 69 public void doActionPerformed(ActionEvent e) { 70 if(!Main.map.mapView.isDrawableLayer()) 71 return; 72 boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0; 73 boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0; 74 74 75 76 77 78 79 80 81 82 83 75 Command c; 76 if (ctrl) { 77 c = DeleteCommand.deleteWithReferences(Main.ds.getSelected()); 78 } else { 79 c = DeleteCommand.delete(Main.ds.getSelected(), !alt); 80 } 81 if (c != null) { 82 Main.main.undoRedo.add(c); 83 } 84 84 85 86 87 85 Main.ds.setSelected(); 86 Main.map.repaint(); 87 } 88 88 89 90 91 92 93 94 95 96 97 98 99 100 89 /** 90 * If user clicked with the left button, delete the nearest object. 91 * position. 92 */ 93 @Override public void mouseClicked(MouseEvent e) { 94 if (e.getButton() != MouseEvent.BUTTON1) 95 return; 96 if(!Main.map.mapView.isDrawableLayer()) 97 return; 98 boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0; 99 boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; 100 boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0; 101 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 102 OsmPrimitive sel = Main.map.mapView.getNearestNode(e.getPoint()); 103 Command c = null; 104 if (sel == null) { 105 WaySegment ws = Main.map.mapView.getNearestWaySegment(e.getPoint()); 106 if (ws != null) { 107 if (shift) { 108 c = DeleteCommand.deleteWaySegment(ws); 109 } else if (ctrl) { 110 c = DeleteCommand.deleteWithReferences(Collections.singleton((OsmPrimitive)ws.way)); 111 } else { 112 c = DeleteCommand.delete(Collections.singleton((OsmPrimitive)ws.way), !alt); 113 } 114 } 115 } else if (ctrl) { 116 c = DeleteCommand.deleteWithReferences(Collections.singleton(sel)); 117 } else { 118 c = DeleteCommand.delete(Collections.singleton(sel), !alt); 119 } 120 if (c != null) { 121 Main.main.undoRedo.add(c); 122 } 123 123 124 125 126 124 Main.ds.setSelected(); 125 Main.map.mapView.repaint(); 126 } 127 127 128 129 130 128 @Override public String getModeHelpText() { 129 return tr("Click to delete. Shift: delete way segment. Alt: don't delete unused nodes when deleting a way. Ctrl: delete referring objects."); 130 } 131 131 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
r1084 r1169 58 58 public class DrawAction extends MapMode implements MapViewPaintable, SelectionChangedListener, AWTEventListener { 59 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 60 private static Node lastUsedNode = null; 61 private double PHI=Math.toRadians(90); 62 63 private boolean ctrl; 64 private boolean alt; 65 private boolean shift; 66 private boolean mouseOnExistingNode; 67 private boolean drawHelperLine; 68 private Point mousePos; 69 private Color selectedColor; 70 71 private Node currentBaseNode; 72 private EastNorth currentMouseEastNorth; 73 74 public DrawAction(MapFrame mapFrame) { 75 super(tr("Draw"), "node/autonode", tr("Draw nodes"), 76 Shortcut.registerShortcut("mapmode:draw", tr("Mode: {0}", tr("Draw")), KeyEvent.VK_A, Shortcut.GROUP_EDIT), 77 mapFrame, getCursor()); 78 79 // Add extra shortcut N 80 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 81 Shortcut.registerShortcut("mapmode:drawfocus", tr("Mode: Draw Focus"), KeyEvent.VK_N, Shortcut.GROUP_EDIT).getKeyStroke(), tr("Draw")); 82 83 //putValue("help", "Action/AddNode/Autnode"); 84 selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW); 85 86 drawHelperLine = Main.pref.getBoolean("draw.helper-line", true); 87 } 88 89 private static Cursor getCursor() { 90 try { 91 return ImageProvider.getCursor("crosshair", null); 92 92 } catch (Exception e) { 93 93 } 94 95 } 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 *<code>null</code> otherwise.460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 94 return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); 95 } 96 97 @Override public void enterMode() { 98 super.enterMode(); 99 Main.map.mapView.addMouseListener(this); 100 Main.map.mapView.addMouseMotionListener(this); 101 Main.map.mapView.addTemporaryLayer(this); 102 DataSet.selListeners.add(this); 103 try { 104 Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK); 105 } catch (SecurityException ex) { 106 } 107 // would like to but haven't got mouse position yet: 108 // computeHelperLine(false, false, false); 109 } 110 @Override public void exitMode() { 111 super.exitMode(); 112 Main.map.mapView.removeMouseListener(this); 113 Main.map.mapView.removeMouseMotionListener(this); 114 Main.map.mapView.removeTemporaryLayer(this); 115 DataSet.selListeners.remove(this); 116 try { 117 Toolkit.getDefaultToolkit().removeAWTEventListener(this); 118 } catch (SecurityException ex) { 119 } 120 } 121 122 /** 123 * redraw to (possibly) get rid of helper line if selection changes. 124 */ 125 public void eventDispatched(AWTEvent event) { 126 if(!Main.map.mapView.isDrawableLayer()) 127 return; 128 InputEvent e = (InputEvent) event; 129 ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0; 130 alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0; 131 shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; 132 computeHelperLine(); 133 } 134 /** 135 * redraw to (possibly) get rid of helper line if selection changes. 136 */ 137 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 138 if(!Main.map.mapView.isDrawableLayer()) 139 return; 140 computeHelperLine(); 141 } 142 143 /** 144 * If user clicked with the left button, add a node at the current mouse 145 * position. 146 * 147 * If in nodeway mode, insert the node into the way. 148 */ 149 @Override public void mouseClicked(MouseEvent e) { 150 151 if (e.getButton() != MouseEvent.BUTTON1) 152 return; 153 if(!Main.map.mapView.isDrawableLayer()) 154 return; 155 156 // we copy ctrl/alt/shift from the event just in case our global 157 // AWTEvent didn't make it through the security manager. Unclear 158 // if that can ever happen but better be safe. 159 ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0; 160 alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0; 161 shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; 162 mousePos = e.getPoint(); 163 164 Collection<OsmPrimitive> selection = Main.ds.getSelected(); 165 Collection<Command> cmds = new LinkedList<Command>(); 166 167 ArrayList<Way> reuseWays = new ArrayList<Way>(), 168 replacedWays = new ArrayList<Way>(); 169 boolean newNode = false; 170 Node n = null; 171 172 if (!ctrl) { 173 n = Main.map.mapView.getNearestNode(mousePos); 174 } 175 176 if (n != null) { 177 // user clicked on node 178 if (shift || selection.isEmpty()) { 179 // select the clicked node and do nothing else 180 // (this is just a convenience option so that people don't 181 // have to switch modes) 182 Main.ds.setSelected(n); 183 return; 184 } 185 186 } else { 187 // no node found in clicked area 188 n = new Node(Main.map.mapView.getLatLon(e.getX(), e.getY())); 189 if (n.coor.isOutSideWorld()) { 190 JOptionPane.showMessageDialog(Main.parent, 191 tr("Cannot add a node outside of the world.")); 192 return; 193 } 194 newNode = true; 195 196 cmds.add(new AddCommand(n)); 197 198 if (!ctrl) { 199 // Insert the node into all the nearby way segments 200 List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(e.getPoint()); 201 Map<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>(); 202 for (WaySegment ws : wss) { 203 List<Integer> is; 204 if (insertPoints.containsKey(ws.way)) { 205 is = insertPoints.get(ws.way); 206 } else { 207 is = new ArrayList<Integer>(); 208 insertPoints.put(ws.way, is); 209 } 210 211 is.add(ws.lowerIndex); 212 } 213 214 Set<Pair<Node,Node>> segSet = new HashSet<Pair<Node,Node>>(); 215 216 for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) { 217 Way w = insertPoint.getKey(); 218 List<Integer> is = insertPoint.getValue(); 219 220 Way wnew = new Way(w); 221 222 pruneSuccsAndReverse(is); 223 for (int i : is) segSet.add( 224 Pair.sort(new Pair<Node,Node>(w.nodes.get(i), w.nodes.get(i+1)))); 225 for (int i : is) wnew.nodes.add(i + 1, n); 226 227 cmds.add(new ChangeCommand(insertPoint.getKey(), wnew)); 228 replacedWays.add(insertPoint.getKey()); 229 reuseWays.add(wnew); 230 } 231 232 adjustNode(segSet, n); 233 } 234 } 235 236 // This part decides whether or not a "segment" (i.e. a connection) is made to an 237 // existing node. 238 239 // For a connection to be made, the user must either have a node selected (connection 240 // is made to that node), or he must have a way selected *and* one of the endpoints 241 // of that way must be the last used node (connection is made to last used node), or 242 // he must have a way and a node selected (connection is made to the selected node). 243 244 boolean extendedWay = false; 245 246 if (!shift && selection.size() > 0 && selection.size() < 3) { 247 248 Node selectedNode = null; 249 Way selectedWay = null; 250 251 for (OsmPrimitive p : selection) { 252 if (p instanceof Node) { 253 if (selectedNode != null) return; 254 selectedNode = (Node) p; 255 } else if (p instanceof Way) { 256 if (selectedWay != null) return; 257 selectedWay = (Way) p; 258 } 259 } 260 261 // the node from which we make a connection 262 Node n0 = null; 263 264 if (selectedNode == null) { 265 if (selectedWay == null) return; 266 if (lastUsedNode == selectedWay.nodes.get(0) || lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) { 267 n0 = lastUsedNode; 268 } 269 } else if (selectedWay == null) { 270 n0 = selectedNode; 271 } else { 272 if (selectedNode == selectedWay.nodes.get(0) || selectedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) { 273 n0 = selectedNode; 274 } 275 } 276 277 if (n0 == null || n0 == n) { 278 return; // Don't create zero length way segments. 279 } 280 281 // Ok we know now that we'll insert a line segment, but will it connect to an 282 // existing way or make a new way of its own? The "alt" modifier means that the 283 // user wants a new way. 284 285 Way way = alt ? null : (selectedWay != null) ? selectedWay : getWayForNode(n0); 286 if (way == null) { 287 way = new Way(); 288 way.nodes.add(n0); 289 cmds.add(new AddCommand(way)); 290 } else { 291 int i; 292 if ((i = replacedWays.indexOf(way)) != -1) { 293 way = reuseWays.get(i); 294 } else { 295 Way wnew = new Way(way); 296 cmds.add(new ChangeCommand(way, wnew)); 297 way = wnew; 298 } 299 } 300 301 if (way.nodes.get(way.nodes.size() - 1) == n0) { 302 way.nodes.add(n); 303 } else { 304 way.nodes.add(0, n); 305 } 306 307 extendedWay = true; 308 Main.ds.setSelected(way); 309 } 310 311 String title; 312 if (!extendedWay && !newNode) { 313 return; // We didn't do anything. 314 } else if (!extendedWay) { 315 if (reuseWays.isEmpty()) { 316 title = tr("Add node"); 317 } else { 318 title = tr("Add node into way"); 319 } 320 for (Way w : reuseWays) w.selected = false; 321 Main.ds.setSelected(n); 322 } else if (!newNode) { 323 title = tr("Connect existing way to node"); 324 } else if (reuseWays.isEmpty()) { 325 title = tr("Add a new node to an existing way"); 326 } else { 327 title = tr("Add node into way and connect"); 328 } 329 330 Command c = new SequenceCommand(title, cmds); 331 332 Main.main.undoRedo.add(c); 333 lastUsedNode = n; 334 computeHelperLine(); 335 Main.map.mapView.repaint(); 336 } 337 338 @Override public void mouseMoved(MouseEvent e) { 339 if(!Main.map.mapView.isDrawableLayer()) 340 return; 341 342 // we copy ctrl/alt/shift from the event just in case our global 343 // AWTEvent didn't make it through the security manager. Unclear 344 // if that can ever happen but better be safe. 345 346 ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0; 347 alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0; 348 shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; 349 mousePos = e.getPoint(); 350 351 computeHelperLine(); 352 } 353 354 /** 355 * This method prepares data required for painting the "helper line" from 356 * the last used position to the mouse cursor. It duplicates some code from 357 * mouseClicked() (FIXME). 358 */ 359 private void computeHelperLine() { 360 if (mousePos == null) { 361 // Don't draw the line. 362 currentMouseEastNorth = null; 363 currentBaseNode = null; 364 return; 365 } 366 367 double distance = -1; 368 double angle = -1; 369 370 Collection<OsmPrimitive> selection = Main.ds.getSelected(); 371 372 Node selectedNode = null; 373 Way selectedWay = null; 374 Node currentMouseNode = null; 375 mouseOnExistingNode = false; 376 377 Main.map.statusLine.setAngle(-1); 378 Main.map.statusLine.setHeading(-1); 379 Main.map.statusLine.setDist(-1); 380 381 if (!ctrl && mousePos != null) { 382 currentMouseNode = Main.map.mapView.getNearestNode(mousePos); 383 } 384 385 if (currentMouseNode != null) { 386 // user clicked on node 387 if (selection.isEmpty()) return; 388 currentMouseEastNorth = currentMouseNode.eastNorth; 389 mouseOnExistingNode = true; 390 } else { 391 // no node found in clicked area 392 currentMouseEastNorth = Main.map.mapView.getEastNorth(mousePos.x, mousePos.y); 393 } 394 395 for (OsmPrimitive p : selection) { 396 if (p instanceof Node) { 397 if (selectedNode != null) return; 398 selectedNode = (Node) p; 399 } else if (p instanceof Way) { 400 if (selectedWay != null) return; 401 selectedWay = (Way) p; 402 } 403 } 404 405 // the node from which we make a connection 406 currentBaseNode = null; 407 Node previousNode = null; 408 409 if (selectedNode == null) { 410 if (selectedWay == null) return; 411 if (lastUsedNode == selectedWay.nodes.get(0) || lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) { 412 currentBaseNode = lastUsedNode; 413 if (lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1) && selectedWay.nodes.size() > 1) { 414 previousNode = selectedWay.nodes.get(selectedWay.nodes.size()-2); 415 } 416 } 417 } else if (selectedWay == null) { 418 currentBaseNode = selectedNode; 419 } else { 420 if (selectedNode == selectedWay.nodes.get(0) || selectedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) { 421 currentBaseNode = selectedNode; 422 } 423 } 424 425 if (currentBaseNode == null || currentBaseNode == currentMouseNode) { 426 return; // Don't create zero length way segments. 427 } 428 429 // find out the distance, in metres, between the base point and the mouse cursor 430 LatLon mouseLatLon = Main.proj.eastNorth2latlon(currentMouseEastNorth); 431 distance = currentBaseNode.coor.greatCircleDistance(mouseLatLon); 432 double hdg = Math.toDegrees(currentBaseNode.coor.heading(mouseLatLon)); 433 if (previousNode != null) { 434 angle = hdg - Math.toDegrees(previousNode.coor.heading(currentBaseNode.coor)); 435 if (angle < 0) angle += 360; 436 } 437 Main.map.statusLine.setAngle(angle); 438 Main.map.statusLine.setHeading(hdg); 439 Main.map.statusLine.setDist(distance); 440 updateStatusLine(); 441 442 if (!drawHelperLine) return; 443 444 Main.map.mapView.repaint(); 445 } 446 447 /** 448 * Repaint on mouse exit so that the helper line goes away. 449 */ 450 @Override public void mouseExited(MouseEvent e) { 451 if(!Main.map.mapView.isDrawableLayer()) 452 return; 453 mousePos = e.getPoint(); 454 Main.map.mapView.repaint(); 455 } 456 457 /** 458 * @return If the node is the end of exactly one way, return this. 459 * <code>null</code> otherwise. 460 */ 461 public static Way getWayForNode(Node n) { 462 Way way = null; 463 for (Way w : Main.ds.ways) { 464 if (w.deleted || w.incomplete || w.nodes.size() < 1) continue; 465 Node firstNode = w.nodes.get(0); 466 Node lastNode = w.nodes.get(w.nodes.size() - 1); 467 if ((firstNode == n || lastNode == n) && (firstNode != lastNode)) { 468 if (way != null) 469 return null; 470 way = w; 471 } 472 } 473 return way; 474 } 475 476 private static void pruneSuccsAndReverse(List<Integer> is) { 477 //if (is.size() < 2) return; 478 479 HashSet<Integer> is2 = new HashSet<Integer>(); 480 for (int i : is) { 481 if (!is2.contains(i - 1) && !is2.contains(i + 1)) { 482 is2.add(i); 483 } 484 } 485 is.clear(); 486 is.addAll(is2); 487 Collections.sort(is); 488 Collections.reverse(is); 489 } 490 491 /** 492 * Adjusts the position of a node to lie on a segment (or a segment 493 * intersection). 494 * 495 * If one or more than two segments are passed, the node is adjusted 496 * to lie on the first segment that is passed. 497 * 498 * If two segments are passed, the node is adjusted to be at their 499 * intersection. 500 * 501 * No action is taken if no segments are passed. 502 * 503 * @param segs the segments to use as a reference when adjusting 504 * @param n the node to adjust 505 */ 506 private static void adjustNode(Collection<Pair<Node,Node>> segs, Node n) { 507 508 switch (segs.size()) { 509 case 0: 510 return; 511 case 2: 512 // This computes the intersection between 513 // the two segments and adjusts the node position. 514 Iterator<Pair<Node,Node>> i = segs.iterator(); 515 Pair<Node,Node> seg = i.next(); 516 EastNorth A = seg.a.eastNorth; 517 EastNorth B = seg.b.eastNorth; 518 seg = i.next(); 519 EastNorth C = seg.a.eastNorth; 520 EastNorth D = seg.b.eastNorth; 521 522 double u=det(B.east() - A.east(), B.north() - A.north(), C.east() - D.east(), C.north() - D.north()); 523 524 // Check for parallel segments and do nothing if they are 525 // In practice this will probably only happen when a way has been duplicated 526 527 if (u == 0) return; 528 529 // q is a number between 0 and 1 530 // It is the point in the segment where the intersection occurs 531 // if the segment is scaled to lenght 1 532 533 double q = det(B.north() - C.north(), B.east() - C.east(), D.north() - C.north(), D.east() - C.east()) / u; 534 EastNorth intersection = new EastNorth( 535 B.east() + q * (A.east() - B.east()), 536 B.north() + q * (A.north() - B.north())); 537 538 int snapToIntersectionThreshold=0; 539 try { snapToIntersectionThreshold = Integer.parseInt(Main.pref.get("edit.snap-intersection-threshold","10")); } catch (NumberFormatException x) {} 540 541 // only adjust to intersection if within snapToIntersectionThreshold pixel of mouse click; otherwise 542 // fall through to default action. 543 // (for semi-parallel lines, intersection might be miles away!) 544 if (Main.map.mapView.getPoint(n.eastNorth).distance(Main.map.mapView.getPoint(intersection)) < snapToIntersectionThreshold) { 545 n.eastNorth = intersection; 546 return; 547 } 548 549 default: 550 EastNorth P = n.eastNorth; 551 seg = segs.iterator().next(); 552 A = seg.a.eastNorth; 553 B = seg.b.eastNorth; 554 double a = P.distanceSq(B); 555 double b = P.distanceSq(A); 556 double c = A.distanceSq(B); 557 557 q = (a - b + c) / (2*c); 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 558 n.eastNorth = new EastNorth( 559 B.east() + q * (A.east() - B.east()), 560 B.north() + q * (A.north() - B.north())); 561 } 562 } 563 564 // helper for adjustNode 565 static double det(double a, double b, double c, double d) 566 { 567 return a * d - b * c; 568 } 569 570 public void paint(Graphics g, MapView mv) { 571 572 // don't draw line if disabled in prefs 573 if (!drawHelperLine) return; 574 575 // sanity checks 576 if (Main.map.mapView == null) return; 577 if (mousePos == null) return; 578 579 // if shift key is held ("no auto-connect"), don't draw a line 580 if (shift) return; 581 582 // don't draw line if we don't know where from or where to 583 if (currentBaseNode == null) return; 584 if (currentMouseEastNorth == null) return; 585 586 // don't draw line if mouse is outside window 587 if (!Main.map.mapView.getBounds().contains(mousePos)) return; 588 589 Graphics2D g2 = (Graphics2D) g; 590 g2.setColor(selectedColor); 591 g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 592 GeneralPath b = new GeneralPath(); 593 Point p1=mv.getPoint(currentBaseNode.eastNorth); 594 Point p2=mv.getPoint(currentMouseEastNorth); 595 596 double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI; 597 598 b.moveTo(p1.x,p1.y); b.lineTo(p2.x, p2.y); 599 600 // if alt key is held ("start new way"), draw a little perpendicular line 601 if (alt) { 602 b.moveTo((int)(p1.x + 8*Math.cos(t+PHI)), (int)(p1.y + 8*Math.sin(t+PHI))); 603 b.lineTo((int)(p1.x + 8*Math.cos(t-PHI)), (int)(p1.y + 8*Math.sin(t-PHI))); 604 } 605 606 g2.draw(b); 607 g2.setStroke(new BasicStroke(1)); 608 609 } 610 611 @Override public String getModeHelpText() { 612 String rv; 613 614 if (currentBaseNode != null && !shift) { 615 if (mouseOnExistingNode) { 616 if (alt && /* FIXME: way exists */true) 617 rv = tr("Click to create a new way to the existing node."); 618 else 619 rv =tr("Click to make a connection to the existing node."); 620 } else { 621 if (alt && /* FIXME: way exists */true) 622 rv = tr("Click to insert a node and create a new way."); 623 else 624 rv = tr("Click to insert a new node and make a connection."); 625 } 626 } 627 else { 628 rv = tr("Click to insert a new node."); 629 } 630 631 //rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way")); 632 //rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way")); 633 return rv.toString(); 634 } 635 635 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java
r1158 r1169 40 40 public class ExtrudeAction extends MapMode implements MapViewPaintable { 41 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 42 enum Mode { EXTRUDE, rotate, select } 43 private Mode mode = null; 44 private long mouseDownTime = 0; 45 private WaySegment selectedSegment = null; 46 private Color selectedColor; 47 48 double xoff; 49 double yoff; 50 double distance; 51 52 /** 53 * The old cursor before the user pressed the mouse button. 54 */ 55 private Cursor oldCursor; 56 /** 57 * The current position of the mouse 58 */ 59 private Point mousePos; 60 /** 61 * The position of the mouse cursor when the drag action was initiated. 62 */ 63 private Point initialMousePos; 64 /** 65 * The time which needs to pass between click and release before something 66 * counts as a move, in milliseconds 67 */ 68 private int initialMoveDelay = 200; 69 70 /** 71 * Create a new SelectAction 72 * @param mapFrame The MapFrame this action belongs to. 73 */ 74 public ExtrudeAction(MapFrame mapFrame) { 75 super(tr("Extrude"), "extrude/extrude", tr("Create areas"), 76 Shortcut.registerShortcut("mapmode:extrude", tr("Mode: {0}", tr("Extrude")), KeyEvent.VK_X, Shortcut.GROUP_EDIT), 77 mapFrame, 78 getCursor("normal", "rectangle", Cursor.DEFAULT_CURSOR)); 79 putValue("help", "Action/Extrude/Extrude"); 80 initialMoveDelay = Main.pref.getInteger("edit.initial-move-delay",200); 81 selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW); 82 } 83 84 private static Cursor getCursor(String name, String mod, int def) { 85 try { 86 return ImageProvider.getCursor(name, mod); 87 87 } catch (Exception e) { 88 88 } 89 90 } 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 89 return Cursor.getPredefinedCursor(def); 90 } 91 92 private void setCursor(Cursor c) { 93 if (oldCursor == null) { 94 oldCursor = Main.map.mapView.getCursor(); 95 Main.map.mapView.setCursor(c); 96 } 97 } 98 99 private void restoreCursor() { 100 if (oldCursor != null) { 101 Main.map.mapView.setCursor(oldCursor); 102 oldCursor = null; 103 } 104 } 105 106 @Override public void enterMode() { 107 super.enterMode(); 108 Main.map.mapView.addMouseListener(this); 109 Main.map.mapView.addMouseMotionListener(this); 110 } 111 112 @Override public void exitMode() { 113 super.exitMode(); 114 Main.map.mapView.removeMouseListener(this); 115 Main.map.mapView.removeMouseMotionListener(this); 116 Main.map.mapView.removeTemporaryLayer(this); 117 118 } 119 120 /** 121 * If the left mouse button is pressed, move all currently selected 122 * objects (if one of them is under the mouse) or the current one under the 123 * mouse (which will become selected). 124 */ 125 @Override public void mouseDragged(MouseEvent e) { 126 if (mode == Mode.select) return; 127 128 // do not count anything as a move if it lasts less than 100 milliseconds. 129 if ((mode == Mode.EXTRUDE) && (System.currentTimeMillis() - mouseDownTime < initialMoveDelay)) return; 130 131 if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0) 132 return; 133 134 if (mode == Mode.EXTRUDE) { 135 setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 136 } 137 138 if (mousePos == null) { 139 mousePos = e.getPoint(); 140 return; 141 } 142 143 Main.map.mapView.repaint(); 144 mousePos = e.getPoint(); 145 146 } 147 148 public void paint(Graphics g, MapView mv) { 149 if (selectedSegment != null) { 150 Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex); 151 Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1); 152 153 EastNorth en1 = n1.eastNorth; 154 EastNorth en2 = n2.eastNorth; 155 if (en1.east() < en2.east()) { en2 = en1; en1 = n2.eastNorth; } 156 EastNorth en3 = mv.getEastNorth(mousePos.x, mousePos.y); 157 158 double u = ((en3.east()-en1.east())*(en2.east()-en1.east()) + (en3.north()-en1.north())*(en2.north()-en1.north()))/en2.distanceSq(en1); 159 // the point on the segment from which the distance to mouse pos is shortest 160 EastNorth base = new EastNorth(en1.east()+u*(en2.east()-en1.east()), en1.north()+u*(en2.north()-en1.north())); 161 162 // the distance, in projection units, between the base point and the mouse cursor 163 double len = base.distance(en3); 164 165 // find out the distance, in metres, between the base point and the mouse cursor 166 distance = Main.proj.eastNorth2latlon(base).greatCircleDistance(Main.proj.eastNorth2latlon(en3)); 167 Main.map.statusLine.setDist(distance); 168 updateStatusLine(); 169 170 // compute the angle at which the segment is drawn 171 // and use it to compute the x and y offsets for the 172 // corner points. 173 double sin_alpha = (en2.north()-en1.north())/en2.distance(en1); 174 175 // this is a kludge because sometimes extrusion just goes the wrong direction 176 if ((en3.east()>base.east()) ^ (sin_alpha < 0)) len=-len; 177 xoff = sin_alpha * len; 178 yoff = Math.sqrt(1-sin_alpha*sin_alpha) * len; 179 180 Graphics2D g2 = (Graphics2D) g; 181 g2.setColor(selectedColor); 182 g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 183 GeneralPath b = new GeneralPath(); 184 Point p1=mv.getPoint(en1); 185 Point p2=mv.getPoint(en2); 186 Point p3=mv.getPoint(en1.add(-xoff, -yoff)); 187 Point p4=mv.getPoint(en2.add(-xoff, -yoff)); 188 189 b.moveTo(p1.x,p1.y); b.lineTo(p3.x, p3.y); 190 b.lineTo(p4.x, p4.y); b.lineTo(p2.x, p2.y); 191 b.lineTo(p1.x,p1.y); 192 g2.draw(b); 193 g2.setStroke(new BasicStroke(1)); 194 } 195 } 196 197 /** 198 */ 199 @Override public void mousePressed(MouseEvent e) { 200 if (!(Boolean)this.getValue("active")) return; 201 if (e.getButton() != MouseEvent.BUTTON1) 202 return; 203 // boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0; 204 // boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0; 205 // boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; 206 207 mouseDownTime = System.currentTimeMillis(); 208 209 selectedSegment = 210 Main.map.mapView.getNearestWaySegment(e.getPoint()); 211 212 mode = (selectedSegment == null) ? Mode.select : Mode.EXTRUDE; 213 oldCursor = Main.map.mapView.getCursor(); 214 215 updateStatusLine(); 216 Main.map.mapView.addTemporaryLayer(this); 217 Main.map.mapView.repaint(); 218 219 mousePos = e.getPoint(); 220 initialMousePos = e.getPoint(); 221 } 222 223 /** 224 * Restore the old mouse cursor. 225 */ 226 @Override public void mouseReleased(MouseEvent e) { 227 restoreCursor(); 228 if (selectedSegment == null) return; 229 if (mousePos.distance(initialMousePos) > 10) { 230 Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex); 231 Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1); 232 EastNorth en3 = n2.eastNorth.add(-xoff, -yoff); 233 Node n3 = new Node(Main.proj.eastNorth2latlon(en3)); 234 EastNorth en4 = n1.eastNorth.add(-xoff, -yoff); 235 Node n4 = new Node(Main.proj.eastNorth2latlon(en4)); 236 Way wnew = new Way(selectedSegment.way); 237 wnew.nodes.add(selectedSegment.lowerIndex+1, n3); 238 wnew.nodes.add(selectedSegment.lowerIndex+1, n4); 239 if (wnew.nodes.size() == 4) wnew.nodes.add(n1); 240 Collection<Command> cmds = new LinkedList<Command>(); 241 cmds.add(new AddCommand(n4)); 242 cmds.add(new AddCommand(n3)); 243 cmds.add(new ChangeCommand(selectedSegment.way, wnew)); 244 Command c = new SequenceCommand(tr("Extrude Way"), cmds); 245 Main.main.undoRedo.add(c); 246 } 247 248 Main.map.mapView.removeTemporaryLayer(this); 249 selectedSegment = null; 250 mode = null; 251 updateStatusLine(); 252 Main.map.mapView.repaint(); 253 } 254 255 @Override public String getModeHelpText() { 256 if (mode == Mode.select) { 257 return tr("Release the mouse button to select the objects in the rectangle."); 258 } else if (mode == Mode.EXTRUDE) { 259 return tr("Draw a rectangle of the desired size, then release the mouse button."); 260 } else if (mode == Mode.rotate) { 261 return tr("Release the mouse button to stop rotating."); 262 } else { 263 return tr("Drag a way segment to make a rectangle."); 264 } 265 } 266 266 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java
r1084 r1169 23 23 */ 24 24 abstract public class MapMode extends JosmAction implements MouseListener, MouseMotionListener { 25 26 25 private final Cursor cursor; 26 private Cursor oldCursor; 27 27 28 29 30 31 32 33 34 35 28 /** 29 * Constructor for mapmodes without an menu 30 */ 31 public MapMode(String name, String iconName, String tooltip, Shortcut shortcut, MapFrame mapFrame, Cursor cursor) { 32 super(name, "mapmode/"+iconName, tooltip, shortcut, false); 33 this.cursor = cursor; 34 putValue("active", false); 35 } 36 36 37 38 39 40 41 42 43 44 45 37 /** 38 * Constructor for mapmodes without an menu 39 */ 40 @Deprecated 41 public MapMode(String name, String iconName, String tooltip, int keystroke, MapFrame mapFrame, Cursor cursor) { 42 super(name, "mapmode/"+iconName, tooltip, keystroke, 0, false); 43 this.cursor = cursor; 44 putValue("active", false); 45 } 46 46 47 48 49 50 51 52 53 54 55 47 /** 48 * Constructor for mapmodes with an menu (no shortcut will be registered) 49 */ 50 public MapMode(String name, String iconName, String tooltip, MapFrame mapFrame, Cursor cursor) { 51 putValue(NAME, name); 52 putValue(SMALL_ICON, ImageProvider.get("mapmode", iconName)); 53 putValue(SHORT_DESCRIPTION, tooltip); 54 this.cursor = cursor; 55 } 56 56 57 58 59 60 61 62 63 64 65 66 57 public void enterMode() { 58 putValue("active", true); 59 oldCursor = Main.map.mapView.getCursor(); 60 Main.map.mapView.setCursor(cursor); 61 updateStatusLine(); 62 } 63 public void exitMode() { 64 putValue("active", false); 65 Main.map.mapView.setCursor(oldCursor); 66 } 67 67 68 69 70 71 68 protected void updateStatusLine() { 69 Main.map.statusLine.setHelpText(getModeHelpText()); 70 Main.map.statusLine.repaint(); 71 } 72 72 73 74 75 76 77 78 79 80 81 82 73 public String getModeHelpText() { 74 return ""; 75 } 76 /** 77 * Call selectMapMode(this) on the parent mapFrame. 78 */ 79 public void actionPerformed(ActionEvent e) { 80 if (Main.map != null) 81 Main.map.selectMapMode(this); 82 } 83 83 84 85 86 87 88 89 90 84 public void mouseReleased(MouseEvent e) {} 85 public void mouseExited(MouseEvent e) {} 86 public void mousePressed(MouseEvent e) {} 87 public void mouseClicked(MouseEvent e) {} 88 public void mouseEntered(MouseEvent e) {} 89 public void mouseMoved(MouseEvent e) {} 90 public void mouseDragged(MouseEvent e) {} 91 91 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/PlayHeadDragMode.java
r1047 r1169 21 21 public class PlayHeadDragMode extends MapMode { 22 22 23 24 25 26 23 private boolean dragging = false; 24 private Point mousePos = null; 25 private Point mouseStart = null; 26 private PlayHeadMarker playHeadMarker = null; 27 27 28 29 30 31 32 28 public PlayHeadDragMode(PlayHeadMarker m) { 29 super("play head drag", "playheaddrag", "play head drag", null, 30 Main.map, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 31 playHeadMarker = m; 32 } 33 33 34 35 36 37 38 34 @Override public void enterMode() { 35 super.enterMode(); 36 Main.map.mapView.addMouseListener(this); 37 Main.map.mapView.addMouseMotionListener(this); 38 } 39 39 40 41 42 43 44 40 @Override public void exitMode() { 41 super.exitMode(); 42 Main.map.mapView.removeMouseListener(this); 43 Main.map.mapView.removeMouseMotionListener(this); 44 } 45 45 46 47 48 46 @Override public void mousePressed(MouseEvent ev) { 47 mouseStart = mousePos = ev.getPoint(); 48 } 49 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 50 @Override public void mouseDragged(MouseEvent ev) { 51 if (mouseStart == null || mousePos == null) return; 52 if ((ev.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0) return; 53 Point p = ev.getPoint(); 54 if (p == null) return; 55 if (! dragging) { 56 if (p.distance(mouseStart) < 3) return; 57 playHeadMarker.startDrag(); 58 dragging = true; 59 } 60 if (p.distance(mousePos) == 0) return; 61 playHeadMarker.drag(Main.map.mapView.getEastNorth(ev.getX(), ev.getY())); 62 mousePos = p; 63 } 64 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 65 @Override public void mouseReleased(MouseEvent ev) { 66 Point p = ev.getPoint(); 67 mouseStart = null; 68 if (ev.getButton() != MouseEvent.BUTTON1 || p == null || ! dragging) 69 return; 70 boolean shift = (ev.getModifiers() & ActionEvent.SHIFT_MASK) != 0; 71 EastNorth en = Main.map.mapView.getEastNorth(ev.getX(), ev.getY()); 72 if (! shift) { 73 playHeadMarker.reposition(en); 74 } else { 75 playHeadMarker.synchronize(en); 76 } 77 mousePos = null; 78 dragging = false; 79 79 80 81 82 83 84 80 /* 81 boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0; 82 boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0; 83 */ 84 } 85 85 86 87 88 86 @Override public String getModeHelpText() { 87 return tr("Drag play head and release near track to play audio from there; SHIFT+release to synchronize audio at that point."); 88 } 89 89 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java
r1084 r1169 30 30 public class ZoomAction extends MapMode implements SelectionEnded { 31 31 32 33 34 35 36 37 38 39 40 32 /** 33 * Shortcut to the mapview. 34 */ 35 private final MapView mv; 36 /** 37 * Manager that manages the selection rectangle with the aspect ratio of the 38 * MapView. 39 */ 40 private final SelectionManager selectionManager; 41 41 42 42 43 44 45 46 47 48 49 50 51 52 53 43 /** 44 * Construct a ZoomAction without a label. 45 * @param mapFrame The MapFrame, whose zoom mode should be enabled. 46 */ 47 public ZoomAction(MapFrame mapFrame) { 48 super(tr("Zoom"), "zoom", tr("Zoom and move map"), 49 Shortcut.registerShortcut("mapmode:zoom", tr("Mode: {0}", tr("Zoom")), KeyEvent.VK_Z, Shortcut.GROUP_EDIT), 50 mapFrame, ImageProvider.getCursor("normal", "zoom")); 51 mv = mapFrame.mapView; 52 selectionManager = new SelectionManager(this, true, mv); 53 } 54 54 55 56 57 58 59 60 61 62 63 64 55 /** 56 * Zoom to the rectangle on the map. 57 */ 58 public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) { 59 if (r.width >= 3 && r.height >= 3) { 60 double scale = mv.getScale() * r.getWidth()/mv.getWidth(); 61 EastNorth newCenter = mv.getEastNorth(r.x+r.width/2, r.y+r.height/2); 62 mv.zoomTo(newCenter, scale); 63 } 64 } 65 65 66 67 68 69 66 @Override public void enterMode() { 67 super.enterMode(); 68 selectionManager.register(mv); 69 } 70 70 71 72 73 74 71 @Override public void exitMode() { 72 super.exitMode(); 73 selectionManager.unregister(mv); 74 } 75 75 76 77 78 76 @Override public String getModeHelpText() { 77 return tr("Zoom by dragging or Ctrl+. or Ctrl+,; move with Ctrl+up,left,down,right; move zoom with right button"); 78 } 79 79 } -
trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java
r1149 r1169 7 7 8 8 public class PushbackTokenizer { 9 9 private PushbackReader search; 10 10 11 11 private LinkedList<String> pushBackBuf = new LinkedList<String>(); 12 12 13 14 15 13 public PushbackTokenizer(PushbackReader search) { 14 this.search = search; 15 } 16 16 17 18 19 20 21 22 23 24 25 26 27 28 17 /** 18 * The token returned is <code>null</code> or starts with an identifier character: 19 * - for an '-'. This will be the only character 20 * : for an key. The value is the next token 21 * | for "OR" 22 * ' ' for anything else. 23 * @return The next token in the stream. 24 */ 25 public String nextToken() { 26 if (!pushBackBuf.isEmpty()) { 27 return pushBackBuf.removeLast(); 28 } 29 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 } 85 30 try { 31 int next; 32 char c = ' '; 33 while (c == ' ' || c == '\t' || c == '\n') { 34 next = search.read(); 35 if (next == -1) 36 return null; 37 c = (char)next; 38 } 39 StringBuilder s; 40 switch (c) { 41 case ':': 42 next = search.read(); 43 c = (char) next; 44 if (next == -1 || c == ' ' || c == '\t') { 45 pushBack(" "); 46 } else { 47 search.unread(next); 48 } 49 return ":"; 50 case '-': 51 return "-"; 52 case '(': 53 return "("; 54 case ')': 55 return ")"; 56 case '|': 57 return "|"; 58 case '"': 59 s = new StringBuilder(" "); 60 for (int nc = search.read(); nc != -1 && nc != '"'; nc = search.read()) 61 s.append((char)nc); 62 return s.toString(); 63 default: 64 s = new StringBuilder(); 65 for (;;) { 66 s.append(c); 67 next = search.read(); 68 if (next == -1) { 69 if (s.toString().equals("OR")) 70 return "|"; 71 return " "+s.toString(); 72 } 73 c = (char)next; 74 if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')' || c == '|') { 75 search.unread(next); 76 if (s.toString().equals("OR")) 77 return "|"; 78 return " "+s.toString(); 79 } 80 } 81 } 82 } catch (IOException e) { 83 throw new RuntimeException(e.getMessage(), e); 84 } 85 } 86 86 87 88 89 90 91 92 93 87 public boolean readIfEqual(String tok) { 88 String nextTok = nextToken(); 89 if (nextTok == null ? tok == null : nextTok.equals(tok)) 90 return true; 91 pushBack(nextTok); 92 return false; 93 } 94 94 95 96 97 98 99 100 101 95 public String readText() { 96 String nextTok = nextToken(); 97 if (nextTok != null && nextTok.startsWith(" ")) 98 return nextTok.substring(1); 99 pushBack(nextTok); 100 return null; 101 } 102 102 103 104 105 103 public void pushBack(String tok) { 104 pushBackBuf.addLast(tok); 105 } 106 106 } -
trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
r1168 r1169 20 20 public class SearchCompiler { 21 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 22 private boolean caseSensitive = false; 23 private PushbackTokenizer tokenizer; 24 25 public SearchCompiler(boolean caseSensitive, PushbackTokenizer tokenizer) { 26 this.caseSensitive = caseSensitive; 27 this.tokenizer = tokenizer; 28 } 29 30 abstract public static class Match { 31 abstract public boolean match(OsmPrimitive osm); 32 } 33 34 private static class Always extends Match { 35 @Override public boolean match(OsmPrimitive osm) { 36 return true; 37 } 38 } 39 40 private static class Not extends Match { 41 private final Match match; 42 public Not(Match match) {this.match = match;} 43 @Override public boolean match(OsmPrimitive osm) { 44 return !match.match(osm); 45 } 46 @Override public String toString() {return "!"+match;} 47 } 48 49 private static class And extends Match { 50 private Match lhs; 51 private Match rhs; 52 public And(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;} 53 @Override public boolean match(OsmPrimitive osm) { 54 return lhs.match(osm) && rhs.match(osm); 55 } 56 @Override public String toString() {return lhs+" && "+rhs;} 57 } 58 59 private static class Or extends Match { 60 private Match lhs; 61 private Match rhs; 62 public Or(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;} 63 @Override public boolean match(OsmPrimitive osm) { 64 return lhs.match(osm) || rhs.match(osm); 65 } 66 @Override public String toString() {return lhs+" || "+rhs;} 67 } 68 69 private static class Id extends Match { 70 private long id; 71 public Id(long id) {this.id = id;} 72 @Override public boolean match(OsmPrimitive osm) { 73 return osm.id == id; 74 } 75 @Override public String toString() {return "id="+id;} 76 } 77 78 private class KeyValue extends Match { 79 private String key; 80 private String value; 81 public KeyValue(String key, String value) {this.key = key; this.value = value; } 82 @Override public boolean match(OsmPrimitive osm) { 83 String value = null; 84 if (key.equals("timestamp")) 85 value = osm.getTimeStr(); 86 else 87 value = osm.get(key); 88 if (value == null) 89 return false; 90 String v1 = caseSensitive ? value : value.toLowerCase(); 91 String v2 = caseSensitive ? this.value : this.value.toLowerCase(); 92 // is not Java 1.5 93 //v1 = java.text.Normalizer.normalize(v1, java.text.Normalizer.Form.NFC); 94 //v2 = java.text.Normalizer.normalize(v2, java.text.Normalizer.Form.NFC); 95 return v1.indexOf(v2) != -1; 96 } 97 @Override public String toString() {return key+"="+value;} 98 } 99 100 private class Any extends Match { 101 private String s; 102 public Any(String s) {this.s = s;} 103 @Override public boolean match(OsmPrimitive osm) { 104 if (osm.keys == null) 105 return s.equals(""); 106 String search = caseSensitive ? s : s.toLowerCase(); 107 // is not Java 1.5 108 //search = java.text.Normalizer.normalize(search, java.text.Normalizer.Form.NFC); 109 for (Entry<String, String> e : osm.keys.entrySet()) { 110 String key = caseSensitive ? e.getKey() : e.getKey().toLowerCase(); 111 String value = caseSensitive ? e.getValue() : e.getValue().toLowerCase(); 112 // is not Java 1.5 113 //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC); 114 if (key.indexOf(search) != -1 || value.indexOf(search) != -1) 115 return true; 116 } 117 if (osm.user != null) { 118 String name = osm.user.name; 119 // is not Java 1.5 120 //String name = java.text.Normalizer.normalize(name, java.text.Normalizer.Form.NFC); 121 if (!caseSensitive) 122 name = name.toLowerCase(); 123 if (name.indexOf(search) != -1) 124 return true; 125 } 126 return false; 127 } 128 @Override public String toString() {return s;} 129 } 130 131 private static class ExactType extends Match { 132 private String type; 133 public ExactType(String type) {this.type = type;} 134 @Override public boolean match(OsmPrimitive osm) { 135 if (osm instanceof Node) 136 return type.equals("node"); 137 if (osm instanceof Way) 138 return type.equals("way"); 139 if (osm instanceof Relation) 140 return type.equals("relation"); 141 throw new IllegalStateException("unknown class "+osm.getClass()); 142 } 143 @Override public String toString() {return "type="+type;} 144 } 145 146 private static class UserMatch extends Match { 147 private User user; 148 public UserMatch(String user) { this.user = User.get(user); } 149 @Override public boolean match(OsmPrimitive osm) { 150 return osm.user == user; 151 } 152 @Override public String toString() { return "user=" + user.name; } 153 } 154 155 private static class NodeCount extends Match { 156 private int count; 157 public NodeCount(int count) {this.count = count;} 158 @Override public boolean match(OsmPrimitive osm) { 159 return osm instanceof Way && ((Way) osm).nodes.size() == count; 160 } 161 @Override public String toString() {return "nodes="+count;} 162 } 163 164 private static class Modified extends Match { 165 @Override public boolean match(OsmPrimitive osm) { 166 return osm.modified || osm.id == 0; 167 } 168 @Override public String toString() {return "modified";} 169 } 170 171 private static class Selected extends Match { 172 @Override public boolean match(OsmPrimitive osm) { 173 return osm.selected; 174 } 175 @Override public String toString() {return "selected";} 176 } 177 178 private static class Incomplete extends Match { 179 @Override public boolean match(OsmPrimitive osm) { 180 180 return osm.incomplete; 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 181 } 182 @Override public String toString() {return "incomplete";} 183 } 184 185 public static class ParseError extends Exception { 186 public ParseError(String msg) { 187 super(msg); 188 } 189 } 190 191 public static Match compile(String searchStr, boolean caseSensitive) 192 throws ParseError { 193 return new SearchCompiler(caseSensitive, 194 new PushbackTokenizer( 195 new PushbackReader(new StringReader(searchStr)))) 196 .parse(); 197 } 198 199 public Match parse() throws ParseError { 200 Match m = parseJuxta(); 201 if (!tokenizer.readIfEqual(null)) { 202 throw new ParseError("Unexpected token: " + tokenizer.nextToken()); 203 } 204 return m; 205 } 206 207 private Match parseJuxta() throws ParseError { 208 Match juxta = new Always(); 209 210 Match m; 211 while ((m = parseOr()) != null) { 212 juxta = new And(m, juxta); 213 } 214 215 return juxta; 216 } 217 218 private Match parseOr() throws ParseError { 219 Match a = parseNot(); 220 if (tokenizer.readIfEqual("|")) { 221 Match b = parseNot(); 222 if (a == null || b == null) { 223 throw new ParseError(tr("Missing arguments for or.")); 224 } 225 return new Or(a, b); 226 } 227 return a; 228 } 229 230 private Match parseNot() throws ParseError { 231 if (tokenizer.readIfEqual("-")) { 232 Match m = parseParens(); 233 if (m == null) { 234 throw new ParseError(tr("Missing argument for not.")); 235 } 236 return new Not(m); 237 } 238 return parseParens(); 239 } 240 241 private Match parseParens() throws ParseError { 242 if (tokenizer.readIfEqual("(")) { 243 Match m = parseJuxta(); 244 if (!tokenizer.readIfEqual(")")) { 245 throw new ParseError(tr("Expected closing parenthesis.")); 246 } 247 return m; 248 } 249 return parsePat(); 250 } 251 252 private Match parsePat() { 253 String tok = tokenizer.readText(); 254 255 if (tokenizer.readIfEqual(":")) { 256 String tok2 = tokenizer.readText(); 257 if (tok == null) tok = ""; 258 if (tok2 == null) tok2 = ""; 259 return parseKV(tok, tok2); 260 } 261 262 if (tok == null) { 263 return null; 264 } else if (tok.equals("modified")) { 265 return new Modified(); 266 } else if (tok.equals("incomplete")) { 267 return new Incomplete(); 268 } else if (tok.equals("selected")) { 269 return new Selected(); 270 } else { 271 return new Any(tok); 272 } 273 } 274 275 private Match parseKV(String key, String value) { 276 if (key.equals("type")) { 277 return new ExactType(value); 278 } else if (key.equals("user")) { 279 return new UserMatch(value); 280 } else if (key.equals("nodes")) { 281 return new NodeCount(Integer.parseInt(value)); 282 } else if (key.equals("id")) { 283 try { 284 return new Id(Long.parseLong(value)); 285 } catch (NumberFormatException x) { 286 return new Id(0); 287 } 288 } else { 289 return new KeyValue(key, value); 290 } 291 } 292 292 } -
trunk/src/org/openstreetmap/josm/actions/search/SelectionWebsiteLoader.java
r627 r1169 1 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others 2 2 /** 3 * 3 * 4 4 */ 5 5 package org.openstreetmap.josm.actions.search; … … 26 26 27 27 public class SelectionWebsiteLoader extends PleaseWaitRunnable { 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 28 public final URL url; 29 public Collection<OsmPrimitive> sel; 30 private final SearchAction.SearchMode mode; 31 private OsmIdReader idReader = new OsmIdReader(); 32 public SelectionWebsiteLoader(String urlStr, SearchAction.SearchMode mode) { 33 super(tr("Load Selection")); 34 this.mode = mode; 35 URL u = null; 36 try {u = new URL(urlStr);} catch (MalformedURLException e) {} 37 this.url = u; 38 } 39 @Override protected void realRun() { 40 Main.pleaseWaitDlg.currentAction.setText(tr("Contact {0}...", url.getHost())); 41 sel = mode != SearchAction.SearchMode.remove ? new LinkedList<OsmPrimitive>() : Main.ds.allNonDeletedPrimitives(); 42 try { 43 URLConnection con = url.openConnection(); 44 InputStream in = new ProgressInputStream(con, Main.pleaseWaitDlg); 45 Main.pleaseWaitDlg.currentAction.setText(tr("Downloading...")); 46 Map<Long, String> ids = idReader.parseIds(in); 47 for (OsmPrimitive osm : Main.ds.allNonDeletedPrimitives()) { 48 if (ids.containsKey(osm.id) && osm.getClass().getName().toLowerCase().endsWith(ids.get(osm.id))) { 49 if (mode == SearchAction.SearchMode.remove) 50 sel.remove(osm); 51 else 52 sel.add(osm); 53 } 54 } 55 } catch (IOException e) { 56 e.printStackTrace(); 57 JOptionPane.showMessageDialog(Main.parent, tr("Could not read from url: \"{0}\"",url)); 58 } catch (SAXException e) { 59 e.printStackTrace(); 60 JOptionPane.showMessageDialog(Main.parent,tr("Parsing error in url: \"{0}\"",url)); 61 } 62 } 63 @Override protected void cancel() { 64 sel = null; 65 idReader.cancel(); 66 } 67 @Override protected void finish() { 68 if (sel != null) 69 Main.ds.setSelected(sel); 70 } 71 71 } -
trunk/src/org/openstreetmap/josm/command/AddCommand.java
r655 r1169 22 22 * A command that adds an osm primitive to a dataset. Keys cannot be added this 23 23 * way. 24 * 24 * 25 25 * See {@link ChangeCommand ChangeCommand} for comments on relation back references. 26 * 26 * 27 27 * @author imi 28 28 */ 29 29 public class AddCommand extends Command { 30 30 31 /** 32 * The primitive to add to the dataset. 33 */ 34 private final OsmPrimitive osm; 35 36 private DataSet ds; 31 /** 32 * The primitive to add to the dataset. 33 */ 34 private final OsmPrimitive osm; 37 35 38 /** 39 * Create the command and specify the element to add. 40 */ 41 public AddCommand(OsmPrimitive osm) { 42 this.osm = osm; 43 this.ds = Main.main.editLayer().data; 44 } 36 private DataSet ds; 45 37 46 @Override public boolean executeCommand() { 47 osm.visit(new AddVisitor(ds)); 48 return true; 49 } 50 51 @Override public void undoCommand() { 52 osm.visit(new DeleteVisitor(ds)); 53 } 54 55 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 56 added.add(osm); 57 } 58 59 // faster implementation 60 @Override public boolean invalidBecauselayerRemoved(Layer oldLayer) { 61 return oldLayer instanceof OsmDataLayer && ((OsmDataLayer)oldLayer).data == ds; 38 /** 39 * Create the command and specify the element to add. 40 */ 41 public AddCommand(OsmPrimitive osm) { 42 this.osm = osm; 43 this.ds = Main.main.editLayer().data; 62 44 } 63 45 64 @Override public MutableTreeNode description() { 65 NameVisitor v = new NameVisitor(); 66 osm.visit(v); 67 return new DefaultMutableTreeNode(new JLabel(tr("Add")+" "+tr(v.className)+" "+v.name, v.icon, JLabel.HORIZONTAL)); 46 @Override public boolean executeCommand() { 47 osm.visit(new AddVisitor(ds)); 48 return true; 49 } 50 51 @Override public void undoCommand() { 52 osm.visit(new DeleteVisitor(ds)); 53 } 54 55 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 56 added.add(osm); 57 } 58 59 // faster implementation 60 @Override public boolean invalidBecauselayerRemoved(Layer oldLayer) { 61 return oldLayer instanceof OsmDataLayer && ((OsmDataLayer)oldLayer).data == ds; 62 } 63 64 @Override public MutableTreeNode description() { 65 NameVisitor v = new NameVisitor(); 66 osm.visit(v); 67 return new DefaultMutableTreeNode(new JLabel(tr("Add")+" "+tr(v.className)+" "+v.name, v.icon, JLabel.HORIZONTAL)); 68 68 } 69 69 } -
trunk/src/org/openstreetmap/josm/command/ChangeCommand.java
r630 r1169 14 14 15 15 /** 16 * Command that basically replaces one OSM primitive by another of the 16 * Command that basically replaces one OSM primitive by another of the 17 17 * same type. 18 * 18 * 19 19 * @author Imi 20 20 */ 21 21 public class ChangeCommand extends Command { 22 22 23 24 23 private final OsmPrimitive osm; 24 private final OsmPrimitive newOsm; 25 25 26 27 28 26 public ChangeCommand(OsmPrimitive osm, OsmPrimitive newOsm) { 27 this.osm = osm; 28 this.newOsm = newOsm; 29 29 } 30 30 31 32 33 34 35 31 @Override public boolean executeCommand() { 32 super.executeCommand(); 33 osm.cloneFrom(newOsm); 34 osm.modified = true; 35 return true; 36 36 } 37 37 38 39 38 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 39 modified.add(osm); 40 40 } 41 41 42 43 44 45 42 @Override public MutableTreeNode description() { 43 NameVisitor v = new NameVisitor(); 44 osm.visit(v); 45 return new DefaultMutableTreeNode(new JLabel(tr("Change")+" "+tr(v.className)+" "+v.name, v.icon, JLabel.HORIZONTAL)); 46 46 } 47 47 } -
trunk/src/org/openstreetmap/josm/command/ChangePropertyCommand.java
r1101 r1169 20 20 * Command that manipulate the key/value structure of several objects. Manages deletion, 21 21 * adding and modify of values and keys. 22 * 22 * 23 23 * @author imi 24 24 */ 25 25 public class ChangePropertyCommand extends Command { 26 /** 27 * All primitives that are affected with this command. 28 */ 29 private final List<OsmPrimitive> objects; 30 /** 31 * The key that is subject to change. 32 */ 33 private final String key; 34 /** 35 * The key value. If it is <code>null</code>, delete all key references with the given 36 * key. Otherwise, change the properties of all objects to the given value or create keys of 37 * those objects that do not have the key yet. 38 */ 39 private final String value; 40 41 public ChangePropertyCommand(Collection<? extends OsmPrimitive> objects, String key, String value) { 42 this.objects = new LinkedList<OsmPrimitive>(); 43 this.key = key; 44 this.value = value; 45 if (value == null) { 46 for (OsmPrimitive osm : objects) { 47 if(osm.get(key) != null) 48 this.objects.add(osm); 49 } 50 } else { 51 for (OsmPrimitive osm : objects) { 52 String val = osm.get(key); 53 if (val == null || !value.equals(val)) { 54 this.objects.add(osm); 55 } 56 } 57 } 58 } 26 /** 27 * All primitives that are affected with this command. 28 */ 29 private final List<OsmPrimitive> objects; 30 /** 31 * The key that is subject to change. 32 */ 33 private final String key; 34 /** 35 * The key value. If it is <code>null</code>, delete all key references with the given 36 * key. Otherwise, change the properties of all objects to the given value or create keys of 37 * those objects that do not have the key yet. 38 */ 39 private final String value; 59 40 60 public ChangePropertyCommand(OsmPrimitive object, String key, String value) { 61 this.objects = new LinkedList<OsmPrimitive>(); 62 this.key = key; 63 this.value = value; 64 String val = object.get(key); 65 if ((value == null && val != null) 66 || (value != null && (val == null || !value.equals(val)))) 67 this.objects.add(object); 68 } 69 70 @Override public boolean executeCommand() { 71 super.executeCommand(); // save old 72 if (value == null) { 73 for (OsmPrimitive osm : objects) { 74 osm.modified = true; 75 osm.remove(key); 76 } 77 } else { 78 for (OsmPrimitive osm : objects) { 79 osm.modified = true; 80 osm.put(key, value); 81 } 82 } 83 return true; 84 } 41 public ChangePropertyCommand(Collection<? extends OsmPrimitive> objects, String key, String value) { 42 this.objects = new LinkedList<OsmPrimitive>(); 43 this.key = key; 44 this.value = value; 45 if (value == null) { 46 for (OsmPrimitive osm : objects) { 47 if(osm.get(key) != null) 48 this.objects.add(osm); 49 } 50 } else { 51 for (OsmPrimitive osm : objects) { 52 String val = osm.get(key); 53 if (val == null || !value.equals(val)) { 54 this.objects.add(osm); 55 } 56 } 57 } 58 } 85 59 86 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 87 modified.addAll(objects); 88 } 60 public ChangePropertyCommand(OsmPrimitive object, String key, String value) { 61 this.objects = new LinkedList<OsmPrimitive>(); 62 this.key = key; 63 this.value = value; 64 String val = object.get(key); 65 if ((value == null && val != null) 66 || (value != null && (val == null || !value.equals(val)))) 67 this.objects.add(object); 68 } 89 69 90 @Override public MutableTreeNode description() { 91 String text = value == null ? tr( "Remove \"{0}\" for", key) : tr("Set {0}={1} for",key,value); 92 if (objects.size() == 1) { 93 NameVisitor v = new NameVisitor(); 94 objects.iterator().next().visit(v); 95 text += " "+tr(v.className)+" "+v.name; 96 } else 97 text += " "+objects.size()+" "+trn("object","objects",objects.size()); 98 DefaultMutableTreeNode root = new DefaultMutableTreeNode(new JLabel(text, ImageProvider.get("data", "key"), JLabel.HORIZONTAL)); 99 if (objects.size() == 1) 100 return root; 101 NameVisitor v = new NameVisitor(); 102 for (OsmPrimitive osm : objects) { 103 osm.visit(v); 104 root.add(new DefaultMutableTreeNode(v.toLabel())); 105 } 106 return root; 70 @Override public boolean executeCommand() { 71 super.executeCommand(); // save old 72 if (value == null) { 73 for (OsmPrimitive osm : objects) { 74 osm.modified = true; 75 osm.remove(key); 76 } 77 } else { 78 for (OsmPrimitive osm : objects) { 79 osm.modified = true; 80 osm.put(key, value); 81 } 82 } 83 return true; 84 } 85 86 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 87 modified.addAll(objects); 88 } 89 90 @Override public MutableTreeNode description() { 91 String text = value == null ? tr( "Remove \"{0}\" for", key) : tr("Set {0}={1} for",key,value); 92 if (objects.size() == 1) { 93 NameVisitor v = new NameVisitor(); 94 objects.iterator().next().visit(v); 95 text += " "+tr(v.className)+" "+v.name; 96 } else 97 text += " "+objects.size()+" "+trn("object","objects",objects.size()); 98 DefaultMutableTreeNode root = new DefaultMutableTreeNode(new JLabel(text, ImageProvider.get("data", "key"), JLabel.HORIZONTAL)); 99 if (objects.size() == 1) 100 return root; 101 NameVisitor v = new NameVisitor(); 102 for (OsmPrimitive osm : objects) { 103 osm.visit(v); 104 root.add(new DefaultMutableTreeNode(v.toLabel())); 105 } 106 return root; 107 107 } 108 108 } -
trunk/src/org/openstreetmap/josm/command/Command.java
r655 r1169 25 25 * one atomic action on a specific dataset, such as move or delete. 26 26 * 27 * Remember that the command must be executable and undoable, even if the 27 * Remember that the command must be executable and undoable, even if the 28 28 * Main.ds has changed, so the command must save the dataset it operates on 29 29 * if necessary. … … 47 47 } 48 48 49 private CloneVisitor orig; 49 private CloneVisitor orig; 50 50 51 51 protected DataSet ds; … … 70 70 71 71 /** 72 * Undoes the command. 72 * Undoes the command. 73 73 * It can be assumed that all objects are in the same state they were before. 74 74 * It can also be assumed that executeCommand was called exactly once before. 75 * 75 * 76 76 * This implementation undoes all objects stored by a former call to executeCommand. 77 77 */ … … 122 122 * Fill in the changed data this command operates on. 123 123 * Add to the lists, don't clear them. 124 * 124 * 125 125 * @param modified The modified primitives 126 126 * @param deleted The deleted primitives -
trunk/src/org/openstreetmap/josm/command/ConflictResolveCommand.java
r630 r1169 25 25 public class ConflictResolveCommand extends Command { 26 26 27 28 29 30 27 private final Collection<ConflictItem> conflicts; 28 private final Map<OsmPrimitive, OsmPrimitive> resolved; 29 private Map<OsmPrimitive, OsmPrimitive> origAllConflicts; 30 private final ConflictDialog conflictDialog; 31 31 32 33 34 35 36 32 public ConflictResolveCommand(List<ConflictItem> conflicts, Map<OsmPrimitive, OsmPrimitive> resolved) { 33 this.conflicts = conflicts; 34 this.resolved = resolved; 35 conflictDialog = Main.map.conflictDialog; 36 } 37 37 38 39 38 @Override public boolean executeCommand() { 39 super.executeCommand(); 40 40 41 origAllConflicts = new HashMap<OsmPrimitive, OsmPrimitive>(conflictDialog.conflicts); 42 43 Set<OsmPrimitive> completed = new HashSet<OsmPrimitive>(resolved.keySet()); 44 for (ConflictItem ci : conflicts) { 45 for (Entry<OsmPrimitive, OsmPrimitive> e : resolved.entrySet()) { 46 if (ci.resolution == ConflictResolver.Resolution.THEIR) 47 ci.apply(e.getKey(), e.getValue()); 48 else if (ci.resolution == ConflictResolver.Resolution.MY) 49 ci.apply(e.getValue(), e.getKey()); 50 else if (ci.hasConflict(e.getKey(), e.getValue())) 51 completed.remove(e.getKey()); 52 } 53 } 54 if (!completed.isEmpty()) { 55 for (OsmPrimitive k : completed) 56 conflictDialog.conflicts.remove(k); 57 conflictDialog.rebuildList(); 58 } 59 return true; 60 } 41 origAllConflicts = new HashMap<OsmPrimitive, OsmPrimitive>(conflictDialog.conflicts); 61 42 62 @Override public void undoCommand() { 63 super.undoCommand(); 64 Main.map.conflictDialog.conflicts.clear(); 65 Main.map.conflictDialog.conflicts.putAll(origAllConflicts); 66 Main.map.conflictDialog.rebuildList(); 67 } 43 Set<OsmPrimitive> completed = new HashSet<OsmPrimitive>(resolved.keySet()); 44 for (ConflictItem ci : conflicts) { 45 for (Entry<OsmPrimitive, OsmPrimitive> e : resolved.entrySet()) { 46 if (ci.resolution == ConflictResolver.Resolution.THEIR) 47 ci.apply(e.getKey(), e.getValue()); 48 else if (ci.resolution == ConflictResolver.Resolution.MY) 49 ci.apply(e.getValue(), e.getKey()); 50 else if (ci.hasConflict(e.getKey(), e.getValue())) 51 completed.remove(e.getKey()); 52 } 53 } 54 if (!completed.isEmpty()) { 55 for (OsmPrimitive k : completed) 56 conflictDialog.conflicts.remove(k); 57 conflictDialog.rebuildList(); 58 } 59 return true; 60 } 68 61 69 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 70 modified.addAll(resolved.keySet()); 71 } 62 @Override public void undoCommand() { 63 super.undoCommand(); 64 Main.map.conflictDialog.conflicts.clear(); 65 Main.map.conflictDialog.conflicts.putAll(origAllConflicts); 66 Main.map.conflictDialog.rebuildList(); 67 } 72 68 73 @Override public MutableTreeNode description() { 74 int i = 0; 75 for (ConflictItem c : conflicts) 76 if (c.resolution != null) 77 i++; 78 return new DefaultMutableTreeNode(new JLabel(tr("Resolve {0} conflicts in {1} objects",i,resolved.size()), ImageProvider.get("data", "object"), JLabel.HORIZONTAL)); 69 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 70 modified.addAll(resolved.keySet()); 71 } 72 73 @Override public MutableTreeNode description() { 74 int i = 0; 75 for (ConflictItem c : conflicts) 76 if (c.resolution != null) 77 i++; 78 return new DefaultMutableTreeNode(new JLabel(tr("Resolve {0} conflicts in {1} objects",i,resolved.size()), ImageProvider.get("data", "object"), JLabel.HORIZONTAL)); 79 79 } 80 80 } -
trunk/src/org/openstreetmap/josm/command/DeleteCommand.java
r1047 r1169 105 105 /** 106 106 * Delete the primitives and everything they reference. 107 * 107 * 108 108 * If a node is deleted, the node and all ways and relations the node is part of are deleted as 109 109 * well. 110 * 110 * 111 111 * If a way is deleted, all relations the way is member of are also deleted. 112 * 112 * 113 113 * If a way is deleted, only the way and no nodes are deleted. 114 * 114 * 115 115 * @param selection The list of all object to be deleted. 116 116 * @return command A command to perform the deletions, or null of there is nothing to delete. … … 130 130 /** 131 131 * Try to delete all given primitives. 132 * 132 * 133 133 * If a node is used by a way, it's removed from that way. If a node or a way is used by a 134 134 * relation, inform the user and do not delete. 135 * 135 * 136 136 * If this would cause ways with less than 2 nodes to be created, delete these ways instead. If 137 137 * they are part of a relation, inform the user and do not delete. 138 * 138 * 139 139 * @param selection The objects to delete. 140 140 * @param alsoDeleteNodesInWay <code>true</code> if nodes should be deleted as well … … 341 341 // leave message in one tr() as there is a grammatical connection. 342 342 tr("You are about to delete nodes outside of the area you have downloaded." + 343 "<br>" + 343 "<br>" + 344 344 "This can cause problems because other objects (that you don't see) might use them." + 345 "<br>" + 345 "<br>" + 346 346 "Do you really want to delete?") + "</html>")); 347 347 return DontShowAgainInfo.show("delete_outside_nodes", msg, false, JOptionPane.YES_NO_OPTION, JOptionPane.YES_OPTION); -
trunk/src/org/openstreetmap/josm/command/MoveCommand.java
r655 r1169 26 26 * MoveCommand moves a set of OsmPrimitives along the map. It can be moved again 27 27 * to collect several MoveCommands into one command. 28 * 28 * 29 29 * @author imi 30 30 */ 31 31 public class MoveCommand extends Command { 32 33 34 35 36 37 38 39 40 41 42 43 32 /** 33 * The objects that should be moved. 34 */ 35 public Collection<Node> objects = new LinkedList<Node>(); 36 /** 37 * x difference movement. Coordinates are in northern/eastern 38 */ 39 private double x; 40 /** 41 * y difference movement. Coordinates are in northern/eastern 42 */ 43 private double y; 44 44 45 /** 46 * Small helper for holding the interesting part of the old data state of the 47 * objects. 48 */ 49 public static class OldState { 50 LatLon latlon; 51 EastNorth eastNorth; 52 boolean modified; 53 } 54 55 /** 56 * List of all old states of the objects. 57 */ 58 private List<OldState> oldState = new LinkedList<OldState>(); 45 /** 46 * Small helper for holding the interesting part of the old data state of the 47 * objects. 48 */ 49 public static class OldState { 50 LatLon latlon; 51 EastNorth eastNorth; 52 boolean modified; 53 } 59 54 60 61 public MoveCommand(OsmPrimitive osm, double x, double y) { 62 this(Collections.singleton(osm), x, y); 63 } 64 /** 65 * Create a MoveCommand and assign the initial object set and movement vector. 66 */ 67 public MoveCommand(Collection<OsmPrimitive> objects, double x, double y) { 68 this.x = x; 69 this.y = y; 70 this.objects = AllNodesVisitor.getAllNodes(objects); 71 for (Node n : this.objects) { 72 OldState os = new OldState(); 73 os.eastNorth = n.eastNorth; 74 os.latlon = n.coor; 75 os.modified = n.modified; 76 oldState.add(os); 77 } 78 } 55 /** 56 * List of all old states of the objects. 57 */ 58 private List<OldState> oldState = new LinkedList<OldState>(); 79 59 80 /**81 * Move the same set of objects again by the specified vector. The vectors82 * are added together and so the resulting will be moved to the previous83 * vector plus this one.84 *85 * The move is immediately executed and any undo will undo both vectors to86 * the original position the objects had before first moving.87 */88 public void moveAgain(double x, double y) {89 for (Node n : objects) {90 n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y);91 n.coor = Main.proj.eastNorth2latlon(n.eastNorth);92 }93 this.x += x;94 this.y += y;95 }96 97 @Override public boolean executeCommand() {98 for (Node n : objects) {99 n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y);100 n.coor = Main.proj.eastNorth2latlon(n.eastNorth);101 n.modified = true;102 }103 return true;104 }105 60 106 @Override public void undoCommand() { 107 Iterator<OldState> it = oldState.iterator(); 108 for (Node n : objects) { 109 OldState os = it.next(); 110 n.eastNorth = os.eastNorth; 111 n.coor = os.latlon; 112 n.modified = os.modified; 113 } 114 } 61 public MoveCommand(OsmPrimitive osm, double x, double y) { 62 this(Collections.singleton(osm), x, y); 63 } 64 /** 65 * Create a MoveCommand and assign the initial object set and movement vector. 66 */ 67 public MoveCommand(Collection<OsmPrimitive> objects, double x, double y) { 68 this.x = x; 69 this.y = y; 70 this.objects = AllNodesVisitor.getAllNodes(objects); 71 for (Node n : this.objects) { 72 OldState os = new OldState(); 73 os.eastNorth = n.eastNorth; 74 os.latlon = n.coor; 75 os.modified = n.modified; 76 oldState.add(os); 77 } 78 } 115 79 116 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 117 for (OsmPrimitive osm : objects) 118 modified.add(osm); 119 } 80 /** 81 * Move the same set of objects again by the specified vector. The vectors 82 * are added together and so the resulting will be moved to the previous 83 * vector plus this one. 84 * 85 * The move is immediately executed and any undo will undo both vectors to 86 * the original position the objects had before first moving. 87 */ 88 public void moveAgain(double x, double y) { 89 for (Node n : objects) { 90 n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y); 91 n.coor = Main.proj.eastNorth2latlon(n.eastNorth); 92 } 93 this.x += x; 94 this.y += y; 95 } 120 96 121 @Override public MutableTreeNode description() { 122 return new DefaultMutableTreeNode(new JLabel(tr("Move")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL)); 97 @Override public boolean executeCommand() { 98 for (Node n : objects) { 99 n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y); 100 n.coor = Main.proj.eastNorth2latlon(n.eastNorth); 101 n.modified = true; 102 } 103 return true; 104 } 105 106 @Override public void undoCommand() { 107 Iterator<OldState> it = oldState.iterator(); 108 for (Node n : objects) { 109 OldState os = it.next(); 110 n.eastNorth = os.eastNorth; 111 n.coor = os.latlon; 112 n.modified = os.modified; 113 } 114 } 115 116 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 117 for (OsmPrimitive osm : objects) 118 modified.add(osm); 119 } 120 121 @Override public MutableTreeNode description() { 122 return new DefaultMutableTreeNode(new JLabel(tr("Move")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL)); 123 123 } 124 124 } -
trunk/src/org/openstreetmap/josm/command/RotateCommand.java
r748 r1169 23 23 /** 24 24 * RotateCommand rotates a number of objects around their centre. 25 * 25 * 26 26 * @author Frederik Ramm <frederik@remote.org> 27 27 */ 28 28 public class RotateCommand extends Command { 29 30 /**31 * The objects to rotate.32 */33 public Collection<Node> objects = new LinkedList<Node>();34 35 /**36 * pivot point37 */38 private Node pivot;39 40 /**41 * angle of rotation starting click to pivot42 */43 private double startAngle;44 45 /**46 * computed rotation angle between starting click and current mouse pos47 */48 private double rotationAngle;49 50 /**51 * List of all old states of the objects.52 */53 private Map<Node, MoveCommand.OldState> oldState = new HashMap<Node, MoveCommand.OldState>();54 55 /**56 * Creates a RotateCommand.57 * Assign the initial object set, compute pivot point and rotation angle.58 * Computation of pivot point is done by the same rules that are used in59 * the "align nodes in circle" action.60 */61 public RotateCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) {62 29 63 this.objects = AllNodesVisitor.getAllNodes(objects); 64 pivot = new Node(new LatLon(0,0)); 65 pivot.eastNorth = new EastNorth(0,0); 30 /** 31 * The objects to rotate. 32 */ 33 public Collection<Node> objects = new LinkedList<Node>(); 66 34 67 for (Node n : this.objects) { 68 MoveCommand.OldState os = new MoveCommand.OldState(); 69 os.eastNorth = n.eastNorth; 70 os.latlon = n.coor; 71 os.modified = n.modified; 72 oldState.put(n, os); 73 pivot.eastNorth = new EastNorth(pivot.eastNorth.east()+os.eastNorth.east(), pivot.eastNorth.north()+os.eastNorth.north()); 74 } 75 pivot.eastNorth = new EastNorth(pivot.eastNorth.east()/this.objects.size(), pivot.eastNorth.north()/this.objects.size()); 76 pivot.coor = Main.proj.eastNorth2latlon(pivot.eastNorth); 35 /** 36 * pivot point 37 */ 38 private Node pivot; 77 39 78 rotationAngle = Math.PI/2; 79 rotateAgain(start, end); 80 } 40 /** 41 * angle of rotation starting click to pivot 42 */ 43 private double startAngle; 81 44 82 /** 83 * Rotate the same set of objects again, by the angle between given 84 * start and end nodes. Internally this is added to the existing 85 * rotation so a later undo will undo the whole rotation. 86 */ 87 public void rotateAgain(EastNorth start, EastNorth end) { 88 // compute angle 89 startAngle = Math.atan2(start.east()-pivot.eastNorth.east(), start.north()-pivot.eastNorth.north()); 90 double endAngle = Math.atan2(end.east()-pivot.eastNorth.east(), end.north()-pivot.eastNorth.north()); 91 rotationAngle += startAngle - endAngle; 92 rotateNodes(false); 93 } 45 /** 46 * computed rotation angle between starting click and current mouse pos 47 */ 48 private double rotationAngle; 94 49 95 /** 96 * Helper for actually rotationg the nodes. 97 * @param setModified - true if rotated nodes should be flagged "modified" 98 */ 99 private void rotateNodes(boolean setModified) { 100 for (Node n : objects) { 101 double cosPhi = Math.cos(rotationAngle); 102 double sinPhi = Math.sin(rotationAngle); 103 EastNorth oldEastNorth = oldState.get(n).eastNorth; 104 double x = oldEastNorth.east() - pivot.eastNorth.east(); 105 double y = oldEastNorth.north() - pivot.eastNorth.north(); 106 double nx = sinPhi * x + cosPhi * y + pivot.eastNorth.east(); 107 double ny = -cosPhi * x + sinPhi * y + pivot.eastNorth.north(); 108 n.eastNorth = new EastNorth(nx, ny); 109 n.coor = Main.proj.eastNorth2latlon(n.eastNorth); 110 if (setModified) 111 n.modified = true; 112 } 113 } 114 115 @Override public boolean executeCommand() { 116 rotateNodes(true); 117 return true; 118 } 50 /** 51 * List of all old states of the objects. 52 */ 53 private Map<Node, MoveCommand.OldState> oldState = new HashMap<Node, MoveCommand.OldState>(); 119 54 120 @Override public void undoCommand() { 121 for (Node n : objects) { 122 MoveCommand.OldState os = oldState.get(n); 123 n.eastNorth = os.eastNorth; 124 n.coor = os.latlon; 125 n.modified = os.modified; 126 } 127 } 55 /** 56 * Creates a RotateCommand. 57 * Assign the initial object set, compute pivot point and rotation angle. 58 * Computation of pivot point is done by the same rules that are used in 59 * the "align nodes in circle" action. 60 */ 61 public RotateCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) { 128 62 129 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 130 for (OsmPrimitive osm : objects) 131 modified.add(osm); 132 } 63 this.objects = AllNodesVisitor.getAllNodes(objects); 64 pivot = new Node(new LatLon(0,0)); 65 pivot.eastNorth = new EastNorth(0,0); 133 66 134 @Override public MutableTreeNode description() { 135 return new DefaultMutableTreeNode(new JLabel(tr("Rotate")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL)); 67 for (Node n : this.objects) { 68 MoveCommand.OldState os = new MoveCommand.OldState(); 69 os.eastNorth = n.eastNorth; 70 os.latlon = n.coor; 71 os.modified = n.modified; 72 oldState.put(n, os); 73 pivot.eastNorth = new EastNorth(pivot.eastNorth.east()+os.eastNorth.east(), pivot.eastNorth.north()+os.eastNorth.north()); 74 } 75 pivot.eastNorth = new EastNorth(pivot.eastNorth.east()/this.objects.size(), pivot.eastNorth.north()/this.objects.size()); 76 pivot.coor = Main.proj.eastNorth2latlon(pivot.eastNorth); 77 78 rotationAngle = Math.PI/2; 79 rotateAgain(start, end); 80 } 81 82 /** 83 * Rotate the same set of objects again, by the angle between given 84 * start and end nodes. Internally this is added to the existing 85 * rotation so a later undo will undo the whole rotation. 86 */ 87 public void rotateAgain(EastNorth start, EastNorth end) { 88 // compute angle 89 startAngle = Math.atan2(start.east()-pivot.eastNorth.east(), start.north()-pivot.eastNorth.north()); 90 double endAngle = Math.atan2(end.east()-pivot.eastNorth.east(), end.north()-pivot.eastNorth.north()); 91 rotationAngle += startAngle - endAngle; 92 rotateNodes(false); 93 } 94 95 /** 96 * Helper for actually rotationg the nodes. 97 * @param setModified - true if rotated nodes should be flagged "modified" 98 */ 99 private void rotateNodes(boolean setModified) { 100 for (Node n : objects) { 101 double cosPhi = Math.cos(rotationAngle); 102 double sinPhi = Math.sin(rotationAngle); 103 EastNorth oldEastNorth = oldState.get(n).eastNorth; 104 double x = oldEastNorth.east() - pivot.eastNorth.east(); 105 double y = oldEastNorth.north() - pivot.eastNorth.north(); 106 double nx = sinPhi * x + cosPhi * y + pivot.eastNorth.east(); 107 double ny = -cosPhi * x + sinPhi * y + pivot.eastNorth.north(); 108 n.eastNorth = new EastNorth(nx, ny); 109 n.coor = Main.proj.eastNorth2latlon(n.eastNorth); 110 if (setModified) 111 n.modified = true; 112 } 113 } 114 115 @Override public boolean executeCommand() { 116 rotateNodes(true); 117 return true; 118 } 119 120 @Override public void undoCommand() { 121 for (Node n : objects) { 122 MoveCommand.OldState os = oldState.get(n); 123 n.eastNorth = os.eastNorth; 124 n.coor = os.latlon; 125 n.modified = os.modified; 126 } 127 } 128 129 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 130 for (OsmPrimitive osm : objects) 131 modified.add(osm); 132 } 133 134 @Override public MutableTreeNode description() { 135 return new DefaultMutableTreeNode(new JLabel(tr("Rotate")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL)); 136 136 } 137 137 } -
trunk/src/org/openstreetmap/josm/command/SequenceCommand.java
r853 r1169 20 20 public class SequenceCommand extends Command { 21 21 22 23 24 25 26 27 28 22 /** 23 * The command sequenz to be executed. 24 */ 25 private Command[] sequence; 26 private boolean sequence_complete; 27 private final String name; 28 public boolean continueOnError = false; 29 29 30 31 32 33 34 35 36 37 38 30 /** 31 * Create the command by specifying the list of commands to execute. 32 * @param sequenz The sequence that should be executed. 33 */ 34 public SequenceCommand(String name, Collection<Command> sequenz) { 35 this.name = name; 36 this.sequence = new Command[sequenz.size()]; 37 this.sequence = sequenz.toArray(this.sequence); 38 } 39 39 40 /** 41 * Convenient constructor, if the commands are known at compile time. 42 */ 43 public SequenceCommand(String name, Command... sequenz) { 44 this(name, Arrays.asList(sequenz)); 45 } 46 47 public int executed_commands = 0; 48 @Override public boolean executeCommand() { 49 for (int i=0; i < sequence.length; i++) { 50 Command c = sequence[i]; 51 boolean result = c.executeCommand(); 52 if (!result) 53 Main.debug("SequenceCommand, executing command[" + i + "] " + c + " result: " + result); 54 if (!result && !continueOnError) { 55 this.undoCommands(i-1); 56 return false; 57 } 58 } 59 sequence_complete = true; 60 return true; 61 } 40 /** 41 * Convenient constructor, if the commands are known at compile time. 42 */ 43 public SequenceCommand(String name, Command... sequenz) { 44 this(name, Arrays.asList(sequenz)); 45 } 62 46 63 public Command getLastCommand() { 64 if(sequence.length == 0) 65 return null; 66 return sequence[sequence.length-1]; 67 } 68 private void undoCommands(int start) { 69 // We probably aborted this halfway though the 70 // execution sequence because of a sub-command 71 // error. We already undid the sub-commands. 72 if (!sequence_complete) 73 return; 74 for (int i = start; i >= 0; --i) 75 sequence[i].undoCommand(); 76 } 47 public int executed_commands = 0; 48 @Override public boolean executeCommand() { 49 for (int i=0; i < sequence.length; i++) { 50 Command c = sequence[i]; 51 boolean result = c.executeCommand(); 52 if (!result) 53 Main.debug("SequenceCommand, executing command[" + i + "] " + c + " result: " + result); 54 if (!result && !continueOnError) { 55 this.undoCommands(i-1); 56 return false; 57 } 58 } 59 sequence_complete = true; 60 return true; 61 } 77 62 78 @Override public void undoCommand() { 79 this.undoCommands(sequence.length-1); 80 } 63 public Command getLastCommand() { 64 if(sequence.length == 0) 65 return null; 66 return sequence[sequence.length-1]; 67 } 68 private void undoCommands(int start) { 69 // We probably aborted this halfway though the 70 // execution sequence because of a sub-command 71 // error. We already undid the sub-commands. 72 if (!sequence_complete) 73 return; 74 for (int i = start; i >= 0; --i) 75 sequence[i].undoCommand(); 76 } 81 77 82 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 83 for (Command c : sequence) 84 c.fillModifiedData(modified, deleted, added); 85 } 78 @Override public void undoCommand() { 79 this.undoCommands(sequence.length-1); 80 } 86 81 87 @Override public MutableTreeNode description() { 88 DefaultMutableTreeNode root = new DefaultMutableTreeNode(tr("Sequence")+": "+name); 89 for (Command c : sequence) 90 root.add(c.description()); 91 return root; 82 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 83 for (Command c : sequence) 84 c.fillModifiedData(modified, deleted, added); 85 } 86 87 @Override public MutableTreeNode description() { 88 DefaultMutableTreeNode root = new DefaultMutableTreeNode(tr("Sequence")+": "+name); 89 for (Command c : sequence) 90 root.add(c.description()); 91 return root; 92 92 } 93 93 } -
trunk/src/org/openstreetmap/josm/corrector/CorrectionTable.java
r1001 r1169 13 13 extends JTable { 14 14 15 15 private static final int MAX_VISIBLE_LINES = 10; 16 16 17 17 public static class BoldRenderer extends JLabel implements 18 18 TableCellRenderer { 19 19 20 21 22 20 public Component getTableCellRendererComponent(JTable table, 21 Object value, boolean isSelected, boolean hasFocus, int row, 22 int column) { 23 23 24 25 24 Font f = getFont(); 25 setFont(new Font(f.getName(), f.getStyle() | Font.BOLD, f.getSize())); 26 26 27 27 setText((String)value); 28 28 29 30 31 29 return this; 30 } 31 } 32 32 33 33 private static BoldRenderer boldRenderer = null; 34 34 35 36 35 protected CorrectionTable(TM correctionTableModel) { 36 super(correctionTableModel); 37 37 38 39 38 final int correctionsSize = correctionTableModel.getCorrections().size(); 39 final int lines = correctionsSize > MAX_VISIBLE_LINES ? MAX_VISIBLE_LINES 40 40 : correctionsSize; 41 42 43 41 setPreferredScrollableViewportSize(new Dimension(400, lines 42 * getRowHeight())); 43 getColumnModel().getColumn(correctionTableModel.getApplyColumn()) 44 44 .setPreferredWidth(40); 45 46 45 setRowSelectionAllowed(false); 46 } 47 47 48 49 50 51 52 53 54 55 48 public TableCellRenderer getCellRenderer(int row, int column) { 49 if (getCorrectionTableModel().isBoldCell(row, column)) { 50 if (boldRenderer == null) 51 boldRenderer = new BoldRenderer(); 52 return boldRenderer; 53 } 54 return super.getCellRenderer(row, column); 55 } 56 56 57 57 @SuppressWarnings("unchecked") 58 58 public TM getCorrectionTableModel() { 59 60 59 return (TM)getModel(); 60 } 61 61 62 62 } -
trunk/src/org/openstreetmap/josm/corrector/CorrectionTableModel.java
r1001 r1169 12 12 AbstractTableModel { 13 13 14 15 16 14 private List<C> corrections; 15 private boolean[] apply; 16 private int applyColumn; 17 17 18 public CorrectionTableModel(List<C> corrections) { 19 super(); 20 this.corrections = corrections; 21 apply = new boolean[this.corrections.size()]; 22 Arrays.fill(apply, true); 23 applyColumn = getColumnCount() - 1; 24 } 25 26 abstract public int getColumnCount(); 27 28 abstract protected boolean isBoldCell(int row, int column); 29 abstract public String getCorrectionColumnName(int colIndex); 30 abstract public Object getCorrectionValueAt(int rowIndex, int colIndex); 31 32 public List<C> getCorrections() { 33 return corrections; 34 } 35 36 public int getApplyColumn() { 37 return applyColumn; 38 } 39 40 public boolean getApply(int i) { 41 return apply[i]; 18 public CorrectionTableModel(List<C> corrections) { 19 super(); 20 this.corrections = corrections; 21 apply = new boolean[this.corrections.size()]; 22 Arrays.fill(apply, true); 23 applyColumn = getColumnCount() - 1; 42 24 } 43 25 44 public int getRowCount() { 45 return corrections.size(); 26 abstract public int getColumnCount(); 27 28 abstract protected boolean isBoldCell(int row, int column); 29 abstract public String getCorrectionColumnName(int colIndex); 30 abstract public Object getCorrectionValueAt(int rowIndex, int colIndex); 31 32 public List<C> getCorrections() { 33 return corrections; 46 34 } 47 35 48 @Override 49 public Class<?> getColumnClass(int columnIndex) { 50 if (columnIndex == applyColumn) 51 return Boolean.class; 52 return String.class; 36 public int getApplyColumn() { 37 return applyColumn; 53 38 } 54 39 55 @Override 56 public String getColumnName(int columnIndex) { 57 if (columnIndex == applyColumn) 58 return tr("Apply?"); 59 60 return getCorrectionColumnName(columnIndex); 61 } 62 63 @Override 64 public boolean isCellEditable(int rowIndex, int columnIndex) { 65 return columnIndex == applyColumn; 40 public boolean getApply(int i) { 41 return apply[i]; 66 42 } 67 43 68 @Override 44 public int getRowCount() { 45 return corrections.size(); 46 } 47 48 @Override 49 public Class<?> getColumnClass(int columnIndex) { 50 if (columnIndex == applyColumn) 51 return Boolean.class; 52 return String.class; 53 } 54 55 @Override 56 public String getColumnName(int columnIndex) { 57 if (columnIndex == applyColumn) 58 return tr("Apply?"); 59 60 return getCorrectionColumnName(columnIndex); 61 } 62 63 @Override 64 public boolean isCellEditable(int rowIndex, int columnIndex) { 65 return columnIndex == applyColumn; 66 } 67 68 @Override 69 69 public void setValueAt(Object aValue, int rowIndex, int columnIndex) { 70 71 70 if (columnIndex == applyColumn && aValue instanceof Boolean) 71 apply[rowIndex] = (Boolean)aValue; 72 72 } 73 73 74 74 public Object getValueAt(int rowIndex, int colIndex) { 75 76 77 78 79 75 if (colIndex == applyColumn) 76 return apply[rowIndex]; 77 78 return getCorrectionValueAt(rowIndex, colIndex); 79 } 80 80 } -
trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
r1002 r1169 22 22 public class ReverseWayTagCorrector extends TagCorrector<Way> { 23 23 24 24 private static class PrefixSuffixSwitcher { 25 25 26 27 28 29 26 private final String a; 27 private final String b; 28 private final Pattern startPattern; 29 private final Pattern endPattern; 30 30 31 32 33 31 private final String SEPARATOR = "[:_]?"; 32 33 public PrefixSuffixSwitcher(String a, String b) { 34 34 this.a = a; 35 35 this.b = b; … … 40 40 SEPARATOR + "(" + a + "|" + b + ")$", 41 41 Pattern.CASE_INSENSITIVE); 42 42 } 43 43 44 45 46 47 44 public String apply(String text) { 45 Matcher m = startPattern.matcher(text); 46 if (!m.lookingAt()) 47 m = endPattern.matcher(text); 48 48 49 50 49 if (m.lookingAt()) { 50 String leftRight = m.group(1).toLowerCase(); 51 51 52 StringBuilder result = new StringBuilder(); 53 result.append(text.substring(0, m.start(1))); 54 result.append(leftRight.equals(a) ? b : a); 55 result.append(text.substring(m.end(1))); 56 57 return result.toString(); 58 } 59 return text; 60 } 61 } 52 StringBuilder result = new StringBuilder(); 53 result.append(text.substring(0, m.start(1))); 54 result.append(leftRight.equals(a) ? b : a); 55 result.append(text.substring(m.end(1))); 62 56 63 private static PrefixSuffixSwitcher[] prefixSuffixSwitchers = 64 new PrefixSuffixSwitcher[] {65 new PrefixSuffixSwitcher("left", "right"),66 new PrefixSuffixSwitcher("forward", "backward")67 }; 57 return result.toString(); 58 } 59 return text; 60 } 61 } 68 62 69 @Override 70 public Collection<Command> execute(Way way) throws UserCancelException { 71 Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap = 72 new HashMap<OsmPrimitive, List<TagCorrection>>(); 63 private static PrefixSuffixSwitcher[] prefixSuffixSwitchers = 64 new PrefixSuffixSwitcher[] { 65 new PrefixSuffixSwitcher("left", "right"), 66 new PrefixSuffixSwitcher("forward", "backward") 67 }; 73 68 74 ArrayList<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>(); 75 primitives.add(way); 76 primitives.addAll(way.nodes); 69 @Override 70 public Collection<Command> execute(Way way) throws UserCancelException { 71 Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap = 72 new HashMap<OsmPrimitive, List<TagCorrection>>(); 77 73 78 for (OsmPrimitive primitive : primitives) { 79 tagCorrectionsMap.put(primitive, new ArrayList<TagCorrection>()); 74 ArrayList<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>(); 75 primitives.add(way); 76 primitives.addAll(way.nodes); 80 77 81 for (String key : primitive.keySet()) { 82 String newKey = key; 83 String value = primitive.get(key); 84 String newValue = value; 78 for (OsmPrimitive primitive : primitives) { 79 tagCorrectionsMap.put(primitive, new ArrayList<TagCorrection>()); 85 80 86 if (key.equals("oneway")) { 87 if (value.equals("-1")) 88 newValue = OsmUtils.trueval; 89 else { 90 Boolean boolValue = OsmUtils.getOsmBoolean(value); 91 if (boolValue != null && boolValue.booleanValue()) { 92 newValue = "-1"; 93 } 94 } 95 } else { 96 for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) { 97 newKey = prefixSuffixSwitcher.apply(key); 98 if (!key.equals(newKey)) 99 break; 100 } 101 } 81 for (String key : primitive.keySet()) { 82 String newKey = key; 83 String value = primitive.get(key); 84 String newValue = value; 102 85 103 if (!key.equals(newKey) || !value.equals(newValue)) 104 tagCorrectionsMap.get(primitive).add( 105 new TagCorrection(key, value, newKey, newValue)); 106 } 107 } 86 if (key.equals("oneway")) { 87 if (value.equals("-1")) 88 newValue = OsmUtils.trueval; 89 else { 90 Boolean boolValue = OsmUtils.getOsmBoolean(value); 91 if (boolValue != null && boolValue.booleanValue()) { 92 newValue = "-1"; 93 } 94 } 95 } else { 96 for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) { 97 newKey = prefixSuffixSwitcher.apply(key); 98 if (!key.equals(newKey)) 99 break; 100 } 101 } 108 102 109 Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap = 110 new HashMap<OsmPrimitive, List<RoleCorrection>>(); 111 roleCorrectionMap.put(way, new ArrayList<RoleCorrection>()); 103 if (!key.equals(newKey) || !value.equals(newValue)) 104 tagCorrectionsMap.get(primitive).add( 105 new TagCorrection(key, value, newKey, newValue)); 106 } 107 } 112 108 113 for (Relation relation : Main.ds.relations) { 114 for (RelationMember member : relation.members) { 115 if (!member.member.realEqual(way, true) 116 || member.role.length() == 0) 117 continue; 109 Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap = 110 new HashMap<OsmPrimitive, List<RoleCorrection>>(); 111 roleCorrectionMap.put(way, new ArrayList<RoleCorrection>()); 118 112 119 boolean found = false; 120 String newRole = null; 121 for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) { 122 newRole = prefixSuffixSwitcher.apply(member.role); 123 if (!newRole.equals(member.role)) { 124 found = true; 125 break; 126 } 127 } 113 for (Relation relation : Main.ds.relations) { 114 for (RelationMember member : relation.members) { 115 if (!member.member.realEqual(way, true) 116 || member.role.length() == 0) 117 continue; 128 118 129 if (found) 130 roleCorrectionMap.get(way).add( 131 new RoleCorrection(relation, member, newRole)); 132 } 133 } 119 boolean found = false; 120 String newRole = null; 121 for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) { 122 newRole = prefixSuffixSwitcher.apply(member.role); 123 if (!newRole.equals(member.role)) { 124 found = true; 125 break; 126 } 127 } 134 128 135 return applyCorrections(tagCorrectionsMap, roleCorrectionMap, 136 tr("When reverting this way, following changes to properties " 137 + "of the way and its nodes are suggested in order " 138 + "to maintain data consistency.")); 139 } 129 if (found) 130 roleCorrectionMap.get(way).add( 131 new RoleCorrection(relation, member, newRole)); 132 } 133 } 134 135 return applyCorrections(tagCorrectionsMap, roleCorrectionMap, 136 tr("When reverting this way, following changes to properties " 137 + "of the way and its nodes are suggested in order " 138 + "to maintain data consistency.")); 139 } 140 140 } -
trunk/src/org/openstreetmap/josm/corrector/TagCorrection.java
r1000 r1169 4 4 public class TagCorrection implements Correction { 5 5 6 7 8 9 6 public final String oldKey; 7 public final String newKey; 8 public final String oldValue; 9 public final String newValue; 10 10 11 11 public TagCorrection(String oldKey, String oldValue, String newKey, 12 12 String newValue) { 13 14 15 16 17 13 this.oldKey = oldKey; 14 this.oldValue = oldValue; 15 this.newKey = newKey; 16 this.newValue = newValue; 17 } 18 18 19 20 21 19 public boolean isKeyChanged() { 20 return !newKey.equals(oldKey); 21 } 22 22 23 24 25 23 public boolean isValueChanged() { 24 return !newValue.equals(oldValue); 25 } 26 26 } -
trunk/src/org/openstreetmap/josm/corrector/TagCorrectionTable.java
r1000 r1169 7 7 CorrectionTable<TagCorrectionTableModel> { 8 8 9 10 11 9 public TagCorrectionTable(List<TagCorrection> tagCorrections) { 10 super(new TagCorrectionTableModel(tagCorrections)); 11 } 12 12 13 13 } -
trunk/src/org/openstreetmap/josm/corrector/TagCorrectionTableModel.java
r1000 r1169 8 8 public class TagCorrectionTableModel extends CorrectionTableModel<TagCorrection> { 9 9 10 11 12 10 public TagCorrectionTableModel(List<TagCorrection> tagCorrections) { 11 super(tagCorrections); 12 } 13 13 14 15 16 17 14 @Override 15 public int getColumnCount() { 16 return 5; 17 } 18 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 19 @Override 20 public String getCorrectionColumnName(int colIndex) { 21 switch (colIndex) { 22 case 0: 23 return tr("Old key"); 24 case 1: 25 return tr("Old value"); 26 case 2: 27 return tr("New key"); 28 case 3: 29 return tr("New value"); 30 } 31 return null; 32 } 33 33 34 34 public Object getCorrectionValueAt(int rowIndex, int colIndex) { 35 35 TagCorrection tagCorrection = getCorrections().get(rowIndex); 36 36 37 38 39 40 41 42 43 44 45 46 47 48 37 switch (colIndex) { 38 case 0: 39 return tagCorrection.oldKey; 40 case 1: 41 return tagCorrection.oldValue; 42 case 2: 43 return tagCorrection.newKey; 44 case 3: 45 return tagCorrection.newValue; 46 } 47 return null; 48 } 49 49 50 51 52 53 54 50 protected boolean isBoldCell(int row, int column) { 51 TagCorrection tagCorrection = getCorrections().get(row); 52 return (column == 2 && tagCorrection.isKeyChanged()) 53 || (column == 3 && tagCorrection.isValueChanged()); 54 } 55 55 56 56 } -
trunk/src/org/openstreetmap/josm/corrector/TagCorrector.java
r1107 r1169 33 33 public abstract class TagCorrector<P extends OsmPrimitive> { 34 34 35 36 35 public abstract Collection<Command> execute(P primitive) 36 throws UserCancelException; 37 37 38 private String[] applicationOptions = new String[] { 39 tr("Apply selected changes"), 40 tr("Don't apply changes"), 41 tr("Cancel") 38 private String[] applicationOptions = new String[] { 39 tr("Apply selected changes"), 40 tr("Don't apply changes"), 41 tr("Cancel") 42 42 }; 43 44 protected Collection<Command> applyCorrections(45 Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap,46 Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap,47 String description) throws UserCancelException {48 43 49 boolean hasCorrections = false; 50 for (List<TagCorrection> tagCorrectionList : tagCorrectionsMap.values()) { 51 if (!tagCorrectionList.isEmpty()) { 52 hasCorrections = true; 53 break; 54 } 55 } 44 protected Collection<Command> applyCorrections( 45 Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap, 46 Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap, 47 String description) throws UserCancelException { 56 48 57 if (!hasCorrections) 58 for (List<RoleCorrection> roleCorrectionList : roleCorrectionMap 59 .values()) { 60 if (!roleCorrectionList.isEmpty()) { 61 hasCorrections = true; 62 break; 63 } 64 } 49 boolean hasCorrections = false; 50 for (List<TagCorrection> tagCorrectionList : tagCorrectionsMap.values()) { 51 if (!tagCorrectionList.isEmpty()) { 52 hasCorrections = true; 53 break; 54 } 55 } 65 56 66 if (hasCorrections) { 67 Collection<Command> commands = new ArrayList<Command>(); 68 Map<OsmPrimitive, TagCorrectionTable> tagTableMap = 69 new HashMap<OsmPrimitive, TagCorrectionTable>(); 70 Map<OsmPrimitive, RoleCorrectionTable> roleTableMap = 71 new HashMap<OsmPrimitive, RoleCorrectionTable>(); 57 if (!hasCorrections) 58 for (List<RoleCorrection> roleCorrectionList : roleCorrectionMap 59 .values()) { 60 if (!roleCorrectionList.isEmpty()) { 61 hasCorrections = true; 62 break; 63 } 64 } 72 65 73 NameVisitor nameVisitor = new NameVisitor(); 66 if (hasCorrections) { 67 Collection<Command> commands = new ArrayList<Command>(); 68 Map<OsmPrimitive, TagCorrectionTable> tagTableMap = 69 new HashMap<OsmPrimitive, TagCorrectionTable>(); 70 Map<OsmPrimitive, RoleCorrectionTable> roleTableMap = 71 new HashMap<OsmPrimitive, RoleCorrectionTable>(); 74 72 75 final JPanel p= newJPanel(new GridBagLayout());73 NameVisitor nameVisitor = new NameVisitor(); 76 74 77 final JMultilineLabel label1 = new JMultilineLabel(description); 78 label1.setMaxWidth(400); 79 p.add(label1, GBC.eop()); 75 final JPanel p = new JPanel(new GridBagLayout()); 80 76 81 final JMultilineLabel label2 = new JMultilineLabel( 82 tr("Please select which property changes you want to apply.")); 83 label2.setMaxWidth(400); 84 p.add(label2, GBC.eop()); 77 final JMultilineLabel label1 = new JMultilineLabel(description); 78 label1.setMaxWidth(400); 79 p.add(label1, GBC.eop()); 85 80 86 for (OsmPrimitive primitive : tagCorrectionsMap.keySet()) { 87 final List<TagCorrection> tagCorrections = tagCorrectionsMap 88 .get(primitive); 81 final JMultilineLabel label2 = new JMultilineLabel( 82 tr("Please select which property changes you want to apply.")); 83 label2.setMaxWidth(400); 84 p.add(label2, GBC.eop()); 89 85 90 if (tagCorrections.isEmpty()) 91 continue; 86 for (OsmPrimitive primitive : tagCorrectionsMap.keySet()) { 87 final List<TagCorrection> tagCorrections = tagCorrectionsMap 88 .get(primitive); 92 89 93 primitive.visit(nameVisitor); 90 if (tagCorrections.isEmpty()) 91 continue; 94 92 95 final JLabel propertiesLabel = new JLabel(tr("Properties of ")); 96 p.add(propertiesLabel, GBC.std()); 93 primitive.visit(nameVisitor); 97 94 98 final JLabel primitiveLabel = new JLabel( 99 nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT); 100 p.add(primitiveLabel, GBC.eol()); 95 final JLabel propertiesLabel = new JLabel(tr("Properties of ")); 96 p.add(propertiesLabel, GBC.std()); 101 97 102 final TagCorrectionTable table = new TagCorrectionTable( 103 tagCorrections); 104 final JScrollPane scrollPane = new JScrollPane(table); 105 p.add(scrollPane, GBC.eop()); 98 final JLabel primitiveLabel = new JLabel( 99 nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT); 100 p.add(primitiveLabel, GBC.eol()); 106 101 107 tagTableMap.put(primitive, table); 108 } 102 final TagCorrectionTable table = new TagCorrectionTable( 103 tagCorrections); 104 final JScrollPane scrollPane = new JScrollPane(table); 105 p.add(scrollPane, GBC.eop()); 109 106 110 for (OsmPrimitive primitive : roleCorrectionMap.keySet()) { 111 final List<RoleCorrection> roleCorrections = roleCorrectionMap 112 .get(primitive); 113 if (roleCorrections.isEmpty()) 114 continue; 107 tagTableMap.put(primitive, table); 108 } 115 109 116 primitive.visit(nameVisitor); 110 for (OsmPrimitive primitive : roleCorrectionMap.keySet()) { 111 final List<RoleCorrection> roleCorrections = roleCorrectionMap 112 .get(primitive); 113 if (roleCorrections.isEmpty()) 114 continue; 117 115 118 final JLabel rolesLabel = new JLabel( 119 tr("Roles in relations referring to")); 120 p.add(rolesLabel, GBC.std()); 116 primitive.visit(nameVisitor); 121 117 122 primitiveLabel = new JLabel(123 nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT);124 p.add(primitiveLabel, GBC.eol());118 final JLabel rolesLabel = new JLabel( 119 tr("Roles in relations referring to")); 120 p.add(rolesLabel, GBC.std()); 125 121 126 final RoleCorrectionTable table = new RoleCorrectionTable( 127 roleCorrections); 128 final JScrollPane scrollPane = new JScrollPane(table); 129 p.add(scrollPane, GBC.eop()); 122 final JLabel primitiveLabel = new JLabel( 123 nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT); 124 p.add(primitiveLabel, GBC.eol()); 130 125 131 roleTableMap.put(primitive, table); 132 } 126 final RoleCorrectionTable table = new RoleCorrectionTable( 127 roleCorrections); 128 final JScrollPane scrollPane = new JScrollPane(table); 129 p.add(scrollPane, GBC.eop()); 133 130 134 int answer = JOptionPane.showOptionDialog(Main.parent, p, 131 roleTableMap.put(primitive, table); 132 } 133 134 int answer = JOptionPane.showOptionDialog(Main.parent, p, 135 135 tr("Automatic tag correction"), JOptionPane.YES_NO_CANCEL_OPTION, 136 JOptionPane.PLAIN_MESSAGE, null, 136 JOptionPane.PLAIN_MESSAGE, null, 137 137 applicationOptions, applicationOptions[0]); 138 138 139 140 141 139 if (answer == JOptionPane.YES_OPTION) { 140 for (OsmPrimitive primitive : tagCorrectionsMap.keySet()) { 141 List<TagCorrection> tagCorrections = 142 142 tagCorrectionsMap.get(primitive); 143 143 144 144 // create the clone 145 145 OsmPrimitive clone = null; … … 147 147 else if (primitive instanceof Node) clone = new Node((Node)primitive); 148 148 else if (primitive instanceof Relation) clone = new Relation((Relation)primitive); 149 149 150 150 // use this structure to remember keys that have been set already so that 151 151 // they're not dropped by a later step 152 152 Set<String> keysChanged = new HashSet<String>(); 153 153 154 154 // apply all changes to this clone 155 156 157 158 159 160 161 162 163 155 for (int i = 0; i < tagCorrections.size(); i++) { 156 if (tagTableMap.get(primitive).getCorrectionTableModel().getApply(i)) { 157 TagCorrection tagCorrection = tagCorrections.get(i); 158 if (tagCorrection.isKeyChanged() && !keysChanged.contains(tagCorrection.oldKey)) clone.remove(tagCorrection.oldKey); 159 clone.put(tagCorrection.newKey, tagCorrection.newValue); 160 keysChanged.add(tagCorrection.newKey); 161 } 162 } 163 164 164 // save the clone 165 165 if (!keysChanged.isEmpty()) commands.add(new ChangeCommand(primitive, clone)); 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 166 } 167 for (OsmPrimitive primitive : roleCorrectionMap.keySet()) { 168 List<RoleCorrection> roleCorrections = roleCorrectionMap 169 .get(primitive); 170 for (int i = 0; i < roleCorrections.size(); i++) { 171 if (roleTableMap.get(primitive) 172 .getCorrectionTableModel().getApply(i)) { 173 RoleCorrection roleCorrection = roleCorrections 174 .get(i); 175 Relation newRelation = new Relation( 176 roleCorrection.relation); 177 for (RelationMember member : newRelation.members) 178 if (member.equals(roleCorrection.member)) 179 member.role = roleCorrection.newRole; 180 commands.add(new ChangeCommand( 181 roleCorrection.relation, newRelation)); 182 } 183 } 184 } 185 } else if (answer != JOptionPane.NO_OPTION) { 186 throw new UserCancelException(); 187 } 188 return commands; 189 } 190 190 191 192 191 return Collections.emptyList(); 192 } 193 193 } -
trunk/src/org/openstreetmap/josm/data/Bounds.java
r999 r1169 8 8 9 9 /** 10 * This is a simple data class for "rectangular" areas of the world, given in 10 * This is a simple data class for "rectangular" areas of the world, given in 11 11 * lat/lon min/max values. 12 * 12 * 13 13 * @author imi 14 14 */ 15 15 public class Bounds { 16 17 18 19 16 /** 17 * The minimum and maximum coordinates. 18 */ 19 public LatLon min, max; 20 20 21 22 23 24 25 26 27 21 /** 22 * Construct bounds out of two points 23 */ 24 public Bounds(LatLon min, LatLon max) { 25 this.min = min; 26 this.max = max; 27 } 28 28 29 /** 30 * Construct bounds that span the whole world. 31 */ 32 public Bounds() { 33 min = new LatLon(-Projection.MAX_LAT, -Projection.MAX_LON); 34 max = new LatLon(Projection.MAX_LAT, Projection.MAX_LON); 35 } 36 37 @Override public String toString() { 38 return "Bounds["+min.lat()+","+min.lon()+","+max.lat()+","+max.lon()+"]"; 39 } 29 /** 30 * Construct bounds that span the whole world. 31 */ 32 public Bounds() { 33 min = new LatLon(-Projection.MAX_LAT, -Projection.MAX_LON); 34 max = new LatLon(Projection.MAX_LAT, Projection.MAX_LON); 35 } 40 36 41 /** 42 * @return Center of the bounding box. 43 */ 44 public LatLon center() { 45 // FIXME: not sure whether this calculation is right; maybe there is some 46 // more complex calculation needed to get a center of a spherical 47 // dimension? 48 return new LatLon((min.lat()+max.lat())/2, (min.lon()+max.lon())/2); 49 } 50 51 /** 52 * Extend the bounds if necessary to include the given point. 53 */ 54 public void extend(LatLon ll) { 55 if (ll.lat() < min.lat() || ll.lon() < min.lon()) 56 min = new LatLon(Math.min(ll.lat(), min.lat()), Math.min(ll.lon(), min.lon())); 57 if (ll.lat() > max.lat() || ll.lon() > max.lon()) 58 max = new LatLon(Math.max(ll.lat(), max.lat()), Math.max(ll.lon(), max.lon())); 59 } 60 /** 61 * Is the given point within this bounds? 62 */ 63 public boolean contains(LatLon ll) { 64 if (ll.lat() < min.lat() || ll.lon() < min.lon()) 65 return false; 66 if (ll.lat() > max.lat() || ll.lon() > max.lon()) 67 return false; 68 return true; 69 } 70 71 /** 72 * Converts the lat/lon bounding box to an object of type Rectangle2D.Double 73 * @return the bounding box to Rectangle2D.Double 74 */ 75 public Rectangle2D.Double asRect() { 76 return new Rectangle2D.Double(min.lon(), min.lat(), max.lon()-min.lon(), max.lat()-min.lat()); 77 } 37 @Override public String toString() { 38 return "Bounds["+min.lat()+","+min.lon()+","+max.lat()+","+max.lon()+"]"; 39 } 40 41 /** 42 * @return Center of the bounding box. 43 */ 44 public LatLon center() { 45 // FIXME: not sure whether this calculation is right; maybe there is some 46 // more complex calculation needed to get a center of a spherical 47 // dimension? 48 return new LatLon((min.lat()+max.lat())/2, (min.lon()+max.lon())/2); 49 } 50 51 /** 52 * Extend the bounds if necessary to include the given point. 53 */ 54 public void extend(LatLon ll) { 55 if (ll.lat() < min.lat() || ll.lon() < min.lon()) 56 min = new LatLon(Math.min(ll.lat(), min.lat()), Math.min(ll.lon(), min.lon())); 57 if (ll.lat() > max.lat() || ll.lon() > max.lon()) 58 max = new LatLon(Math.max(ll.lat(), max.lat()), Math.max(ll.lon(), max.lon())); 59 } 60 /** 61 * Is the given point within this bounds? 62 */ 63 public boolean contains(LatLon ll) { 64 if (ll.lat() < min.lat() || ll.lon() < min.lon()) 65 return false; 66 if (ll.lat() > max.lat() || ll.lon() > max.lon()) 67 return false; 68 return true; 69 } 70 71 /** 72 * Converts the lat/lon bounding box to an object of type Rectangle2D.Double 73 * @return the bounding box to Rectangle2D.Double 74 */ 75 public Rectangle2D.Double asRect() { 76 return new Rectangle2D.Double(min.lon(), min.lat(), max.lon()-min.lon(), max.lat()-min.lat()); 77 } 78 78 79 79 } -
trunk/src/org/openstreetmap/josm/data/DataSetChecker.java
r627 r1169 14 14 public class DataSetChecker { 15 15 16 17 18 16 public static void check() { 17 if (Main.map == null) 18 return; 19 19 20 Set<OsmPrimitive> s = new HashSet<OsmPrimitive>(); 21 for (Layer l : Main.map.mapView.getAllLayers()) { 22 if (l instanceof OsmDataLayer) { 23 for (OsmPrimitive osm : ((OsmDataLayer)l).data.allPrimitives()) { 24 if (s.contains(osm)) { 25 JOptionPane.showMessageDialog(Main.parent, "cross references"); 26 return; 27 } 28 s.add(osm); 29 } 30 } 31 } 32 33 if (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) { 34 OsmDataLayer l = (OsmDataLayer)Main.map.mapView.getActiveLayer(); 35 if (l.data != Main.ds) { 36 JOptionPane.showMessageDialog(Main.parent, "Main.ds / active layer mismatch"); 37 return; 38 } 39 } 20 Set<OsmPrimitive> s = new HashSet<OsmPrimitive>(); 21 for (Layer l : Main.map.mapView.getAllLayers()) { 22 if (l instanceof OsmDataLayer) { 23 for (OsmPrimitive osm : ((OsmDataLayer)l).data.allPrimitives()) { 24 if (s.contains(osm)) { 25 JOptionPane.showMessageDialog(Main.parent, "cross references"); 26 return; 27 } 28 s.add(osm); 29 } 30 } 31 } 40 32 41 JOptionPane.showMessageDialog(Main.parent, "working"); 42 } 33 if (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) { 34 OsmDataLayer l = (OsmDataLayer)Main.map.mapView.getActiveLayer(); 35 if (l.data != Main.ds) { 36 JOptionPane.showMessageDialog(Main.parent, "Main.ds / active layer mismatch"); 37 return; 38 } 39 } 40 41 JOptionPane.showMessageDialog(Main.parent, "working"); 42 } 43 43 } -
trunk/src/org/openstreetmap/josm/data/Preferences.java
r1159 r1169 35 35 */ 36 36 public class Preferences { 37 38 /** 39 * Internal storage for the preferenced directory. 37 38 /** 39 * Internal storage for the preferenced directory. 40 40 * Do not access this variable directly! 41 41 * @see #getPreferencesDirFile() 42 42 */ 43 43 private File preferencesDirFile = null; 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 44 45 public static interface PreferenceChangedListener { 46 void preferenceChanged(String key, String newValue); 47 } 48 49 /** 50 * Class holding one bookmarkentry. 51 * @author imi 52 */ 53 public static class Bookmark implements Comparable<Bookmark> { 54 public String name; 55 public double[] latlon = new double[4]; // minlat, minlon, maxlat, maxlon 56 @Override public String toString() { 57 return name; 58 } 59 public int compareTo(Bookmark b) { 60 return name.toLowerCase().compareTo(b.name.toLowerCase()); 61 } 62 } 63 64 public final ArrayList<PreferenceChangedListener> listener = new ArrayList<PreferenceChangedListener>(); 65 66 /** 67 * Map the property name to the property object. 68 */ 69 protected final SortedMap<String, String> properties = new TreeMap<String, String>(); 70 protected final SortedMap<String, String> defaults = new TreeMap<String, String>(); 71 72 /** 73 * Override some values on read. This is intended to be used for technology previews 74 * where we want to temporarily modify things without changing the user's preferences 75 * file. 76 */ 77 protected static final SortedMap<String, String> override = new TreeMap<String, String>(); 78 static { 79 //override.put("osm-server.version", "0.5"); 80 //override.put("osm-server.additional-versions", ""); 81 //override.put("osm-server.url", "http://openstreetmap.gryph.de/api"); 82 //override.put("plugins", null); 83 } 84 85 /** 86 * Return the location of the user defined preferences file 87 */ 88 public String getPreferencesDir() { 89 final String path = getPreferencesDirFile().getPath(); 90 if (path.endsWith(File.separator)) 91 return path; 92 return path + File.separator; 93 } 94 94 95 95 public File getPreferencesDirFile() { … … 110 110 return preferencesDirFile; 111 111 } 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 112 113 public File getPluginsDirFile() { 114 return new File(getPreferencesDirFile(), "plugins"); 115 } 116 117 /** 118 * @return A list of all existing directories where resources could be stored. 119 */ 120 public Collection<String> getAllPossiblePreferenceDirs() { 121 LinkedList<String> locations = new LinkedList<String>(); 122 locations.add(Main.pref.getPreferencesDir()); 123 String s; 124 if ((s = System.getenv("JOSM_RESOURCES")) != null) { 125 if (!s.endsWith(File.separator)) 126 s = s + File.separator; 127 locations.add(s); 128 } 129 if ((s = System.getProperty("josm.resources")) != null) { 130 if (!s.endsWith(File.separator)) 131 s = s + File.separator; 132 locations.add(s); 133 } 134 String appdata = System.getenv("APPDATA"); 135 if (System.getenv("ALLUSERSPROFILE") != null && appdata != null 136 && appdata.lastIndexOf(File.separator) != -1) { 137 appdata = appdata.substring(appdata.lastIndexOf(File.separator)); 138 locations.add(new File(new File(System.getenv("ALLUSERSPROFILE"), 139 appdata), "JOSM").getPath()); 140 } 141 locations.add("/usr/local/share/josm/"); 142 locations.add("/usr/local/lib/josm/"); 143 locations.add("/usr/share/josm/"); 144 locations.add("/usr/lib/josm/"); 145 return locations; 146 } 147 148 synchronized public boolean hasKey(final String key) { 149 return override.containsKey(key) ? override.get(key) != null : properties.containsKey(key); 150 } 151 152 synchronized public String get(final String key) { 153 putDefault(key, null); 154 if (override.containsKey(key)) 155 return override.get(key); 156 if (!properties.containsKey(key)) 157 return ""; 158 return properties.get(key); 159 } 160 161 synchronized public String get(final String key, final String def) { 162 putDefault(key, def); 163 if (override.containsKey(key)) 164 return override.get(key); 165 final String prop = properties.get(key); 166 if (prop == null || prop.equals("")) 167 return def; 168 return prop; 169 } 170 171 synchronized public Map<String, String> getAllPrefix(final String prefix) { 172 final Map<String,String> all = new TreeMap<String,String>(); 173 for (final Entry<String,String> e : properties.entrySet()) 174 if (e.getKey().startsWith(prefix)) 175 all.put(e.getKey(), e.getValue()); 176 for (final Entry<String,String> e : override.entrySet()) 177 if (e.getKey().startsWith(prefix)) 178 if (e.getValue() == null) 179 all.remove(e.getKey()); 180 else 181 all.put(e.getKey(), e.getValue()); 182 return all; 183 } 184 185 synchronized public Map<String, String> getDefaults() { 186 return defaults; 187 } 188 189 synchronized public void putDefault(final String key, final String def) { 190 if(!defaults.containsKey(key) || defaults.get(key) == null) 191 defaults.put(key, def); 192 else if(def != null && !defaults.get(key).equals(def)) 193 System.out.println("Defaults for " + key + " differ: " + def + " != " + defaults.get(key)); 194 } 195 196 synchronized public boolean getBoolean(final String key) { 197 putDefault(key, null); 198 if (override.containsKey(key)) 199 return override.get(key) == null ? false : Boolean.parseBoolean(override.get(key)); 200 return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : false; 201 } 202 203 synchronized public boolean getBoolean(final String key, final boolean def) { 204 putDefault(key, Boolean.toString(def)); 205 if (override.containsKey(key)) 206 return override.get(key) == null ? def : Boolean.parseBoolean(override.get(key)); 207 return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : def; 208 } 209 210 synchronized public void put(final String key, String value) { 211 String oldvalue = properties.get(key); 212 if(value != null && value.length() == 0) 213 value = null; 214 if(!((oldvalue == null && value == null) || (value != null 215 && oldvalue != null && oldvalue.equals(value)))) 216 { 217 if (value == null) 218 properties.remove(key); 219 else 220 properties.put(key, value); 221 save(); 222 firePreferenceChanged(key, value); 223 } 224 } 225 226 synchronized public void put(final String key, final boolean value) { 227 put(key, Boolean.toString(value)); 228 } 229 230 private final void firePreferenceChanged(final String key, final String value) { 231 for (final PreferenceChangedListener l : listener) 232 l.preferenceChanged(key, value); 233 } 234 235 /** 236 * Called after every put. In case of a problem, do nothing but output the error 237 * in log. 238 */ 239 public void save() { 240 try { 241 setSystemProperties(); 242 final PrintWriter out = new PrintWriter(new FileWriter(getPreferencesDir() + "preferences"), false); 243 for (final Entry<String, String> e : properties.entrySet()) { 244 out.println(e.getKey() + "=" + e.getValue()); 245 } 246 out.close(); 247 } catch (final IOException e) { 248 e.printStackTrace(); 249 // do not message anything, since this can be called from strange 250 // places. 251 } 252 } 253 254 public void load() throws IOException { 255 properties.clear(); 256 final BufferedReader in = new BufferedReader(new FileReader(getPreferencesDir()+"preferences")); 257 int lineNumber = 0; 258 ArrayList<Integer> errLines = new ArrayList<Integer>(); 259 for (String line = in.readLine(); line != null; line = in.readLine(), lineNumber++) { 260 final int i = line.indexOf('='); 261 if (i == -1 || i == 0) { 262 errLines.add(lineNumber); 263 continue; 264 } 265 properties.put(line.substring(0,i), line.substring(i+1)); 266 } 267 if (!errLines.isEmpty()) { 268 throw new IOException("Malformed config file at lines " + errLines); 269 } 270 setSystemProperties(); 271 } 272 273 public final void resetToDefault() { 274 properties.clear(); 275 properties.put("projection", "org.openstreetmap.josm.data.projection.Epsg4326"); 276 properties.put("draw.segment.direction", "true"); 277 properties.put("draw.wireframe", "false"); 278 properties.put("layerlist.visible", "true"); 279 properties.put("propertiesdialog.visible", "true"); 280 properties.put("selectionlist.visible", "true"); 281 properties.put("commandstack.visible", "true"); 282 properties.put("osm-server.url", "http://www.openstreetmap.org/api"); 283 if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") == -1) { 284 properties.put("laf", "javax.swing.plaf.metal.MetalLookAndFeel"); 285 } else { 286 properties.put("laf", "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); 287 } 288 save(); 289 } 290 291 public Collection<Bookmark> loadBookmarks() throws IOException { 292 File bookmarkFile = new File(getPreferencesDir()+"bookmarks"); 293 if (!bookmarkFile.exists()) 294 bookmarkFile.createNewFile(); 295 BufferedReader in = new BufferedReader(new FileReader(bookmarkFile)); 296 297 LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>(); 298 // use pattern matches to scan text, as text may contain a "," itself 299 for (String line = in.readLine(); line != null; line = in.readLine()) { 300 Matcher m = Pattern.compile("^(.+),(-?\\d+.\\d+),(-?\\d+.\\d+),(-?\\d+.\\d+),(-?\\d+.\\d+)$").matcher(line); 301 if(m.matches()) 302 { 303 Bookmark b = new Bookmark(); 304 b.name = m.group(1); 305 for (int i = 0; i < b.latlon.length; ++i) 306 b.latlon[i] = Double.parseDouble(m.group(i+2)); 307 bookmarks.add(b); 308 } 309 } 310 in.close(); 311 Collections.sort(bookmarks); 312 return bookmarks; 313 } 314 315 public void saveBookmarks(Collection<Bookmark> bookmarks) throws IOException { 316 File bookmarkFile = new File(Main.pref.getPreferencesDir()+"bookmarks"); 317 if (!bookmarkFile.exists()) 318 bookmarkFile.createNewFile(); 319 PrintWriter out = new PrintWriter(new FileWriter(bookmarkFile)); 320 for (Bookmark b : bookmarks) { 321 out.print(b.name+","); 322 for (int i = 0; i < b.latlon.length; ++i) 323 out.print(b.latlon[i]+(i<b.latlon.length-1?",":"")); 324 out.println(); 325 } 326 out.close(); 327 } 328 329 /** 330 * Convenience method for accessing colour preferences. 331 * 332 * @param colName name of the colour 333 * @param def default value 334 * @return a Color object for the configured colour, or the default value if none configured. 335 */ 336 synchronized public Color getColor(String colName, Color def) { 337 String colStr = get("color."+colName); 338 if (colStr.equals("")) { 339 put("color."+colName, ColorHelper.color2html(def)); 340 return def; 341 } 342 return ColorHelper.html2color(colStr); 343 } 344 345 // only for compatibility. Don't use any more. 346 @Deprecated 347 public static Color getPreferencesColor(String colName, Color def) 348 { 349 return Main.pref.getColor(colName, def); 350 } 351 352 /** 353 * Convenience method for accessing colour preferences. 354 * 355 * @param colName name of the colour 356 * @param specName name of the special colour settings 357 * @param def default value 358 * @return a Color object for the configured colour, or the default value if none configured. 359 */ 360 synchronized public Color getColor(String colName, String specName, Color def) { 361 String colStr = get("color."+specName); 362 if(colStr.equals("")) 363 { 364 colStr = get("color."+colName); 365 if (colStr.equals("")) { 366 put("color."+colName, ColorHelper.color2html(def)); 367 return def; 368 } 369 } 370 putDefault("color."+colName, ColorHelper.color2html(def)); 371 return ColorHelper.html2color(colStr); 372 } 373 374 synchronized public void putColor(String colName, Color val) { 375 put("color."+colName, val != null ? ColorHelper.color2html(val) : null); 376 } 377 378 synchronized public int getInteger(String key, int def) { 379 putDefault(key, Integer.toString(def)); 380 String v = get(key); 381 if(null == v) 382 return def; 383 384 try { 385 return Integer.parseInt(v); 386 } catch(NumberFormatException e) { 387 // fall out 388 } 389 return def; 390 } 391 392 synchronized public long getLong(String key, long def) { 393 putDefault(key, Long.toString(def)); 394 String v = get(key); 395 if(null == v) 396 return def; 397 398 try { 399 return Long.parseLong(v); 400 } catch(NumberFormatException e) { 401 // fall out 402 } 403 return def; 404 } 405 406 synchronized public double getDouble(String key, double def) { 407 putDefault(key, Double.toString(def)); 408 String v = get(key); 409 if(null == v) 410 return def; 411 412 try { 413 return Double.parseDouble(v); 414 } catch(NumberFormatException e) { 415 // fall out 416 } 417 return def; 418 } 419 420 synchronized public Collection<String> getCollection(String key, Collection<String> def) { 421 String s = get(key); 422 if(s != null && s.length() != 0) 423 { 424 /* handle old comma separated stuff - remove in future */ 425 if(s.indexOf(',') >= 0) 426 return Arrays.asList(s.split(",")); 427 /* handle space separated stuff - remove in future */ 428 else if(s.indexOf(' ') >= 0) 429 return Arrays.asList(s.split(",")); 430 else 431 return Arrays.asList(s.split(";")); 432 } 433 else if(def != null) 434 return def; 435 return null; 436 } 437 synchronized public void removeFromCollection(String key, String value) { 438 ArrayList<String> a = new ArrayList<String>(getCollection(key, null)); 439 if(a != null) 440 { 441 a.remove(value); 442 putCollection(key, a); 443 } 444 } 445 synchronized public void putCollection(String key, Collection<String> val) { 446 String s = null; 447 if(val != null) 448 { 449 for(String a : val) 450 { 451 if(s != null) 452 s += ";" + a; 453 else 454 s = a; 455 } 456 } 457 458 put(key, s); 459 } 460 461 private void setSystemProperties() { 462 Properties sysProp = System.getProperties(); 463 if (getBoolean(ProxyPreferences.PROXY_ENABLE)) { 464 sysProp.put("proxySet", "true"); 465 sysProp.put("http.proxyHost", get(ProxyPreferences.PROXY_HOST)); 466 sysProp.put("proxyPort", get(ProxyPreferences.PROXY_PORT)); 467 if (!getBoolean(ProxyPreferences.PROXY_ANONYMOUS)) { 468 sysProp.put("proxyUser", get(ProxyPreferences.PROXY_USER)); 469 sysProp.put("proxyPassword", get(ProxyPreferences.PROXY_PASS)); 470 } 471 }/* else { 472 sysProp.put("proxySet", "false"); 473 sysProp.remove("http.proxyHost"); 474 sysProp.remove("proxyPort"); 475 sysProp.remove("proxyUser"); 476 sysProp.remove("proxyPassword"); 477 }*/ 478 System.setProperties(sysProp); 479 } 480 480 } -
trunk/src/org/openstreetmap/josm/data/SelectionChangedListener.java
r655 r1169 10 10 * a selection of any data member changes, the dataSet gets informed about this 11 11 * and fires a selectionChanged event. 12 * 12 * 13 13 * Note that these events are not fired immediately but are inserted in the 14 14 * Swing event queue and packed together. So only one selection changed event 15 15 * is issued within a one message dispatch routine. 16 * 16 * 17 17 * @author imi 18 18 */ 19 19 public interface SelectionChangedListener { 20 20 21 22 23 24 25 21 /** 22 * Informs the listener that the selection in the dataset has changed. 23 * @param newSelection The new selection. 24 */ 25 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection); 26 26 } -
trunk/src/org/openstreetmap/josm/data/ServerSidePreferences.java
r733 r1169 32 32 * This class tweak the Preferences class to provide server side preference settings, as example 33 33 * used in the applet version. 34 * 34 * 35 35 * @author Imi 36 36 */ 37 37 public class ServerSidePreferences extends Preferences { 38 38 39 39 private final Connection connection; 40 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 41 private class Connection extends OsmConnection { 42 URL serverUrl; 43 public Connection(URL serverUrl) { 44 this.serverUrl = serverUrl; 45 } 46 public String download() { 47 try { 48 System.out.println("reading preferences from "+serverUrl); 49 URLConnection con = serverUrl.openConnection(); 50 if (con instanceof HttpURLConnection) addAuth((HttpURLConnection) con); 51 con.connect(); 52 BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream())); 53 StringBuilder b = new StringBuilder(); 54 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 55 b.append(line); 56 b.append("\n"); 57 } 58 if (con instanceof HttpURLConnection) ((HttpURLConnection) con).disconnect(); 59 return b.toString(); 60 } catch (IOException e) { 61 e.printStackTrace(); 62 } 63 return null; 64 } 65 public void upload(String s) { 66 try { 67 URL u = new URL(getPreferencesDir()); 68 System.out.println("uploading preferences to "+u); 69 HttpURLConnection con = (HttpURLConnection)u.openConnection(); 70 con.addRequestProperty("Authorization", "Basic "+Base64.encode(get("osm-server.username")+":"+get("osm-server.password"))); 71 con.setRequestMethod("POST"); 72 con.setDoOutput(true); 73 con.connect(); 74 PrintWriter out = new PrintWriter(new OutputStreamWriter(con.getOutputStream())); 75 out.println(s); 76 out.close(); 77 con.getInputStream().close(); 78 con.disconnect(); 79 JOptionPane.showMessageDialog(Main.parent, tr("Preferences stored on {0}", u.getHost())); 80 } catch (Exception e) { 81 e.printStackTrace(); 82 JOptionPane.showMessageDialog(Main.parent, tr("Could not upload preferences. Reason: {0}", e.getMessage())); 83 } 84 } 85 } 86 86 87 88 89 90 91 92 93 94 95 96 87 public ServerSidePreferences(URL serverUrl) { 88 Connection connection = null; 89 try { 90 connection = new Connection(new URL(serverUrl+"user/preferences")); 91 } catch (MalformedURLException e) { 92 e.printStackTrace(); 93 JOptionPane.showMessageDialog(Main.parent, tr("Could not load preferences from server.")); 94 } 95 this.connection = connection; 96 } 97 97 98 99 100 98 @Override public String getPreferencesDir() { 99 return connection.serverUrl.toString(); 100 } 101 101 102 103 104 105 106 102 /** 103 * Do nothing on load. Preferences are loaded with download(). 104 */ 105 @Override public void load() { 106 } 107 107 108 109 110 111 112 108 /** 109 * Do nothing on save. Preferences are uploaded using upload(). 110 */ 111 @Override public void save() { 112 } 113 113 114 115 116 117 114 public static class Prop { 115 public String key; 116 public String value; 117 } 118 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 119 public void download(String userName, String password) { 120 resetToDefault(); 121 if (!properties.containsKey("osm-server.username") && userName != null) 122 properties.put("osm-server.username", userName); 123 if (!properties.containsKey("osm-server.password") && password != null) 124 properties.put("osm-server.password", password); 125 String cont = connection.download(); 126 if (cont == null) return; 127 Reader in = new StringReader(cont); 128 try { 129 XmlObjectParser.Uniform<Prop> parser = new XmlObjectParser.Uniform<Prop>(in, "tag", Prop.class); 130 for (Prop p : parser) 131 properties.put(p.key, p.value); 132 } catch (RuntimeException e) { 133 e.printStackTrace(); 134 } 135 } 136 136 137 138 139 140 * 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 137 /** 138 * Use this instead of save() for the ServerSidePreferences, since uploads 139 * are costly while save is called often. 140 * 141 * This is triggered by an explicit menu option. 142 */ 143 public void upload() { 144 StringBuilder b = new StringBuilder("<preferences>\n"); 145 for (Entry<String, String> p : properties.entrySet()) { 146 if (p.getKey().equals("osm-server.password")) 147 continue; // do not upload password. It would get stored in plain! 148 b.append("<tag key='"); 149 b.append(XmlWriter.encode(p.getKey())); 150 b.append("' value='"); 151 b.append(XmlWriter.encode(p.getValue())); 152 b.append("' />\n"); 153 } 154 b.append("</preferences>"); 155 connection.upload(b.toString()); 156 } 157 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 158 @Override public Collection<Bookmark> loadBookmarks() { 159 try { 160 Collection<Bookmark> bookmarks; 161 BufferedReader in = new BufferedReader(new InputStreamReader(new URL("http://"+connection.serverUrl.getHost()+"/josm/bookmarks").openStream())); 162 bookmarks = new LinkedList<Bookmark>(); 163 for (String line = in.readLine(); line != null; line = in.readLine()) { 164 StringTokenizer st = new StringTokenizer(line, ","); 165 if (st.countTokens() < 5) 166 continue; 167 Bookmark b = new Bookmark(); 168 b.name = st.nextToken(); 169 try { 170 for (int i = 0; i < b.latlon.length; ++i) 171 b.latlon[i] = Double.parseDouble(st.nextToken()); 172 bookmarks.add(b); 173 } catch (NumberFormatException x) { 174 // line not parsed 175 } 176 } 177 in.close(); 178 return bookmarks; 179 } catch (MalformedURLException e) { 180 e.printStackTrace(); 181 } catch (IllegalArgumentException e) { 182 e.printStackTrace(); 183 } catch (IOException e) { 184 e.printStackTrace(); 185 } 186 return Collections.emptyList(); 187 } 188 188 189 190 189 @Override public void saveBookmarks(Collection<Bookmark> bookmarks) { 190 } 191 191 } -
trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java
r661 r1169 15 15 public class UndoRedoHandler implements LayerChangeListener { 16 16 17 18 19 20 21 22 23 24 17 /** 18 * All commands that were made on the dataset. Don't write from outside! 19 */ 20 public final LinkedList<Command> commands = new LinkedList<Command>(); 21 /** 22 * The stack for redoing commands 23 */ 24 private final Stack<Command> redoCommands = new Stack<Command>(); 25 25 26 26 public final LinkedList<CommandQueueListener> listenerCommands = new LinkedList<CommandQueueListener>(); 27 27 28 28 29 30 31 29 public UndoRedoHandler() { 30 Layer.listeners.add(this); 31 } 32 32 33 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 34 /** 35 * Execute the command and add it to the intern command queue. 36 */ 37 public void add(final Command c) { 38 c.executeCommand(); 39 commands.add(c); 40 redoCommands.clear(); 41 if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) { 42 OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer(); 43 data.setModified(true); 44 data.fireDataChange(); 45 } 46 fireCommandsChanged(); 47 } 48 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 } 63 64 65 49 /** 50 * Undoes the last added command. 51 */ 52 public void undo() { 53 if (commands.isEmpty()) 54 return; 55 final Command c = commands.removeLast(); 56 c.undoCommand(); 57 redoCommands.push(c); 58 if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) { 59 OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer(); 60 data.setModified(data.uploadedModified || !commands.isEmpty()); 61 data.fireDataChange(); 62 } 63 fireCommandsChanged(); 64 Main.ds.setSelected(); 65 } 66 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 67 /** 68 * Redoes the last undoed command. 69 * TODO: This has to be moved to a central place in order to support multiple layers. 70 */ 71 public void redo() { 72 if (redoCommands.isEmpty()) 73 return; 74 final Command c = redoCommands.pop(); 75 c.executeCommand(); 76 commands.add(c); 77 if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) { 78 OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer(); 79 data.setModified(true); 80 data.fireDataChange(); 81 } 82 fireCommandsChanged(); 83 } 84 84 85 86 87 88 85 public void fireCommandsChanged() { 86 for (final CommandQueueListener l : listenerCommands) 87 l.commandChanged(commands.size(), redoCommands.size()); 88 } 89 89 90 91 92 93 94 90 public void clean() { 91 redoCommands.clear(); 92 commands.clear(); 93 fireCommandsChanged(); 94 } 95 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 96 public void layerRemoved(Layer oldLayer) { 97 boolean changed = false; 98 for (Iterator<Command> it = commands.iterator(); it.hasNext();) { 99 if (it.next().invalidBecauselayerRemoved(oldLayer)) { 100 it.remove(); 101 changed = true; 102 } 103 } 104 for (Iterator<Command> it = redoCommands.iterator(); it.hasNext();) { 105 if (it.next().invalidBecauselayerRemoved(oldLayer)) { 106 it.remove(); 107 changed = true; 108 } 109 } 110 if (changed) 111 fireCommandsChanged(); 112 } 113 113 114 115 114 public void layerAdded(Layer newLayer) {} 115 public void activeLayerChange(Layer oldLayer, Layer newLayer) {} 116 116 } -
trunk/src/org/openstreetmap/josm/data/conflict/ConflictItem.java
r627 r1169 12 12 public abstract class ConflictItem { 13 13 14 15 14 public String my, their; 15 public Resolution resolution = null; 16 16 17 18 19 20 17 public final void initialize(Map<OsmPrimitive,OsmPrimitive> conflicts) { 18 my = collectStr(conflicts.keySet()); 19 their = collectStr(conflicts.values()); 20 } 21 21 22 23 24 25 22 abstract public boolean hasConflict(OsmPrimitive key, OsmPrimitive value); 23 abstract protected String str(OsmPrimitive osm); 24 abstract public String key(); 25 abstract public void apply(OsmPrimitive target, OsmPrimitive other); 26 26 27 28 29 30 31 32 33 34 35 36 37 38 39 27 protected final String collectStr(Collection<OsmPrimitive> c) { 28 String value = null; 29 for (OsmPrimitive osm : c) { 30 String v = str(osm); 31 if (value == null) 32 value = v; 33 else if (!value.equals(v)) { 34 value = "<html><i><"+tr("different")+"></i></html>"; 35 break; 36 } 37 } 38 return value == null ? "" : value; 39 } 40 40 } -
trunk/src/org/openstreetmap/josm/data/conflict/DeleteConflict.java
r627 r1169 8 8 public class DeleteConflict extends ConflictItem { 9 9 10 11 12 10 @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) { 11 return key.deleted != value.deleted; 12 } 13 13 14 15 16 14 @Override public String key() { 15 return "deleted|"+tr("deleted"); 16 } 17 17 18 19 20 18 @Override protected String str(OsmPrimitive osm) { 19 return osm.deleted ? tr("true") : tr("false"); 20 } 21 21 22 23 24 22 @Override public void apply(OsmPrimitive target, OsmPrimitive other) { 23 target.deleted = other.deleted; 24 } 25 25 } -
trunk/src/org/openstreetmap/josm/data/conflict/PositionConflict.java
r627 r1169 8 8 9 9 public class PositionConflict extends ConflictItem { 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 10 11 @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) { 12 return key instanceof Node && !((Node)key).coor.equals(((Node)value).coor); 13 } 14 15 @Override protected String str(OsmPrimitive osm) { 16 return osm instanceof Node ? ((Node)osm).coor.lat()+", "+((Node)osm).coor.lon() : null; 17 } 18 19 @Override public String key() { 20 return "node|"+tr("position"); 21 } 22 23 @Override public void apply(OsmPrimitive target, OsmPrimitive other) { 24 if (target instanceof Node) { 25 ((Node)target).coor = ((Node)other).coor; 26 ((Node)target).eastNorth = ((Node)other).eastNorth; 27 } 28 28 } 29 29 } -
trunk/src/org/openstreetmap/josm/data/conflict/PropertyConflict.java
r627 r1169 5 5 6 6 public class PropertyConflict extends ConflictItem { 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 7 private String key; 8 9 public PropertyConflict(String key) { 10 this.key = key; 11 } 12 13 @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) { 14 String k = key.get(this.key); 15 String v = value.get(this.key); 16 return k == null ? v!=null : !k.equals(v); 17 } 18 19 @Override protected String str(OsmPrimitive osm) { 20 String v = osm.get(key); 21 return v == null ? "" : v; 22 } 23 24 @Override public String key() { 25 return "key|"+key; 26 } 27 28 @Override public void apply(OsmPrimitive target, OsmPrimitive other) { 29 target.put(key, other.get(key)); 30 30 } 31 31 } -
trunk/src/org/openstreetmap/josm/data/coor/Coordinate.java
r1094 r1169 7 7 /** 8 8 * Base class of points of both coordinate systems. 9 * 10 * The variables are default package protected to allow routines in the 9 * 10 * The variables are default package protected to allow routines in the 11 11 * data package to access them directly. 12 * 13 * As the class itself is package protected too, it is not visible 14 * outside of the data package. Routines there should only use LatLon or 12 * 13 * As the class itself is package protected too, it is not visible 14 * outside of the data package. Routines there should only use LatLon or 15 15 * EastNorth. 16 16 * 17 17 * @author imi 18 */ 18 */ 19 19 abstract class Coordinate extends Point2D implements Serializable { 20 20 21 21 protected double x; 22 22 protected double y; 23 24 25 26 * 27 28 29 30 23 24 /** 25 * Construct the point with latitude / longitude values. 26 * 27 * @param x X coordinate of the point. 28 * @param y Y coordinate of the point. 29 */ 30 Coordinate(double x, double y) { 31 31 this.x = x; this.y = y; 32 33 32 } 33 34 34 public double getX() { 35 35 return x; 36 36 } 37 37 38 38 public double getY() { 39 return y; 39 return y; 40 40 } 41 41 42 42 public void setLocation (double x, double y) { 43 this.x = x; 43 this.x = x; 44 44 this.y = y; 45 45 } -
trunk/src/org/openstreetmap/josm/data/coor/EastNorth.java
r1076 r1169 4 4 /** 5 5 * Northing, Easting of the projected coordinates. 6 * 6 * 7 7 * This class is immutable. 8 * 8 * 9 9 * @author Imi 10 10 */ 11 11 public class EastNorth extends Coordinate { 12 12 13 public EastNorth(double east, double north) { 14 super(east,north); 15 } 16 17 public double east() { 18 return x; 19 } 13 public EastNorth(double east, double north) { 14 super(east,north); 15 } 20 16 21 north() {22 y;23 17 public double east() { 18 return x; 19 } 24 20 25 public EastNorth add(double dx, double dy) { 26 return new EastNorth(x+dx, y+dy); 27 } 28 29 public EastNorth interpolate(EastNorth en2, double proportion) { 30 return new EastNorth(this.x + proportion * (en2.x - this.x), 21 public double north() { 22 return y; 23 } 24 25 public EastNorth add(double dx, double dy) { 26 return new EastNorth(x+dx, y+dy); 27 } 28 29 public EastNorth interpolate(EastNorth en2, double proportion) { 30 return new EastNorth(this.x + proportion * (en2.x - this.x), 31 31 this.y + proportion * (en2.y - this.y)); 32 33 32 } 33 34 34 /** 35 * Returns the heading, in radians, that you have to use to get from 35 * Returns the heading, in radians, that you have to use to get from 36 36 * this EastNorth to another. Heading is mapped into [0, 2pi) 37 * 37 * 38 38 * @param other the "destination" position 39 * @return heading 39 * @return heading 40 40 */ 41 41 public double heading(EastNorth other) { 42 42 double hd = Math.atan2(other.east() - east(), other.north() - north()); 43 43 if(hd < 0) hd = 2 * Math.PI + hd; 44 return hd; 44 return hd; 45 45 } 46 46 47 47 public EastNorth sub(EastNorth en) { 48 48 return new EastNorth(en.east() - east(), en.north() - north()); 49 49 } 50 50 51 51 /** 52 52 * Returns an EastNorth representing the this EastNorth rotatedaround … … 54 54 * @param pivot the center of the rotation 55 55 * @param angle the angle of the rotation 56 * @return EastNorth rotated object 56 * @return EastNorth rotated object 57 57 */ 58 58 public EastNorth rotate(EastNorth pivot, double angle) { … … 65 65 return new EastNorth(nx, ny); 66 66 } 67 68 69 70 67 68 @Override public String toString() { 69 return "EastNorth[e="+x+", n="+y+"]"; 70 } 71 71 72 72 /** -
trunk/src/org/openstreetmap/josm/data/coor/LatLon.java
r1108 r1169 13 13 /** 14 14 * LatLon are unprojected latitude / longitude coordinates. 15 * 15 * 16 16 * This class is immutable. 17 * 17 * 18 18 * @author Imi 19 19 */ … … 23 23 private static DecimalFormat cDmsSecondFormatter = new DecimalFormat("00.0"); 24 24 private static DecimalFormat cDdFormatter = new DecimalFormat("###0.0000"); 25 26 /** 27 * Possible ways to display coordinates 28 */ 29 public enum CoordinateFormat { 30 DECIMAL_DEGREES {public String toString() {return tr("Decimal Degrees");}}, 31 DEGREES_MINUTES_SECONDS {public String toString() {return tr("Degrees Minutes Seconds");}}; 32 } 33 34 public static String dms(double pCoordinate) { 25 26 /** 27 * Possible ways to display coordinates 28 */ 29 public enum CoordinateFormat { 30 DECIMAL_DEGREES {public String toString() {return tr("Decimal Degrees");}}, 31 DEGREES_MINUTES_SECONDS {public String toString() {return tr("Degrees Minutes Seconds");}}; 32 } 33 34 public static String dms(double pCoordinate) { 35 35 36 36 double tAbsCoord = Math.abs(pCoordinate); … … 40 40 double tSeconds = (tTmpMinutes - tMinutes) * 60; 41 41 42 return tDegree + "\u00B0" + cDmsMinuteFormatter.format(tMinutes) + "\'" 42 return tDegree + "\u00B0" + cDmsMinuteFormatter.format(tMinutes) + "\'" 43 43 + cDmsSecondFormatter.format(tSeconds) + "\""; 44 } 44 } 45 45 46 46 public LatLon(double lat, double lon) { … … 51 51 return y; 52 52 } 53 53 54 54 public String latToString(CoordinateFormat d) { 55 55 switch(d) { … … 59 59 } 60 60 } 61 61 62 62 public double lon() { 63 63 return x; 64 64 } 65 65 66 66 public String lonToString(CoordinateFormat d) { 67 67 switch(d) { … … 71 71 } 72 72 } 73 74 73 74 75 75 76 76 /** … … 86 86 /** 87 87 * @return <code>true</code>, if the coordinate is outside the world, compared 88 89 90 91 92 93 88 * by using lat/lon. 89 */ 90 public boolean isOutSideWorld() { 91 return lat() < -Projection.MAX_LAT || lat() > Projection.MAX_LAT || 92 lon() < -Projection.MAX_LON || lon() > Projection.MAX_LON; 93 } 94 94 95 /** 96 * @return <code>true</code> if this is within the given bounding box. 97 */ 98 public boolean isWithin(Bounds b) { 99 return lat() >= b.min.lat() && lat() <= b.max.lat() && lon() > b.min.lon() && lon() < b.max.lon(); 100 } 101 102 /** 103 * Computes the distance between this lat/lon and another point on the earth. 104 * Uses spherical law of cosines formula, not Haversine. 105 * @param other the other point. 106 * @return distance in metres. 107 */ 108 public double greatCircleDistance(LatLon other) { 109 return (Math.acos( 110 Math.sin(Math.toRadians(lat())) * Math.sin(Math.toRadians(other.lat())) + 111 Math.cos(Math.toRadians(lat()))*Math.cos(Math.toRadians(other.lat())) * 112 Math.cos(Math.toRadians(other.lon()-lon()))) * 6378135); 113 } 114 115 /** 116 * Returns the heading, in radians, that you have to use to get from 117 * this lat/lon to another. 118 * 119 * @param other the "destination" position 120 * @return heading 121 */ 122 public double heading(LatLon other) { 123 double rv; 124 if (other.lat() == lat()) { 125 rv = (other.lon()>lon() ? Math.PI / 2 : Math.PI * 3 / 2); 126 } else { 127 rv = Math.atan((other.lon()-lon())/(other.lat()-lat())); 128 if (rv < 0) rv += Math.PI; 129 if (other.lon() < lon()) rv += Math.PI; 130 } 131 return rv; 132 } 95 /** 96 * @return <code>true</code> if this is within the given bounding box. 97 */ 98 public boolean isWithin(Bounds b) { 99 return lat() >= b.min.lat() && lat() <= b.max.lat() && lon() > b.min.lon() && lon() < b.max.lon(); 100 } 133 101 134 /** 135 * Returns this lat/lon pair in human-readable format. 136 * 137 * @return String in the format "lat=1.23456°, lon=2.34567°" 138 */ 139 public String toDisplayString() { 140 NumberFormat nf = NumberFormat.getInstance(); 141 nf.setMaximumFractionDigits(5); 142 return "lat=" + nf.format(lat()) + "°, lon=" + nf.format(lon()) + "°"; 143 } 144 145 @Override public String toString() { 146 return "LatLon[lat="+lat()+",lon="+lon()+"]"; 102 /** 103 * Computes the distance between this lat/lon and another point on the earth. 104 * Uses spherical law of cosines formula, not Haversine. 105 * @param other the other point. 106 * @return distance in metres. 107 */ 108 public double greatCircleDistance(LatLon other) { 109 return (Math.acos( 110 Math.sin(Math.toRadians(lat())) * Math.sin(Math.toRadians(other.lat())) + 111 Math.cos(Math.toRadians(lat()))*Math.cos(Math.toRadians(other.lat())) * 112 Math.cos(Math.toRadians(other.lon()-lon()))) * 6378135); 113 } 114 115 /** 116 * Returns the heading, in radians, that you have to use to get from 117 * this lat/lon to another. 118 * 119 * @param other the "destination" position 120 * @return heading 121 */ 122 public double heading(LatLon other) { 123 double rv; 124 if (other.lat() == lat()) { 125 rv = (other.lon()>lon() ? Math.PI / 2 : Math.PI * 3 / 2); 126 } else { 127 rv = Math.atan((other.lon()-lon())/(other.lat()-lat())); 128 if (rv < 0) rv += Math.PI; 129 if (other.lon() < lon()) rv += Math.PI; 130 } 131 return rv; 132 } 133 134 /** 135 * Returns this lat/lon pair in human-readable format. 136 * 137 * @return String in the format "lat=1.23456°, lon=2.34567°" 138 */ 139 public String toDisplayString() { 140 NumberFormat nf = NumberFormat.getInstance(); 141 nf.setMaximumFractionDigits(5); 142 return "lat=" + nf.format(lat()) + "°, lon=" + nf.format(lon()) + "°"; 143 } 144 145 @Override public String toString() { 146 return "LatLon[lat="+lat()+",lon="+lon()+"]"; 147 147 } 148 148 } -
trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java
r655 r1169 15 15 * It uses GPX v1.1, see {@link <a href="http://www.topografix.com/GPX/1/1/">the spec</a>} 16 16 * for details. 17 * 17 * 18 18 * @author Raphael Mack <ramack@raphael-mack.de> 19 19 */ 20 20 public class GpxData extends WithAttributes { 21 22 21 public File storageFile; 22 public boolean fromServer; 23 23 24 25 26 24 public Collection<GpxTrack> tracks = new LinkedList<GpxTrack>(); 25 public Collection<GpxRoute> routes = new LinkedList<GpxRoute>(); 26 public Collection<WayPoint> waypoints = new LinkedList<WayPoint>(); 27 27 28 28 public Bounds bounds; 29 29 30 31 32 33 34 30 public void mergeFrom(GpxData other) { 31 if (storageFile == null && other.storageFile != null) { 32 storageFile = other.storageFile; 33 } 34 fromServer = fromServer && other.fromServer; 35 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 36 for (Map.Entry<String, Object> ent : other.attr.entrySet()) { 37 // TODO: Detect conflicts. 38 String k = ent.getKey(); 39 if (k.equals("link") && attr.containsKey("link")) { 40 ((Collection<GpxLink>) attr.get("link")).addAll( 41 (Collection<GpxLink>) ent.getValue()); 42 } else { 43 attr.put(k, ent.getValue()); 44 } 45 } 46 tracks.addAll(other.tracks); 47 routes.addAll(other.routes); 48 waypoints.addAll(other.waypoints); 49 } 50 50 51 52 53 54 55 56 57 58 59 51 public boolean hasTrackPoints() { 52 for (GpxTrack trk : tracks) { 53 for (Collection<WayPoint> trkseg : trk.trackSegs) { 54 if (!trkseg.isEmpty()) 55 return true; 56 } 57 } 58 return false; 59 } 60 60 61 62 63 64 65 66 67 61 public boolean hasRoutePoints() { 62 for (GpxRoute rte : routes) { 63 if (!rte.routePoints.isEmpty()) 64 return true; 65 } 66 return false; 67 } 68 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 69 // FIXME might perhaps use visitor pattern? 70 public void recalculateBounds() { 71 bounds = null; 72 for (WayPoint wpt : waypoints) { 73 if (bounds == null) { 74 bounds = new Bounds(wpt.latlon, wpt.latlon); 75 } else { 76 bounds.extend(wpt.latlon); 77 } 78 } 79 for (GpxRoute rte : routes) { 80 for (WayPoint wpt : rte.routePoints) { 81 if (bounds == null) { 82 bounds = new Bounds(wpt.latlon, wpt.latlon); 83 } else { 84 bounds.extend(wpt.latlon); 85 } 86 } 87 } 88 for (GpxTrack trk : tracks) { 89 for (Collection<WayPoint> trkseg : trk.trackSegs) { 90 for (WayPoint wpt : trkseg) { 91 if (bounds == null) { 92 bounds = new Bounds(wpt.latlon, wpt.latlon); 93 } else { 94 bounds.extend(wpt.latlon); 95 } 96 } 97 } 98 } 99 if (bounds == null) { 100 bounds = new Bounds(); 101 } 102 } 103 104 104 /** 105 105 * calculates the sum of the lengths of all track segments … … 108 108 double result = 0.0; // in meters 109 109 WayPoint last = null; 110 110 111 111 for (GpxTrack trk : tracks) { 112 112 for (Collection<WayPoint> trkseg : trk.trackSegs) { … … 129 129 double lat1, lon1, lat2, lon2; 130 130 double dlon, dlat; 131 131 132 132 lat1 = p1.lat() * Math.PI / 180.0; 133 133 lon1 = p1.lon() * Math.PI / 180.0; -
trunk/src/org/openstreetmap/josm/data/gpx/GpxLink.java
r627 r1169 5 5 6 6 public class GpxLink { 7 8 9 7 public String uri; 8 public String text; 9 public String type; 10 10 11 12 13 11 public GpxLink(String uri) { 12 this.uri = uri; 13 } 14 14 } -
trunk/src/org/openstreetmap/josm/data/gpx/GpxRoute.java
r627 r1169 8 8 9 9 public class GpxRoute extends WithAttributes { 10 10 public Collection<WayPoint> routePoints = new LinkedList<WayPoint>(); 11 11 } -
trunk/src/org/openstreetmap/josm/data/gpx/GpxTrack.java
r627 r1169 8 8 9 9 public class GpxTrack extends WithAttributes { 10 11 10 public Collection<Collection<WayPoint>> trackSegs 11 = new LinkedList<Collection<WayPoint>>(); 12 12 } -
trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java
r1167 r1169 15 15 public class WayPoint extends WithAttributes implements Comparable<WayPoint> 16 16 { 17 18 19 20 21 22 17 public final LatLon latlon; 18 public final EastNorth eastNorth; 19 public double time; 20 public Color speedLineColor; 21 public boolean drawLine; 22 public int dir; 23 23 24 25 26 27 24 public WayPoint(LatLon ll) { 25 latlon = ll; 26 eastNorth = Main.proj.latlon2eastNorth(ll); 27 } 28 28 29 @Override 30 public String toString() { 31 return "WayPoint (" + (attr.containsKey("name") ? attr.get("name") + ", " :"") + latlon.toString() + ", " + attr + ")"; 32 } 33 34 /** 35 * Convert the time stamp of the waypoint into seconds from the epoch 36 */ 37 public final static SimpleDateFormat GPXTIMEFMT = 38 new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); // ignore timezone 39 40 public void setTime() { 41 if (! attr.containsKey("time")) { 42 return; 43 } 44 Date d = GPXTIMEFMT.parse(attr.get("time").toString(), new ParsePosition(0)); 45 if (d != null /* parsing ok */) { 46 time = d.getTime() / 1000.0; /* ms => seconds */ 47 } 48 } 29 @Override 30 public String toString() { 31 return "WayPoint (" + (attr.containsKey("name") ? attr.get("name") + ", " :"") + latlon.toString() + ", " + attr + ")"; 32 } 49 33 50 /** 51 * Convert a time stamp of the waypoint from the <cmt> or <desc> field 52 * into seconds from the epoch. Handles the date format as it is used by 53 * Garmin handhelds. Does not overwrite an existing timestamp (!= 0.0). 54 * A value of <time> fields overwrites values set with by method. 55 * Does nothing if specified key does not exist or text cannot be parsed. 56 * 57 * @param key The key that contains the text to convert. 58 */ 59 public void setGarminCommentTime(String key) { 60 // do not overwrite time if already set 61 if (time != 0.0) { 62 return; 63 } 64 if (! attr.containsKey(key)) { 65 return; 66 } 67 // example date format "18-AUG-08 13:33:03" 68 SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yy HH:mm:ss"); // Garmin wpts have no timezone 69 Date d = f.parse(attr.get(key).toString(), new ParsePosition(0)); 70 if (d != null /* parsing OK */) { 71 time = d.getTime() / 1000.0; /* ms => seconds */ 72 } 73 } 34 /** 35 * Convert the time stamp of the waypoint into seconds from the epoch 36 */ 37 public final static SimpleDateFormat GPXTIMEFMT = 38 new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); // ignore timezone 74 39 75 public int compareTo(WayPoint w) 76 { 77 return Double.compare(time, w.time); 78 } 40 public void setTime() { 41 if (! attr.containsKey("time")) { 42 return; 43 } 44 Date d = GPXTIMEFMT.parse(attr.get("time").toString(), new ParsePosition(0)); 45 if (d != null /* parsing ok */) { 46 time = d.getTime() / 1000.0; /* ms => seconds */ 47 } 48 } 49 50 /** 51 * Convert a time stamp of the waypoint from the <cmt> or <desc> field 52 * into seconds from the epoch. Handles the date format as it is used by 53 * Garmin handhelds. Does not overwrite an existing timestamp (!= 0.0). 54 * A value of <time> fields overwrites values set with by method. 55 * Does nothing if specified key does not exist or text cannot be parsed. 56 * 57 * @param key The key that contains the text to convert. 58 */ 59 public void setGarminCommentTime(String key) { 60 // do not overwrite time if already set 61 if (time != 0.0) { 62 return; 63 } 64 if (! attr.containsKey(key)) { 65 return; 66 } 67 // example date format "18-AUG-08 13:33:03" 68 SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yy HH:mm:ss"); // Garmin wpts have no timezone 69 Date d = f.parse(attr.get(key).toString(), new ParsePosition(0)); 70 if (d != null /* parsing OK */) { 71 time = d.getTime() / 1000.0; /* ms => seconds */ 72 } 73 } 74 75 public int compareTo(WayPoint w) 76 { 77 return Double.compare(time, w.time); 78 } 79 79 } -
trunk/src/org/openstreetmap/josm/data/gpx/WithAttributes.java
r627 r1169 1 // License: GPL. 1 // License: GPL. 2 2 package org.openstreetmap.josm.data.gpx; 3 3 … … 9 9 * The "attr" hash is used to store the XML payload 10 10 * (not only XML attributes!) 11 * 11 * 12 12 * @author Frederik Ramm <frederik@remote.org> 13 13 * 14 14 */ 15 15 public class WithAttributes { 16 17 18 19 20 21 22 16 17 public Map<String, Object> attr = new HashMap<String, Object>(0); 18 19 public String getString(String key) { 20 Object value = attr.get(key); 21 return (value instanceof String) ? (String)value : null; 22 } 23 23 } -
trunk/src/org/openstreetmap/josm/data/osm/Changeset.java
r655 r1169 20 20 */ 21 21 public final class Changeset /*extends OsmPrimitive*/ implements OsmWriterInterface { 22 23 24 25 22 /** 23 * The key/value list for this primitive. 24 */ 25 public Map<String, String> keys; 26 26 27 28 29 /** 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 27 public long id = 0; 28 29 /** 30 * User that created this changeset, as specified by the server. 31 * Never changed by JOSM. 32 */ 33 public User user = null; 34 35 /** 36 * Time of last modification to this object. This is not set by JOSM but 37 * read from the server and delivered back to the server unmodified. 38 */ 39 public String end_timestamp = null; 40 41 /** 42 * Time of first modification to this object. This is not set by JOSM but 43 * read from the server and delivered back to the server unmodified. 44 */ 45 public String start_timestamp = null; 46 46 47 47 private void addTags(PrintWriter out) { … … 53 53 } 54 54 55 56 55 public final void header(PrintWriter out) { 56 out.print("<osm version='"); 57 57 out.print(Main.pref.get("osm-server.version", "0.6")); 58 58 out.println("' generator='JOSM'>"); 59 } 60 public final void write(PrintWriter out) { 61 out.print(" <changeset"); 62 if (id != 0) 63 out.print(" id="+id); 64 if (this.user != null) { 65 out.print(" user='"+XmlWriter.encode(this.user.name)+"'"); 66 } 67 out.println(">\n"); 68 addTags( out ); 69 out.println(" </changeset>"); 70 } 71 public final void footer(PrintWriter out) { 72 out.println("</osm>"); 73 } 74 75 /****************************************************** 76 * This tag stuff is copied from OsmPrimitive. Perhaps a changeset 77 * really is a primitive, but it's not right now. Perhaps it should 78 * be... 79 ******************************************************/ 80 81 /** 82 * Set the given value to the given key 83 * @param key The key, for which the value is to be set. 84 * @param value The value for the key. 85 */ 86 public final void put(String key, String value) { 87 if (value == null) 88 remove(key); 89 else { 90 if (keys == null) 91 keys = new HashMap<String, String>(); 92 keys.put(key, value); 93 } 94 } 95 /** 96 * Remove the given key from the list. 97 */ 98 public final void remove(String key) { 99 if (keys != null) { 100 keys.remove(key); 101 if (keys.isEmpty()) 102 keys = null; 103 } 104 } 59 } 60 public final void write(PrintWriter out) { 61 out.print(" <changeset"); 62 if (id != 0) 63 out.print(" id="+id); 64 if (this.user != null) { 65 out.print(" user='"+XmlWriter.encode(this.user.name)+"'"); 66 } 67 out.println(">\n"); 68 addTags( out ); 69 out.println(" </changeset>"); 70 } 71 public final void footer(PrintWriter out) { 72 out.println("</osm>"); 73 } 105 74 106 public final String get(String key) { 107 return keys == null ? null : keys.get(key); 108 } 75 /****************************************************** 76 * This tag stuff is copied from OsmPrimitive. Perhaps a changeset 77 * really is a primitive, but it's not right now. Perhaps it should 78 * be... 79 ******************************************************/ 109 80 110 public final Collection<Entry<String, String>> entrySet() { 111 if (keys == null) 112 return Collections.emptyList(); 113 return keys.entrySet(); 114 } 81 /** 82 * Set the given value to the given key 83 * @param key The key, for which the value is to be set. 84 * @param value The value for the key. 85 */ 86 public final void put(String key, String value) { 87 if (value == null) 88 remove(key); 89 else { 90 if (keys == null) 91 keys = new HashMap<String, String>(); 92 keys.put(key, value); 93 } 94 } 95 /** 96 * Remove the given key from the list. 97 */ 98 public final void remove(String key) { 99 if (keys != null) { 100 keys.remove(key); 101 if (keys.isEmpty()) 102 keys = null; 103 } 104 } 115 105 116 public final Collection<String> keySet() { 117 if (keys == null) 118 return Collections.emptyList(); 119 return keys.keySet(); 120 } 106 public final String get(String key) { 107 return keys == null ? null : keys.get(key); 108 } 109 110 public final Collection<Entry<String, String>> entrySet() { 111 if (keys == null) 112 return Collections.emptyList(); 113 return keys.entrySet(); 114 } 115 116 public final Collection<String> keySet() { 117 if (keys == null) 118 return Collections.emptyList(); 119 return keys.keySet(); 120 } 121 121 } -
trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
r1004 r1169 17 17 * DataSet is the data behind the application. It can consists of only a few points up to the whole 18 18 * osm database. DataSet's can be merged together, saved, (up/down/disk)loaded etc. 19 * 19 * 20 20 * Note that DataSet is not an osm-primitive and so has no key association but a few members to 21 21 * store some information. 22 * 22 * 23 23 * @author imi 24 24 */ … … 33 33 /** 34 34 * All ways (Streets etc.) in the DataSet. 35 * 35 * 36 36 * The way nodes are stored only in the way list. 37 37 */ … … 235 235 236 236 // Provide well-defined sorting for collections of OsmPrimitives. 237 // FIXME: probably not a good place to put this code. 237 // FIXME: probably not a good place to put this code. 238 238 public static OsmPrimitive[] sort(Collection<? extends OsmPrimitive> list) { 239 239 OsmPrimitive[] selArr = new OsmPrimitive[list.size()]; -
trunk/src/org/openstreetmap/josm/data/osm/DataSource.java
r627 r1169 5 5 6 6 public class DataSource implements Cloneable { 7 8 9 10 11 12 7 public final Bounds bounds; 8 public final String origin; 9 10 public DataSource(Bounds bounds, String origin) { 11 this.bounds = bounds; 12 this.origin = origin; 13 13 } 14 14 15 16 15 @Override protected Object clone() throws CloneNotSupportedException { 16 return new DataSource(bounds, origin); 17 17 } 18 18 } -
trunk/src/org/openstreetmap/josm/data/osm/DateFormatter.java
r627 r1169 9 9 /** 10 10 * Outputs a date in a format suitable for an OSM XML file. 11 * 11 * 12 12 * @author Brett Henderson 13 13 */ 14 14 public class DateFormatter { 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 * 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 15 16 private GregorianCalendar calendar; 17 18 19 /** 20 * Creates a new instance. 21 */ 22 public DateFormatter() { 23 calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); 24 } 25 26 27 /** 28 * Formats a date in XML format. 29 * 30 * @param date 31 * The date to be formatted. 32 * @return The string representing the date. 33 */ 34 public String format(Date date) { 35 StringBuilder result; 36 int year; 37 int month; 38 int day; 39 int hour; 40 int minute; 41 int second; 42 43 calendar.setTime(date); 44 45 result = new StringBuilder(20); 46 47 year = calendar.get(Calendar.YEAR); 48 month = calendar.get(Calendar.MONTH) + 1; 49 day = calendar.get(Calendar.DATE); 50 hour = calendar.get(Calendar.HOUR_OF_DAY); 51 minute = calendar.get(Calendar.MINUTE); 52 second = calendar.get(Calendar.SECOND); 53 54 result.append(year); 55 result.append('-'); 56 if (month < 10) { 57 result.append('0'); 58 } 59 result.append(month); 60 result.append('-'); 61 if (day < 10) { 62 result.append('0'); 63 } 64 result.append(day); 65 result.append('T'); 66 if (hour < 10) { 67 result.append('0'); 68 } 69 result.append(hour); 70 result.append(':'); 71 if (minute < 10) { 72 result.append('0'); 73 } 74 result.append(minute); 75 result.append(':'); 76 if (second < 10) { 77 result.append('0'); 78 } 79 result.append(second); 80 result.append('Z'); 81 82 return result.toString(); 83 } 84 84 } -
trunk/src/org/openstreetmap/josm/data/osm/Node.java
r1108 r1169 19 19 */ 20 20 public final class Node extends OsmPrimitive { 21 22 23 24 21 22 public LatLon coor; 23 public volatile EastNorth eastNorth; 24 25 25 private static CoordinateFormat mCord; 26 26 27 27 static { 28 28 try { … … 33 33 } 34 34 35 /** 36 * Create an incomplete Node object 37 */ 38 public Node(long id) { 39 this.id = id; 40 incomplete = true; 41 } 42 43 /** 44 * Create an identical clone of the argument (including the id) 45 */ 46 public Node(Node clone) { 47 cloneFrom(clone); 48 } 35 /** 36 * Create an incomplete Node object 37 */ 38 public Node(long id) { 39 this.id = id; 40 incomplete = true; 41 } 49 42 50 public Node(LatLon latlon) { 51 this.coor = latlon; 52 eastNorth = Main.proj.latlon2eastNorth(latlon); 53 } 43 /** 44 * Create an identical clone of the argument (including the id) 45 */ 46 public Node(Node clone) { 47 cloneFrom(clone); 48 } 54 49 55 @Override public void visit(Visitor visitor) { 56 visitor.visit(this); 57 } 58 59 @Override public void cloneFrom(OsmPrimitive osm) { 60 super.cloneFrom(osm); 61 coor = ((Node)osm).coor; 62 eastNorth = ((Node)osm).eastNorth; 63 } 50 public Node(LatLon latlon) { 51 this.coor = latlon; 52 eastNorth = Main.proj.latlon2eastNorth(latlon); 53 } 64 54 65 @Override public String toString() { 66 if (coor == null) return "{Node id="+id+"}"; 67 return "{Node id="+id+",version="+version+",lat="+coor.lat()+",lon="+coor.lon()+"}"; 68 } 55 @Override public void visit(Visitor visitor) { 56 visitor.visit(this); 57 } 69 58 70 @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) { 71 if (osm instanceof Node) { 59 @Override public void cloneFrom(OsmPrimitive osm) { 60 super.cloneFrom(osm); 61 coor = ((Node)osm).coor; 62 eastNorth = ((Node)osm).eastNorth; 63 } 64 65 @Override public String toString() { 66 if (coor == null) return "{Node id="+id+"}"; 67 return "{Node id="+id+",version="+version+",lat="+coor.lat()+",lon="+coor.lon()+"}"; 68 } 69 70 @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) { 71 if (osm instanceof Node) { 72 72 if (super.realEqual(osm, semanticOnly)) { 73 73 if ((coor == null) && ((Node)osm).coor == null) … … 80 80 } 81 81 82 83 84 82 public int compareTo(OsmPrimitive o) { 83 return o instanceof Node ? Long.valueOf(id).compareTo(o.id) : 1; 84 } 85 85 86 87 88 89 90 91 92 93 94 95 96 97 86 public String getName() { 87 String name; 88 if (incomplete) { 89 name = tr("incomplete"); 90 } else { 91 name = get("name"); 92 if (name == null) 93 name = id == 0 ? "" : ""+id; 94 name += " (" + coor.latToString(mCord) + ", " + coor.lonToString(mCord) + ")"; 95 } 96 return name; 97 } 98 98 } -
trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
r795 r1169 30 30 abstract public class OsmPrimitive implements Comparable<OsmPrimitive> { 31 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 32 /** 33 * The key/value list for this primitive. 34 */ 35 public Map<String, String> keys; 36 37 /** 38 * Unique identifier in OSM. This is used to identify objects on the server. 39 * An id of 0 means an unknown id. The object has not been uploaded yet to 40 * know what id it will get. 41 * 42 * Do not write to this attribute except you know exactly what you are doing. 43 * More specific, it is not good to set this to 0 and think the object is now 44 * new to the server! To create a new object, call the default constructor of 45 * the respective class. 46 */ 47 public long id = 0; 48 49 /** 50 * <code>true</code> if the object has been modified since it was loaded from 51 * the server. In this case, on next upload, this object will be updated. 52 * Deleted objects are deleted from the server. If the objects are added (id=0), 53 * the modified is ignored and the object is added to the server. 54 */ 55 public boolean modified = false; 56 57 /** 58 * <code>true</code>, if the object has been deleted. 59 */ 60 public boolean deleted = false; 61 62 /** 63 * Visibility status as specified by the server. The visible attribute was 64 * introduced with the 0.4 API to be able to communicate deleted objects 65 * (they will have visible=false). Currently JOSM does never deal with 66 * these, so this is really for future use only. 67 */ 68 public boolean visible = true; 69 70 /** 71 * User that last modified this primitive, as specified by the server. 72 * Never changed by JOSM. 73 */ 74 public User user = null; 75 76 /** 77 * true if this object is considered "tagged". To be "tagged", an object 78 * must have one or more "non-standard" tags. "created_by" and "source" 79 * are typically considered "standard" tags and do not make an object 80 * "tagged". 81 */ 82 public boolean tagged = false; 83 84 /** 85 * true if this object has direction dependent tags (e.g. oneway) 86 */ 87 public boolean hasDirectionKeys = false; 88 89 /** 90 * If set to true, this object is currently selected. 91 */ 92 public volatile boolean selected = false; 93 94 /** 95 * Time of last modification to this object. This is not set by JOSM but 96 * read from the server and delivered back to the server unmodified. It is 97 * used to check against edit conflicts. 98 */ 99 public String timestamp = null; 100 101 /** 102 * The timestamp is only parsed when this is really necessary, and this 103 * is the cache for the result. 104 */ 105 public Date parsedTimestamp = null; 106 107 /** 108 * If set to true, this object is incomplete, which means only the id 109 * and type is known (type is the objects instance class) 110 */ 111 public boolean incomplete = false; 112 113 /** 114 * Contains the version number as returned by the API. Needed to 115 * ensure update consistency 116 */ 117 public int version = -1; 118 119 /** 120 * Contains a list of "uninteresting" keys that do not make an object 121 * "tagged". 122 * Initialized by checkTagged() 123 */ 124 private static Collection<String> uninteresting = null; 125 126 /** 127 * Contains a list of direction-dependent keys that make an object 128 * direction dependent. 129 * Initialized by checkDirectionTagged() 130 */ 131 private static Collection<String> directionKeys = null; 132 133 /** 134 * Implementation of the visitor scheme. Subclasses have to call the correct 135 * visitor function. 136 * @param visitor The visitor from which the visit() function must be called. 137 */ 138 abstract public void visit(Visitor visitor); 139 140 public final void delete(boolean deleted) { 141 this.deleted = deleted; 142 selected = false; 143 modified = true; 144 } 145 146 /** 147 * Returns the timestamp for this object, or the current time if none is set. 148 * Internally, parses the timestamp from XML into a Date object and caches it 149 * for possible repeated calls. 150 */ 151 public Date getTimestamp() { 152 if (parsedTimestamp == null) { 153 try { 154 parsedTimestamp = DateParser.parse(timestamp); 155 } catch (ParseException ex) { 156 parsedTimestamp = new Date(); 157 } 158 } 159 return parsedTimestamp; 160 } 161 162 /** 163 * Equal, if the id (and class) is equal. 164 * 165 * An primitive is equal to its incomplete counter part. 166 */ 167 @Override public boolean equals(Object obj) { 168 if (id == 0) return obj == this; 169 if (obj instanceof OsmPrimitive) { // not null too 170 return ((OsmPrimitive)obj).id == id && obj.getClass() == getClass(); 171 } 172 return false; 173 } 174 175 /** 176 * Return the id plus the class type encoded as hashcode or super's hashcode if id is 0. 177 * 178 * An primitive has the same hashcode as its incomplete counterpart. 179 */ 180 @Override public final int hashCode() { 181 if (id == 0) 182 return super.hashCode(); 183 final int[] ret = new int[1]; 184 Visitor v = new Visitor(){ 185 public void visit(Node n) { ret[0] = 1; } 186 public void visit(Way w) { ret[0] = 2; } 187 public void visit(Relation e) { ret[0] = 3; } 188 }; 189 visit(v); 190 return id == 0 ? super.hashCode() : (int)(id<<2)+ret[0]; 191 } 192 193 /** 194 * Set the given value to the given key 195 * @param key The key, for which the value is to be set. 196 * @param value The value for the key. 197 */ 198 public final void put(String key, String value) { 199 if (value == null) 200 remove(key); 201 else { 202 if (keys == null) 203 keys = new HashMap<String, String>(); 204 keys.put(key, value); 205 } 206 checkTagged(); 207 checkDirectionTagged(); 208 } 209 /** 210 * Remove the given key from the list. 211 */ 212 public final void remove(String key) { 213 if (keys != null) { 214 keys.remove(key); 215 if (keys.isEmpty()) 216 keys = null; 217 } 218 checkTagged(); 219 checkDirectionTagged(); 220 } 221 222 public String getName() { 223 return null; 224 } 225 226 public final String get(String key) { 227 return keys == null ? null : keys.get(key); 228 } 229 230 public final Collection<Entry<String, String>> entrySet() { 231 if (keys == null) 232 return Collections.emptyList(); 233 return keys.entrySet(); 234 } 235 236 public final Collection<String> keySet() { 237 if (keys == null) 238 return Collections.emptyList(); 239 return keys.keySet(); 240 } 241 242 /** 243 * Get and write all attributes from the parameter. Does not fire any listener, so 244 * use this only in the data initializing phase 245 */ 246 public void cloneFrom(OsmPrimitive osm) { 247 keys = osm.keys == null ? null : new HashMap<String, String>(osm.keys); 248 id = osm.id; 249 modified = osm.modified; 250 deleted = osm.deleted; 251 selected = osm.selected; 252 timestamp = osm.timestamp; 253 version = osm.version; 254 tagged = osm.tagged; 255 incomplete = osm.incomplete; 256 } 257 258 /** 259 * Perform an equality compare for all non-volatile fields not only for the id 260 * but for the whole object (for conflict resolving) 261 * @param semanticOnly if <code>true</code>, modified flag and timestamp are not compared 262 */ 263 public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) { 264 return 265 id == osm.id && 266 incomplete == osm.incomplete && 267 (semanticOnly || (modified == osm.modified)) && 268 deleted == osm.deleted && 269 (semanticOnly || (timestamp == null ? osm.timestamp==null : timestamp.equals(osm.timestamp))) && 270 (semanticOnly || (version==osm.version)) && 271 (semanticOnly || (user == null ? osm.user==null : user==osm.user)) && 272 (semanticOnly || (visible == osm.visible)) && 273 (keys == null ? osm.keys==null : keys.equals(osm.keys)); 274 } 275 276 public String getTimeStr() { 277 return timestamp == null ? null : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp); 278 } 279 280 /** 281 * Updates the "tagged" flag. "keys" property should probably be made private 282 * to make sure this gets called when keys are set. 283 */ 284 public void checkTagged() { 285 tagged = false; 286 if(uninteresting == null) 287 uninteresting = new HashSet<String>(Arrays.asList(Main.pref.get("tags.uninteresting", 288 "source;note;converted_by;created_by").split(";"))); 289 if (keys != null) { 290 for (Entry<String,String> e : keys.entrySet()) { 291 if (!uninteresting.contains(e.getKey())) { 292 tagged = true; 293 break; 294 } 295 } 296 } 297 } 298 /** 299 * Updates the "hasDirectionKeys" flag. "keys" property should probably be made private 300 * to make sure this gets called when keys are set. 301 */ 302 public void checkDirectionTagged() { 303 hasDirectionKeys = false; 304 if(directionKeys == null) 305 directionKeys = new HashSet<String>(Arrays.asList(Main.pref.get("tags.direction", 306 "oneway;incline;incline_step;aerialway").split(";"))); 307 if (keys != null) { 308 for (Entry<String,String> e : keys.entrySet()) { 309 if (directionKeys.contains(e.getKey())) { 310 hasDirectionKeys = true; 311 break; 312 } 313 } 314 } 315 } 316 316 } -
trunk/src/org/openstreetmap/josm/data/osm/OsmUtils.java
r702 r1169 8 8 public class OsmUtils { 9 9 10 11 12 13 10 static ArrayList<String> TRUE_VALUES = new ArrayList<String>(Arrays 11 .asList(new String[] { "true", "yes", "1", "on" })); 12 static ArrayList<String> FALSE_VALUES = new ArrayList<String>(Arrays 13 .asList(new String[] { "false", "no", "0", "off" })); 14 14 15 16 15 public static final String trueval = "yes"; 16 public static final String falseval = "no"; 17 17 18 19 20 21 22 23 24 25 26 27 28 18 public static Boolean getOsmBoolean(String value) { 19 if(value == null) return null; 20 String lowerValue = value.toLowerCase(Locale.ENGLISH); 21 if (TRUE_VALUES.contains(lowerValue)) return Boolean.TRUE; 22 if (FALSE_VALUES.contains(lowerValue)) return Boolean.FALSE; 23 return null; 24 } 25 public static String getNamedOsmBoolean(String value) { 26 Boolean res = getOsmBoolean(value); 27 return res == null ? value : (res ? trueval : falseval); 28 } 29 29 } -
trunk/src/org/openstreetmap/josm/data/osm/Relation.java
r1162 r1169 11 11 /** 12 12 * An relation, having a set of tags and any number (0...n) of members. 13 * 13 * 14 14 * @author Frederik Ramm <frederik@remote.org> 15 15 */ 16 16 public final class Relation extends OsmPrimitive { 17 18 /**19 * All members of this relation. Note that after changing this,20 * makeBackReferences and/or removeBackReferences should be called.21 */22 public final List<RelationMember> members = new ArrayList<RelationMember>();23 17 24 @Override public void visit(Visitor visitor) { 25 visitor.visit(this); 26 } 18 /** 19 * All members of this relation. Note that after changing this, 20 * makeBackReferences and/or removeBackReferences should be called. 21 */ 22 public final List<RelationMember> members = new ArrayList<RelationMember>(); 27 23 28 /** 29 * Create an identical clone of the argument (including the id) 30 */ 31 public Relation(Relation clone) { 32 cloneFrom(clone); 33 } 34 35 /** 36 * Create an incomplete Relation. 37 */ 38 public Relation(long id) { 39 this.id = id; 40 incomplete = true; 41 } 42 43 /** 44 * Create an empty Relation. Use this only if you set meaningful values 45 * afterwards. 46 */ 47 public Relation() { 48 } 49 50 @Override public void cloneFrom(OsmPrimitive osm) { 51 super.cloneFrom(osm); 52 members.clear(); 53 // we must not add the members themselves, but instead 54 // add clones of the members 55 for (RelationMember em : ((Relation)osm).members) { 56 members.add(new RelationMember(em)); 57 } 58 } 24 @Override public void visit(Visitor visitor) { 25 visitor.visit(this); 26 } 59 27 60 @Override public String toString() { 61 // return "{Relation id="+id+" version="+version+" members="+Arrays.toString(members.toArray())+"}"; 62 // adding members in string increases memory usage a lot and overflows for looped relations 63 return "{Relation id="+id+" version="+version+"}"; 64 } 28 /** 29 * Create an identical clone of the argument (including the id) 30 */ 31 public Relation(Relation clone) { 32 cloneFrom(clone); 33 } 65 34 66 @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) { 67 return osm instanceof Relation ? super.realEqual(osm, semanticOnly) && members.equals(((Relation)osm).members) : false; 68 } 35 /** 36 * Create an incomplete Relation. 37 */ 38 public Relation(long id) { 39 this.id = id; 40 incomplete = true; 41 } 69 42 70 public int compareTo(OsmPrimitive o) { 71 return o instanceof Relation ? Long.valueOf(id).compareTo(o.id) : -1; 72 } 43 /** 44 * Create an empty Relation. Use this only if you set meaningful values 45 * afterwards. 46 */ 47 public Relation() { 48 } 73 49 74 public String getName() { 75 String name; 76 if (incomplete) { 77 name = tr("incomplete"); 78 } else { 79 name = get("type"); 80 // FIXME add names of members 81 if (name == null) 82 name = tr("relation"); 83 84 name += " ("; 85 String nameTag = get("name"); 86 if (nameTag == null) nameTag = get("ref"); 87 if (nameTag == null) nameTag = get("note"); 88 if (nameTag != null) name += "\"" + nameTag + "\", "; 89 int mbno = members.size(); 90 name += trn("{0} member", "{0} members", mbno, mbno) + ")"; 91 } 92 return name; 93 } 50 @Override public void cloneFrom(OsmPrimitive osm) { 51 super.cloneFrom(osm); 52 members.clear(); 53 // we must not add the members themselves, but instead 54 // add clones of the members 55 for (RelationMember em : ((Relation)osm).members) { 56 members.add(new RelationMember(em)); 57 } 58 } 94 59 95 public boolean isIncomplete() { 96 for (RelationMember m : members) 97 if (m.member == null) 98 return true; 99 return false; 100 } 60 @Override public String toString() { 61 // return "{Relation id="+id+" version="+version+" members="+Arrays.toString(members.toArray())+"}"; 62 // adding members in string increases memory usage a lot and overflows for looped relations 63 return "{Relation id="+id+" version="+version+"}"; 64 } 65 66 @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) { 67 return osm instanceof Relation ? super.realEqual(osm, semanticOnly) && members.equals(((Relation)osm).members) : false; 68 } 69 70 public int compareTo(OsmPrimitive o) { 71 return o instanceof Relation ? Long.valueOf(id).compareTo(o.id) : -1; 72 } 73 74 public String getName() { 75 String name; 76 if (incomplete) { 77 name = tr("incomplete"); 78 } else { 79 name = get("type"); 80 // FIXME add names of members 81 if (name == null) 82 name = tr("relation"); 83 84 name += " ("; 85 String nameTag = get("name"); 86 if (nameTag == null) nameTag = get("ref"); 87 if (nameTag == null) nameTag = get("note"); 88 if (nameTag != null) name += "\"" + nameTag + "\", "; 89 int mbno = members.size(); 90 name += trn("{0} member", "{0} members", mbno, mbno) + ")"; 91 } 92 return name; 93 } 94 95 public boolean isIncomplete() { 96 for (RelationMember m : members) 97 if (m.member == null) 98 return true; 99 return false; 100 } 101 101 } -
trunk/src/org/openstreetmap/josm/data/osm/RelationMember.java
r627 r1169 2 2 3 3 /** 4 * A linkage class that can be used by an relation to keep a list of 4 * A linkage class that can be used by an relation to keep a list of 5 5 * members. Since membership may be qualified by a "role", a simple 6 6 * list is not sufficient. 7 * 7 * 8 8 * @author Frederik Ramm <frederik@remote.org> 9 9 */ 10 10 public class RelationMember { 11 11 12 public String role; 13 public OsmPrimitive member; 14 15 /** 16 * Default constructor. Does nothing. 17 */ 18 public RelationMember() { } 12 public String role; 13 public OsmPrimitive member; 19 14 20 public RelationMember(String role, OsmPrimitive member) { 21 this.role = role; 22 this.member = member; 23 } 24 25 /** 26 * Copy constructor. 27 * @param other relation member to be copied. 28 */ 29 public RelationMember(RelationMember other) { 30 role = other.role; 31 member = other.member; 32 } 33 34 @Override public boolean equals(Object other) { 35 if (!(other instanceof RelationMember)) return false; 36 RelationMember otherMember = (RelationMember) other; 37 return otherMember.role.equals(role) && otherMember.member.equals(member); 38 } 15 /** 16 * Default constructor. Does nothing. 17 */ 18 public RelationMember() { } 39 19 40 @Override public String toString() { 41 return '"' + role + "\"=" + member; 42 } 20 public RelationMember(String role, OsmPrimitive member) { 21 this.role = role; 22 this.member = member; 23 } 24 25 /** 26 * Copy constructor. 27 * @param other relation member to be copied. 28 */ 29 public RelationMember(RelationMember other) { 30 role = other.role; 31 member = other.member; 32 } 33 34 @Override public boolean equals(Object other) { 35 if (!(other instanceof RelationMember)) return false; 36 RelationMember otherMember = (RelationMember) other; 37 return otherMember.role.equals(role) && otherMember.member.equals(member); 38 } 39 40 @Override public String toString() { 41 return '"' + role + "\"=" + member; 42 } 43 43 } -
trunk/src/org/openstreetmap/josm/data/osm/TigerUtils.java
r627 r1169 5 5 import java.util.TreeSet; 6 6 7 /** 7 /** 8 8 * A simple class to keep helper functions for merging TIGER data 9 * 9 * 10 10 * @author daveh 11 11 * 12 12 */ 13 13 public class TigerUtils { 14 15 16 { 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 14 15 public static boolean isTigerTag(String tag) 16 { 17 if (tag.indexOf("tiger:") == -1) 18 return false; 19 return true; 20 } 21 22 public static boolean tagIsInt(String name) { 23 if (name.equals("tiger:tlid")) 24 return true; 25 return false; 26 } 27 28 public static Object tagObj(String name) { 29 if (tagIsInt(name)) 30 return new Integer(name); 31 return name; 32 } 33 34 public static String combineTags(String name, Set<String> values) { 35 35 TreeSet<Object> resultSet = new TreeSet<Object>(); 36 36 for (String value: values) { 37 37 for (String part: value.split(":")) { 38 38 resultSet.add(tagObj(part)); 39 39 } … … 42 42 for (Object part : resultSet) { 43 43 if (combined.length() > 0) 44 45 44 combined += ":"; 45 combined += part; 46 46 } 47 48 49 50 51 52 53 54 55 47 return combined; 48 } 49 50 public static String combineTags(String name, String t1, String t2) { 51 Set<String> set = new TreeSet<String>(); 52 set.add(t1); 53 set.add(t2); 54 return TigerUtils.combineTags(name, set); 55 } 56 56 } -
trunk/src/org/openstreetmap/josm/data/osm/User.java
r655 r1169 4 4 import java.util.HashMap; 5 5 6 /** 6 /** 7 7 * A simple class to keep a list of user names. 8 * 8 * 9 9 * Instead of storing user names as strings with every OSM primitive, we store 10 10 * a reference to an user object, and make sure that for each username there 11 11 * is only one user object. 12 * 12 * 13 13 * @author fred 14 14 * … … 16 16 public class User { 17 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 18 /** storage for existing User objects. */ 19 private static HashMap<String,User> userMap = new HashMap<String,User>(); 20 21 /** the username. */ 22 public String name; 23 24 /** private constructor, only called from get method. */ 25 private User(String name) { 26 this.name = name; 27 } 28 29 /** returns a new or existing User object that represents the given name. */ 30 public static User get(String name) { 31 User user = userMap.get(name); 32 if (user == null) { 33 user = new User(name); 34 userMap.put(name, user); 35 } 36 return user; 37 } 38 38 } -
trunk/src/org/openstreetmap/josm/data/osm/Way.java
r755 r1169 21 21 public final class Way extends OsmPrimitive { 22 22 23 24 25 26 23 /** 24 * All way nodes in this way 25 */ 26 public final List<Node> nodes = new ArrayList<Node>(); 27 27 28 29 30 31 28 public void visitNodes(Visitor v) { 29 for (Node n : this.nodes) 30 v.visit(n); 31 } 32 32 33 34 35 36 33 public ArrayList<Pair<Node,Node>> getNodePairs(boolean sort) { 34 ArrayList<Pair<Node,Node>> chunkSet = new ArrayList<Pair<Node,Node>>(); 35 Node lastN = null; 36 for (Node n : this.nodes) { 37 37 if (lastN == null) { 38 39 40 41 42 43 44 45 46 47 48 49 38 lastN = n; 39 continue; 40 } 41 Pair<Node,Node> np = new Pair<Node,Node>(lastN, n); 42 if (sort) { 43 Pair.sort(np); 44 } 45 chunkSet.add(np); 46 lastN = n; 47 } 48 return chunkSet; 49 } 50 50 51 51 52 53 54 52 @Override public void visit(Visitor visitor) { 53 visitor.visit(this); 54 } 55 55 56 57 58 59 60 cloneFrom(clone); 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 56 /** 57 * Create an identical clone of the argument (including the id) 58 */ 59 public Way(Way clone) { 60 cloneFrom(clone); 61 } 62 63 /** 64 * Create an empty way without id. Use this only if you set meaningful 65 * values yourself. 66 */ 67 public Way() { 68 } 69 70 /** 71 * Create an incomplete Way. 72 */ 73 public Way(long id) { 74 this.id = id; 75 incomplete = true; 76 } 77 78 @Override public void cloneFrom(OsmPrimitive osm) { 79 super.cloneFrom(osm); 80 nodes.clear(); 81 nodes.addAll(((Way)osm).nodes); 82 82 checkDirectionTagged(); 83 83 } 84 84 85 85 @Override public String toString() { … … 87 87 } 88 88 89 90 89 @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) { 90 return osm instanceof Way ? super.realEqual(osm, semanticOnly) && nodes.equals(((Way)osm).nodes) : false; 91 91 } 92 92 93 94 95 96 97 93 public int compareTo(OsmPrimitive o) { 94 if(o instanceof Relation) 95 return 1; 96 return o instanceof Way ? Long.valueOf(id).compareTo(o.id) : -1; 97 } 98 98 99 100 101 102 103 104 105 106 107 name = 108 109 110 111 112 99 public String getName() { 100 String name; 101 if (incomplete) { 102 name = tr("incomplete"); 103 } else { 104 name = get("name"); 105 if (name == null) name = get("ref"); 106 if (name == null) { 107 name = 108 (get("highway") != null) ? tr("highway") : 109 (get("railway") != null) ? tr("railway") : 110 (get("waterway") != null) ? tr("waterway") : 111 (get("landuse") != null) ? tr("landuse") : ""; 112 } 113 113 114 115 116 117 118 114 int nodesNo = new HashSet<Node>(nodes).size(); 115 name += trn(" ({0} node)", " ({0} nodes)", nodesNo, nodesNo); 116 } 117 return name; 118 } 119 119 120 121 122 123 120 @Deprecated 121 public boolean isIncomplete() { 122 return incomplete; 123 } 124 124 } -
trunk/src/org/openstreetmap/josm/data/osm/WaySegment.java
r627 r1169 6 6 */ 7 7 public final class WaySegment { 8 9 10 11 8 /** 9 * The way. 10 */ 11 public Way way; 12 12 13 14 15 16 17 13 /** 14 * The index of one of the 2 nodes in the way. The other node has the 15 * index <code>lowerIndex + 1</code>. 16 */ 17 public int lowerIndex; 18 18 19 20 21 22 19 public WaySegment(Way w, int i) { 20 way = w; 21 lowerIndex = i; 22 } 23 23 24 25 26 27 28 24 @Override public boolean equals(Object o) { 25 return o != null && o instanceof WaySegment 26 && ((WaySegment) o).way == way 27 && ((WaySegment) o).lowerIndex == lowerIndex; 28 } 29 29 30 31 32 30 @Override public int hashCode() { 31 return way.hashCode() ^ lowerIndex; 32 } 33 33 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/AddVisitor.java
r655 r1169 9 9 /** 10 10 * Visitor that adds the visited object to the dataset given at constructor. 11 * 11 * 12 12 * Is not capable of adding keys. 13 * 13 * 14 14 * @author imi 15 15 */ 16 16 public class AddVisitor implements Visitor { 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 17 18 protected final DataSet ds; 19 20 public AddVisitor(DataSet ds) { 21 this.ds = ds; 22 } 23 24 public void visit(Node n) { 25 ds.nodes.add(n); 26 } 27 public void visit(Way w) { 28 ds.ways.add(w); 29 } 30 public void visit(Relation e) { 31 ds.relations.add(e); 32 } 33 33 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/AllNodesVisitor.java
r627 r1169 13 13 /** 14 14 * Collect all nodes a specific osm primitive has. 15 * 15 * 16 16 * @author imi 17 17 */ 18 18 public class AllNodesVisitor implements Visitor { 19 19 20 21 22 23 20 /** 21 * The resulting nodes collected so far. 22 */ 23 public Collection<Node> nodes = new HashSet<Node>(); 24 24 25 26 27 28 29 30 25 /** 26 * Nodes have only itself as nodes. 27 */ 28 public void visit(Node n) { 29 nodes.add(n); 30 } 31 31 32 33 34 35 36 37 32 /** 33 * Ways have their way nodes. 34 */ 35 public void visit(Way w) { 36 w.visitNodes(this); 37 } 38 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 39 /** 40 * Relations may have any number of nodes. 41 * FIXME: do we want to collect nodes from segs/ways that are relation members? 42 * if so, use AutomatchVisitor! 43 */ 44 public void visit(Relation e) { 45 for (RelationMember m : e.members) 46 if (m.member instanceof Node) visit((Node)m.member); 47 } 48 /** 49 * @return All nodes the given primitive has. 50 */ 51 public static Collection<Node> getAllNodes(Collection<? extends OsmPrimitive> osms) { 52 AllNodesVisitor v = new AllNodesVisitor(); 53 for (OsmPrimitive osm : osms) 54 osm.visit(v); 55 return v.nodes; 56 } 57 57 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java
r948 r1169 12 12 13 13 /** 14 * Calculates the total bounding rectangle of a series of {@link OsmPrimitive} objects, using the 14 * Calculates the total bounding rectangle of a series of {@link OsmPrimitive} objects, using the 15 15 * EastNorth values as reference. 16 16 * @author imi … … 61 61 62 62 /** 63 * Enlarges the calculated bounding box by 0.0001 degrees. 63 * Enlarges the calculated bounding box by 0.0001 degrees. 64 64 * If the bounding box has not been set (<code>min</code> or <code>max</code> 65 65 * equal <code>null</code>) this method does not do anything. 66 * 66 * 67 67 * @param enlargeDegree 68 68 */ … … 72 72 73 73 /** 74 * Enlarges the calculated bounding box by the specified number of degrees. 74 * Enlarges the calculated bounding box by the specified number of degrees. 75 75 * If the bounding box has not been set (<code>min</code> or <code>max</code> 76 76 * equal <code>null</code>) this method does not do anything. 77 * 77 * 78 78 * @param enlargeDegree 79 79 */ -
trunk/src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java
r627 r1169 14 14 /** 15 15 * Helper that collect all ways a node is part of. 16 * 16 * 17 17 * Deleted objects are not collected. 18 * 18 * 19 19 * @author imi 20 20 */ 21 21 public class CollectBackReferencesVisitor implements Visitor { 22 22 23 24 23 private final DataSet ds; 24 private final boolean indirectRefs; 25 25 26 27 28 29 26 /** 27 * The result list of primitives stored here. 28 */ 29 public final Collection<OsmPrimitive> data = new HashSet<OsmPrimitive>(); 30 30 31 31 32 33 34 35 36 37 38 39 32 /** 33 * Construct a back reference counter. 34 * @param ds The dataset to operate on. 35 */ 36 public CollectBackReferencesVisitor(DataSet ds) { 37 this.ds = ds; 38 this.indirectRefs = true; 39 } 40 40 41 42 43 44 41 public CollectBackReferencesVisitor(DataSet ds, boolean indirectRefs) { 42 this.ds = ds; 43 this.indirectRefs = indirectRefs; 44 } 45 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 46 public void visit(Node n) { 47 for (Way w : ds.ways) { 48 if (w.deleted || w.incomplete) continue; 49 for (Node n2 : w.nodes) { 50 if (n == n2) { 51 data.add(w); 52 if (indirectRefs) { 53 visit(w); 54 } 55 } 56 } 57 } 58 checkRelationMembership(n); 59 } 60 61 public void visit(Way w) { 62 checkRelationMembership(w); 63 } 64 65 public void visit(Relation r) { 66 checkRelationMembership(r); 67 } 68 69 private void checkRelationMembership(OsmPrimitive p) { 70 // FIXME - this might be a candidate for optimisation 71 // if OSM primitives are made to hold a list of back 72 // references. 73 for (Relation r : ds.relations) { 74 if (r.incomplete || r.deleted) continue; 75 for (RelationMember m : r.members) { 76 if (m.member == p) { 77 if (!data.contains(r)) { 78 data.add(r); 79 if (indirectRefs) { 80 // move up the tree (there might be relations 81 // referring to this relation) 82 checkRelationMembership(r); 83 } 84 } 85 break; 86 } 87 } 88 } 89 } 90 90 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/CreateOsmChangeVisitor.java
r1071 r1169 16 16 /** 17 17 * Creates an OsmChange document from JOSM edits. 18 * See http://wiki.openstreetmap.org/index.php/OsmChange for a documentation of the 18 * See http://wiki.openstreetmap.org/index.php/OsmChange for a documentation of the 19 19 * OsmChange format. 20 * 20 * 21 21 * @author fred 22 22 * … … 30 30 StringWriter swriter; 31 31 OsmWriter osmwriter; 32 32 33 33 public CreateOsmChangeVisitor(Changeset changeset) { 34 34 writer = new PrintWriter(swriter = new StringWriter()); 35 35 writer.write("<osmChange version=\""); 36 36 writer.write(Main.pref.get("osm-server.version", "0.6")); 37 writer.write("\" generator=\"JOSM\">\n"); 37 writer.write("\" generator=\"JOSM\">\n"); 38 38 this.changeset = changeset; 39 39 osmwriter = new OsmWriter(writer, false, changeset); 40 40 } 41 41 42 42 public void visit(Node n) { 43 43 if (n.deleted) { … … 55 55 } 56 56 } 57 57 58 58 public void visit(Way w) { 59 59 if (w.deleted) { … … 69 69 switchMode((w.id == 0) ? "create" : "modify"); 70 70 w.visit(osmwriter); 71 } 71 } 72 72 } 73 73 74 74 public void visit(Relation r) { 75 75 if (r.deleted) { … … 85 85 switchMode((r.id == 0) ? "create" : "modify"); 86 86 r.visit(osmwriter); 87 } 87 } 88 88 } 89 89 90 90 private void switchMode(String newMode) { 91 91 if ((newMode != null && !newMode.equals(currentMode))||(newMode == null && currentMode != null)) { … … 105 105 } 106 106 } 107 107 108 108 public String getDocument() { 109 109 switchMode(null); 110 110 return swriter.toString() + "</osmChange>\n"; 111 111 } 112 112 113 113 public Map<OsmPrimitive,Long> getNewIdMap() { 114 114 return osmwriter.usedNewIds; -
trunk/src/org/openstreetmap/josm/data/osm/visitor/DeleteVisitor.java
r655 r1169 9 9 /** 10 10 * Visitor that adds the visited object to the dataset given at constructor. 11 * 11 * 12 12 * Is not capable of adding keys. 13 * 13 * 14 14 * @author imi 15 15 */ 16 16 public class DeleteVisitor implements Visitor { 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 17 18 private final DataSet ds; 19 20 public DeleteVisitor(DataSet ds) { 21 this.ds = ds; 22 } 23 24 public void visit(Node n) { 25 ds.nodes.remove(n); 26 } 27 public void visit(Way w) { 28 ds.ways.remove(w); 29 } 30 public void visit(Relation e) { 31 ds.relations.remove(e); 32 } 33 33 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java
r1077 r1169 33 33 34 34 public class MapPaintVisitor extends SimplePaintVisitor { 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 35 protected boolean useRealWidth; 36 protected boolean zoomLevelDisplay; 37 protected boolean fillAreas; 38 protected int fillAlpha; 39 protected Color untaggedColor; 40 protected Color textColor; 41 protected boolean currentDashed = false; 42 protected int currentWidth = 0; 43 protected Stroke currentStroke = null; 44 protected Font orderFont; 45 protected ElemStyles styles; 46 protected double circum; 47 protected String regionalNameOrder[]; 48 49 protected boolean isZoomOk(ElemStyle e) { 50 if (!zoomLevelDisplay) /* show everything if the user wishes so */ 51 return true; 52 53 if(e == null) /* the default for things that don't have a rule (show, if scale is smaller than 1500m) */ 54 return (circum < 1500); 55 56 // formula to calculate a map scale: natural size / map size = scale 57 // example: 876000mm (876m as displayed) / 22mm (roughly estimated screen size of legend bar) = 39818 58 // 59 // so the exact "correcting value" below depends only on the screen size and resolution 60 // XXX - do we need a Preference setting for this (if things vary widely)? 61 return !(circum >= e.maxScale / 22 || circum < e.minScale / 22); 62 } 63 64 /** 65 * Draw a small rectangle. 66 * White if selected (as always) or red otherwise. 67 * 68 * @param n The node to draw. 69 */ 70 public void visit(Node n) { 71 IconElemStyle nodeStyle = styles.get(n); 72 if (nodeStyle != null && isZoomOk(nodeStyle)) 73 drawNode(n, nodeStyle.icon, nodeStyle.annotate); 74 else if (n.selected) 75 drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode); 76 else if (n.tagged) 77 drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode); 78 else 79 drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode); 80 } 81 82 /** 83 * Draw a line for all segments, according to tags. 84 * @param w The way to draw. 85 */ 86 public void visit(Way w) { 87 if(w.nodes.size() < 2) 88 return; 89 // show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key 90 // (even if the tag is negated as in oneway=false) or the way is selected 91 boolean showDirection = w.selected || ((!useRealWidth) && (showDirectionArrow 92 && (!showRelevantDirectionsOnly || w.hasDirectionKeys))); 93 94 Color color = untaggedColor; 95 int width = defaultSegmentWidth; 96 int realWidth = 0; //the real width of the element in meters 97 boolean dashed = false; 98 ElemStyle wayStyle = styles.get(w); 99 100 if(!isZoomOk(wayStyle)) 101 return; 102 103 LineElemStyle l = null; 104 if(wayStyle!=null) 105 { 106 Color areacolor = untaggedColor; 107 boolean area = false; 108 if(wayStyle instanceof LineElemStyle) 109 l = (LineElemStyle)wayStyle; 110 else if (wayStyle instanceof AreaElemStyle) 111 { 112 areacolor = ((AreaElemStyle)wayStyle).color; 113 color = areacolor; 114 l = ((AreaElemStyle)wayStyle).line; 115 area = true; 116 } 117 if(l != null) 118 { 119 color = l.color; 120 width = l.width; 121 realWidth = l.realWidth; 122 dashed = l.dashed; 123 } 124 if (area && fillAreas) 125 drawWayAsArea(w, areacolor); 126 } 127 128 if (realWidth > 0 && useRealWidth && !showDirection) 129 { 130 int tmpWidth = (int) (100 / (float) (circum / realWidth)); 131 if (tmpWidth > width) width = tmpWidth; 132 } 133 if(w.selected) 134 color = selectedColor; 135 136 Node lastN; 137 if(l != null && l.overlays != null) 138 { 139 for(LineElemStyle s : l.overlays) 140 { 141 if(!s.over) 142 { 143 lastN = null; 144 for(Node n : w.nodes) 145 { 146 if(lastN != null) 147 { 148 drawSeg(lastN, n, s.color != null && !w.selected ? s.color : color, 149 false, s.getWidth(width), s.dashed); 150 } 151 lastN = n; 152 } 153 } 154 } 155 } 156 157 lastN = null; 158 for(Node n : w.nodes) 159 { 160 if(lastN != null) 161 drawSeg(lastN, n, color, showDirection, width, dashed); 162 lastN = n; 163 } 164 165 if(l != null && l.overlays != null) 166 { 167 for(LineElemStyle s : l.overlays) 168 { 169 if(s.over) 170 { 171 lastN = null; 172 for(Node n : w.nodes) 173 { 174 if(lastN != null) 175 { 176 drawSeg(lastN, n, s.color != null && !w.selected ? s.color : color, 177 false, s.getWidth(width), s.dashed); 178 } 179 lastN = n; 180 } 181 } 182 } 183 } 184 185 if(showOrderNumber) 186 { 187 int orderNumber = 0; 188 lastN = null; 189 for(Node n : w.nodes) 190 { 191 if(lastN != null) 192 { 193 orderNumber++; 194 drawOrderNumber(lastN, n, orderNumber); 195 } 196 lastN = n; 197 } 198 } 199 displaySegments(); 200 } 201 202 public void visit(Relation e) { 203 // relations are not (yet?) drawn. 204 } 205 206 // This assumes that all segments are aligned in the same direction! 207 protected void drawWayAsArea(Way w, Color color) 208 { 209 Polygon polygon = new Polygon(); 210 211 for (Node n : w.nodes) 212 { 213 Point p = nc.getPoint(n.eastNorth); 214 polygon.addPoint(p.x,p.y); 215 } 216 217 Color mycolor = w.selected ? selectedColor : color; 218 // set the opacity (alpha) level of the filled polygon 219 g.setColor(new Color( mycolor.getRed(), mycolor.getGreen(), mycolor.getBlue(), fillAlpha)); 220 221 g.fillPolygon(polygon); 222 } 223 224 // NEW 225 protected void drawNode(Node n, ImageIcon icon, boolean annotate) { 226 Point p = nc.getPoint(n.eastNorth); 227 if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return; 228 int w = icon.getIconWidth(), h=icon.getIconHeight(); 229 icon.paintIcon ( Main.map.mapView, g, p.x-w/2, p.y-h/2 ); 230 String name = getNodeName(n); 231 if (name!=null && annotate) 232 { 233 g.setColor(textColor); 234 Font defaultFont = g.getFont(); 235 g.setFont (orderFont); 236 g.drawString (name, p.x+w/2+2, p.y+h/2+2); 237 g.setFont(defaultFont); 238 } 239 if (n.selected) 240 { 241 g.setColor ( selectedColor ); 242 g.drawRect (p.x-w/2-2,p.y-w/2-2, w+4, h+4); 243 } 244 } 245 246 protected String getNodeName(Node n) { 247 String name = null; 248 if (n.keys != null) { 249 for (int i = 0; i < regionalNameOrder.length; i++) { 250 name = n.keys.get(regionalNameOrder[i]); 251 if (name != null) break; 252 } 253 } 254 return name; 255 } 256 257 private void drawSeg(Node n1, Node n2, Color col, boolean showDirection, int width, boolean dashed) { 258 if (col != currentColor || width != currentWidth || dashed != currentDashed) { 259 displaySegments(col, width, dashed); 260 } 261 Point p1 = nc.getPoint(n1.eastNorth); 262 Point p2 = nc.getPoint(n2.eastNorth); 263 264 if (!isSegmentVisible(p1, p2)) { 265 return; 266 } 267 currentPath.moveTo(p1.x, p1.y); 268 currentPath.lineTo(p2.x, p2.y); 269 270 if (showDirection) { 271 double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI; 272 currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI))); 273 currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI))); 274 currentPath.lineTo(p2.x, p2.y); 275 } 276 } 277 278 protected void displaySegments() { 279 displaySegments(null, 0, false); 280 } 281 282 protected void displaySegments(Color newColor, int newWidth, boolean newDash) { 283 if (currentPath != null) { 284 Graphics2D g2d = (Graphics2D)g; 285 g2d.setColor(inactive ? inactiveColor : currentColor); 286 if (currentStroke == null) { 287 if (currentDashed) 288 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,0,new float[] {9},0)); 289 else 290 g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND)); 291 } 292 g2d.draw(currentPath); 293 g2d.setStroke(new BasicStroke(1)); 294 295 currentPath = new GeneralPath(); 296 currentColor = newColor; 297 currentWidth = newWidth; 298 currentDashed = newDash; 299 currentStroke = null; 300 } 301 } 302 303 /** 304 * Draw the node as small rectangle with the given color. 305 * 306 * @param n The node to draw. 307 * @param color The color of the node. 308 */ 309 public void drawNode(Node n, Color color, int size, int radius, boolean fill) { 310 if (isZoomOk(null) && size > 1) { 311 Point p = nc.getPoint(n.eastNorth); 312 if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) 313 || (p.y > nc.getHeight())) 314 return; 315 g.setColor(color); 316 if (fill) { 317 g.fillRect(p.x - radius, p.y - radius, size, size); 318 g.drawRect(p.x - radius, p.y - radius, size, size); 319 } else 320 g.drawRect(p.x - radius, p.y - radius, size, size); 321 } 322 } 323 324 // NW 111106 Overridden from SimplePaintVisitor in josm-1.4-nw1 325 // Shows areas before non-areas 326 public void visitAll(DataSet data, Boolean virtual) { 327 getSettings(virtual); 328 untaggedColor = Main.pref.getColor(marktr("untagged"),Color.GRAY); 329 textColor = Main.pref.getColor (marktr("text"), Color.WHITE); 330 useRealWidth = Main.pref.getBoolean("mappaint.useRealWidth",false); 331 zoomLevelDisplay = Main.pref.getBoolean("mappaint.zoomLevelDisplay",false); 332 fillAreas = Main.pref.getBoolean("mappaint.fillareas", true); 333 fillAlpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.fillalpha", 50)))); 334 circum = Main.map.mapView.getScale()*100*Main.proj.scaleFactor()*40041455; // circumference of the earth in meter 335 styles = MapPaintStyles.getStyles(); 336 orderFont = new Font(Main.pref.get("mappaint.font","Helvetica"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8)); 337 String currentLocale = Locale.getDefault().getLanguage(); 338 regionalNameOrder = Main.pref.get("mappaint.nameOrder", "name:"+currentLocale+";name;int_name").split(";"); 339 340 if (styles.hasAreas()) { 341 Collection<Way> noAreaWays = new LinkedList<Way>(); 342 343 for (final OsmPrimitive osm : data.ways) 344 if (!osm.incomplete && !osm.deleted && styles.isArea((Way)osm)) 345 osm.visit(this); 346 else if (!osm.deleted && !osm.incomplete) 347 noAreaWays.add((Way)osm); 348 349 for (final OsmPrimitive osm : noAreaWays) 350 osm.visit(this); 351 } 352 else 353 { 354 for (final OsmPrimitive osm : data.ways) 355 if (!osm.incomplete && !osm.deleted) 356 osm.visit(this); 357 } 358 359 for (final OsmPrimitive osm : data.getSelected()) 360 if (!osm.incomplete && !osm.deleted){ 361 osm.visit(this); 362 } 363 364 displaySegments(); 365 366 for (final OsmPrimitive osm : data.nodes) 367 if (!osm.incomplete && !osm.deleted) 368 osm.visit(this); 369 370 if (virtualNodeSize != 0) 371 { 372 currentColor = nodeColor; 373 for (final OsmPrimitive osm : data.ways) 374 if (!osm.deleted) 375 visitVirtual((Way)osm); 376 displaySegments(null); 377 } 378 } 379 380 /** 381 * Draw a number of the order of the two consecutive nodes within the 382 * parents way 383 */ 384 protected void drawOrderNumber(Node n1, Node n2, int orderNumber) { 385 Point p1 = nc.getPoint(n1.eastNorth); 386 Point p2 = nc.getPoint(n2.eastNorth); 387 drawOrderNumber(p1, p2, orderNumber); 388 } 389 389 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java
r627 r1169 19 19 * A visitor that get a data set at construction time and merge every visited object 20 20 * into it. 21 * 21 * 22 22 * @author imi 23 23 */ 24 24 public class MergeVisitor implements Visitor { 25 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 } 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 26 /** 27 * Map from primitives in the database to visited primitives. (Attention: The other way 28 * round than merged) 29 */ 30 public Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>(); 31 32 private final DataSet ds; 33 private final DataSet mergeds; 34 35 private final HashMap<Long, Node> nodeshash = new HashMap<Long, Node>(); 36 private final HashMap<Long, Way> wayshash = new HashMap<Long, Way>(); 37 private final HashMap<Long, Relation> relshash = new HashMap<Long, Relation>(); 38 39 /** 40 * A list of all primitives that got replaced with other primitives. 41 * Key is the primitives in the other's dataset and the value is the one that is now 42 * in ds.nodes instead. 43 */ 44 private final Map<OsmPrimitive, OsmPrimitive> merged 45 = new HashMap<OsmPrimitive, OsmPrimitive>(); 46 47 public MergeVisitor(DataSet ds, DataSet mergeds) { 48 this.ds = ds; 49 this.mergeds = mergeds; 50 51 for (Node n : ds.nodes) if (n.id != 0) nodeshash.put(n.id, n); 52 for (Way w : ds.ways) if (w.id != 0) wayshash.put(w.id, w); 53 for (Relation r : ds.relations) if (r.id != 0) relshash.put(r.id, r); 54 } 55 56 private <P extends OsmPrimitive> void genMerge(P other, 57 Collection<P> myprims, Collection<P> mergeprims, 58 HashMap<Long, P> primhash) { 59 // 1. Try to find an identical prim with the same id. 60 if (mergeAfterId(myprims, primhash, other)) 61 return; 62 63 // 2. Try to find a prim we can merge with the prim from the other ds. 64 for (P my : myprims) { 65 // LinkedList.contains calls equal, and OsmPrimitive.equal 66 // compares just the id. 67 if (match(my, other) && !mergeprims.contains(my)) { 68 merged.put(other, my); 69 mergeCommon(my, other); 70 return; 71 } 72 } 73 74 // 3. No idea how to merge that. Simply add it unchanged. 75 myprims.add(other); 76 } 77 78 public void visit(Node other) { 79 genMerge(other, ds.nodes, mergeds.nodes, nodeshash); 80 } 81 82 public void visit(Way other) { 83 fixWay(other); 84 genMerge(other, ds.ways, mergeds.ways, wayshash); 85 } 86 87 public void visit(Relation other) { 88 fixRelation(other); 89 genMerge(other, ds.relations, mergeds.relations, relshash); 90 } 91 92 /** 93 * Postprocess the dataset and fix all merged references to point to the actual 94 * data. 95 */ 96 public void fixReferences() { 97 for (Way w : ds.ways) fixWay(w); 98 for (Relation r : ds.relations) fixRelation(r); 99 for (OsmPrimitive osm : conflicts.values()) 100 if (osm instanceof Way) 101 fixWay((Way)osm); 102 else if (osm instanceof Relation) 103 fixRelation((Relation) osm); 104 } 105 106 private void fixWay(Way w) { 107 boolean replacedSomething = false; 108 LinkedList<Node> newNodes = new LinkedList<Node>(); 109 for (Node n : w.nodes) { 110 Node otherN = (Node) merged.get(n); 111 newNodes.add(otherN == null ? n : otherN); 112 if (otherN != null) 113 replacedSomething = true; 114 } 115 if (replacedSomething) { 116 w.nodes.clear(); 117 w.nodes.addAll(newNodes); 118 } 119 } 120 121 private void fixRelation(Relation r) { 122 boolean replacedSomething = false; 123 LinkedList<RelationMember> newMembers = new LinkedList<RelationMember>(); 124 for (RelationMember m : r.members) { 125 OsmPrimitive otherP = merged.get(m.member); 126 if (otherP == null) { 127 newMembers.add(m); 128 } else { 129 RelationMember mnew = new RelationMember(m); 130 mnew.member = otherP; 131 newMembers.add(mnew); 132 replacedSomething = true; 133 } 134 } 135 if (replacedSomething) { 136 r.members.clear(); 137 r.members.addAll(newMembers); 138 } 139 } 140 141 private static <P extends OsmPrimitive> boolean match(P p1, P p2) { 142 if ((p1.id == 0 || p2.id == 0) && !p1.incomplete && !p2.incomplete) { 143 return realMatch(p1, p2); 144 } 145 return p1.id == p2.id; 146 } 147 148 /** @return true if the prims have pretty much the same data, i.e. the 149 * same position, the same members, ... 150 */ 151 // Java cannot dispatch on generics... 152 private static boolean realMatch(OsmPrimitive p1, OsmPrimitive p2) { 153 if (p1 instanceof Node && p2 instanceof Node) { 154 return realMatch((Node) p1, (Node) p2); 155 } else if (p1 instanceof Way && p2 instanceof Way) { 156 return realMatch((Way) p1, (Way) p2); 157 } else if (p1 instanceof Relation && p2 instanceof Relation) { 158 return realMatch((Relation) p1, (Relation) p2); 159 } else { 160 throw new RuntimeException("arguments have unknown type"); 161 } 162 } 163 164 private static boolean realMatch(Node n1, Node n2) { 165 return n1.coor.equalsEpsilon(n2.coor); 166 } 167 168 private static boolean realMatch(Way w1, Way w2) { 169 if (w1.nodes.size() != w2.nodes.size()) 170 return false; 171 Iterator<Node> it = w1.nodes.iterator(); 172 for (Node n : w2.nodes) 173 if (!match(n, it.next())) 174 return false; 175 return true; 176 } 177 178 private static boolean realMatch(Relation w1, Relation w2) { 179 // FIXME this is not perfect yet... 180 if (w1.members.size() != w2.members.size()) 181 return false; 182 for (RelationMember em : w1.members) { 183 if (!w2.members.contains(em)) { 184 return false; 185 } 186 } 187 return true; 188 } 189 190 /** 191 * Merge the common parts of an osm primitive. 192 * @param my The object, the information gets merged into 193 * @param other The object, the information gets merged from 194 */ 195 private void mergeCommon(OsmPrimitive my, OsmPrimitive other) { 196 if (other.deleted) 197 my.delete(true); 198 if (my.id == 0 || !my.modified || other.modified) { 199 if (my.id == 0 && other.id != 0) { 200 my.id = other.id; 201 my.modified = other.modified; // match a new node 202 } else if (my.id != 0 && other.id != 0 && other.modified) 203 my.modified = true; 204 } 205 if (other.keys == null) 206 return; 207 if (my.keySet().containsAll(other.keys.keySet())) 208 return; 209 if (my.keys == null) 210 my.keys = other.keys; 211 else 212 my.keys.putAll(other.keys); 213 214 my.modified = true; 215 } 216 217 /** 218 * @return <code>true</code>, if no merge is needed or merge is performed already. 219 */ 220 private <P extends OsmPrimitive> boolean mergeAfterId( 221 Collection<P> primitives, HashMap<Long, P> hash, P other) { 222 // Fast-path merging of identical objects 223 if (hash.containsKey(other.id)) { 224 P my = hash.get(other.id); 225 if (my.realEqual(other, true)) { 226 merged.put(other, my); 227 return true; 228 } 229 } 230 231 for (P my : primitives) { 232 if (my.realEqual(other, false)) { 233 merged.put(other, my); 234 return true; // no merge needed. 235 } 236 if (my.realEqual(other, true)) { 237 Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp(); 238 Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp(); 239 240 // they differ in modified/timestamp combination only. Auto-resolve it. 241 merged.put(other, my); 242 if (myd.before(otherd)) { 243 my.modified = other.modified; 244 my.timestamp = other.timestamp; 245 } 246 return true; // merge done. 247 } 248 if (my.id == other.id && my.id != 0) { 249 Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp(); 250 Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp(); 251 252 if (my.incomplete || other.incomplete) { 253 if (my.incomplete) { 254 my.cloneFrom(other); 255 } 256 } else if (my.modified && other.modified) { 257 conflicts.put(my, other); 258 } else if (!my.modified && !other.modified) { 259 if (myd.before(otherd)) { 260 my.cloneFrom(other); 261 } 262 } else if (other.modified) { 263 if (myd.after(otherd)) { 264 conflicts.put(my, other); 265 } else { 266 my.cloneFrom(other); 267 } 268 } else if (my.modified) { 269 if (myd.before(otherd)) { 270 conflicts.put(my, other); 271 } 272 } 273 merged.put(other, my); 274 return true; 275 } 276 } 277 return false; 278 } 279 279 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/NameVisitor.java
r756 r1169 17 17 /** 18 18 * Able to create a name and an icon for each data element. 19 * 19 * 20 20 * @author imi 21 21 */ 22 22 public class NameVisitor implements Visitor { 23 23 24 /** 25 * The name of the item class 26 */ 27 public String className; 28 public String classNamePlural; 29 /** 30 * The name of this item. 31 */ 32 public String name; 33 /** 34 * The icon of this item. 35 */ 36 public Icon icon; 37 38 /** 39 * If the node has a name-key or id-key, this is displayed. If not, (lat,lon) 40 * is displayed. 41 */ 42 public void visit(Node n) { 43 name = n.getName(); 44 addId(n); 45 icon = ImageProvider.get("data", "node"); 46 className = "node"; 47 classNamePlural = trn("node", "nodes", 2); 48 } 24 /** 25 * The name of the item class 26 */ 27 public String className; 28 public String classNamePlural; 29 /** 30 * The name of this item. 31 */ 32 public String name; 33 /** 34 * The icon of this item. 35 */ 36 public Icon icon; 49 37 50 /** 51 * If the way has a name-key or id-key, this is displayed. If not, (x nodes) 52 * is displayed with x being the number of nodes in the way. 53 */ 54 public void visit(Way w) { 55 name = w.getName(); 56 addId(w); 57 icon = ImageProvider.get("data", "way"); 58 className = "way"; 59 classNamePlural = trn("way", "ways", 2); 60 } 61 62 /** 63 */ 64 public void visit(Relation e) { 65 name = e.getName(); 66 addId(e); 67 icon = ImageProvider.get("data", "relation"); 68 className = "relation"; 69 classNamePlural = trn("relation", "relations", 2); 70 } 71 72 public JLabel toLabel() { 73 return new JLabel(name, icon, JLabel.HORIZONTAL); 74 } 38 /** 39 * If the node has a name-key or id-key, this is displayed. If not, (lat,lon) 40 * is displayed. 41 */ 42 public void visit(Node n) { 43 name = n.getName(); 44 addId(n); 45 icon = ImageProvider.get("data", "node"); 46 className = "node"; 47 classNamePlural = trn("node", "nodes", 2); 48 } 49 50 /** 51 * If the way has a name-key or id-key, this is displayed. If not, (x nodes) 52 * is displayed with x being the number of nodes in the way. 53 */ 54 public void visit(Way w) { 55 name = w.getName(); 56 addId(w); 57 icon = ImageProvider.get("data", "way"); 58 className = "way"; 59 classNamePlural = trn("way", "ways", 2); 60 } 61 62 /** 63 */ 64 public void visit(Relation e) { 65 name = e.getName(); 66 addId(e); 67 icon = ImageProvider.get("data", "relation"); 68 className = "relation"; 69 classNamePlural = trn("relation", "relations", 2); 70 } 71 72 public JLabel toLabel() { 73 return new JLabel(name, icon, JLabel.HORIZONTAL); 74 } 75 75 76 76 77 78 79 77 private void addId(OsmPrimitive osm) { 78 if (Main.pref.getBoolean("osm-primitives.showid")) 79 name += tr(" [id: {0}]", osm.id); 80 80 } 81 81 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java
r999 r1169 32 32 public class SimplePaintVisitor implements Visitor { 33 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 34 public final static Color darkerblue = new Color(0,0,96); 35 public final static Color darkblue = new Color(0,0,128); 36 public final static Color darkgreen = new Color(0,128,0); 37 public final static Color teal = new Color(0,128,128); 38 39 /** 40 * The environment to paint to. 41 */ 42 protected Graphics g; 43 /** 44 * MapView to get screen coordinates. 45 */ 46 protected NavigatableComponent nc; 47 48 public boolean inactive; 49 50 protected static final double PHI = Math.toRadians(20); 51 52 /** 53 * Preferences 54 */ 55 protected Color inactiveColor; 56 protected Color selectedColor; 57 protected Color nodeColor; 58 protected Color dfltWayColor; 59 protected Color relationColor; 60 protected Color untaggedWayColor; 61 protected Color incompleteColor; 62 protected Color backgroundColor; 63 protected boolean showDirectionArrow; 64 protected boolean showRelevantDirectionsOnly; 65 protected boolean showOrderNumber; 66 protected boolean fillSelectedNode; 67 protected boolean fillUnselectedNode; 68 protected int selectedNodeRadius; 69 protected int unselectedNodeRadius; 70 protected int selectedNodeSize; 71 protected int unselectedNodeSize; 72 protected int defaultSegmentWidth; 73 protected int virtualNodeSize; 74 protected int virtualNodeSpace; 75 protected int segmentNumberSpace; 76 protected int taggedNodeRadius; 77 protected int taggedNodeSize; 78 79 /** 80 * Draw subsequent segments of same color as one Path 81 */ 82 protected Color currentColor = null; 83 protected GeneralPath currentPath = new GeneralPath(); 84 85 Rectangle bbox = new Rectangle(); 86 87 protected void getSettings(Boolean virtual) { 88 inactiveColor = Main.pref.getColor(marktr("inactive"), Color.DARK_GRAY); 89 selectedColor = Main.pref.getColor(marktr("selected"), Color.WHITE); 90 nodeColor = Main.pref.getColor(marktr("node"), Color.RED); 91 dfltWayColor = Main.pref.getColor(marktr("way"), darkblue); 92 relationColor = Main.pref.getColor(marktr("relation"), teal); 93 untaggedWayColor = Main.pref.getColor(marktr("untagged way"), darkgreen); 94 incompleteColor = Main.pref.getColor(marktr("incomplete way"), darkerblue); 95 backgroundColor = Main.pref.getColor(marktr("background"), Color.BLACK); 96 showDirectionArrow = Main.pref.getBoolean("draw.segment.direction"); 97 showRelevantDirectionsOnly = Main.pref.getBoolean("draw.segment.relevant_directions_only"); 98 showOrderNumber = Main.pref.getBoolean("draw.segment.order_number"); 99 selectedNodeRadius = Main.pref.getInteger("mappaint.node.selected-size", 5) / 2; 100 selectedNodeSize = selectedNodeRadius * 2; 101 unselectedNodeRadius = Main.pref.getInteger("mappaint.node.unselected-size", 3) / 2; 102 unselectedNodeSize = unselectedNodeRadius * 2; 103 taggedNodeRadius = Main.pref.getInteger("mappaint.node.tagged-size", 5) / 2; 104 taggedNodeSize = taggedNodeRadius * 2; 105 defaultSegmentWidth = Main.pref.getInteger("mappaint.segment.default-width", 2); 106 fillSelectedNode = Main.pref.getBoolean("mappaint.node.fill-selected", true); 107 fillUnselectedNode = Main.pref.getBoolean("mappaint.node.fill-unselected", false); 108 virtualNodeSize = virtual ? Main.pref.getInteger("mappaint.node.virtual-size", 8) / 2 : 0; 109 virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70); 110 segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40); 111 112 ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, 113 Main.pref.getBoolean("mappaint.use-antialiasing", false) ? 114 RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); 115 } 116 117 public void visitAll(DataSet data, Boolean virtual) { 118 getSettings(virtual); 119 // draw tagged ways first, then untagged ways. takes 120 // time to iterate through list twice, OTOH does not 121 // require changing the colour while painting... 122 for (final OsmPrimitive osm : data.relations) 123 if (!osm.deleted && !osm.selected) 124 osm.visit(this); 125 126 for (final OsmPrimitive osm : data.ways) 127 if (!osm.deleted && !osm.selected && osm.tagged) 128 osm.visit(this); 129 displaySegments(); 130 131 for (final OsmPrimitive osm : data.ways) 132 if (!osm.deleted && !osm.selected && !osm.tagged) 133 osm.visit(this); 134 displaySegments(); 135 136 for (final OsmPrimitive osm : data.getSelected()) 137 if (!osm.deleted) 138 osm.visit(this); 139 displaySegments(); 140 141 for (final OsmPrimitive osm : data.nodes) 142 if (!osm.deleted && !osm.selected) 143 osm.visit(this); 144 if(virtualNodeSize != 0) 145 { 146 currentColor = nodeColor; 147 for (final OsmPrimitive osm : data.ways) 148 if (!osm.deleted) 149 visitVirtual((Way)osm); 150 displaySegments(); 151 } 152 } 153 154 /** 155 * Draw a small rectangle. 156 * White if selected (as always) or red otherwise. 157 * 158 * @param n The node to draw. 159 */ 160 public void visit(Node n) { 161 if (n.incomplete) return; 162 163 if (inactive) 164 drawNode(n, inactiveColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode); 165 else if (n.selected) 166 drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode); 167 else if(n.tagged) 168 drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode); 169 else 170 drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode); 171 } 172 173 public static Boolean isLargeSegment(Point p1, Point p2, int space) 174 { 175 int xd = p1.x-p2.x; if(xd < 0) xd = -xd; 176 int yd = p1.y-p2.y; if(yd < 0) yd = -yd; 177 return (xd+yd > space); 178 } 179 180 public void visitVirtual(Way w) { 181 Iterator<Node> it = w.nodes.iterator(); 182 if (it.hasNext()) { 183 Point lastP = nc.getPoint(it.next().eastNorth); 184 while(it.hasNext()) 185 { 186 Point p = nc.getPoint(it.next().eastNorth); 187 if(isSegmentVisible(lastP, p) && isLargeSegment(lastP, p, virtualNodeSpace)) 188 { 189 int x = (p.x+lastP.x)/2; 190 int y = (p.y+lastP.y)/2; 191 currentPath.moveTo(x-virtualNodeSize, y); 192 currentPath.lineTo(x+virtualNodeSize, y); 193 currentPath.moveTo(x, y-virtualNodeSize); 194 currentPath.lineTo(x, y+virtualNodeSize); 195 } 196 lastP = p; 197 } 198 } 199 } 200 201 /** 202 * Draw a darkblue line for all segments. 203 * @param w The way to draw. 204 */ 205 public void visit(Way w) { 206 if (w.incomplete || w.nodes.size() < 2) 207 return; 208 209 // show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key 210 // (even if the tag is negated as in oneway=false) or the way is selected 211 212 boolean showThisDirectionArrow = w.selected 213 || (showDirectionArrow && (!showRelevantDirectionsOnly || w.hasDirectionKeys)); 214 Color wayColor; 215 216 if (inactive) { 217 wayColor = inactiveColor; 218 } else if (!w.tagged) { 219 wayColor = untaggedWayColor; 220 } else { 221 wayColor = dfltWayColor; 222 } 223 224 Iterator<Node> it = w.nodes.iterator(); 225 if (it.hasNext()) { 226 Point lastP = nc.getPoint(it.next().eastNorth); 227 for (int orderNumber = 1; it.hasNext(); orderNumber++) { 228 Point p = nc.getPoint(it.next().eastNorth); 229 drawSegment(lastP, p, w.selected && !inactive ? selectedColor : wayColor, showThisDirectionArrow); 230 if (showOrderNumber) 231 drawOrderNumber(lastP, p, orderNumber); 232 lastP = p; 233 } 234 } 235 } 236 237 private Stroke relatedWayStroke = new BasicStroke( 238 4, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL); 239 public void visit(Relation r) { 240 if (r.incomplete) return; 241 242 Color col; 243 if (inactive) { 244 col = inactiveColor; 245 } else if (r.selected) { 246 col = selectedColor; 247 } else { 248 col = relationColor; 249 } 250 g.setColor(col); 251 252 for (RelationMember m : r.members) { 253 if (m.member.incomplete || m.member.deleted) continue; 254 255 if (m.member instanceof Node) { 256 Point p = nc.getPoint(((Node) m.member).eastNorth); 257 if (p.x < 0 || p.y < 0 258 || p.x > nc.getWidth() || p.y > nc.getHeight()) continue; 259 260 g.drawOval(p.x-3, p.y-3, 6, 6); 261 } else if (m.member instanceof Way) { 262 GeneralPath path = new GeneralPath(); 263 264 boolean first = true; 265 for (Node n : ((Way) m.member).nodes) { 266 if (n.incomplete || n.deleted) continue; 267 Point p = nc.getPoint(n.eastNorth); 268 if (first) { 269 path.moveTo(p.x, p.y); 270 first = false; 271 } else { 272 path.lineTo(p.x, p.y); 273 } 274 } 275 276 ((Graphics2D) g).draw(relatedWayStroke.createStrokedShape(path)); 277 } 278 } 279 } 280 281 /** 282 * Draw an number of the order of the two consecutive nodes within the 283 * parents way 284 */ 285 protected void drawOrderNumber(Point p1, Point p2, int orderNumber) { 286 if (isSegmentVisible(p1, p2) && isLargeSegment(p1, p2, segmentNumberSpace)) { 287 String on = Integer.toString(orderNumber); 288 int strlen = on.length(); 289 int x = (p1.x+p2.x)/2 - 4*strlen; 290 int y = (p1.y+p2.y)/2 + 4; 291 292 if(virtualNodeSize != 0 && isLargeSegment(p1, p2, virtualNodeSpace)) 293 { 294 y = (p1.y+p2.y)/2 - virtualNodeSize - 3; 295 } 296 297 displaySegments(); // draw nodes on top! 298 Color c = g.getColor(); 299 g.setColor(backgroundColor); 300 g.fillRect(x-1, y-12, 8*strlen+1, 14); 301 g.setColor(c); 302 g.drawString(on, x, y); 303 } 304 } 305 306 /** 307 * Draw the node as small rectangle with the given color. 308 * 309 * @param n The node to draw. 310 * @param color The color of the node. 311 */ 312 public void drawNode(Node n, Color color, int size, int radius, boolean fill) { 313 if (size > 1) { 314 Point p = nc.getPoint(n.eastNorth); 315 if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) 316 || (p.y > nc.getHeight())) 317 return; 318 g.setColor(color); 319 if (fill) { 320 g.fillRect(p.x - radius, p.y - radius, size, size); 321 g.drawRect(p.x - radius, p.y - radius, size, size); 322 } else 323 g.drawRect(p.x - radius, p.y - radius, size, size); 324 } 325 } 326 327 /** 328 * Draw a line with the given color. 329 */ 330 protected void drawSegment(Point p1, Point p2, Color col, boolean showDirection) { 331 if (col != currentColor) displaySegments(col); 332 333 if (isSegmentVisible(p1, p2)) { 334 currentPath.moveTo(p1.x, p1.y); 335 currentPath.lineTo(p2.x, p2.y); 336 337 if (showDirection) { 338 double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI; 339 currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI))); 340 currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI))); 341 currentPath.lineTo(p2.x, p2.y); 342 } 343 } 344 } 345 346 protected boolean isSegmentVisible(Point p1, Point p2) { 347 if ((p1.x < 0) && (p2.x < 0)) return false; 348 if ((p1.y < 0) && (p2.y < 0)) return false; 349 if ((p1.x > nc.getWidth()) && (p2.x > nc.getWidth())) return false; 350 if ((p1.y > nc.getHeight()) && (p2.y > nc.getHeight())) return false; 351 return true; 352 } 353 354 public void setGraphics(Graphics g) { 355 this.g = g; 356 } 357 358 public void setNavigatableComponent(NavigatableComponent nc) { 359 this.nc = nc; 360 } 361 362 protected void displaySegments() { 363 displaySegments(null); 364 } 365 protected void displaySegments(Color newColor) { 366 if (currentPath != null) { 367 g.setColor(currentColor); 368 ((Graphics2D) g).draw(currentPath); 369 currentPath = new GeneralPath(); 370 currentColor = newColor; 371 } 372 } 373 373 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/Visitor.java
r627 r1169 9 9 * Implementation of the visitor scheme. Every OsmPrimitive can be visited by 10 10 * several different visitors. 11 * 11 * 12 12 * @author imi 13 13 */ 14 14 public interface Visitor { 15 16 17 15 void visit(Node n); 16 void visit(Way w); 17 void visit(Relation e); 18 18 } -
trunk/src/org/openstreetmap/josm/data/projection/Epsg4326.java
r1032 r1169 12 12 public class Epsg4326 implements Projection { 13 13 14 15 16 14 public EastNorth latlon2eastNorth(LatLon p) { 15 return new EastNorth(p.lon(), p.lat()); 16 } 17 17 18 19 20 18 public LatLon eastNorth2latlon(EastNorth p) { 19 return new LatLon(p.north(), p.east()); 20 } 21 21 22 23 24 22 @Override public String toString() { 23 return tr("EPSG:4326"); 24 } 25 25 26 26 public String getCacheDirectoryName() { … … 28 28 } 29 29 30 31 30 public double scaleFactor() { 31 return 1.0/360; 32 32 } 33 33 34 35 36 34 @Override public boolean equals(Object o) { 35 return o instanceof Epsg4326; 36 } 37 37 38 39 40 38 @Override public int hashCode() { 39 return Epsg4326.class.hashCode(); 40 } 41 41 } -
trunk/src/org/openstreetmap/josm/data/projection/Lambert.java
r865 r1169 14 14 15 15 public class Lambert implements Projection { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 16 /** 17 * Lambert I, II, III, and IV projection exponents 18 */ 19 public static final double n[] = { 0.7604059656, 0.7289686274, 0.6959127966, 0.6712679322 }; 20 21 /** 22 * Lambert I, II, III, and IV projection constants 23 */ 24 public static final double c[] = { 11603796.98, 11745793.39, 11947992.52, 12136281.99 }; 25 26 /** 27 * Lambert I, II, III, and IV false east 28 */ 29 public static final double Xs[] = { 600000.0, 600000.0, 600000.0, 234.358 }; 30 31 /** 32 * Lambert I, II, III, and IV false north 33 */ 34 public static final double Ys[] = { 5657616.674, 6199695.768, 6791905.085, 7239161.542 }; 35 36 /** 37 * Lambert I, II, III, and IV longitudinal offset to Greenwich meridian 38 */ 39 public static final double lg0 = 0.04079234433198; // 2deg20'14.025" 40 41 /** 42 * precision in iterative schema 43 */ 44 45 public static final double epsilon = 1e-11; 46 47 /** 48 * France is divided in 4 Lambert projection zones (1,2,3 + 4th for Corsica) 49 */ 50 public static final double cMaxLatZone1 = Math.toRadians(57 * 0.9); 51 52 public static final double zoneLimits[] = { Math.toRadians(53.5 * 0.9), // between Zone 1 and Zone 2 (in grad *0.9) 53 Math.toRadians(50.5 * 0.9), // between Zone 2 and Zone 3 54 Math.toRadians(47.51963 * 0.9), // between Zone 3 and Zone 4 55 Math.toRadians(46.17821 * 0.9) };// lowest latitude of Zone 4 56 57 public static final double cMinLonZones = Math.toRadians(-4.9074074074074059 * 0.9); 58 59 public static final double cMaxLonZones = Math.toRadians(10.2 * 0.9); 60 61 /** 62 * Because josm cannot work correctly if two zones are displayed, we allow some overlapping 63 */ 64 public static final double cMaxOverlappingZones = Math.toRadians(1.5 * 0.9); 65 66 public static int layoutZone = -1; 67 68 private static int currentZone = 0; 69 70 private static boolean dontDisplayErrors = false; 71 72 /** 73 * @param p WGS84 lat/lon (ellipsoid GRS80) (in degree) 74 * @return eastnorth projection in Lambert Zone (ellipsoid Clark) 75 */ 76 public EastNorth latlon2eastNorth(LatLon p) { 77 // translate ellipsoid GRS80 (WGS83) => Clark 78 LatLon geo = GRS802Clark(p); 79 double lt = geo.lat(); // in radian 80 double lg = geo.lon(); 81 82 // check if longitude and latitude are inside the french Lambert zones 83 currentZone = 0; 84 boolean outOfLambertZones = false; 85 if (lt >= zoneLimits[3] && lt <= cMaxLatZone1 && lg >= cMinLonZones && lg <= cMaxLonZones) { 86 // zone I 87 if (lt > zoneLimits[0]) 88 currentZone = 0; 89 // zone II 90 else if (lt > zoneLimits[1]) 91 currentZone = 1; 92 // zone III 93 else if (lt > zoneLimits[2]) 94 currentZone = 2; 95 // zone III or IV 96 else if (lt > zoneLimits[3]) 97 // Note: zone IV is dedicated to Corsica island and extends from 47.8 to 98 // 45.9 degrees of latitude. There is an overlap with zone III that can be 99 // solved only with longitude (covers Corsica if lon > 7.2 degree) 100 if (lg < Math.toRadians(8 * 0.9)) 101 currentZone = 2; 102 else 103 currentZone = 3; 104 } else { 105 outOfLambertZones = true; // possible when MAX_LAT is used 106 if (p.lat() != 0 && Math.abs(p.lat()) != Projection.MAX_LAT 107 && p.lon() != 0 && Math.abs(p.lon()) != Projection.MAX_LON 108 && dontDisplayErrors == false) { 109 JOptionPane.showMessageDialog(Main.parent, 110 tr("The projection \"{0}\" is designed for\n" 111 + "latitudes between 46.1° and 57° only.\n" 112 + "Use another projection system if you are not using\n" 113 + "a french WMS server.\n" 114 + "Do not upload any data after this message.", this.toString())); 115 dontDisplayErrors = true; 116 } 117 } 118 if (!outOfLambertZones) { 119 if (layoutZone == -1) { 120 layoutZone = currentZone; 121 dontDisplayErrors = false; 122 } else if (layoutZone != currentZone) { 123 if ((currentZone < layoutZone && Math.abs(zoneLimits[currentZone] - lt) > cMaxOverlappingZones) 124 || (currentZone > layoutZone && Math.abs(zoneLimits[layoutZone] - lt) > cMaxOverlappingZones)) { 125 JOptionPane.showMessageDialog(Main.parent, 126 tr("IMPORTANT : data positionned far away from\n" 127 + "the current Lambert zone limits.\n" 128 + "Do not upload any data after this message.\n" 129 + "Undo your last action, Save your work \n" 130 + "and Start a new layer on the new zone.")); 131 layoutZone = -1; 132 dontDisplayErrors = true; 133 } else { 134 System.out.println("temporarily extend Lambert zone " + layoutZone + " projection at lat,lon:" 135 + lt + "," + lg); 136 } 137 } 138 } 139 if (layoutZone == -1) { 140 return ConicProjection(lt, lg, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]); 141 } // else 142 return ConicProjection(lt, lg, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]); 143 } 144 145 public LatLon eastNorth2latlon(EastNorth p) { 146 LatLon geo; 147 if (layoutZone == -1) 148 // possible until the Lambert zone is determined by latlon2eastNorth() with a valid LatLon 149 geo = Geographic(p, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]); 150 else 151 geo = Geographic(p, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]); 152 // translate ellipsoid Clark => GRS80 (WGS83) 153 LatLon wgs = Clark2GRS80(geo); 154 return new LatLon(Math.toDegrees(wgs.lat()), Math.toDegrees(wgs.lon())); 155 } 156 157 @Override public String toString() { 158 return tr("Lambert Zone (France)"); 159 } 160 161 public String getCacheDirectoryName() { 162 return "lambert"; 163 } 164 165 public double scaleFactor() { 166 return 1.0 / 360; 167 } 168 169 @Override 170 public boolean equals(Object o) { 171 return o instanceof Lambert; 172 } 173 174 @Override 175 public int hashCode() { 176 return Lambert.class.hashCode(); 177 } 178 179 /** 180 * Initializes from geographic coordinates. Note that reference ellipsoid 181 * used by Lambert is the Clark ellipsoid. 182 * 183 * @param lat latitude in grad 184 * @param lon longitude in grad 185 * @param Xs false east (coordinate system origin) in meters 186 * @param Ys false north (coordinate system origin) in meters 187 * @param c projection constant 188 * @param n projection exponent 189 * @return EastNorth projected coordinates in meter 190 */ 191 private EastNorth ConicProjection(double lat, double lon, double Xs, double Ys, double c, double n) { 192 double eslt = Ellipsoid.clarke.e * Math.sin(lat); 193 double l = Math.log(Math.tan(Math.PI / 4.0 + (lat / 2.0)) 194 * Math.pow((1.0 - eslt) / (1.0 + eslt), Ellipsoid.clarke.e / 2.0)); 195 double east = Xs + c * Math.exp(-n * l) * Math.sin(n * (lon - lg0)); 196 double north = Ys - c * Math.exp(-n * l) * Math.cos(n * (lon - lg0)); 197 return new EastNorth(east, north); 198 } 199 200 /** 201 * Initializes from projected coordinates (conic projection). Note that 202 * reference ellipsoid used by Lambert is Clark 203 * 204 * @param coord projected coordinates pair in meters 205 * @param Xs false east (coordinate system origin) in meters 206 * @param Ys false north (coordinate system origin) in meters 207 * @param c projection constant 208 * @param n projection exponent 209 * @return LatLon in radian 210 */ 211 private LatLon Geographic(EastNorth eastNorth, double Xs, double Ys, double c, double n) { 212 double dx = eastNorth.east() - Xs; 213 double dy = Ys - eastNorth.north(); 214 double R = Math.sqrt(dx * dx + dy * dy); 215 double gamma = Math.atan(dx / dy); 216 double l = -1.0 / n * Math.log(Math.abs(R / c)); 217 l = Math.exp(l); 218 double lon = lg0 + gamma / n; 219 double lat = 2.0 * Math.atan(l) - Math.PI / 2.0; 220 double delta = 1.0; 221 while (delta > epsilon) { 222 double eslt = Ellipsoid.clarke.e * Math.sin(lat); 223 double nlt = 2.0 * Math.atan(Math.pow((1.0 + eslt) / (1.0 - eslt), Ellipsoid.clarke.e / 2.0) * l) - Math.PI 224 / 2.0; 225 delta = Math.abs(nlt - lat); 226 lat = nlt; 227 } 228 return new LatLon(lat, lon); // in radian 229 } 230 231 /** 232 * Translate latitude/longitude in WGS84, (ellipsoid GRS80) to Lambert 233 * geographic, (ellipsoid Clark) 234 * 235 * @param wgs 236 * @return 237 */ 238 private LatLon GRS802Clark(LatLon wgs) { 239 double lat = Math.toRadians(wgs.lat()); // degree to radian 240 double lon = Math.toRadians(wgs.lon()); 241 // WGS84 geographic => WGS84 cartesian 242 double N = Ellipsoid.GRS80.a / (Math.sqrt(1.0 - Ellipsoid.GRS80.e2 * Math.sin(lat) * Math.sin(lat))); 243 double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon); 244 double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon); 245 double Z = (N * (1.0 - Ellipsoid.GRS80.e2)/* + height */) * Math.sin(lat); 246 // WGS84 => Lambert ellipsoide similarity 247 X += 168.0; 248 Y += 60.0; 249 Z += -320.0; 250 // Lambert cartesian => Lambert geographic 251 return Geographic(X, Y, Z, Ellipsoid.clarke); 252 } 253 254 /** 255 * @param lambert 256 * @return 257 */ 258 private LatLon Clark2GRS80(LatLon lambert) { 259 double lat = lambert.lat(); // in radian 260 double lon = lambert.lon(); 261 // Lambert geographic => Lambert cartesian 262 double N = Ellipsoid.clarke.a / (Math.sqrt(1.0 - Ellipsoid.clarke.e2 * Math.sin(lat) * Math.sin(lat))); 263 double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon); 264 double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon); 265 double Z = (N * (1.0 - Ellipsoid.clarke.e2)/* + height */) * Math.sin(lat); 266 // Lambert => WGS84 ellipsoide similarity 267 X += -168.0; 268 Y += -60.0; 269 Z += 320.0; 270 // WGS84 cartesian => WGS84 geographic 271 return Geographic(X, Y, Z, Ellipsoid.GRS80); 272 } 273 274 /** 275 * initializes from cartesian coordinates 276 * 277 * @param X 278 * 1st coordinate in meters 279 * @param Y 280 * 2nd coordinate in meters 281 * @param Z 282 * 3rd coordinate in meters 283 * @param ell 284 * reference ellipsoid 285 */ 286 private LatLon Geographic(double X, double Y, double Z, Ellipsoid ell) { 287 double norm = Math.sqrt(X * X + Y * Y); 288 double lg = 2.0 * Math.atan(Y / (X + norm)); 289 double lt = Math.atan(Z / (norm * (1.0 - (ell.a * ell.e2 / Math.sqrt(X * X + Y * Y + Z * Z))))); 290 double delta = 1.0; 291 while (delta > epsilon) { 292 double s2 = Math.sin(lt); 293 s2 *= s2; 294 double l = Math.atan((Z / norm) 295 / (1.0 - (ell.a * ell.e2 * Math.cos(lt) / (norm * Math.sqrt(1.0 - ell.e2 * s2))))); 296 delta = Math.abs(l - lt); 297 lt = l; 298 } 299 double s2 = Math.sin(lt); 300 s2 *= s2; 301 // h = norm / Math.cos(lt) - ell.a / Math.sqrt(1.0 - ell.e2 * s2); 302 return new LatLon(lt, lg); 303 } 304 304 305 305 } -
trunk/src/org/openstreetmap/josm/data/projection/Mercator.java
r1032 r1169 10 10 * Implement Mercator Projection code, coded after documentation 11 11 * from wikipedia. 12 * 13 * The center of the mercator projection is always the 0 grad 12 * 13 * The center of the mercator projection is always the 0 grad 14 14 * coordinate. 15 * 15 * 16 16 * @author imi 17 17 */ 18 18 public class Mercator implements Projection { 19 19 20 21 22 23 24 20 public EastNorth latlon2eastNorth(LatLon p) { 21 return new EastNorth( 22 p.lon()*Math.PI/180, 23 Math.log(Math.tan(Math.PI/4+p.lat()*Math.PI/360))); 24 } 25 25 26 27 28 29 30 26 public LatLon eastNorth2latlon(EastNorth p) { 27 return new LatLon( 28 Math.atan(Math.sinh(p.north()))*180/Math.PI, 29 p.east()*180/Math.PI); 30 } 31 31 32 33 34 32 @Override public String toString() { 33 return tr("Mercator"); 34 } 35 35 36 36 public String getCacheDirectoryName() { … … 38 38 } 39 39 40 41 40 public double scaleFactor() { 41 return 1/Math.PI/2; 42 42 } 43 43 44 45 46 44 @Override public boolean equals(Object o) { 45 return o instanceof Mercator; 46 } 47 47 48 49 50 48 @Override public int hashCode() { 49 return Mercator.class.hashCode(); 50 } 51 51 } -
trunk/src/org/openstreetmap/josm/data/projection/Projection.java
r656 r1169 6 6 7 7 /** 8 * Classes implementing this are able to convert lat/lon values to 8 * Classes implementing this are able to convert lat/lon values to 9 9 * planar screen coordinates. 10 * 10 * 11 11 * @author imi 12 12 */ 13 13 public interface Projection { 14 14 15 /** 16 * Maximum latitude representable. 17 */ 18 public static final double MAX_LAT = 85.05112877980659; // Mercator squares the world 19 20 /** 21 * Maximum longditude representable. 22 */ 23 public static final double MAX_LON = 180; 15 /** 16 * Maximum latitude representable. 17 */ 18 public static final double MAX_LAT = 85.05112877980659; // Mercator squares the world 24 19 25 26 * Minimum difference in location to not be represented as the same position.27 28 SERVER_PRECISION = 1e12;20 /** 21 * Maximum longditude representable. 22 */ 23 public static final double MAX_LON = 180; 29 24 30 /** 31 * List of all available projections. 32 */ 33 public static Projection[] allProjections = new Projection[]{ 34 new Epsg4326(), 35 new Mercator(), 36 new Lambert() 37 }; 38 39 /** 40 * Convert from lat/lon to northing/easting. 41 * 42 * @param p The geo point to convert. x/y members of the point are filled. 43 */ 44 EastNorth latlon2eastNorth(LatLon p); 45 46 /** 47 * Convert from norting/easting to lat/lon. 48 * 49 * @param p The geo point to convert. lat/lon members of the point are filled. 50 */ 51 LatLon eastNorth2latlon(EastNorth p); 25 /** 26 * Minimum difference in location to not be represented as the same position. 27 */ 28 public static final double MAX_SERVER_PRECISION = 1e12; 52 29 53 /** 54 * Describe the projection converter in one or two words. 55 */ 56 String toString(); 57 30 /** 31 * List of all available projections. 32 */ 33 public static Projection[] allProjections = new Projection[]{ 34 new Epsg4326(), 35 new Mercator(), 36 new Lambert() 37 }; 38 39 /** 40 * Convert from lat/lon to northing/easting. 41 * 42 * @param p The geo point to convert. x/y members of the point are filled. 43 */ 44 EastNorth latlon2eastNorth(LatLon p); 45 46 /** 47 * Convert from norting/easting to lat/lon. 48 * 49 * @param p The geo point to convert. lat/lon members of the point are filled. 50 */ 51 LatLon eastNorth2latlon(EastNorth p); 52 53 /** 54 * Describe the projection converter in one or two words. 55 */ 56 String toString(); 57 58 58 /** 59 59 * Get a filename compatible string (for the cache directory) 60 60 */ 61 61 String getCacheDirectoryName(); 62 62 63 63 /** 64 * The factor to multiply with an easting coordinate to get from "easting 64 * The factor to multiply with an easting coordinate to get from "easting 65 65 * units per pixel" to "meters per pixel" 66 66 */ -
trunk/src/org/openstreetmap/josm/gui/BookmarkList.java
r627 r1169 21 21 public class BookmarkList extends JList { 22 22 23 24 25 26 27 28 29 30 23 /** 24 * Create a bookmark list as well as the Buttons add and remove. 25 */ 26 public BookmarkList() { 27 setModel(new DefaultListModel()); 28 load(); 29 setVisibleRowCount(7); 30 } 31 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 32 /** 33 * Loads the bookmarks from file. 34 */ 35 public void load() { 36 DefaultListModel model = (DefaultListModel)getModel(); 37 model.removeAllElements(); 38 try { 39 for (Preferences.Bookmark b : Main.pref.loadBookmarks()) 40 model.addElement(b); 41 } catch (IOException e) { 42 e.printStackTrace(); 43 JOptionPane.showMessageDialog(Main.parent, tr("Could not read bookmarks.")+"\n"+e.getMessage()); 44 } 45 } 46 46 47 48 49 50 51 52 53 54 55 56 57 58 59 47 /** 48 * Save all bookmarks to the preferences file 49 */ 50 public void save() { 51 try { 52 Collection<Preferences.Bookmark> bookmarks = new LinkedList<Preferences.Bookmark>(); 53 for (Object o : ((DefaultListModel)getModel()).toArray()) 54 bookmarks.add((Preferences.Bookmark)o); 55 Main.pref.saveBookmarks(bookmarks); 56 } catch (IOException e) { 57 JOptionPane.showMessageDialog(Main.parent,tr("Could not write bookmark.")+"\n"+e.getMessage()); 58 } 59 } 60 60 } -
trunk/src/org/openstreetmap/josm/gui/ConflictResolver.java
r627 r1169 46 46 * three tables in the screen, one for each both sides and one resulting table. The user can 47 47 * move items from either one of the sides ("my" and "their") to the resulting table. 48 * 48 * 49 49 * @author Imi 50 50 */ 51 51 public class ConflictResolver extends JPanel { 52 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 53 public static enum Resolution {MY, THEIR} 54 55 private final class ConflictTableModel implements TableModel { 56 private final Resolution resolution; 57 public ConflictTableModel(Resolution resolution) { 58 this.resolution = resolution; 59 } 60 61 public int getRowCount() { 62 return conflicts.size(); 63 } 64 65 public Object getValueAt(int rowIndex, int columnIndex) { 66 ConflictItem ci = conflicts.get(rowIndex); 67 if (columnIndex == 0) 68 return ci.key(); 69 Resolution r = resolution == null ? ci.resolution : resolution; 70 if (r == null) 71 return "<html><i>???</i></html>"; 72 JLabel l = new JLabel(r == Resolution.MY ? ci.my : ci.their); 73 if (ci.resolution == resolution && resolution != null) 74 l.setFont(l.getFont().deriveFont(Font.BOLD)); 75 return l; 76 } 77 78 public String getColumnName(int columnIndex) {return columnIndex == 0 ? tr("Key") : tr("Value");} 79 public int getColumnCount() {return 2;} 80 public boolean isCellEditable(int row, int column) {return false;} 81 public Class<?> getColumnClass(int columnIndex) {return Object.class;} 82 83 public void addTableModelListener(TableModelListener l) {} 84 public void removeTableModelListener(TableModelListener l) {} 85 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {} 86 } 87 88 private final class DblClickListener extends MouseAdapter { 89 private final Resolution resolution; 90 public DblClickListener(Resolution resolution) { 91 this.resolution = resolution; 92 } 93 @Override public void mouseClicked(MouseEvent e) { 94 if (e.getClickCount() >= 2) { 95 int sel = ((JTable)e.getSource()).getSelectedRow(); 96 if (sel == -1) 97 return; 98 ConflictResolver.this.conflicts.get(sel).resolution = resolution; 99 repaint(); 100 } 101 } 102 } 103 private final class ResolveAction extends AbstractAction { 104 private final Resolution resolution; 105 public ResolveAction(String name, Resolution resolution) { 106 super(null, ImageProvider.get("dialogs", name)); 107 this.resolution = resolution; 108 } 109 public void actionPerformed(ActionEvent e) { 110 int sel = myTable.getSelectedRow(); 111 if (sel == -1) 112 return; 113 conflicts.get(sel).resolution = resolution; 114 if (sel == myTable.getRowCount()-1) 115 myTable.clearSelection(); 116 else 117 myTable.getSelectionModel().setSelectionInterval(sel+1, sel+1); 118 repaint(); 119 } 120 } 121 122 public final List<ConflictItem> conflicts = new ArrayList<ConflictItem>(); 123 124 private final ConflictTableModel my = new ConflictTableModel(Resolution.MY); 125 private final JTable myTable; 126 private final ConflictTableModel their = new ConflictTableModel(Resolution.THEIR); 127 private final JTable theirTable; 128 private final ConflictTableModel resolve = new ConflictTableModel(null); 129 private final JTable resolveTable; 130 131 132 public ConflictResolver(Map<OsmPrimitive, OsmPrimitive> conflicts) { 133 super(new GridBagLayout()); 134 Collection<ConflictItem> possibleConflicts = new ArrayList<ConflictItem>(); 135 possibleConflicts.add(new DeleteConflict()); 136 possibleConflicts.add(new PositionConflict()); 137 TreeSet<String> allkeys = new TreeSet<String>(); 138 for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) { 139 allkeys.addAll(e.getKey().keySet()); 140 allkeys.addAll(e.getValue().keySet()); 141 } 142 for (String s : allkeys) 143 possibleConflicts.add(new PropertyConflict(s)); 144 145 for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) { 146 for (Iterator<ConflictItem> it = possibleConflicts.iterator(); it.hasNext();) { 147 ConflictItem ci = it.next(); 148 if (ci.hasConflict(e.getKey(), e.getValue())) { 149 ci.initialize(conflicts); 150 this.conflicts.add(ci); 151 it.remove(); 152 } 153 } 154 } 155 156 157 // have to initialize the JTables here and not in the declaration, because its constructor 158 // may access this.conflicts (indirectly) 159 myTable = new JTable(my); 160 theirTable = new JTable(their); 161 resolveTable = new JTable(resolve); 162 163 myTable.setPreferredScrollableViewportSize(new Dimension(250,70)); 164 theirTable.setPreferredScrollableViewportSize(new Dimension(250,70)); 165 resolveTable.setPreferredScrollableViewportSize(new Dimension(250,70)); 166 167 TableCellRenderer renderer = new DefaultTableCellRenderer(){ 168 final Font defFont = new JLabel().getFont(); 169 @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 170 JLabel c = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 171 c.setIcon(null); 172 c.setFont(defFont); 173 if (value instanceof JLabel) { 174 JLabel l = (JLabel)value; 175 String text = l.getText(); 176 c.setText(text); 177 c.setFont(l.getFont()); 178 if (text.startsWith("<html>") && l.getFont().isBold()) 179 c.setText("<html>"+"<b>"+text.substring(6, text.length()-12)); 180 } else { 181 String s = value.toString(); 182 int i = s.indexOf('|'); 183 if (i != -1) { 184 c.setIcon(ImageProvider.get("data", s.substring(0,i))); 185 c.setText(s.substring(i+1)); 186 } 187 } 188 return c; 189 } 190 }; 191 myTable.setDefaultRenderer(Object.class, renderer); 192 theirTable.setDefaultRenderer(Object.class, renderer); 193 resolveTable.setDefaultRenderer(Object.class, renderer); 194 195 myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 196 theirTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 197 resolveTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 198 ListSelectionListener selListener = new ListSelectionListener(){ 199 public void valueChanged(ListSelectionEvent e) { 200 if (((ListSelectionModel)e.getSource()).isSelectionEmpty()) { 201 myTable.clearSelection(); 202 theirTable.clearSelection(); 203 resolveTable.clearSelection(); 204 } else { 205 int i = ((ListSelectionModel)e.getSource()).getMinSelectionIndex(); 206 myTable.scrollRectToVisible(myTable.getCellRect(i, 0, true)); 207 myTable.getSelectionModel().setSelectionInterval(i, i); 208 theirTable.scrollRectToVisible(theirTable.getCellRect(i, 0, true)); 209 theirTable.getSelectionModel().setSelectionInterval(i, i); 210 resolveTable.scrollRectToVisible(resolveTable.getCellRect(i, 0, true)); 211 resolveTable.getSelectionModel().setSelectionInterval(i, i); 212 } 213 } 214 }; 215 myTable.getSelectionModel().addListSelectionListener(selListener); 216 theirTable.getSelectionModel().addListSelectionListener(selListener); 217 resolveTable.getSelectionModel().addListSelectionListener(selListener); 218 myTable.getSelectionModel().setSelectionInterval(0,0); 219 220 myTable.addMouseListener(new DblClickListener(Resolution.MY)); 221 theirTable.addMouseListener(new DblClickListener(Resolution.THEIR)); 222 resolveTable.addMouseListener(new DblClickListener(null)); 223 224 add(new JLabel(trn("{0} object has conflicts:","{0} objects have conflicts:",conflicts.size(),conflicts.size())), GBC.eol().insets(0,0,0,10)); 225 226 JPanel p = new JPanel(new GridBagLayout()); 227 p.add(new JLabel(tr("my version:")), GBC.eol()); 228 p.add(new JScrollPane(myTable), GBC.eol().fill(GBC.BOTH)); 229 p.add(new JButton(new ResolveAction("down", Resolution.MY)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0)); 230 add(p, GBC.std().insets(0,0,5,0)); 231 232 p = new JPanel(new GridBagLayout()); 233 p.add(new JLabel(tr("their version:")), GBC.eol()); 234 p.add(new JScrollPane(theirTable), GBC.eol().fill(GBC.BOTH)); 235 p.add(new JButton(new ResolveAction("down", Resolution.THEIR)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0)); 236 add(p, GBC.eop().insets(5,0,0,0)); 237 238 add(new JButton(new ResolveAction("up", null)), GBC.eol().anchor(GBC.CENTER)); 239 add(new JLabel(tr("resolved version:")), GBC.eol().insets(0,5,0,0)); 240 add(new JScrollPane(resolveTable), GBC.eol().anchor(GBC.CENTER).fill(GBC.BOTH)); 241 } 242 242 } -
trunk/src/org/openstreetmap/josm/gui/GettingStarted.java
r1163 r1169 25 25 public class GettingStarted extends JPanel { 26 26 27 static private String content = ""; 27 static private String content = ""; 28 28 29 29 public class LinkGeneral extends JEditorPane implements HyperlinkListener { … … 74 74 boolean included = false; 75 75 if (condition.equals("%3E")) { 76 if ((myVersion == 0 || myVersion > targetVersion) 76 if ((myVersion == 0 || myVersion > targetVersion) 77 77 /* && ! Main.pref.getBoolean("motd.gt."+targetVersion) */) { 78 78 /* Main.pref.put("motd.gt."+targetVersion, true); */ … … 80 80 } 81 81 } else if (condition.equals("%3E%3D")) { 82 if ((myVersion == 0 || myVersion >= targetVersion) 82 if ((myVersion == 0 || myVersion >= targetVersion) 83 83 /* && ! Main.pref.getBoolean("motd.ge."+targetVersion) */) { 84 84 /* Main.pref.put("motd.ge."+targetVersion, true); */ … … 114 114 content += wr.read(url).replace("<html>", "").replace("</html>", "").replace("<div id=\"searchable\">", "").replace("</div>", ""); 115 115 } catch (IOException ioe2) { 116 } 117 } 116 } 117 } 118 118 } 119 119 } 120 120 content += motdcontent.substring(start); 121 121 content = content.replace("<html>", "<html><style type=\"text/css\">\nbody { font-family: sans-serif; font-weight: bold; }\nh1 {text-align: center;}</style>"); 122 /* replace the wiki title */ 123 content = content.replace("JOSM, the Java OpenStreetMap editor", tr("JOSM, the Java OpenStreetMap editor")); 122 /* replace the wiki title */ 123 content = content.replace("JOSM, the Java OpenStreetMap editor", tr("JOSM, the Java OpenStreetMap editor")); 124 124 } 125 125 126 126 } 127 127 128 128 public GettingStarted() { 129 129 super(new BorderLayout()); 130 130 assignContent(); 131 131 132 132 // panel.add(GBC.glue(0,1), GBC.eol()); 133 133 //panel.setMinimumSize(new Dimension(400, 600)); -
trunk/src/org/openstreetmap/josm/gui/IconToggleButton.java
r627 r1169 18 18 public class IconToggleButton extends JToggleButton implements PropertyChangeListener { 19 19 20 20 public boolean groupbutton; 21 21 22 23 24 25 26 27 22 /** 23 * Construct the toggle button with the given action. 24 */ 25 public IconToggleButton(Action action) { 26 super(action); 27 setText(null); 28 28 29 30 31 29 Object o = action.getValue(Action.SHORT_DESCRIPTION); 30 if (o != null) 31 setToolTipText(o.toString()); 32 32 33 34 35 36 37 33 action.addPropertyChangeListener(this); 34 35 addMouseListener(new MouseAdapter(){ 36 @Override public void mousePressed(MouseEvent e) { 37 groupbutton = e.getX() > getWidth()/2 && e.getY() > getHeight()/2; 38 38 } 39 40 39 }); 40 } 41 41 42 43 44 45 46 47 42 public void propertyChange(PropertyChangeEvent evt) { 43 if (evt.getPropertyName().equals("active")) { 44 setSelected((Boolean)evt.getNewValue()); 45 requestFocusInWindow(); 46 } 47 } 48 48 } -
trunk/src/org/openstreetmap/josm/gui/JMultilineLabel.java
r729 r1169 1 1 // License: GPL. For details, see LICENSE file. 2 2 3 // This class was taken from 3 // This class was taken from 4 4 // http://forum.java.sun.com/thread.jspa?threadID=459705&messageID=2104021 5 5 // - Removed hardcoded margin … … 22 22 23 23 public class JMultilineLabel extends JComponent { 24 25 26 27 24 private String text; 25 private int maxWidth = Integer.MAX_VALUE; 26 private boolean justify; 27 private final FontRenderContext frc = new FontRenderContext(null, false, false); 28 28 29 30 31 32 29 public JMultilineLabel(String description) { 30 super(); 31 setText(description); 32 } 33 33 34 35 36 37 34 private void morph() { 35 revalidate(); 36 repaint(); 37 } 38 38 39 40 41 39 public String getText() { 40 return text; 41 } 42 42 43 44 45 46 47 48 49 43 public void setText(String text) { 44 String old = this.text; 45 this.text = text; 46 firePropertyChange("text", old, this.text); 47 if ((old == null) ? text!=null : !old.equals(text)) 48 morph(); 49 } 50 50 51 52 53 51 public int getMaxWidth() { 52 return maxWidth; 53 } 54 54 55 56 57 58 59 60 61 62 63 55 public void setMaxWidth(int maxWidth) { 56 if (maxWidth <= 0) 57 throw new IllegalArgumentException(); 58 int old = this.maxWidth; 59 this.maxWidth = maxWidth; 60 firePropertyChange("maxWidth", old, this.maxWidth); 61 if (old != this.maxWidth) 62 morph(); 63 } 64 64 65 66 67 65 public boolean isJustified() { 66 return justify; 67 } 68 68 69 70 71 72 73 74 75 69 public void setJustified(boolean justify) { 70 boolean old = this.justify; 71 this.justify = justify; 72 firePropertyChange("justified", old, this.justify); 73 if (old != this.justify) 74 repaint(); 75 } 76 76 77 78 79 77 public Dimension getPreferredSize() { 78 return paintOrGetSize(null, getMaxWidth()); 79 } 80 80 81 82 83 81 public Dimension getMinimumSize() { 82 return getPreferredSize(); 83 } 84 84 85 86 87 88 85 protected void paintComponent(Graphics g) { 86 super.paintComponent(g); 87 paintOrGetSize((Graphics2D)g, getWidth()); 88 } 89 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 90 private Dimension paintOrGetSize(Graphics2D g, int width) { 91 Insets insets = getInsets(); 92 width -= insets.left + insets.right; 93 float w = insets.left + insets.right; 94 float x = insets.left, y=insets.top; 95 if (width > 0 && text != null && text.length() > 0) { 96 AttributedString as = new AttributedString(getText()); 97 as.addAttribute(TextAttribute.FONT, getFont()); 98 AttributedCharacterIterator aci = as.getIterator(); 99 LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc); 100 float max = 0; 101 while (lbm.getPosition() < aci.getEndIndex()) { 102 TextLayout textLayout = lbm.nextLayout(width); 103 if (g != null && isJustified() && textLayout.getVisibleAdvance() > 0.80 * width) 104 textLayout = textLayout.getJustifiedLayout(width); 105 if (g != null) 106 textLayout.draw(g, x, y + textLayout.getAscent()); 107 y += textLayout.getDescent() + textLayout.getLeading() + textLayout.getAscent(); 108 max = Math.max(max, textLayout.getVisibleAdvance()); 109 } 110 w += max; 111 } 112 return new Dimension((int)Math.ceil(w), (int)Math.ceil(y) + insets.bottom); 113 } 114 114 } -
trunk/src/org/openstreetmap/josm/gui/MainApplet.java
r1146 r1169 33 33 public class MainApplet extends JApplet { 34 34 35 36 37 38 35 public static final class UploadPreferencesAction extends JosmAction { 36 public UploadPreferencesAction() { 37 super(tr("Upload Preferences"), "upload-preferences", tr("Upload the current preferences to the server"), 38 Shortcut.registerShortcut("applet:uploadprefs", tr("Upload Preferences"), KeyEvent.VK_U, Shortcut.GROUP_HOTKEY), true); 39 39 } 40 41 42 40 public void actionPerformed(ActionEvent e) { 41 ((ServerSidePreferences)Main.pref).upload(); 42 } 43 43 } 44 44 45 45 private final class MainCaller extends Main { 46 47 48 49 50 51 46 private MainCaller() { 47 setContentPane(contentPane); 48 setJMenuBar(menu); 49 setBounds(bounds); 50 } 51 } 52 52 53 54 55 56 57 58 59 60 61 53 private final static String[][] paramInfo = { 54 {"username", tr("string"), tr("Name of the user.")}, 55 {"password", tr("string"), tr("OSM Password.")}, 56 {"geometry", tr("string"), tr("Resize the applet to the given geometry (format: WIDTHxHEIGHT)")}, 57 {"download", tr("string;string;..."), tr("Download each. Can be x1,y1,x2,y2 an url containing lat=y&lon=x&zoom=z or a filename")}, 58 {"downloadgps", tr("string;string;..."), tr("Download each as raw gps. Can be x1,y1,x2,y2 an url containing lat=y&lon=x&zoom=z or a filename")}, 59 {"selection", tr("string;string;..."), tr("Add each to the initial selection. Can be a google-like search string or an url which returns osm-xml")}, 60 {"reset-preferences", tr("any"),tr("If specified, reset the configuration instead of reading it.")} 61 }; 62 62 63 63 private Map<String, Collection<String>> args = new HashMap<String, Collection<String>>(); 64 64 65 66 67 65 @Override public String[][] getParameterInfo() { 66 return paramInfo; 67 } 68 68 69 70 71 72 73 74 75 76 77 78 69 @Override public void init() { 70 for (String[] s : paramInfo) { 71 Collection<String> p = readParameter(s[0], args.get(s[0])); 72 if (p != null) 73 args.put(s[0], p); 74 } 75 if (!args.containsKey("geometry") && getParameter("width") != null && getParameter("height") != null) { 76 args.put("geometry", Arrays.asList(new String[]{getParameter("width")+"x"+getParameter("height")})); 77 } 78 } 79 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 80 @Override public void start() { 81 String username = args.containsKey("username") ? args.get("username").iterator().next() : null; 82 String password = args.containsKey("password") ? args.get("password").iterator().next() : null; 83 if (username == null || password == null) { 84 JPanel p = new JPanel(new GridBagLayout()); 85 p.add(new JLabel(tr("Username")), GBC.std().insets(0,0,20,0)); 86 JTextField user = new JTextField(username == null ? "" : username); 87 p.add(user, GBC.eol().fill(GBC.HORIZONTAL)); 88 p.add(new JLabel(tr("Password")), GBC.std().insets(0,0,20,0)); 89 JPasswordField pass = new JPasswordField(password == null ? "" : password); 90 p.add(pass, GBC.eol().fill(GBC.HORIZONTAL)); 91 JOptionPane.showMessageDialog(null, p); 92 username = user.getText(); 93 password = new String(pass.getPassword()); 94 args.put("password", Arrays.asList(new String[]{password})); 95 } 96 96 97 98 99 97 Main.applet = true; 98 Main.pref = new ServerSidePreferences(getCodeBase()); 99 ((ServerSidePreferences)Main.pref).download(username, password); 100 100 101 102 103 101 Main.preConstructorInit(args); 102 Main.parent = this; 103 new MainCaller().postConstructorProcessCmdLine(args); 104 104 105 105 MainMenu m = Main.main.menu; // shortcut 106 106 107 108 109 110 111 112 113 114 115 107 // remove offending stuff from JOSM (that would break the SecurityManager) 108 m.remove(m.fileMenu); 109 m.editMenu.add(new UploadPreferencesAction()); 110 m.openFile.setEnabled(false); 111 m.exit.setEnabled(false); 112 m.save.setEnabled(false); 113 m.saveAs.setEnabled(false); 114 m.gpxExport.setEnabled(false); 115 } 116 116 117 118 119 120 121 122 123 124 125 117 private Collection<String> readParameter(String s, Collection<String> v) { 118 String param = getParameter(s); 119 if (param != null) { 120 if (v == null) 121 v = new LinkedList<String>(); 122 v.addAll(Arrays.asList(param.split(";"))); 123 } 124 return v; 125 } 126 126 127 128 129 130 131 132 133 127 public static void main(String[] args) { 128 final JFrame frame = new JFrame("Java OpenStreetMap Applet"); 129 MainApplet applet = new MainApplet(); 130 applet.setStub(new AppletStub() { 131 public void appletResize(int w, int h) { 132 frame.setSize(w, h); 133 } 134 134 135 136 137 135 public AppletContext getAppletContext() { 136 return null; 137 } 138 138 139 140 141 142 143 144 145 146 139 public URL getCodeBase() { 140 try { 141 return new File(".").toURI().toURL(); 142 } catch (Exception e) { 143 e.printStackTrace(); 144 return null; 145 } 146 } 147 147 148 149 150 148 public URL getDocumentBase() { 149 return getCodeBase(); 150 } 151 151 152 153 154 152 public String getParameter(String k) { 153 return null; 154 } 155 155 156 157 158 159 160 161 162 163 164 156 public boolean isActive() { 157 return true; 158 } 159 }); 160 applet.init(); 161 applet.start(); 162 frame.setContentPane(applet); 163 frame.setVisible(true); 164 } 165 165 } -
trunk/src/org/openstreetmap/josm/gui/MainApplication.java
r1082 r1169 37 37 */ 38 38 public class MainApplication extends Main { 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 39 /** 40 * Allow subclassing (see JOSM.java) 41 */ 42 public MainApplication() {} 43 44 /** 45 * Construct an main frame, ready sized and operating. Does not 46 * display the frame. 47 */ 48 public MainApplication(JFrame mainFrame) { 49 super(); 50 mainFrame.setContentPane(contentPane); 51 mainFrame.setJMenuBar(menu); 52 mainFrame.setBounds(bounds); 53 mainFrame.setIconImage(ImageProvider.get("logo.png").getImage()); 54 mainFrame.addWindowListener(new WindowAdapter(){ 55 @Override public void windowClosing(final WindowEvent arg0) { 56 if (Main.breakBecauseUnsavedChanges()) 57 return; 58 System.exit(0); 59 } 60 }); 61 mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 62 } 63 64 /** 65 * Main application Startup 66 */ 67 public static void main(final String[] argArray) { 68 ///////////////////////////////////////////////////////////////////////// 69 // TO ALL TRANSLATORS 70 ///////////////////////////////////////////////////////////////////////// 71 // Do not translate the early strings below until the locale is set up. 72 // (By the eager loaded plugins) 73 // 74 // These strings cannot be translated. That's life. Really. Sorry. 75 // 76 // Imi. 77 ///////////////////////////////////////////////////////////////////////// 78 79 Thread.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler()); 80 81 // initialize the plaform hook, and 82 Main.determinePlatformHook(); 83 // call the really early hook before we anything else 84 Main.platform.preStartupHook(); 85 86 // construct argument table 87 List<String> argList = Arrays.asList(argArray); 88 final Map<String, Collection<String>> args = new HashMap<String, Collection<String>>(); 89 for (String arg : argArray) { 90 if (!arg.startsWith("--")) 91 arg = "--download="+arg; 92 int i = arg.indexOf('='); 93 String key = i == -1 ? arg.substring(2) : arg.substring(2,i); 94 String value = i == -1 ? "" : arg.substring(i+1); 95 Collection<String> v = args.get(key); 96 if (v == null) 97 v = new LinkedList<String>(); 98 v.add(value); 99 args.put(key, v); 100 } 101 102 if (argList.contains("--help") || argList.contains("-?") || argList.contains("-h")) { 103 // TODO: put in a platformHook for system that have no console by default 104 System.out.println(tr("Java OpenStreetMap Editor")+"\n\n"+ 105 tr("usage")+":\n"+ 106 "\tjava -jar josm.jar <option> <option> <option>...\n\n"+ 107 tr("options")+":\n"+ 108 "\t--help|-?|-h "+tr("Show this help")+"\n"+ 109 "\t--geometry=widthxheight(+|-)x(+|-)y "+tr("Standard unix geometry argument")+"\n"+ 110 "\t[--download=]minlat,minlon,maxlat,maxlon "+tr("Download the bounding box")+"\n"+ 111 "\t[--download=]<url> "+tr("Download the location at the url (with lat=x&lon=y&zoom=z)")+"\n"+ 112 "\t[--download=]<filename> "+tr("Open file (as raw gps, if .gpx)")+"\n"+ 113 "\t--downloadgps=minlat,minlon,maxlat,maxlon "+tr("Download the bounding box as raw gps")+"\n"+ 114 "\t--selection=<searchstring> "+tr("Select with the given search")+"\n"+ 115 "\t--no-fullscreen "+tr("Don't launch in fullscreen mode")+"\n"+ 116 "\t--reset-preferences "+tr("Reset the preferences to default")+"\n\n"+ 117 "\t--language=<language> "+tr("Set the language.")+"\n\n"+ 118 tr("examples")+":\n"+ 119 "\tjava -jar josm.jar track1.gpx track2.gpx london.osm\n"+ 120 "\tjava -jar josm.jar http://www.openstreetmap.org/index.html?lat=43.2&lon=11.1&zoom=13\n"+ 121 "\tjava -jar josm.jar london.osm --selection=http://www.ostertag.name/osm/OSM_errors_node-duplicate.xml\n"+ 122 "\tjava -jar josm.jar 43.2,11.1,43.4,11.4\n\n"+ 123 124 tr("Parameters are read in the order they are specified, so make sure you load\n"+ 125 "some data before --selection")+"\n\n"+ 126 tr("Instead of --download=<bbox> you may specify osm://<bbox>\n")); 127 System.exit(0); 128 } 129 130 // get the preferences. 131 final File prefDir = new File(Main.pref.getPreferencesDir()); 132 // check if preferences directory has moved (TODO: Update code. Remove this after some time) 133 File oldPrefDir = new File(System.getProperty("user.home"), ".josm"); 134 if (!prefDir.isDirectory() && oldPrefDir.isDirectory()) { 135 if (oldPrefDir.renameTo(prefDir)) { 136 // do not translate this 137 JOptionPane.showMessageDialog(null, "The preference directory has been moved to "+prefDir); 138 } else { 139 JOptionPane.showMessageDialog(null, "The preference directory location has changed. Please move "+oldPrefDir+" to "+prefDir); 140 } 141 } 142 143 if (prefDir.exists() && !prefDir.isDirectory()) { 144 JOptionPane.showMessageDialog(null, "Cannot open preferences directory: "+Main.pref.getPreferencesDir()); 145 return; 146 } 147 if (!prefDir.exists()) 148 prefDir.mkdirs(); 149 150 if (!new File(Main.pref.getPreferencesDir()+"preferences").exists()) { 151 Main.pref.resetToDefault(); 152 } 153 154 try { 155 if (args.containsKey("reset-preferences")) { 156 Main.pref.resetToDefault(); 157 } else { 158 Main.pref.load(); 159 } 160 } catch (final IOException e1) { 161 e1.printStackTrace(); 162 String backup = Main.pref.getPreferencesDir() + "preferences.bak"; 163 JOptionPane.showMessageDialog(null, "Preferences file had errors. Making backup of old one to " + backup); 164 new File(Main.pref.getPreferencesDir() + "preferences").renameTo(new File(backup)); 165 Main.pref.save(); 166 } 167 167 168 168 // TODO remove this in early 2009 - just here to weed out color setting we don't use any more 169 169 Main.pref.put("downloaded Area", null); 170 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 171 String localeName = null; //The locale to use 172 173 //Check if passed as parameter 174 if(args.containsKey("language")) 175 localeName = (String)(args.get("language").toArray()[0]); 176 177 if (localeName == null) { 178 localeName = Main.pref.get("language", null); 179 } 180 181 if (localeName != null) { 182 Locale l; 183 int i = localeName.indexOf('_'); 184 if (i > 0) { 185 l = new Locale(localeName.substring(0, i), localeName.substring(i + 1)); 186 } else { 187 l = new Locale(localeName); 188 } 189 Locale.setDefault(l); 190 } 191 191 try { 192 192 i18n = I18nFactory.getI18n(MainApplication.class); … … 194 194 System.out.println("Unable to find translation for the locale: " + Locale.getDefault().getDisplayName() + " reverting to English."); 195 195 } 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 196 197 SplashScreen splash = new SplashScreen(Main.pref.getBoolean("draw.splashscreen", true)); 198 199 splash.setStatus(tr("Activating updated plugins")); 200 if (!PluginDownloader.moveUpdatedPlugins()) { 201 JOptionPane.showMessageDialog(null, 202 tr("Activating the updated plugins failed. Check if JOSM has the permission to overwrite the existing ones."), 203 tr("Plugins"), JOptionPane.ERROR_MESSAGE); 204 } 205 206 // load the early plugins 207 splash.setStatus(tr("Loading early plugins")); 208 Main.loadPlugins(true); 209 210 splash.setStatus(tr("Setting defaults")); 211 preConstructorInit(args); 212 splash.setStatus(tr("Creating main GUI")); 213 JFrame mainFrame = new JFrame(tr("Java OpenStreetMap - Editor")); 214 Main.parent = mainFrame; 215 final Main main = new MainApplication(mainFrame); 216 splash.setStatus(tr("Loading plugins")); 217 Main.loadPlugins(false); 218 toolbar.refreshToolbarControl(); 219 220 mainFrame.setVisible(true); 221 splash.closeSplash(); 222 223 if (!args.containsKey("no-fullscreen") && !args.containsKey("geometry") && Toolkit.getDefaultToolkit().isFrameStateSupported(JFrame.MAXIMIZED_BOTH)) 224 mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH); 225 226 EventQueue.invokeLater(new Runnable(){ 227 public void run() { 228 main.postConstructorProcessCmdLine(args); 229 } 230 }); 231 } 232 232 233 233 } -
trunk/src/org/openstreetmap/josm/gui/MainMenu.java
r1161 r1169 68 68 * This is the JOSM main menu bar. It is overwritten to initialize itself and provide all menu 69 69 * entries as member variables (sort of collect them). 70 * 70 * 71 71 * It also provides possibilities to attach new menu entries (used by plugins). 72 * 72 * 73 73 * @author Immanuel.Scholz 74 74 */ … … 140 140 /** 141 141 * Add a JosmAction to a menu. 142 * 142 * 143 143 * This method handles all the shortcut handling. It also makes sure that actions that are 144 144 * handled by the OS are not duplicated on the menu. … … 156 156 /** 157 157 * Add a menu to the main menu. 158 * 158 * 159 159 * This method handles all the shortcut handling. 160 160 */ -
trunk/src/org/openstreetmap/josm/gui/MapFrame.java
r1153 r1169 35 35 * One Map frame with one dataset behind. This is the container gui class whose 36 36 * display can be set to the different views. 37 * 37 * 38 38 * @author imi 39 39 */ 40 40 public class MapFrame extends JPanel implements Destroyable { 41 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 } 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 * 190 191 192 193 194 195 196 197 198 199 200 201 202 42 /** 43 * The current mode, this frame operates. 44 */ 45 public MapMode mapMode; 46 /** 47 * The view control displayed. 48 */ 49 public MapView mapView; 50 /** 51 * The toolbar with the action icons. To add new toggle dialog actions, use addToggleDialog 52 * instead of adding directly to this list. To add a new mode use addMapMode. 53 */ 54 public JToolBar toolBarActions = new JToolBar(JToolBar.VERTICAL); 55 public JToolBar toolBarToggle = new JToolBar(JToolBar.VERTICAL); 56 /** 57 * The status line below the map 58 */ 59 public MapStatus statusLine; 60 61 public ConflictDialog conflictDialog; 62 /** 63 * The dialog that shows all relations and lets the user edit them. 64 */ 65 public RelationListDialog relationListDialog; 66 /** 67 * The panel list of all toggle dialog icons. To add new toggle dialog actions, use addToggleDialog 68 * instead of adding directly to this list. 69 */ 70 public JPanel toggleDialogs = new JPanel(); 71 72 public final ButtonGroup toolGroup = new ButtonGroup(); 73 74 public MapFrame() { 75 setSize(400,400); 76 setLayout(new BorderLayout()); 77 78 add(mapView = new MapView(), BorderLayout.CENTER); 79 80 // show menu entry 81 Main.main.menu.viewMenu.setVisible(true); 82 83 // toolbar 84 toolBarActions.setFloatable(false); 85 addMapMode(new IconToggleButton(new ZoomAction(this))); 86 addMapMode(new IconToggleButton(new SelectAction(this))); 87 addMapMode(new IconToggleButton(new DrawAction(this))); 88 addMapMode(new IconToggleButton(new DeleteAction(this))); 89 addMapMode(new IconToggleButton(new ExtrudeAction(this))); 90 91 toolGroup.setSelected(((AbstractButton)toolBarActions.getComponent(0)).getModel(), true); 92 93 add(toggleDialogs, BorderLayout.EAST); 94 toggleDialogs.setLayout(new BoxLayout(toggleDialogs, BoxLayout.Y_AXIS)); 95 96 toolBarToggle.setFloatable(false); 97 addToggleDialog(new LayerListDialog(this)); 98 addToggleDialog(new PropertiesDialog(this)); 99 addToggleDialog(new HistoryDialog()); 100 addToggleDialog(new SelectionListDialog()); 101 addToggleDialog(new UserListDialog()); 102 addToggleDialog(conflictDialog = new ConflictDialog()); 103 addToggleDialog(new CommandStackDialog(this)); 104 addToggleDialog(relationListDialog = new RelationListDialog()); 105 106 // status line below the map 107 statusLine = new MapStatus(this); 108 } 109 110 /** 111 * Called as some kind of destructor when the last layer has been removed. 112 * Delegates the call to all Destroyables within this component (e.g. MapModes) 113 */ 114 public void destroy() { 115 for (int i = 0; i < toolBarActions.getComponentCount(); ++i) 116 if (toolBarActions.getComponent(i) instanceof Destroyable) 117 ((Destroyable)toolBarActions).destroy(); 118 for (int i = 0; i < toolBarToggle.getComponentCount(); ++i) 119 if (toolBarToggle.getComponent(i) instanceof Destroyable) 120 ((Destroyable)toolBarToggle).destroy(); 121 122 // remove menu entries 123 Main.main.menu.viewMenu.setVisible(false); 124 } 125 126 public Action getDefaultButtonAction() { 127 return ((AbstractButton)toolBarActions.getComponent(0)).getAction(); 128 } 129 130 /** 131 * Open all ToggleDialogs that have their preferences property set. Close all others. 132 */ 133 public void setVisibleDialogs() { 134 for (Component c : toggleDialogs.getComponents()) { 135 if (c instanceof ToggleDialog) { 136 boolean sel = Main.pref.getBoolean(((ToggleDialog)c).prefName+".visible"); 137 ((ToggleDialog)c).action.button.setSelected(sel); 138 c.setVisible(sel); 139 } 140 } 141 } 142 143 /** 144 * Call this to add new toggle dialogs to the left button-list 145 * @param dlg The toggle dialog. It must not be in the list already. 146 */ 147 public void addToggleDialog(ToggleDialog dlg) { 148 IconToggleButton button = new IconToggleButton(dlg.action); 149 dlg.action.button = button; 150 dlg.parent = toggleDialogs; 151 toolBarToggle.add(button); 152 toggleDialogs.add(dlg); 153 } 154 155 public void addMapMode(IconToggleButton b) { 156 toolBarActions.add(b); 157 toolGroup.add((AbstractButton)b); 158 } 159 160 /** 161 * Fires an property changed event "visible". 162 */ 163 @Override public void setVisible(boolean aFlag) { 164 boolean old = isVisible(); 165 super.setVisible(aFlag); 166 if (old != aFlag) 167 firePropertyChange("visible", old, aFlag); 168 } 169 170 171 172 /** 173 * Change the operating map mode for the view. Will call unregister on the 174 * old MapMode and register on the new one. 175 * @param mapMode The new mode to set. 176 */ 177 public void selectMapMode(MapMode mapMode) { 178 if (mapMode == this.mapMode) 179 return; 180 if (this.mapMode != null) 181 this.mapMode.exitMode(); 182 this.mapMode = mapMode; 183 mapMode.enterMode(); 184 } 185 186 /** 187 * Fill the given panel by adding all necessary components to the different 188 * locations. 189 * 190 * @param panel The container to fill. Must have an BorderLayout. 191 */ 192 public void fillPanel(Container panel) { 193 panel.add(this, BorderLayout.CENTER); 194 JToolBar jb = new JToolBar(JToolBar.VERTICAL); 195 jb.setFloatable(false); 196 jb.add(toolBarActions); 197 jb.addSeparator(); 198 jb.add(toolBarToggle); 199 panel.add(jb, BorderLayout.WEST); 200 if (statusLine != null) 201 panel.add(statusLine, BorderLayout.SOUTH); 202 } 203 203 } -
trunk/src/org/openstreetmap/josm/gui/MapMover.java
r1084 r1169 28 28 public class MapMover extends MouseAdapter implements MouseMotionListener, MouseWheelListener { 29 29 30 31 32 33 30 private final class ZoomerAction extends AbstractAction { 31 private final String action; 32 public ZoomerAction(String action) { 33 this.action = action; 34 34 } 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 } 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 35 public void actionPerformed(ActionEvent e) { 36 if (action.equals(".") || action.equals(",")) { 37 Point mouse = nc.getMousePosition(); 38 if (mouse == null) 39 mouse = new Point((int)nc.getBounds().getCenterX(), (int)nc.getBounds().getCenterY()); 40 MouseWheelEvent we = new MouseWheelEvent(nc, e.getID(), e.getWhen(), e.getModifiers(), mouse.x, mouse.y, 0, false, MouseWheelEvent.WHEEL_UNIT_SCROLL, 1, action.equals(",") ? -1 : 1); 41 mouseWheelMoved(we); 42 } else { 43 EastNorth center = nc.getCenter(); 44 EastNorth newcenter = nc.getEastNorth(nc.getWidth()/2+nc.getWidth()/5, nc.getHeight()/2+nc.getHeight()/5); 45 if (action.equals("left")) 46 nc.zoomTo(new EastNorth(2*center.east()-newcenter.east(), center.north()), nc.getScale()); 47 else if (action.equals("right")) 48 nc.zoomTo(new EastNorth(newcenter.east(), center.north()), nc.getScale()); 49 else if (action.equals("up")) 50 nc.zoomTo(new EastNorth(center.east(), 2*center.north()-newcenter.north()), nc.getScale()); 51 else if (action.equals("down")) 52 nc.zoomTo(new EastNorth(center.east(), newcenter.north()), nc.getScale()); 53 } 54 } 55 } 56 57 /** 58 * The point in the map that was the under the mouse point 59 * when moving around started. 60 */ 61 private EastNorth mousePosMove; 62 /** 63 * The map to move around. 64 */ 65 private final NavigatableComponent nc; 66 /** 67 * The old cursor when we changed it to movement cursor. 68 */ 69 private Cursor oldCursor; 70 71 private boolean movementInPlace = false; 72 73 /** 74 * Create a new MapMover 75 */ 76 public MapMover(NavigatableComponent navComp, JPanel contentPane) { 77 this.nc = navComp; 78 nc.addMouseListener(this); 79 nc.addMouseMotionListener(this); 80 nc.addMouseWheelListener(this); 81 82 if (contentPane != null) { 83 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 84 Shortcut.registerShortcut("system:movefocusright", tr("Map: {0}", tr("Move right")), KeyEvent.VK_RIGHT, Shortcut.GROUP_HOTKEY).getKeyStroke(), 85 "MapMover.Zoomer.right"); 86 contentPane.getActionMap().put("MapMover.Zoomer.right", new ZoomerAction("right")); 87 88 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 89 Shortcut.registerShortcut("system:movefocusleft", tr("Map: {0}", tr("Move left")), KeyEvent.VK_LEFT, Shortcut.GROUP_HOTKEY).getKeyStroke(), 90 "MapMover.Zoomer.left"); 91 contentPane.getActionMap().put("MapMover.Zoomer.left", new ZoomerAction("left")); 92 93 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 94 Shortcut.registerShortcut("system:movefocusup", tr("Map: {0}", tr("Move up")), KeyEvent.VK_UP, Shortcut.GROUP_HOTKEY).getKeyStroke(), 95 "MapMover.Zoomer.up"); 96 contentPane.getActionMap().put("MapMover.Zoomer.up", new ZoomerAction("up")); 97 98 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 99 Shortcut.registerShortcut("system:movefocusdown", tr("Map: {0}", tr("Move down")), KeyEvent.VK_DOWN, Shortcut.GROUP_HOTKEY).getKeyStroke(), 100 "MapMover.Zoomer.down"); 101 contentPane.getActionMap().put("MapMover.Zoomer.down", new ZoomerAction("down")); 102 103 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 104 Shortcut.registerShortcut("view:zoominalternate", tr("Map: {0}", tr("Zoom in")), KeyEvent.VK_COMMA, Shortcut.GROUP_HOTKEY).getKeyStroke(), 105 "MapMover.Zoomer.in"); 106 contentPane.getActionMap().put("MapMover.Zoomer.in", new ZoomerAction(",")); 107 108 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 109 Shortcut.registerShortcut("view:zoomoutalternate", tr("Map: {0}", tr("Zoom out")), KeyEvent.VK_PERIOD, Shortcut.GROUP_HOTKEY).getKeyStroke(), 110 "MapMover.Zoomer.out"); 111 contentPane.getActionMap().put("MapMover.Zoomer.out", new ZoomerAction(".")); 112 } 113 } 114 115 /** 116 * If the right (and only the right) mouse button is pressed, move the map 117 */ 118 public void mouseDragged(MouseEvent e) { 119 int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK; 120 if ((e.getModifiersEx() & (MouseEvent.BUTTON3_DOWN_MASK | offMask)) == MouseEvent.BUTTON3_DOWN_MASK) { 121 if (mousePosMove == null) 122 startMovement(e); 123 EastNorth center = nc.getCenter(); 124 EastNorth mouseCenter = nc.getEastNorth(e.getX(), e.getY()); 125 EastNorth p = new EastNorth( 126 mousePosMove.east() + center.east() - mouseCenter.east(), 127 mousePosMove.north() + center.north() - mouseCenter.north()); 128 nc.zoomTo(p, nc.getScale()); 129 } else 130 endMovement(); 131 } 132 133 /** 134 * Start the movement, if it was the 3rd button (right button). 135 */ 136 @Override public void mousePressed(MouseEvent e) { 137 int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK; 138 if (e.getButton() == MouseEvent.BUTTON3 && (e.getModifiersEx() & offMask) == 0) 139 startMovement(e); 140 } 141 142 /** 143 * Change the cursor back to it's pre-move cursor. 144 */ 145 @Override public void mouseReleased(MouseEvent e) { 146 if (e.getButton() == MouseEvent.BUTTON3) 147 endMovement(); 148 } 149 150 /** 151 * Start movement by setting a new cursor and remember the current mouse 152 * position. 153 * @param e The mouse event that leat to the movement from. 154 */ 155 private void startMovement(MouseEvent e) { 156 if (movementInPlace) 157 return; 158 movementInPlace = true; 159 mousePosMove = nc.getEastNorth(e.getX(), e.getY()); 160 oldCursor = nc.getCursor(); 161 nc.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 162 } 163 164 /** 165 * End the movement. Setting back the cursor and clear the movement variables 166 */ 167 private void endMovement() { 168 if (!movementInPlace) 169 return; 170 movementInPlace = false; 171 if (oldCursor != null) 172 nc.setCursor(oldCursor); 173 else 174 nc.setCursor(Cursor.getDefaultCursor()); 175 mousePosMove = null; 176 oldCursor = null; 177 } 178 179 /** 180 * Zoom the map by 1/5th of current zoom per wheel-delta. 181 * @param e The wheel event. 182 */ 183 public void mouseWheelMoved(MouseWheelEvent e) { 184 int w = nc.getWidth(); 185 int h = nc.getHeight(); 186 187 double zoom = Math.max(0.1, 1 + e.getWheelRotation()/5.0); 188 double zoomfactor = (zoom-1)/2+1; 189 190 double newHalfWidth = w*zoomfactor - w/2; 191 double newHalfHeight = h*zoomfactor - h/2; 192 double centerx = e.getX() - (e.getX()-w/2)*newHalfWidth*2/w; 193 double centery = e.getY() - (e.getY()-h/2)*newHalfHeight*2/h; 194 EastNorth newCenter = nc.getEastNorth((int)centerx, (int)centery); 195 196 nc.zoomTo(newCenter, nc.getScale()*zoom); 197 } 198 199 /** 200 * Does nothing. Only to satisfy MouseMotionListener 201 */ 202 public void mouseMoved(MouseEvent e) {} 203 203 } -
trunk/src/org/openstreetmap/josm/gui/MapScaler.java
r999 r1169 18 18 public class MapScaler extends JComponent implements Helpful { 19 19 20 21 22 23 24 20 private final NavigatableComponent mv; 21 public MapScaler(NavigatableComponent mv, Projection proj) { 22 this.mv = mv; 23 setSize(100,30); 24 setOpaque(false); 25 25 } 26 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 27 @Override public void paint(Graphics g) { 28 LatLon ll1 = mv.getLatLon(0,0); 29 LatLon ll2 = mv.getLatLon(100,0); 30 double dist = ll1.greatCircleDistance(ll2); 31 String text = dist > 1000 ? (Math.round(dist/100)/10.0)+" km" : Math.round(dist*10)/10+" m"; 32 Rectangle2D bound = g.getFontMetrics().getStringBounds(text, g); 33 g.setColor(Main.pref.getColor(marktr("scale"), Color.white)); 34 g.drawLine(0, 5, 99, 5); 35 g.drawLine(0, 0, 0, 10); 36 g.drawLine(99, 0, 99, 10); 37 g.drawLine(49, 0, 49, 10); 38 g.drawLine(24, 3, 24, 7); 39 g.drawLine(74, 3, 74, 7); 40 g.drawString(text, (int)(50-bound.getWidth()/2), 23); 41 41 } 42 42 43 44 43 public String helpTopic() { 44 return "MapView/Scaler"; 45 45 } 46 46 } -
trunk/src/org/openstreetmap/josm/gui/MapSlider.java
r627 r1169 15 15 16 16 class MapSlider extends JSlider implements PropertyChangeListener, ChangeListener, Helpful { 17 17 18 18 private final MapView mv; 19 boolean clicked = false; 20 21 public MapSlider(MapView mv) { 22 super(0, 20); 23 setOpaque(false); 24 this.mv = mv; 25 addMouseListener(new MouseAdapter(){ 26 @Override public void mousePressed(MouseEvent e) { 27 clicked = true; 28 } 29 @Override public void mouseReleased(MouseEvent e) { 30 clicked = false; 31 } 32 }); 33 mv.addPropertyChangeListener("scale", this); 34 addChangeListener(this); 35 } 36 37 public void propertyChange(PropertyChangeEvent evt) { 38 if (!getModel().getValueIsAdjusting()) 39 setValue(this.mv.zoom()); 40 } 41 42 public void stateChanged(ChangeEvent e) { 43 if (!clicked) 44 return; 45 EastNorth pos = MapView.world; 46 for (int zoom = 0; zoom < getValue(); ++zoom) 47 pos = new EastNorth(pos.east()/2, pos.north()/2); 48 if (this.mv.getWidth() < this.mv.getHeight()) 49 this.mv.zoomTo(this.mv.center, pos.east()*2/(this.mv.getWidth()-20)); 50 else 51 this.mv.zoomTo(this.mv.center, pos.north()*2/(this.mv.getHeight()-20)); 52 } 19 boolean clicked = false; 53 20 54 public String helpTopic() { 55 return "MapView/Slider"; 21 public MapSlider(MapView mv) { 22 super(0, 20); 23 setOpaque(false); 24 this.mv = mv; 25 addMouseListener(new MouseAdapter(){ 26 @Override public void mousePressed(MouseEvent e) { 27 clicked = true; 28 } 29 @Override public void mouseReleased(MouseEvent e) { 30 clicked = false; 31 } 32 }); 33 mv.addPropertyChangeListener("scale", this); 34 addChangeListener(this); 35 } 36 37 public void propertyChange(PropertyChangeEvent evt) { 38 if (!getModel().getValueIsAdjusting()) 39 setValue(this.mv.zoom()); 40 } 41 42 public void stateChanged(ChangeEvent e) { 43 if (!clicked) 44 return; 45 EastNorth pos = MapView.world; 46 for (int zoom = 0; zoom < getValue(); ++zoom) 47 pos = new EastNorth(pos.east()/2, pos.north()/2); 48 if (this.mv.getWidth() < this.mv.getHeight()) 49 this.mv.zoomTo(this.mv.center, pos.east()*2/(this.mv.getWidth()-20)); 50 else 51 this.mv.zoomTo(this.mv.center, pos.north()*2/(this.mv.getHeight()-20)); 52 } 53 54 public String helpTopic() { 55 return "MapView/Slider"; 56 56 } 57 57 } -
trunk/src/org/openstreetmap/josm/gui/MapStatus.java
r1108 r1169 57 57 public class MapStatus extends JPanel implements Helpful { 58 58 59 60 61 62 63 64 /** 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 59 /** 60 * The MapView this status belongs to. 61 */ 62 final MapView mv; 63 64 /** 65 * A small user interface component that consists of an image label and 66 * a fixed text content to the right of the image. 67 */ 68 class ImageLabel extends JPanel { 69 private JLabel tf; 70 private int chars; 71 public ImageLabel(String img, String tooltip, int chars) { 72 super(); 73 setLayout(new GridBagLayout()); 74 setBackground(Color.decode("#b8cfe5")); 75 add(new JLabel(ImageProvider.get("statusline/"+img+".png")), GBC.std().anchor(GBC.WEST).insets(0,1,1,0)); 76 add(tf = new JLabel(), GBC.std().fill(GBC.BOTH).anchor(GBC.WEST).insets(2,1,1,0)); 77 setToolTipText(tooltip); 78 this.chars = chars; 79 } 80 public void setText(String t) { 81 tf.setText(t); 82 } 83 @Override public Dimension getPreferredSize() { 84 return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getPreferredSize().height); 85 } 86 @Override public Dimension getMinimumSize() { 87 return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getMinimumSize().height); 88 } 89 } 90 91 LatLon.CoordinateFormat mCord; 92 92 93 93 ImageLabel lonText = new ImageLabel("lon", tr("The geographic longitude at the mouse pointer."), 11); … … 99 99 ImageLabel distText = new ImageLabel("dist", tr("The length of the new way segment being drawn."), 8); 100 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 101 /** 102 * The collector class that waits for notification and then update 103 * the display objects. 104 * 105 * @author imi 106 */ 107 private final class Collector implements Runnable { 108 /** 109 * The last object displayed in status line. 110 */ 111 Collection<OsmPrimitive> osmStatus; 112 /** 113 * The old modifiers that was pressed the last time this collector ran. 114 */ 115 private int oldModifiers; 116 /** 117 * The popup displayed to show additional information 118 */ 119 private Popup popup; 120 121 private MapFrame parent; 122 123 public Collector(MapFrame parent) { 124 this.parent = parent; 125 } 126 127 /** 128 * Execution function for the Collector. 129 */ 130 public void run() { 131 for (;;) { 132 MouseState ms = new MouseState(); 133 synchronized (this) { 134 try {wait();} catch (InterruptedException e) {} 135 ms.modifiers = mouseState.modifiers; 136 ms.mousePos = mouseState.mousePos; 137 } 138 if (parent != Main.map) 139 return; // exit, if new parent. 140 if ((ms.modifiers & MouseEvent.CTRL_DOWN_MASK) != 0 || ms.mousePos == null) 141 continue; // freeze display when holding down ctrl 142 143 if (mv.center == null) 144 continue; 145 146 // This try/catch is a hack to stop the flooding bug reports about this. 147 // The exception needed to handle with in the first place, means that this 148 // access to the data need to be restarted, if the main thread modifies 149 // the data. 150 try { 151 OsmPrimitive osmNearest = null; 152 // Set the text label in the bottom status bar 153 osmNearest = mv.getNearest(ms.mousePos); 154 if (osmNearest != null) { 155 NameVisitor visitor = new NameVisitor(); 156 osmNearest.visit(visitor); 157 nameText.setText(visitor.name); 158 } else 159 nameText.setText(tr("(no object)")); 160 161 // Popup Information 162 if ((ms.modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0 ) { 163 Collection<OsmPrimitive> osms = mv.getAllNearest(ms.mousePos); 164 165 if (osms == null) 166 continue; 167 if (osms != null && osms.equals(osmStatus) && ms.modifiers == oldModifiers) 168 continue; 169 170 if (popup != null) { 171 try { 172 EventQueue.invokeAndWait(new Runnable() { 173 public void run() { 174 popup.hide(); 175 } 176 }); 177 177 } catch (InterruptedException e) { 178 178 } catch (InvocationTargetException e) { 179 179 throw new RuntimeException(e); 180 180 } 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 181 } 182 183 JPanel c = new JPanel(new GridBagLayout()); 184 for (final OsmPrimitive osm : osms) { 185 NameVisitor visitor = new NameVisitor(); 186 osm.visit(visitor); 187 final StringBuilder text = new StringBuilder(); 188 if (osm.id == 0 || osm.modified) 189 visitor.name = "<i><b>"+visitor.name+"*</b></i>"; 190 text.append(visitor.name); 191 if (osm.id != 0) 192 text.append("<br>id="+osm.id); 193 for (Entry<String, String> e : osm.entrySet()) 194 text.append("<br>"+e.getKey()+"="+e.getValue()); 195 final JLabel l = new JLabel("<html>"+text.toString()+"</html>", visitor.icon, JLabel.HORIZONTAL); 196 l.setFont(l.getFont().deriveFont(Font.PLAIN)); 197 l.setVerticalTextPosition(JLabel.TOP); 198 l.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 199 l.addMouseListener(new MouseAdapter(){ 200 @Override public void mouseEntered(MouseEvent e) { 201 l.setText("<html><u color='blue'>"+text.toString()+"</u></html>"); 202 } 203 @Override public void mouseExited(MouseEvent e) { 204 l.setText("<html>"+text.toString()+"</html>"); 205 } 206 @Override public void mouseClicked(MouseEvent e) { 207 Main.ds.setSelected(osm); 208 mv.repaint(); 209 } 210 }); 211 c.add(l, GBC.eol()); 212 } 213 214 Point p = mv.getLocationOnScreen(); 215 popup = PopupFactory.getSharedInstance().getPopup(mv, c, p.x+ms.mousePos.x+16, p.y+ms.mousePos.y+16); 216 final Popup staticPopup = popup; 217 EventQueue.invokeLater(new Runnable(){ 218 public void run() { 219 staticPopup.show(); 220 220 } 221 222 223 224 225 226 227 221 }); 222 } else if (popup != null) { 223 final Popup staticPopup = popup; 224 popup = null; 225 EventQueue.invokeLater(new Runnable(){ 226 public void run() { 227 staticPopup.hide(); 228 228 } 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 229 }); 230 } 231 } catch (ConcurrentModificationException x) { 232 } catch (NullPointerException x) { 233 } 234 } 235 } 236 } 237 238 /** 239 * Everything, the collector is interested of. Access must be synchronized. 240 * @author imi 241 */ 242 class MouseState { 243 Point mousePos; 244 int modifiers; 245 } 246 /** 247 * The last sent mouse movement event. 248 */ 249 MouseState mouseState = new MouseState(); 250 251 /** 252 * Construct a new MapStatus and attach it to the map view. 253 * @param mapFrame The MapFrame the status line is part of. 254 */ 255 public MapStatus(final MapFrame mapFrame) { 256 this.mv = mapFrame.mapView; 257 258 258 try { 259 259 mCord = LatLon.CoordinateFormat.valueOf(Main.pref.get("coordinates")); … … 261 261 mCord =LatLon.CoordinateFormat.DECIMAL_DEGREES; 262 262 } 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 263 // Listen for mouse movements and set the position text field 264 mv.addMouseMotionListener(new MouseMotionListener(){ 265 public void mouseDragged(MouseEvent e) { 266 mouseMoved(e); 267 } 268 public void mouseMoved(MouseEvent e) { 269 if (mv.center == null) 270 return; 271 // Do not update the view if ctrl is pressed. 272 if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) == 0) { 273 LatLon p = mv.getLatLon(e.getX(),e.getY()); 274 latText.setText(p.latToString(mCord)); 275 lonText.setText(p.lonToString(mCord)); 276 } 277 } 278 }); 279 280 setLayout(new GridBagLayout()); 281 setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 282 282 283 283 add(latText, GBC.std()); … … 287 287 add(distText, GBC.std().insets(3,0,0,0)); 288 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 289 helpText.setEditable(false); 290 add(nameText, GBC.std().insets(3,0,0,0)); 291 add(helpText, GBC.eol().insets(3,0,0,0).fill(GBC.HORIZONTAL)); 292 293 // The background thread 294 final Collector collector = new Collector(mapFrame); 295 new Thread(collector).start(); 296 297 // Listen to keyboard/mouse events for pressing/releasing alt key and 298 // inform the collector. 299 try { 300 Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener(){ 301 public void eventDispatched(AWTEvent event) { 302 synchronized (collector) { 303 mouseState.modifiers = ((InputEvent)event).getModifiersEx(); 304 if (event instanceof MouseEvent) 305 mouseState.mousePos = ((MouseEvent)event).getPoint(); 306 collector.notify(); 307 } 308 } 309 }, AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); 310 } catch (SecurityException ex) { 311 mapFrame.mapView.addMouseMotionListener(new MouseMotionListener() { 312 public void mouseMoved(MouseEvent e) { 313 synchronized (collector) { 314 mouseState.modifiers = e.getModifiersEx(); 315 mouseState.mousePos = e.getPoint(); 316 collector.notify(); 317 } 318 } 319 320 public void mouseDragged(MouseEvent e) { 321 mouseMoved(e); 322 } 323 }); 324 325 mapFrame.mapView.addKeyListener(new KeyAdapter() { 326 @Override public void keyPressed(KeyEvent e) { 327 synchronized (collector) { 328 mouseState.modifiers = e.getModifiersEx(); 329 collector.notify(); 330 } 331 } 332 333 @Override public void keyReleased(KeyEvent e) { 334 keyPressed(e); 335 } 336 }); 337 } 338 } 339 340 public String helpTopic() { 341 return "Statusline"; 342 } 343 344 public void setHelpText(String t) { 345 helpText.setText(t); 346 helpText.setToolTipText(t); 347 } 348 public void setAngle(double a) { 349 angleText.setText(a < 0 ? "--" : Math.round(a*10)/10.0 + " °"); 350 } 351 public void setHeading(double h) { 352 headingText.setText(h < 0 ? "--" : Math.round(h*10)/10.0 + " °"); 353 } 354 public void setDist(double dist) { 355 String text = dist > 1000 ? (Math.round(dist/100)/10.0)+" km" : Math.round(dist*10)/10.0 +" m"; 356 distText.setText(dist < 0 ? "--" : text); 357 } 358 359 359 } -
trunk/src/org/openstreetmap/josm/gui/MapView.java
r1084 r1169 56 56 public class MapView extends NavigatableComponent { 57 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 58 /** 59 * Interface to notify listeners of the change of the active layer. 60 * @author imi 61 * @deprecated Use Layer.LayerChangeListener instead 62 */ 63 @Deprecated public interface LayerChangeListener { 64 void activeLayerChange(Layer oldLayer, Layer newLayer); 65 void layerAdded(Layer newLayer); 66 void layerRemoved(Layer oldLayer); 67 } 68 69 /** 70 * A list of all layers currently loaded. 71 */ 72 private ArrayList<Layer> layers = new ArrayList<Layer>(); 73 /** 74 * The play head marker: there is only one of these so it isn't in any specific layer 75 */ 76 public PlayHeadMarker playHeadMarker = null; 77 /** 78 * Direct link to the edit layer (if any) in the layers list. 79 */ 80 public OsmDataLayer editLayer; 81 /** 82 * The layer from the layers list that is currently active. 83 */ 84 private Layer activeLayer; 85 86 /** 87 * The last event performed by mouse. 88 */ 89 public MouseEvent lastMEvent; 90 91 private LinkedList<MapViewPaintable> temporaryLayers = new LinkedList<MapViewPaintable>(); 92 93 private BufferedImage offscreenBuffer; 94 95 /** 96 * The listener of the active layer changes. 97 * @deprecated Use Layer.listener instead. 98 */ 99 @Deprecated private Collection<LayerChangeListener> listeners = new LinkedList<LayerChangeListener>(); 100 101 public MapView() { 102 addComponentListener(new ComponentAdapter(){ 103 @Override public void componentResized(ComponentEvent e) { 104 removeComponentListener(this); 105 106 if (!zoomToEditLayerBoundingBox()) 107 new AutoScaleAction("data").actionPerformed(null); 108 109 new MapMover(MapView.this, Main.contentPane); 110 JosmAction mv; 111 mv = new MoveAction(MoveAction.Direction.UP); 112 if (mv.getShortcut() != null) { 113 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "UP"); 114 Main.contentPane.getActionMap().put("UP", mv); 115 } 116 mv = new MoveAction(MoveAction.Direction.DOWN); 117 if (mv.getShortcut() != null) { 118 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "DOWN"); 119 Main.contentPane.getActionMap().put("DOWN", mv); 120 } 121 mv = new MoveAction(MoveAction.Direction.LEFT); 122 if (mv.getShortcut() != null) { 123 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "LEFT"); 124 Main.contentPane.getActionMap().put("LEFT", mv); 125 } 126 mv = new MoveAction(MoveAction.Direction.RIGHT); 127 if (mv.getShortcut() != null) { 128 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "RIGHT"); 129 Main.contentPane.getActionMap().put("RIGHT", mv); 130 } 131 132 MapSlider zoomSlider = new MapSlider(MapView.this); 133 add(zoomSlider); 134 zoomSlider.setBounds(3, 0, 114, 30); 135 136 MapScaler scaler = new MapScaler(MapView.this, Main.proj); 137 add(scaler); 138 scaler.setLocation(10,30); 139 } 140 }); 141 142 // listend to selection changes to redraw the map 143 DataSet.selListeners.add(new SelectionChangedListener(){ 144 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 145 repaint(); 146 } 147 }); 148 149 //store the last mouse action 150 this.addMouseMotionListener(new MouseMotionListener() { 151 public void mouseDragged(MouseEvent e) { 152 mouseMoved(e); 153 } 154 public void mouseMoved(MouseEvent e) { 155 lastMEvent = e; 156 } 157 }); 158 } 159 160 /** 161 * Add a layer to the current MapView. The layer will be added at topmost 162 * position. 163 */ 164 public void addLayer(Layer layer) { 165 if (layer instanceof OsmDataLayer) { 166 editLayer = (OsmDataLayer)layer; 167 Main.ds = editLayer.data; 168 editLayer.listenerModified.add(new ModifiedChangedListener(){ 169 public void modifiedChanged(boolean value, OsmDataLayer source) { 170 JOptionPane.getFrameForComponent(Main.parent).setTitle((value?"*":"")+tr("Java OpenStreetMap - Editor")); 171 } 172 }); 173 } 174 if (layer instanceof MarkerLayer && playHeadMarker == null) 175 playHeadMarker = PlayHeadMarker.create(); 176 int pos = layers.size(); 177 while(pos > 0 && layers.get(pos-1).background) 178 --pos; 179 layers.add(pos, layer); 180 181 // TODO: Deprecated 182 for (LayerChangeListener l : listeners) 183 l.layerAdded(layer); 184 for (Layer.LayerChangeListener l : Layer.listeners) 185 l.layerAdded(layer); 186 if (layer instanceof OsmDataLayer || activeLayer == null) { 187 // autoselect the new layer 188 Layer old = activeLayer; 189 setActiveLayer(layer); 190 for (Layer.LayerChangeListener l : Layer.listeners) 191 l.activeLayerChange(old, layer); 192 } 193 repaint(); 194 } 195 196 @Override 197 protected DataSet getData() 198 { 199 if(activeLayer != null && activeLayer instanceof OsmDataLayer) 200 return ((OsmDataLayer)activeLayer).data; 201 return new DataSet(); 202 } 203 204 public Boolean isDrawableLayer() 205 { 206 return activeLayer != null && activeLayer instanceof OsmDataLayer; 207 } 208 209 /** 210 * Remove the layer from the mapview. If the layer was in the list before, 211 * an LayerChange event is fired. 212 */ 213 public void removeLayer(Layer layer) { 214 if (layers.remove(layer)) { 215 // TODO: Deprecated 216 for (LayerChangeListener l : listeners) 217 l.layerRemoved(layer); 218 for (Layer.LayerChangeListener l : Layer.listeners) 219 l.layerRemoved(layer); 220 } 221 if (layer == editLayer) { 222 editLayer = null; 223 Main.ds.setSelected(); 224 } 225 layer.destroy(); 226 } 227 228 private Boolean virtualnodes = false; 229 public void enableVirtualNodes(Boolean state) 230 { 231 if(virtualnodes != state) 232 { 233 virtualnodes = state; 234 repaint(); 235 } 236 } 237 public Boolean useVirtualNodes() 238 { 239 return virtualnodes; 240 } 241 242 /** 243 * Moves the layer to the given new position. No event is fired. 244 * @param layer The layer to move 245 * @param pos The new position of the layer 246 */ 247 public void moveLayer(Layer layer, int pos) { 248 int curLayerPos = layers.indexOf(layer); 249 if (curLayerPos == -1) 250 throw new IllegalArgumentException(tr("layer not in list.")); 251 if (pos == curLayerPos) 252 return; // already in place. 253 layers.remove(curLayerPos); 254 if (pos >= layers.size()) 255 layers.add(layer); 256 else 257 layers.add(pos, layer); 258 } 259 260 /** 261 * Draw the component. 262 */ 263 @Override public void paint(Graphics g) { 264 if (center == null) 265 return; // no data loaded yet. 266 267 // re-create offscreen-buffer if we've been resized, otherwise 268 // just re-use it. 269 if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth() 270 || offscreenBuffer.getHeight() != getHeight()) 271 offscreenBuffer = new BufferedImage(getWidth(), getHeight(), 272 BufferedImage.TYPE_INT_ARGB); 273 274 Graphics2D tempG = offscreenBuffer.createGraphics(); 275 tempG.setColor(Main.pref.getColor("background", Color.BLACK)); 276 tempG.fillRect(0, 0, getWidth(), getHeight()); 277 278 for (int i = layers.size()-1; i >= 0; --i) { 279 Layer l = layers.get(i); 280 if (l.visible/* && l != getActiveLayer()*/) 281 l.paint(tempG, this); 282 } 283 284 /*if (getActiveLayer() != null && getActiveLayer().visible) 285 getActiveLayer().paint(tempG, this);*/ 286 287 for (MapViewPaintable mvp : temporaryLayers) { 288 mvp.paint(tempG, this); 289 } 290 291 // draw world borders 292 tempG.setColor(Color.WHITE); 293 Bounds b = new Bounds(); 294 Point min = getPoint(getProjection().latlon2eastNorth(b.min)); 295 Point max = getPoint(getProjection().latlon2eastNorth(b.max)); 296 int x1 = Math.min(min.x, max.x); 297 int y1 = Math.min(min.y, max.y); 298 int x2 = Math.max(min.x, max.x); 299 int y2 = Math.max(min.y, max.y); 300 if (x1 > 0 || y1 > 0 || x2 < getWidth() || y2 < getHeight()) 301 tempG.drawRect(x1, y1, x2-x1+1, y2-y1+1); 302 303 if (playHeadMarker != null) 304 playHeadMarker.paint(tempG, this); 305 306 g.drawImage(offscreenBuffer, 0, 0, null); 307 super.paint(g); 308 } 309 310 /** 311 * Set the new dimension to the projection class. Also adjust the components 312 * scale, if in autoScale mode. 313 */ 314 public void recalculateCenterScale(BoundingXYVisitor box) { 315 // -20 to leave some border 316 int w = getWidth()-20; 317 if (w < 20) 318 w = 20; 319 int h = getHeight()-20; 320 if (h < 20) 321 h = 20; 322 323 EastNorth oldCenter = center; 324 double oldScale = this.scale; 325 326 if (box == null || box.min == null || box.max == null || box.min.equals(box.max)) { 327 // no bounds means whole world 328 center = getProjection().latlon2eastNorth(new LatLon(0,0)); 329 EastNorth world = getProjection().latlon2eastNorth(new LatLon(Projection.MAX_LAT,Projection.MAX_LON)); 330 double scaleX = world.east()*2/w; 331 double scaleY = world.north()*2/h; 332 scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen 333 } else { 334 center = new EastNorth(box.min.east()/2+box.max.east()/2, box.min.north()/2+box.max.north()/2); 335 double scaleX = (box.max.east()-box.min.east())/w; 336 double scaleY = (box.max.north()-box.min.north())/h; 337 scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen 338 } 339 340 if (!center.equals(oldCenter)) 341 firePropertyChange("center", oldCenter, center); 342 if (oldScale != scale) 343 firePropertyChange("scale", oldScale, scale); 344 repaint(); 345 } 346 347 /** 348 * Add a listener for changes of active layer. 349 * @param listener The listener that get added. 350 * @deprecated Use Layer.listener.add instead. 351 */ 352 @Deprecated public void addLayerChangeListener(LayerChangeListener listener) { 353 if (listener != null) 354 listeners.add(listener); 355 } 356 357 /** 358 * Remove the listener. 359 * @param listener The listener that get removed from the list. 360 * @deprecated Use Layer.listener.remove instead 361 */ 362 @Deprecated public void removeLayerChangeListener(LayerChangeListener listener) { 363 listeners.remove(listener); 364 } 365 366 /** 367 * @return An unmodificable list of all layers 368 */ 369 public Collection<Layer> getAllLayers() { 370 return Collections.unmodifiableCollection(layers); 371 } 372 373 /** 374 * Set the active selection to the given value and raise an layerchange event. 375 */ 376 public void setActiveLayer(Layer layer) { 377 if (!layers.contains(layer)) 378 throw new IllegalArgumentException("Layer must be in layerlist"); 379 if (layer instanceof OsmDataLayer) { 380 editLayer = (OsmDataLayer)layer; 381 Main.ds = editLayer.data; 382 } 383 else 384 Main.ds.setSelected(); 385 DataSet.fireSelectionChanged(Main.ds.getSelected()); 386 Layer old = activeLayer; 387 activeLayer = layer; 388 if (old != layer) { 389 // TODO: Deprecated 390 for (LayerChangeListener l : listeners) 391 l.activeLayerChange(old, layer); 392 for (Layer.LayerChangeListener l : Layer.listeners) 393 l.activeLayerChange(old, layer); 394 } 395 repaint(); 396 } 397 398 /** 399 * @return The current active layer 400 */ 401 public Layer getActiveLayer() { 402 return activeLayer; 403 } 404 405 /** 406 * In addition to the base class funcitonality, this keep trak of the autoscale 407 * feature. 408 */ 409 @Override public void zoomTo(EastNorth newCenter, double scale) { 410 EastNorth oldCenter = center; 411 double oldScale = this.scale; 412 super.zoomTo(newCenter, scale); 413 if ((oldCenter == null && center != null) || !oldCenter.equals(center)) 414 firePropertyChange("center", oldCenter, center); 415 if (oldScale != scale) 416 firePropertyChange("scale", oldScale, scale); 417 } 418 419 /** 420 * Tries to zoom to the download boundingbox[es] of the current edit layer 421 * (aka {@link OsmDataLayer}). If the edit layer has multiple download bounding 422 * boxes it zooms to a large virtual bounding box containing all smaller ones. 423 * This implementation can be used for resolving ticket #1461. 424 * 425 * @return <code>true</code> if a zoom operation has been performed 426 * @author Jan Peter Stotz 427 */ 428 public boolean zoomToEditLayerBoundingBox() { 429 // workaround for #1461 (zoom to download bounding box instead of all data) 430 // In case we already have an existing data layer ... 431 Collection<DataSource> dataSources = Main.main.editLayer().data.dataSources; 432 // ... with bounding box[es] of data loaded from OSM or a file... 433 BoundingXYVisitor bbox = new BoundingXYVisitor(); 434 for (DataSource ds : dataSources) { 435 if (ds.bounds != null) { 436 bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.max)); 437 bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.min)); 438 } 439 if (bbox.max != null && bbox.min != null && !bbox.max.equals(bbox.min)) { 440 // ... we zoom to it's bounding box 441 recalculateCenterScale(bbox); 442 return true; 443 } 444 } 445 return false; 446 } 447 448 public boolean addTemporaryLayer(MapViewPaintable mvp) { 449 if (temporaryLayers.contains(mvp)) return false; 450 return temporaryLayers.add(mvp); 451 } 452 453 public boolean removeTemporaryLayer(MapViewPaintable mvp) { 454 return temporaryLayers.remove(mvp); 455 } 456 456 } -
trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java
r860 r1169 33 33 public class NavigatableComponent extends JComponent implements Helpful { 34 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 *change the center by accessing the return value. Use zoomTo instead.82 83 84 85 86 87 88 89 90 91 92 *on the screen.93 94 95 96 97 98 99 100 101 102 103 104 105 *on the screen.106 107 108 109 110 111 112 113 114 115 116 *to the own top/left.117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 * 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 * 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 *if no item under or near the point. The returned279 *list is never empty.280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 *if no node under or near the point. The returned320 *list is never empty.321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 * 337 338 339 340 341 342 35 public static final EastNorth world = Main.proj.latlon2eastNorth(new LatLon(Projection.MAX_LAT, Projection.MAX_LON)); 36 public static final int snapDistance = sqr(Main.pref.getInteger("node.snap-distance", 10)); 37 38 private static int sqr(int a) { return a*a;} 39 /** 40 * The scale factor in x or y-units per pixel. This means, if scale = 10, 41 * every physical pixel on screen are 10 x or 10 y units in the 42 * northing/easting space of the projection. 43 */ 44 protected double scale; 45 /** 46 * Center n/e coordinate of the desired screen center. 47 */ 48 protected EastNorth center; 49 50 public NavigatableComponent() { 51 setLayout(null); 52 } 53 54 protected DataSet getData() 55 { 56 return Main.ds; 57 } 58 59 /** 60 * Return the OSM-conform zoom factor (0 for whole world, 1 for half, 2 for quarter...) 61 */ 62 public int zoom() { 63 double sizex = scale * getWidth(); 64 double sizey = scale * getHeight(); 65 for (int zoom = 0; zoom <= 32; zoom++, sizex *= 2, sizey *= 2) 66 if (sizex > world.east() || sizey > world.north()) 67 return zoom; 68 return 32; 69 } 70 71 /** 72 * Return the current scale value. 73 * @return The scale value currently used in display 74 */ 75 public double getScale() { 76 return scale; 77 } 78 79 /** 80 * @return Returns the center point. A copy is returned, so users cannot 81 * change the center by accessing the return value. Use zoomTo instead. 82 */ 83 public EastNorth getCenter() { 84 return center; 85 } 86 87 /** 88 * @param x X-Pixelposition to get coordinate from 89 * @param y Y-Pixelposition to get coordinate from 90 * 91 * @return Geographic coordinates from a specific pixel coordination 92 * on the screen. 93 */ 94 public EastNorth getEastNorth(int x, int y) { 95 return new EastNorth( 96 center.east() + (x - getWidth()/2.0)*scale, 97 center.north() - (y - getHeight()/2.0)*scale); 98 } 99 100 /** 101 * @param x X-Pixelposition to get coordinate from 102 * @param y Y-Pixelposition to get coordinate from 103 * 104 * @return Geographic unprojected coordinates from a specific pixel coordination 105 * on the screen. 106 */ 107 public LatLon getLatLon(int x, int y) { 108 109 return getProjection().eastNorth2latlon(getEastNorth(x, y)); 110 } 111 112 /** 113 * Return the point on the screen where this Coordinate would be. 114 * @param p The point, where this geopoint would be drawn. 115 * @return The point on screen where "point" would be drawn, relative 116 * to the own top/left. 117 */ 118 public Point getPoint(EastNorth p) { 119 if(null == p) 120 return new Point(); 121 double x = (p.east()-center.east())/scale + getWidth()/2; 122 double y = (center.north()-p.north())/scale + getHeight()/2; 123 return new Point((int)x,(int)y); 124 } 125 126 /** 127 * Zoom to the given coordinate. 128 * @param newCenter The center x-value (easting) to zoom to. 129 * @param scale The scale to use. 130 */ 131 public void zoomTo(EastNorth newCenter, double scale) { 132 center = newCenter; 133 getProjection().eastNorth2latlon(center); 134 this.scale = scale; 135 repaint(); 136 } 137 138 /** 139 * Return the nearest point to the screen point given. 140 * If a node within 10 pixel is found, the nearest node is returned. 141 */ 142 public final Node getNearestNode(Point p) { 143 double minDistanceSq = Double.MAX_VALUE; 144 Node minPrimitive = null; 145 for (Node n : getData().nodes) { 146 if (n.deleted || n.incomplete) 147 continue; 148 Point sp = getPoint(n.eastNorth); 149 double dist = p.distanceSq(sp); 150 if (minDistanceSq > dist && dist < snapDistance) { 151 minDistanceSq = p.distanceSq(sp); 152 minPrimitive = n; 153 } 154 // prefer already selected node when multiple nodes on one point 155 else if(minDistanceSq == dist && n.selected && !minPrimitive.selected) 156 { 157 minPrimitive = n; 158 } 159 } 160 return minPrimitive; 161 } 162 163 /** 164 * @return all way segments within 10px of p, sorted by their 165 * perpendicular distance. 166 * 167 * @param p the point for which to search the nearest segment. 168 */ 169 public final List<WaySegment> getNearestWaySegments(Point p) { 170 TreeMap<Double, List<WaySegment>> nearest = new TreeMap<Double, List<WaySegment>>(); 171 for (Way w : getData().ways) { 172 if (w.deleted || w.incomplete) continue; 173 Node lastN = null; 174 int i = -2; 175 for (Node n : w.nodes) { 176 i++; 177 if (n.deleted || n.incomplete) continue; 178 if (lastN == null) { 179 lastN = n; 180 continue; 181 } 182 183 Point A = getPoint(lastN.eastNorth); 184 Point B = getPoint(n.eastNorth); 185 double c = A.distanceSq(B); 186 double a = p.distanceSq(B); 187 double b = p.distanceSq(A); 188 double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared 189 if (perDist < snapDistance && a < c+snapDistance && b < c+snapDistance) { 190 if(w.selected) // prefer selected ways a little bit 191 perDist -= 0.00001; 192 List<WaySegment> l; 193 if (nearest.containsKey(perDist)) { 194 l = nearest.get(perDist); 195 } else { 196 l = new LinkedList<WaySegment>(); 197 nearest.put(perDist, l); 198 } 199 l.add(new WaySegment(w, i)); 200 } 201 202 lastN = n; 203 } 204 } 205 ArrayList<WaySegment> nearestList = new ArrayList<WaySegment>(); 206 for (List<WaySegment> wss : nearest.values()) { 207 nearestList.addAll(wss); 208 } 209 return nearestList; 210 } 211 212 /** 213 * @return the nearest way segment to the screen point given that is not 214 * in ignore. 215 * 216 * @param p the point for which to search the nearest segment. 217 * @param ignore a collection of segments which are not to be returned. 218 * May be null. 219 */ 220 public final WaySegment getNearestWaySegment(Point p, Collection<WaySegment> ignore) { 221 List<WaySegment> nearest = getNearestWaySegments(p); 222 if (ignore != null) nearest.removeAll(ignore); 223 return nearest.isEmpty() ? null : nearest.get(0); 224 } 225 226 /** 227 * @return the nearest way segment to the screen point given. 228 */ 229 public final WaySegment getNearestWaySegment(Point p) { 230 return getNearestWaySegment(p, null); 231 } 232 233 /** 234 * @return the nearest way to the screen point given. 235 */ 236 public final Way getNearestWay(Point p) { 237 WaySegment nearestWaySeg = getNearestWaySegment(p); 238 return nearestWaySeg == null ? null : nearestWaySeg.way; 239 } 240 241 /** 242 * Return the object, that is nearest to the given screen point. 243 * 244 * First, a node will be searched. If a node within 10 pixel is found, the 245 * nearest node is returned. 246 * 247 * If no node is found, search for near ways. 248 * 249 * If nothing is found, return <code>null</code>. 250 * 251 * @param p The point on screen. 252 * @return The primitive that is nearest to the point p. 253 */ 254 public OsmPrimitive getNearest(Point p) { 255 OsmPrimitive osm = getNearestNode(p); 256 if (osm == null) 257 { 258 osm = getNearestWay(p); 259 } 260 return osm; 261 } 262 263 /** 264 * Returns a singleton of the nearest object, or else an empty collection. 265 */ 266 public Collection<OsmPrimitive> getNearestCollection(Point p) { 267 OsmPrimitive osm = getNearest(p); 268 if (osm == null) 269 return Collections.emptySet(); 270 return Collections.singleton(osm); 271 } 272 273 /** 274 * @return A list of all objects that are nearest to 275 * the mouse. Does a simple sequential scan on all the data. 276 * 277 * @return A collection of all items or <code>null</code> 278 * if no item under or near the point. The returned 279 * list is never empty. 280 */ 281 public Collection<OsmPrimitive> getAllNearest(Point p) { 282 Collection<OsmPrimitive> nearest = new HashSet<OsmPrimitive>(); 283 for (Way w : getData().ways) { 284 if (w.deleted || w.incomplete) continue; 285 Node lastN = null; 286 for (Node n : w.nodes) { 287 if (n.deleted || n.incomplete) continue; 288 if (lastN == null) { 289 lastN = n; 290 continue; 291 } 292 Point A = getPoint(lastN.eastNorth); 293 Point B = getPoint(n.eastNorth); 294 double c = A.distanceSq(B); 295 double a = p.distanceSq(B); 296 double b = p.distanceSq(A); 297 double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared 298 if (perDist < snapDistance && a < c+snapDistance && b < c+snapDistance) { 299 nearest.add(w); 300 break; 301 } 302 lastN = n; 303 } 304 } 305 for (Node n : getData().nodes) { 306 if (!n.deleted && !n.incomplete 307 && getPoint(n.eastNorth).distanceSq(p) < snapDistance) { 308 nearest.add(n); 309 } 310 } 311 return nearest.isEmpty() ? null : nearest; 312 } 313 314 /** 315 * @return A list of all nodes that are nearest to 316 * the mouse. Does a simple sequential scan on all the data. 317 * 318 * @return A collection of all nodes or <code>null</code> 319 * if no node under or near the point. The returned 320 * list is never empty. 321 */ 322 public Collection<Node> getNearestNodes(Point p) { 323 Collection<Node> nearest = new HashSet<Node>(); 324 for (Node n : getData().nodes) { 325 if (!n.deleted && !n.incomplete 326 && getPoint(n.eastNorth).distanceSq(p) < snapDistance) { 327 nearest.add(n); 328 } 329 } 330 return nearest.isEmpty() ? null : nearest; 331 } 332 333 /** 334 * @return the nearest nodes to the screen point given that is not 335 * in ignore. 336 * 337 * @param p the point for which to search the nearest segment. 338 * @param ignore a collection of nodes which are not to be returned. 339 * May be null. 340 */ 341 public final Collection<Node> getNearestNodes(Point p, Collection<Node> ignore) { 342 Collection<Node> nearest = getNearestNodes(p); 343 343 if (nearest == null) return null; 344 345 346 347 348 349 350 351 352 353 354 355 356 357 344 if (ignore != null) nearest.removeAll(ignore); 345 return nearest.isEmpty() ? null : nearest; 346 } 347 348 /** 349 * @return The projection to be used in calculating stuff. 350 */ 351 protected Projection getProjection() { 352 return Main.proj; 353 } 354 355 public String helpTopic() { 356 String n = getClass().getName(); 357 return n.substring(n.lastIndexOf('.')+1); 358 358 } 359 359 } -
trunk/src/org/openstreetmap/josm/gui/OsmPrimitivRenderer.java
r627 r1169 17 17 /** 18 18 * Renderer that renders the objects from an OsmPrimitive as data. 19 * 19 * 20 20 * Can be used in lists and tables. 21 * 21 * 22 22 * @author imi 23 23 * @author Frederik Ramm <frederik@remote.org> … … 25 25 public class OsmPrimitivRenderer implements ListCellRenderer, TableCellRenderer { 26 26 27 28 29 30 27 /** 28 * NameVisitor provides proper names and icons for OsmPrimitives 29 */ 30 private NameVisitor visitor = new NameVisitor(); 31 31 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(); 32 /** 33 * Default list cell renderer - delegate for ListCellRenderer operation 34 */ 35 private DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer(); 41 36 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 } 37 /** 38 * Default table cell renderer - delegate for TableCellRenderer operation 39 */ 40 private DefaultTableCellRenderer defaultTableCellRenderer = new DefaultTableCellRenderer(); 49 41 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) { 67 (value).visit(visitor); 68 ((JLabel)def).setText(visitor.name); 69 ((JLabel)def).setIcon(visitor.icon); 70 } 71 return def; 72 } 73 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) { 67 (value).visit(visitor); 68 ((JLabel)def).setText(visitor.name); 69 ((JLabel)def).setIcon(visitor.icon); 70 } 71 return def; 72 } 73 74 74 } -
trunk/src/org/openstreetmap/josm/gui/PleaseWaitDialog.java
r1073 r1169 20 20 public class PleaseWaitDialog extends JDialog { 21 21 22 22 private final JProgressBar progressBar = new JProgressBar(); 23 23 24 25 26 24 public final JLabel currentAction = new JLabel(I18n.tr("Contacting the OSM server...")); 25 public final BoundedRangeModel progress = progressBar.getModel(); 26 public final JButton cancel = new JButton(I18n.tr("Cancel")); 27 27 28 29 30 31 32 33 34 35 36 37 38 39 28 public PleaseWaitDialog(Component parent) { 29 super(JOptionPane.getFrameForComponent(parent), true); 30 setLayout(new GridBagLayout()); 31 JPanel pane = new JPanel(new GridBagLayout()); 32 pane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); 33 pane.add(currentAction, GBC.eol().fill(GBC.HORIZONTAL)); 34 pane.add(progressBar, GBC.eop().fill(GBC.HORIZONTAL)); 35 pane.add(cancel, GBC.eol().anchor(GBC.CENTER)); 36 setContentPane(pane); 37 setSize(Main.pref.getInteger("progressdialog.size",400),100); 38 setLocationRelativeTo(Main.parent); 39 } 40 40 } -
trunk/src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java
r627 r1169 26 26 public abstract class PleaseWaitRunnable implements Runnable { 27 27 28 28 public String errorMessage; 29 29 30 31 30 private boolean closeDialogCalled = false; 31 private boolean cancelled = false; 32 32 33 33 private final String title; 34 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 35 /** 36 * Create the runnable object with a given message for the user. 37 */ 38 public PleaseWaitRunnable(String title) { 39 this.title = title; 40 Main.pleaseWaitDlg.cancel.addActionListener(new ActionListener(){ 41 public void actionPerformed(ActionEvent e) { 42 if (!cancelled) { 43 cancelled = true; 44 cancel(); 45 } 46 } 47 }); 48 Main.pleaseWaitDlg.addWindowListener(new WindowAdapter(){ 49 @Override public void windowClosing(WindowEvent e) { 50 if (!closeDialogCalled) { 51 if (!cancelled) { 52 cancelled = true; 53 cancel(); 54 } 55 closeDialog(); 56 } 57 } 58 }); 59 } 60 60 61 62 63 64 61 public final void run() { 62 try { 63 if (cancelled) 64 return; // since realRun isn't executed, do not call to finish 65 65 66 67 68 69 66 // reset dialog state 67 Main.pleaseWaitDlg.setTitle(title); 68 errorMessage = null; 69 closeDialogCalled = false; 70 70 71 72 73 74 75 76 77 78 79 80 81 82 71 // show the dialog 72 synchronized (this) { 73 EventQueue.invokeLater(new Runnable() { 74 public void run() { 75 synchronized (PleaseWaitRunnable.this) { 76 PleaseWaitRunnable.this.notifyAll(); 77 } 78 Main.pleaseWaitDlg.setVisible(true); 79 } 80 }); 81 try {wait();} catch (InterruptedException e) {} 82 } 83 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 84 realRun(); 85 } catch (SAXException x) { 86 x.printStackTrace(); 87 errorMessage = tr("Error while parsing")+": "+x.getMessage(); 88 } catch (FileNotFoundException x) { 89 x.printStackTrace(); 90 errorMessage = tr("File not found")+": "+x.getMessage(); 91 } catch (IOException x) { 92 x.printStackTrace(); 93 errorMessage = x.getMessage(); 94 } finally { 95 closeDialog(); 96 } 97 } 98 98 99 100 101 102 99 /** 100 * User pressed cancel button. 101 */ 102 protected abstract void cancel(); 103 103 104 105 106 107 108 109 104 /** 105 * Called in the worker thread to do the actual work. When any of the 106 * exception is thrown, a message box will be displayed and closeDialog 107 * is called. finish() is called in any case. 108 */ 109 protected abstract void realRun() throws SAXException, IOException; 110 110 111 112 113 114 115 111 /** 112 * Finish up the data work. Is guaranteed to be called if realRun is called. 113 * Finish is called in the gui thread just after the dialog disappeared. 114 */ 115 protected abstract void finish(); 116 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 117 /** 118 * Close the dialog. Usually called from worker thread. 119 */ 120 public void closeDialog() { 121 if (closeDialogCalled) 122 return; 123 closeDialogCalled = true; 124 try { 125 Runnable runnable = new Runnable(){ 126 public void run() { 127 try { 128 finish(); 129 } finally { 130 Main.pleaseWaitDlg.setVisible(false); 131 Main.pleaseWaitDlg.dispose(); 132 } 133 if (errorMessage != null) 134 JOptionPane.showMessageDialog(Main.parent, errorMessage); 135 } 136 }; 137 137 138 139 140 141 142 138 // make sure, this is called in the dispatcher thread ASAP 139 if (EventQueue.isDispatchThread()) 140 runnable.run(); 141 else 142 EventQueue.invokeAndWait(runnable); 143 143 144 145 146 147 148 144 } catch (InterruptedException e) { 145 } catch (InvocationTargetException e) { 146 throw new RuntimeException(e); 147 } 148 } 149 149 } -
trunk/src/org/openstreetmap/josm/gui/QuadStateCheckBox.java
r747 r1169 23 23 public class QuadStateCheckBox extends JCheckBox { 24 24 25 25 public enum State { NOT_SELECTED, SELECTED, UNSET, PARTIAL } 26 26 27 28 27 private final QuadStateDecorator model; 28 private State[] allowed; 29 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 30 public QuadStateCheckBox(String text, Icon icon, State initial, State[] allowed) { 31 super(text, icon); 32 this.allowed = allowed; 33 // Add a listener for when the mouse is pressed 34 super.addMouseListener(new MouseAdapter() { 35 @Override public void mousePressed(MouseEvent e) { 36 grabFocus(); 37 model.nextState(); 38 } 39 }); 40 // Reset the keyboard action map 41 ActionMap map = new ActionMapUIResource(); 42 map.put("pressed", new AbstractAction() { 43 public void actionPerformed(ActionEvent e) { 44 grabFocus(); 45 model.nextState(); 46 } 47 }); 48 map.put("released", null); 49 SwingUtilities.replaceUIActionMap(this, map); 50 // set the model to the adapted model 51 model = new QuadStateDecorator(getModel()); 52 setModel(model); 53 setState(initial); 54 } 55 public QuadStateCheckBox(String text, State initial, State[] allowed) { 56 this(text, null, initial, allowed); 57 } 58 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 59 /** Do not let anyone add mouse listeners */ 60 @Override public void addMouseListener(MouseListener l) { } 61 /** 62 * Set the new state. 63 */ 64 public void setState(State state) { model.setState(state); } 65 /** Return the current state, which is determined by the 66 * selection status of the model. */ 67 public State getState() { return model.getState(); } 68 @Override public void setSelected(boolean b) { 69 if (b) { 70 setState(State.SELECTED); 71 } else { 72 setState(State.NOT_SELECTED); 73 } 74 } 75 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 * 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 76 private class QuadStateDecorator implements ButtonModel { 77 private final ButtonModel other; 78 private QuadStateDecorator(ButtonModel other) { 79 this.other = other; 80 } 81 private void setState(State state) { 82 if (state == State.NOT_SELECTED) { 83 other.setArmed(false); 84 other.setPressed(false); 85 other.setSelected(false); 86 setToolTipText(tr("false: the property is explicitly switched off")); 87 } else if (state == State.SELECTED) { 88 other.setArmed(false); 89 other.setPressed(false); 90 other.setSelected(true); 91 setToolTipText(tr("true: the property is explicitly switched on")); 92 } else if (state == State.PARTIAL) { 93 other.setArmed(true); 94 other.setPressed(true); 95 other.setSelected(true); 96 setToolTipText(tr("partial: different selected objects have different values, do not change")); 97 } else { 98 other.setArmed(true); 99 other.setPressed(true); 100 other.setSelected(false); 101 setToolTipText(tr("unset: do not set this property on the selected objects")); 102 } 103 } 104 /** 105 * The current state is embedded in the selection / armed 106 * state of the model. 107 * 108 * We return the SELECTED state when the checkbox is selected 109 * but not armed, PARTIAL state when the checkbox is 110 * selected and armed (grey) and NOT_SELECTED when the 111 * checkbox is deselected. 112 */ 113 private State getState() { 114 if (isSelected() && !isArmed()) { 115 // normal black tick 116 return State.SELECTED; 117 } else if (isSelected() && isArmed()) { 118 // don't care grey tick 119 return State.PARTIAL; 120 } else if (!isSelected() && !isArmed()) { 121 return State.NOT_SELECTED; 122 } else { 123 return State.UNSET; 124 } 125 } 126 /** Rotate to the next allowed state.*/ 127 private void nextState() { 128 State current = getState(); 129 for (int i = 0; i < allowed.length; i++) { 130 if (allowed[i] == current) { 131 setState((i == allowed.length-1) ? allowed[0] : allowed[i+1]); 132 break; 133 } 134 } 135 } 136 /** Filter: No one may change the armed/selected/pressed status except us. */ 137 public void setArmed(boolean b) { } 138 public void setSelected(boolean b) { } 139 public void setPressed(boolean b) { } 140 /** We disable focusing on the component when it is not 141 * enabled. */ 142 public void setEnabled(boolean b) { 143 setFocusable(b); 144 other.setEnabled(b); 145 } 146 /** All these methods simply delegate to the "other" model 147 * that is being decorated. */ 148 public boolean isArmed() { return other.isArmed(); } 149 public boolean isSelected() { return other.isSelected(); } 150 public boolean isEnabled() { return other.isEnabled(); } 151 public boolean isPressed() { return other.isPressed(); } 152 public boolean isRollover() { return other.isRollover(); } 153 public void setRollover(boolean b) { other.setRollover(b); } 154 public void setMnemonic(int key) { other.setMnemonic(key); } 155 public int getMnemonic() { return other.getMnemonic(); } 156 public void setActionCommand(String s) { 157 other.setActionCommand(s); 158 } 159 public String getActionCommand() { 160 return other.getActionCommand(); 161 } 162 public void setGroup(ButtonGroup group) { 163 other.setGroup(group); 164 } 165 public void addActionListener(ActionListener l) { 166 other.addActionListener(l); 167 } 168 public void removeActionListener(ActionListener l) { 169 other.removeActionListener(l); 170 } 171 public void addItemListener(ItemListener l) { 172 other.addItemListener(l); 173 } 174 public void removeItemListener(ItemListener l) { 175 other.removeItemListener(l); 176 } 177 public void addChangeListener(ChangeListener l) { 178 other.addChangeListener(l); 179 } 180 public void removeChangeListener(ChangeListener l) { 181 other.removeChangeListener(l); 182 } 183 public Object[] getSelectedObjects() { 184 return other.getSelectedObjects(); 185 } 186 } 187 187 } 188 188 -
trunk/src/org/openstreetmap/josm/gui/SelectionManager.java
r1003 r1169 23 23 * Manages the selection of a rectangle. Listening to left and right mouse button 24 24 * presses and to mouse motions and draw the rectangle accordingly. 25 * 25 * 26 26 * Left mouse button selects a rectangle from the press until release. Pressing 27 27 * right mouse button while left is still pressed enable the rectangle to move … … 29 29 * at constructor, except if the right is still pressed, which just remove the 30 30 * selection rectangle and does nothing. 31 * 32 * The point where the left mouse button was pressed and the current mouse 31 * 32 * The point where the left mouse button was pressed and the current mouse 33 33 * position are two opposite corners of the selection rectangle. 34 * 35 * It is possible to specify an aspect ratio (width per height) which the 34 * 35 * It is possible to specify an aspect ratio (width per height) which the 36 36 * selection rectangle always must have. In this case, the selection rectangle 37 37 * will be the largest window with this aspect ratio, where the position the left 38 * mouse button was pressed and the corner of the current mouse position are at 38 * mouse button was pressed and the corner of the current mouse position are at 39 39 * opposite sites (the mouse position corner is the corner nearest to the mouse 40 * cursor). 41 * 42 * When the left mouse button was released, an ActionEvent is send to the 40 * cursor). 41 * 42 * When the left mouse button was released, an ActionEvent is send to the 43 43 * ActionListener given at constructor. The source of this event is this manager. 44 * 44 * 45 45 * @author imi 46 46 */ 47 47 public class SelectionManager implements MouseListener, MouseMotionListener, PropertyChangeListener { 48 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 *the left button is released.104 105 *ratio of the drawComponent.106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 49 /** 50 * This is the interface that an user of SelectionManager has to implement 51 * to get informed when a selection closes. 52 * @author imi 53 */ 54 public interface SelectionEnded { 55 /** 56 * Called, when the left mouse button was released. 57 * @param r The rectangle that is currently the selection. 58 * @param alt Whether the alt key was pressed 59 * @param shift Whether the shift key was pressed 60 * @param ctrl Whether the ctrl key was pressed 61 * @see InputEvent#getModifiersEx() 62 */ 63 public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl); 64 /** 65 * Called to register the selection manager for "active" property. 66 * @param listener The listener to register 67 */ 68 public void addPropertyChangeListener(PropertyChangeListener listener); 69 /** 70 * Called to remove the selection manager from the listener list 71 * for "active" property. 72 * @param listener The listener to register 73 */ 74 public void removePropertyChangeListener(PropertyChangeListener listener); 75 } 76 /** 77 * The listener that receives the events after left mouse button is released. 78 */ 79 private final SelectionEnded selectionEndedListener; 80 /** 81 * Position of the map when the mouse button was pressed. 82 * If this is not <code>null</code>, a rectangle is drawn on screen. 83 */ 84 private Point mousePosStart; 85 /** 86 * Position of the map when the selection rectangle was last drawn. 87 */ 88 private Point mousePos; 89 /** 90 * The Component, the selection rectangle is drawn onto. 91 */ 92 private final NavigatableComponent nc; 93 /** 94 * Whether the selection rectangle must obtain the aspect ratio of the 95 * drawComponent. 96 */ 97 private boolean aspectRatio; 98 99 /** 100 * Create a new SelectionManager. 101 * 102 * @param selectionEndedListener The action listener that receives the event when 103 * the left button is released. 104 * @param aspectRatio If true, the selection window must obtain the aspect 105 * ratio of the drawComponent. 106 * @param navComp The component, the rectangle is drawn onto. 107 */ 108 public SelectionManager(SelectionEnded selectionEndedListener, boolean aspectRatio, NavigatableComponent navComp) { 109 this.selectionEndedListener = selectionEndedListener; 110 this.aspectRatio = aspectRatio; 111 this.nc = navComp; 112 } 113 114 /** 115 * Register itself at the given event source. 116 * @param eventSource The emitter of the mouse events. 117 */ 118 public void register(NavigatableComponent eventSource) { 119 eventSource.addMouseListener(this); 120 eventSource.addMouseMotionListener(this); 121 selectionEndedListener.addPropertyChangeListener(this); 122 122 eventSource.addPropertyChangeListener("scale", new PropertyChangeListener(){ 123 124 125 126 127 123 public void propertyChange(PropertyChangeEvent evt) { 124 if (mousePosStart != null) { 125 paintRect(); 126 mousePos = mousePosStart = null; 127 } 128 128 } 129 129 }); 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 *that are touched, instead those which are completly covered.267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 130 } 131 /** 132 * Unregister itself from the given event source. If a selection rectangle is 133 * shown, hide it first. 134 * 135 * @param eventSource The emitter of the mouse events. 136 */ 137 public void unregister(Component eventSource) { 138 eventSource.removeMouseListener(this); 139 eventSource.removeMouseMotionListener(this); 140 selectionEndedListener.removePropertyChangeListener(this); 141 } 142 143 /** 144 * If the correct button, from the "drawing rectangle" mode 145 */ 146 public void mousePressed(MouseEvent e) { 147 if (e.getButton() == MouseEvent.BUTTON1) 148 mousePosStart = mousePos = e.getPoint(); 149 } 150 151 /** 152 * If the correct button is hold, draw the rectangle. 153 */ 154 public void mouseDragged(MouseEvent e) { 155 int buttonPressed = e.getModifiersEx() & (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK); 156 157 158 if (buttonPressed != 0) { 159 if (mousePosStart == null) 160 mousePosStart = mousePos = e.getPoint(); 161 paintRect(); 162 } 163 164 if (buttonPressed == MouseEvent.BUTTON1_DOWN_MASK) { 165 mousePos = e.getPoint(); 166 paintRect(); 167 } else if (buttonPressed == (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK)) { 168 mousePosStart.x += e.getX()-mousePos.x; 169 mousePosStart.y += e.getY()-mousePos.y; 170 mousePos = e.getPoint(); 171 paintRect(); 172 } 173 } 174 175 /** 176 * Check the state of the keys and buttons and set the selection accordingly. 177 */ 178 public void mouseReleased(MouseEvent e) { 179 if (e.getButton() != MouseEvent.BUTTON1) 180 return; 181 if (mousePos == null || mousePosStart == null) 182 return; // injected release from outside 183 184 // disable the selection rect 185 paintRect(); 186 Rectangle r = getSelectionRectangle(); 187 mousePosStart = null; 188 mousePos = null; 189 190 boolean shift = (e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0; 191 boolean alt = (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0; 192 boolean ctrl = (e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0; 193 if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) == 0) 194 selectionEndedListener.selectionEnded(r, alt, shift, ctrl); 195 } 196 197 198 /** 199 * Draw a selection rectangle on screen. If already a rectangle is drawn, 200 * it is removed instead. 201 */ 202 private void paintRect() { 203 if (mousePos == null || mousePosStart == null || mousePos == mousePosStart) 204 return; 205 Graphics g = nc.getGraphics(); 206 g.setColor(Color.BLACK); 207 g.setXORMode(Color.WHITE); 208 209 Rectangle r = getSelectionRectangle(); 210 g.drawRect(r.x,r.y,r.width,r.height); 211 } 212 213 /** 214 * Calculate and return the current selection rectangle 215 * @return A rectangle that spans from mousePos to mouseStartPos 216 */ 217 private Rectangle getSelectionRectangle() { 218 int x = mousePosStart.x; 219 int y = mousePosStart.y; 220 int w = mousePos.x - mousePosStart.x; 221 int h = mousePos.y - mousePosStart.y; 222 if (w < 0) { 223 x += w; 224 w = -w; 225 } 226 if (h < 0) { 227 y += h; 228 h = -h; 229 } 230 231 if (aspectRatio) { 232 /* Keep the aspect ratio by growing the rectangle; the 233 * rectangle is always under the cursor. */ 234 double aspectRatio = (double)nc.getWidth()/nc.getHeight(); 235 if ((double)w/h < aspectRatio) { 236 int neww = (int)(h*aspectRatio); 237 if (mousePos.x < mousePosStart.x) 238 x += w - neww; 239 w = neww; 240 } else { 241 int newh = (int)(w/aspectRatio); 242 if (mousePos.y < mousePosStart.y) 243 y += h - newh; 244 h = newh; 245 } 246 } 247 248 return new Rectangle(x,y,w,h); 249 } 250 251 /** 252 * If the action goes inactive, remove the selection rectangle from screen 253 */ 254 public void propertyChange(PropertyChangeEvent evt) { 255 if (evt.getPropertyName().equals("active") && !(Boolean)evt.getNewValue() && mousePosStart != null) { 256 paintRect(); 257 mousePosStart = null; 258 mousePos = null; 259 } 260 } 261 262 /** 263 * Return a list of all objects in the rectangle, respecting the different 264 * modifier. 265 * @param alt Whether the alt key was pressed, which means select all objects 266 * that are touched, instead those which are completly covered. 267 */ 268 public Collection<OsmPrimitive> getObjectsInRectangle(Rectangle r, boolean alt) { 269 Collection<OsmPrimitive> selection = new LinkedList<OsmPrimitive>(); 270 271 // whether user only clicked, not dragged. 272 boolean clicked = r.width <= 2 && r.height <= 2; 273 Point center = new Point(r.x+r.width/2, r.y+r.height/2); 274 275 if (clicked) { 276 OsmPrimitive osm = nc.getNearest(center); 277 if (osm != null) 278 selection.add(osm); 279 } else { 280 // nodes 281 for (Node n : nc.getData().nodes) { 282 if (!n.deleted && !n.incomplete && r.contains(nc.getPoint(n.eastNorth))) 283 selection.add(n); 284 } 285 286 // ways 287 for (Way w : nc.getData().ways) { 288 if (w.deleted || w.nodes.isEmpty() || w.incomplete) 289 continue; 290 if (alt) { 291 for (Node n : w.nodes) { 292 if (!n.incomplete && r.contains(nc.getPoint(n.eastNorth))) { 293 selection.add(w); 294 break; 295 } 296 } 297 } else { 298 boolean allIn = true; 299 for (Node n : w.nodes) { 300 if (!n.incomplete && !r.contains(nc.getPoint(n.eastNorth))) { 301 allIn = false; 302 break; 303 } 304 } 305 if (allIn) selection.add(w); 306 } 307 } 308 } 309 return selection; 310 } 311 312 public void mouseClicked(MouseEvent e) {} 313 public void mouseEntered(MouseEvent e) {} 314 public void mouseExited(MouseEvent e) {} 315 public void mouseMoved(MouseEvent e) {} 316 316 } -
trunk/src/org/openstreetmap/josm/gui/SideButton.java
r1103 r1169 12 12 13 13 public class SideButton extends JButton { 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 14 public SideButton(Action action) 15 { 16 super(action); 17 doStyle(); 18 setText(null); 19 } 20 public SideButton(String imagename, String property, String tooltip, ActionListener actionListener) 21 { 22 super(ImageProvider.get("dialogs", imagename)); 23 doStyle(); 24 setActionCommand(imagename); 25 addActionListener(actionListener); 26 setToolTipText(tooltip); 27 } 28 @Deprecated 29 public SideButton(String name, String imagename, String property, String tooltip, int mnemonic, ActionListener actionListener) 30 { 31 super(tr(name), ImageProvider.get("dialogs", imagename)); 32 setMnemonic(mnemonic); 33 setup(name, property, tooltip, actionListener); 34 } 35 public SideButton(String name, String imagename, String property, String tooltip, Shortcut shortcut, ActionListener actionListener) 36 { 37 super(tr(name), ImageProvider.get("dialogs", imagename)); 38 if(shortcut != null) 39 39 { 40 40 shortcut.setMnemonic(this); 41 41 if(tooltip != null) 42 42 tooltip = Main.platform.makeTooltip(tooltip, shortcut); 43 43 } 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 44 setup(name, property, tooltip, actionListener); 45 } 46 public SideButton(String name, String imagename, String property, String tooltip, ActionListener actionListener) 47 { 48 super(tr(name), ImageProvider.get("dialogs", imagename)); 49 setup(name, property, tooltip, actionListener); 50 } 51 private void setup(String name, String property, String tooltip, ActionListener actionListener) 52 { 53 doStyle(); 54 setActionCommand(name); 55 addActionListener(actionListener); 56 setToolTipText(tooltip); 57 putClientProperty("help", "Dialog/"+property+"/"+name); 58 } 59 private void doStyle() 60 { 61 setMargin(new Insets(1,1,1,1)); 62 setIconTextGap(2); 63 } 64 64 } -
trunk/src/org/openstreetmap/josm/gui/SplashScreen.java
r1138 r1169 30 30 /** 31 31 * Show a splash screen so the user knows what is happening during startup. 32 * 33 * @author cbrill 32 * 33 * @author cbrill 34 34 */ 35 35 public class SplashScreen extends JWindow { 36 36 37 38 37 private JLabel status; 38 private boolean visible; 39 39 40 40 private Runnable closerRunner; 41 41 42 43 44 42 public SplashScreen(boolean visible) { 43 super(); 44 this.visible=visible; 45 45 46 47 46 if (!visible) 47 return; 48 48 49 50 51 52 49 // Add a nice border to the main splash screen 50 JPanel contentPane = (JPanel)this.getContentPane(); 51 Border margin = new EtchedBorder(1, Color.white, Color.gray); 52 contentPane.setBorder(margin); 53 53 54 55 56 57 58 54 // Add a margin from the border to the content 55 JPanel innerContentPane = new JPanel(); 56 innerContentPane.setBorder(new EmptyBorder(10, 10, 2, 10)); 57 contentPane.add(innerContentPane); 58 innerContentPane.setLayout(new GridBagLayout()); 59 59 60 61 62 63 64 60 // Add the logo 61 JLabel logo = new JLabel(ImageProvider.get("logo.png")); 62 GridBagConstraints gbc = new GridBagConstraints(); 63 gbc.gridheight = 2; 64 innerContentPane.add(logo, gbc); 65 65 66 67 68 69 70 71 72 66 // Add the name of this application 67 JLabel caption = new JLabel(tr("JOSM - Java OpenStreetMap Editor")); 68 caption.setFont(new Font("Helvetica", Font.BOLD, 20)); 69 gbc.gridheight = 1; 70 gbc.gridx = 1; 71 gbc.insets = new Insets(30, 0, 0, 0); 72 innerContentPane.add(caption, gbc); 73 73 74 75 76 77 78 74 // Add the version number 75 JLabel version = new JLabel(tr("Version {0}", AboutAction.getVersionString())); 76 gbc.gridy = 1; 77 gbc.insets = new Insets(0, 0, 0, 0); 78 innerContentPane.add(version, gbc); 79 79 80 81 82 83 84 85 86 87 80 // Add a separator to the status text 81 JSeparator separator = new JSeparator(JSeparator.HORIZONTAL); 82 gbc.gridx = 0; 83 gbc.gridy = 2; 84 gbc.gridwidth = 2; 85 gbc.fill = GridBagConstraints.HORIZONTAL; 86 gbc.insets = new Insets(15, 0, 5, 0); 87 innerContentPane.add(separator, gbc); 88 88 89 90 91 92 93 94 89 // Add a status message 90 status = new JLabel(); 91 gbc.gridy = 3; 92 gbc.insets = new Insets(0, 0, 0, 0); 93 innerContentPane.add(status, gbc); 94 setStatus(tr("Initializing")); 95 95 96 96 pack(); 97 97 98 99 100 101 102 98 // Center the splash screen 99 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 100 Dimension labelSize = contentPane.getPreferredSize(); 101 setLocation(screenSize.width / 2 - (labelSize.width / 2), 102 screenSize.height / 2 - (labelSize.height / 2)); 103 103 104 105 106 107 108 109 110 104 // Method to close the splash screen when being clicked or when closeSplash is called 105 closerRunner = new Runnable() { 106 public void run() { 107 setVisible(false); 108 dispose(); 109 } 110 }; 111 111 112 113 114 115 116 117 118 119 120 121 122 123 124 112 // Add ability to hide splash screen by clicking it 113 addMouseListener(new MouseAdapter() { 114 public void mousePressed(MouseEvent event) { 115 try { 116 closerRunner.run(); 117 } catch (Exception e) { 118 e.printStackTrace(); 119 // can catch InvocationTargetException 120 // can catch InterruptedException 121 } 122 } 123 }); 124 125 125 // Hide splashscreen when other window is created 126 Toolkit.getDefaultToolkit().addAWTEventListener(awtListener, AWTEvent.WINDOW_EVENT_MASK); 127 128 setVisible(true); 129 } 130 131 private AWTEventListener awtListener = new AWTEventListener() { 132 public void eventDispatched(AWTEvent event) { 133 if (event.getSource() != SplashScreen.this) { 134 closeSplash(); 135 } 136 } 137 }; 126 Toolkit.getDefaultToolkit().addAWTEventListener(awtListener, AWTEvent.WINDOW_EVENT_MASK); 138 127 139 /** 140 * This method sets the status message. It should be called prior to 141 * actually doing the action. 142 * 143 * @param message 144 * the message to be displayed 145 */ 146 public void setStatus(String message) { 147 if (!visible) 148 return; 149 status.setText(message + " ..."); 150 } 128 setVisible(true); 129 } 151 130 152 /** 153 * Closes the splashscreen. Call once you are done starting. 154 */ 155 public void closeSplash() { 156 if (!visible) 157 return; 158 Toolkit.getDefaultToolkit().removeAWTEventListener(awtListener); 159 try { 160 SwingUtilities.invokeLater(closerRunner); 161 } catch (Exception e) { 162 e.printStackTrace(); 163 // can catch InvocationTargetException 164 // can catch InterruptedException 165 } 166 } 131 private AWTEventListener awtListener = new AWTEventListener() { 132 public void eventDispatched(AWTEvent event) { 133 if (event.getSource() != SplashScreen.this) { 134 closeSplash(); 135 } 136 } 137 }; 138 139 /** 140 * This method sets the status message. It should be called prior to 141 * actually doing the action. 142 * 143 * @param message 144 * the message to be displayed 145 */ 146 public void setStatus(String message) { 147 if (!visible) 148 return; 149 status.setText(message + " ..."); 150 } 151 152 /** 153 * Closes the splashscreen. Call once you are done starting. 154 */ 155 public void closeSplash() { 156 if (!visible) 157 return; 158 Toolkit.getDefaultToolkit().removeAWTEventListener(awtListener); 159 try { 160 SwingUtilities.invokeLater(closerRunner); 161 } catch (Exception e) { 162 e.printStackTrace(); 163 // can catch InvocationTargetException 164 // can catch InterruptedException 165 } 166 } 167 167 168 168 } -
trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java
r1084 r1169 24 24 public class CommandStackDialog extends ToggleDialog implements CommandQueueListener { 25 25 26 26 private DefaultTreeModel treeModel = new DefaultTreeModel(new DefaultMutableTreeNode()); 27 27 private JTree tree = new JTree(treeModel); 28 28 29 30 31 32 29 public CommandStackDialog(final MapFrame mapFrame) { 30 super(tr("Command Stack"), "commandstack", tr("Open a list of all commands (undo buffer)."), 31 Shortcut.registerShortcut("subwindow:commandstack", tr("Toggle: {0}", tr("Command Stack")), KeyEvent.VK_O, Shortcut.GROUP_LAYER), 100); 32 Main.main.undoRedo.listenerCommands.add(this); 33 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 34 tree.setRootVisible(false); 35 tree.setShowsRootHandles(true); 36 tree.expandRow(0); 37 tree.setCellRenderer(new DefaultTreeCellRenderer(){ 38 @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { 39 super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); 40 DefaultMutableTreeNode v = (DefaultMutableTreeNode)value; 41 if (v.getUserObject() instanceof JLabel) { 42 JLabel l = (JLabel)v.getUserObject(); 43 setIcon(l.getIcon()); 44 setText(l.getText()); 45 } 46 return this; 47 } 48 }); 49 tree.setVisibleRowCount(8); 50 add(new JScrollPane(tree), BorderLayout.CENTER); 51 } 52 52 53 54 55 56 57 58 59 53 @Override public void setVisible(boolean v) { 54 if (v) 55 buildList(); 56 else if (tree != null) 57 treeModel.setRoot(new DefaultMutableTreeNode()); 58 super.setVisible(v); 59 } 60 60 61 62 63 64 65 66 67 68 69 70 61 private void buildList() { 62 if (Main.map == null || Main.map.mapView == null || Main.map.mapView.editLayer == null) 63 return; 64 Collection<Command> commands = Main.main.undoRedo.commands; 65 DefaultMutableTreeNode root = new DefaultMutableTreeNode(); 66 for (Command c : commands) 67 root.add(c.description()); 68 treeModel.setRoot(root); 69 tree.scrollRowToVisible(treeModel.getChildCount(root)-1); 70 } 71 71 72 73 74 72 public void commandChanged(int queueSize, int redoSize) { 73 if (!isVisible()) 74 return; 75 75 treeModel.setRoot(new DefaultMutableTreeNode()); 76 76 buildList(); 77 77 } 78 78 } -
trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java
r1117 r1169 47 47 public final class ConflictDialog extends ToggleDialog { 48 48 49 50 51 49 public final Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>(); 50 private final DefaultListModel model = new DefaultListModel(); 51 private final JList displaylist = new JList(model); 52 52 53 54 55 56 57 58 59 60 61 62 63 64 53 public ConflictDialog() { 54 super(tr("Conflict"), "conflict", tr("Merging conflicts."), 55 Shortcut.registerShortcut("subwindow:conflict", tr("Toggle: {0}", tr("Conflict")), KeyEvent.VK_C, Shortcut.GROUP_LAYER), 100); 56 displaylist.setCellRenderer(new OsmPrimitivRenderer()); 57 displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 58 displaylist.addMouseListener(new MouseAdapter(){ 59 @Override public void mouseClicked(MouseEvent e) { 60 if (e.getClickCount() >= 2) 61 resolve(); 62 } 63 }); 64 add(new JScrollPane(displaylist), BorderLayout.CENTER); 65 65 66 67 68 69 70 71 72 66 JPanel buttonPanel = new JPanel(new GridLayout(1,2)); 67 buttonPanel.add(new SideButton(marktr("Resolve"), "conflict", "Conflict", 68 tr("Open a merge dialog of all selected items in the list above."), new ActionListener(){ 69 public void actionPerformed(ActionEvent e) { 70 resolve(); 71 } 72 })); 73 73 74 75 76 77 78 79 80 81 82 83 74 buttonPanel.add(new SideButton(marktr("Select"), "select", "Conflict", 75 tr("Set the selected elements on the map to the selected items in the list above."), new ActionListener(){ 76 public void actionPerformed(ActionEvent e) { 77 Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>(); 78 for (Object o : displaylist.getSelectedValues()) 79 sel.add((OsmPrimitive)o); 80 Main.ds.setSelected(sel); 81 } 82 })); 83 add(buttonPanel, BorderLayout.SOUTH); 84 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 85 DataSet.selListeners.add(new SelectionChangedListener(){ 86 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 87 displaylist.clearSelection(); 88 for (OsmPrimitive osm : newSelection) { 89 if (conflicts.containsKey(osm)) { 90 int pos = model.indexOf(osm); 91 displaylist.addSelectionInterval(pos, pos); 92 } 93 } 94 } 95 }); 96 displaylist.getSelectionModel().addListSelectionListener(new ListSelectionListener(){ 97 public void valueChanged(ListSelectionEvent e) { 98 Main.map.mapView.repaint(); 99 } 100 }); 101 } 102 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 103 private final void resolve() { 104 if (displaylist.getSelectedIndex() == -1) { 105 JOptionPane.showMessageDialog(Main.parent,tr("Please select something from the conflict list.")); 106 return; 107 } 108 Map<OsmPrimitive, OsmPrimitive> sel = new HashMap<OsmPrimitive, OsmPrimitive>(); 109 for (int i : displaylist.getSelectedIndices()) { 110 OsmPrimitive s = (OsmPrimitive)model.get(i); 111 sel.put(s, conflicts.get(s)); 112 } 113 ConflictResolver resolver = new ConflictResolver(sel); 114 int answer = JOptionPane.showConfirmDialog(Main.parent, resolver, tr("Resolve Conflicts"), JOptionPane.OK_CANCEL_OPTION); 115 if (answer != JOptionPane.OK_OPTION) 116 return; 117 Main.main.undoRedo.add(new ConflictResolveCommand(resolver.conflicts, sel)); 118 Main.map.mapView.repaint(); 119 } 120 120 121 122 123 124 125 126 127 128 121 public final void rebuildList() { 122 model.removeAllElements(); 123 for (OsmPrimitive osm : this.conflicts.keySet()) 124 if (osm instanceof Node) 125 model.addElement(osm); 126 for (OsmPrimitive osm : this.conflicts.keySet()) 127 if (osm instanceof Way) 128 model.addElement(osm); 129 129 for (OsmPrimitive osm : this.conflicts.keySet()) 130 130 if (osm instanceof Relation) … … 132 132 } 133 133 134 135 136 137 134 public final void add(Map<OsmPrimitive, OsmPrimitive> conflicts) { 135 this.conflicts.putAll(conflicts); 136 rebuildList(); 137 } 138 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 139 /** 140 * Paint all conflicts that can be expressed on the main window. 141 */ 142 public void paintConflicts(final Graphics g, final NavigatableComponent nc) { 143 Color preferencesColor = Main.pref.getColor("conflict", Color.gray); 144 if (preferencesColor.equals(Color.BLACK)) 145 return; 146 g.setColor(preferencesColor); 147 Visitor conflictPainter = new Visitor(){ 148 public void visit(Node n) { 149 Point p = nc.getPoint(n.eastNorth); 150 g.drawRect(p.x-1, p.y-1, 2, 2); 151 } 152 public void visit(Node n1, Node n2) { 153 Point p1 = nc.getPoint(n1.eastNorth); 154 Point p2 = nc.getPoint(n2.eastNorth); 155 g.drawLine(p1.x, p1.y, p2.x, p2.y); 156 } 157 public void visit(Way w) { 158 Node lastN = null; 159 for (Node n : w.nodes) { 160 if (lastN == null) { 161 lastN = n; 162 continue; 163 } 164 visit(lastN, n); 165 lastN = n; 166 } 167 } 168 public void visit(Relation e) { 169 for (RelationMember em : e.members) 170 em.member.visit(this); 171 } 172 }; 173 for (Object o : displaylist.getSelectedValues()) 174 conflicts.get(o).visit(conflictPainter); 175 } 176 176 } -
trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java
r1084 r1169 54 54 public class HistoryDialog extends ToggleDialog implements SelectionChangedListener { 55 55 56 57 58 59 60 61 62 56 public static final Date unifyDate(Date d) { 57 Calendar c = Calendar.getInstance(); 58 c.setTime(d); 59 c.set(Calendar.MINUTE, 0); 60 c.set(Calendar.SECOND, 0); 61 return c.getTime(); 62 } 63 63 64 65 66 64 private static class HistoryItem implements Comparable<HistoryItem> { 65 OsmPrimitive osm; 66 boolean visible; 67 67 68 69 70 71 68 public int compareTo(HistoryItem o) { 69 return unifyDate(osm.getTimestamp()).compareTo(unifyDate(o.osm.getTimestamp())); 70 } 71 } 72 72 73 74 75 76 77 73 private final DefaultTableModel data = new DefaultTableModel(){ 74 @Override public boolean isCellEditable(int row, int column) { 75 return false; 76 } 77 }; 78 78 79 80 81 82 83 84 79 /** 80 * Main table. 3 columns: 81 * Object | Date | visible (icon, no text) 82 */ 83 private JTable history = new JTable(data); 84 private JScrollPane historyPane = new JScrollPane(history); 85 85 86 87 86 private Map<OsmPrimitive, List<HistoryItem>> cache = new HashMap<OsmPrimitive, List<HistoryItem>>(); 87 private JLabel notLoaded = new JLabel("<html><i>"+tr("Click Reload to refresh list")+"</i></html>"); 88 88 89 90 91 92 93 94 95 89 public HistoryDialog() { 90 super(tr("History"), "history", tr("Display the history of all selected items."), 91 Shortcut.registerShortcut("subwindow:history", tr("Toggle: {0}", tr("History")), KeyEvent.VK_H, 92 Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150); 93 historyPane.setVisible(false); 94 notLoaded.setVisible(true); 95 notLoaded.setHorizontalAlignment(JLabel.CENTER); 96 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 97 history.setDefaultRenderer(Object.class, new DefaultTableCellRenderer(){ 98 @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 99 return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 100 } 101 }); 102 data.setColumnIdentifiers(new Object[]{tr("Object"),tr("Date"),""}); 103 history.getColumnModel().getColumn(0).setPreferredWidth(200); 104 history.getColumnModel().getColumn(1).setPreferredWidth(200); 105 history.getColumnModel().getColumn(2).setPreferredWidth(20); 106 final TableCellRenderer oldRenderer = history.getTableHeader().getDefaultRenderer(); 107 history.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer(){ 108 @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 109 JComponent c = (JComponent)oldRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 110 if (!value.equals("")) 111 return c; 112 JLabel l = new JLabel(ImageProvider.get("misc","showhide")); 113 l.setForeground(c.getForeground()); 114 l.setBackground(c.getBackground()); 115 l.setFont(c.getFont()); 116 l.setBorder(c.getBorder()); 117 l.setOpaque(true); 118 return l; 119 } 120 }); 121 121 122 123 124 125 122 JPanel centerPanel = new JPanel(new GridBagLayout()); 123 centerPanel.add(notLoaded, GBC.eol().fill(GBC.BOTH)); 124 centerPanel.add(historyPane, GBC.eol().fill(GBC.BOTH)); 125 add(centerPanel, BorderLayout.CENTER); 126 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 127 JPanel buttons = new JPanel(new GridLayout(1,2)); 128 buttons.add(new SideButton(marktr("Reload"), "refresh", "History", tr("Reload all currently selected objects and refresh the list."), 129 new ActionListener(){ 130 public void actionPerformed(ActionEvent e) { 131 reload(); 132 } 133 })); 134 buttons.add(new SideButton(marktr("Revert"), "revert", "History", 135 tr("Revert the state of all currently selected objects to the version selected in the history list."), new ActionListener(){ 136 public void actionPerformed(ActionEvent e) { 137 JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet.")); 138 } 139 })); 140 add(buttons, BorderLayout.SOUTH); 141 141 142 143 142 DataSet.selListeners.add(this); 143 } 144 144 145 145 146 147 148 149 150 146 @Override public void setVisible(boolean b) { 147 super.setVisible(b); 148 if (b) 149 update(); 150 } 151 151 152 152 153 154 155 156 153 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 154 if (isVisible()) 155 update(); 156 } 157 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 158 /** 159 * Identify all new objects in the selection and if any, hide the list. 160 * Else, update the list with the selected items shown. 161 */ 162 private void update() { 163 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 164 if (!cache.keySet().containsAll(sel)) { 165 historyPane.setVisible(false); 166 notLoaded.setVisible(true); 167 } else { 168 SortedSet<HistoryItem> orderedHistory = new TreeSet<HistoryItem>(); 169 for (OsmPrimitive osm : sel) 170 orderedHistory.addAll(cache.get(osm)); 171 data.setRowCount(0); 172 for (HistoryItem i : orderedHistory) 173 data.addRow(new Object[]{i.osm, i.osm.timestamp, i.visible}); 174 historyPane.setVisible(true); 175 notLoaded.setVisible(false); 176 } 177 } 178 178 179 180 181 179 void reload() { 180 JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet.")); 181 } 182 182 } -
trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
r1084 r1169 50 50 public class LayerListDialog extends ToggleDialog implements LayerChangeListener { 51 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 52 /** 53 * The last layerlist created. Used to update the list in the Show/Hide and Delete actions. 54 * TODO: Replace with Listener-Pattern. 55 */ 56 static JList instance; 57 private JScrollPane listScrollPane; 58 59 public final static class DeleteLayerAction extends AbstractAction { 60 61 private final Layer layer; 62 63 public DeleteLayerAction(Layer layer) { 64 super(tr("Delete"), ImageProvider.get("dialogs", "delete")); 65 putValue(SHORT_DESCRIPTION, tr("Delete the selected layer.")); 66 putValue("help", "Action/LayerDelete"); 67 this.layer = layer; 68 } 69 70 public void actionPerformed(ActionEvent e) { 71 int sel = instance.getSelectedIndex(); 72 Layer l = layer != null ? layer : (Layer)instance.getSelectedValue(); 73 if(l == null) 74 return; 75 if (l instanceof OsmDataLayer) 76 { 77 if (((OsmDataLayer)l).isModified()) 78 { 79 if(JOptionPane.showConfirmDialog(instance, tr("There are unsaved changes. Delete the layer anwyay?"), 80 tr("Unsaved Changes"), JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) 81 return; 82 } 83 else if(!DontShowAgainInfo.show("delete_layer", tr("Do you really want to delete the whole layer?"), false)) 84 return; 85 } 86 Main.main.removeLayer(l); 87 if (sel >= instance.getModel().getSize()) 88 sel = instance.getModel().getSize()-1; 89 if (instance.getSelectedValue() == null) 90 instance.setSelectedIndex(sel); 91 if (Main.map != null) 92 Main.map.mapView.setActiveLayer((Layer)instance.getSelectedValue()); 93 } 94 } 95 96 public final static class ShowHideLayerAction extends AbstractAction { 97 private final Layer layer; 98 99 public ShowHideLayerAction(Layer layer) { 100 super(tr("Show/Hide"), ImageProvider.get("dialogs", "showhide")); 101 putValue(SHORT_DESCRIPTION, tr("Toggle visible state of the selected layer.")); 102 putValue("help", "Action/LayerShowHide"); 103 this.layer = layer; 104 } 105 106 public void actionPerformed(ActionEvent e) { 107 Layer l = layer == null ? (Layer)instance.getSelectedValue() : layer; 108 if(l == null) 109 return; 110 l.visible = !l.visible; 111 Main.map.mapView.repaint(); 112 instance.repaint(); 113 } 114 } 115 116 public final static class ShowHideMarkerText extends AbstractAction { 117 private final Layer layer; 118 119 public ShowHideMarkerText(Layer layer) { 120 super(tr("Show/Hide Text/Icons"), ImageProvider.get("dialogs", "showhide")); 121 putValue(SHORT_DESCRIPTION, tr("Toggle visible state of the marker text and icons.")); 122 putValue("help", "Action/ShowHideTextIcons"); 123 this.layer = layer; 124 } 125 126 public void actionPerformed(ActionEvent e) { 127 Layer l = layer == null ? (Layer)instance.getSelectedValue() : layer; 128 String current = Main.pref.get("marker.show "+l.name,"show"); 129 Main.pref.put("marker.show "+l.name, current.equalsIgnoreCase("show") ? "hide" : "show"); 130 Main.map.mapView.repaint(); 131 instance.repaint(); 132 } 133 } 134 135 /** 136 * The data model for the list component. 137 */ 138 DefaultListModel model = new DefaultListModel(); 139 /** 140 * The merge action. This is only called, if the current selection and its 141 * item below are editable datasets and the merge button is clicked. 142 */ 143 private final SideButton mergeButton; 144 /** 145 * Button for moving layer up. 146 */ 147 private final SideButton upButton; 148 /** 149 * Button for moving layer down. 150 */ 151 private final SideButton downButton; 152 /** 153 * Button for delete layer. 154 */ 155 private Action deleteAction = new DeleteLayerAction(null); 156 157 /** 158 * Create an layerlist and attach it to the given mapView. 159 */ 160 public LayerListDialog(MapFrame mapFrame) { 161 super(tr("Layers"), "layerlist", tr("Open a list of all loaded layers."), 162 Shortcut.registerShortcut("subwindow:layers", tr("Toggle: {0}", tr("Layers")), KeyEvent.VK_L, Shortcut.GROUP_LAYER), 100); 163 instance = new JList(model); 164 listScrollPane = new JScrollPane(instance); 165 add(listScrollPane, BorderLayout.CENTER); 166 instance.setBackground(UIManager.getColor("Button.background")); 167 instance.setCellRenderer(new DefaultListCellRenderer(){ 168 @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 169 Layer layer = (Layer)value; 170 JLabel label = (JLabel)super.getListCellRendererComponent(list, 171 layer.name, index, isSelected, cellHasFocus); 172 Icon icon = layer.getIcon(); 173 if (!layer.visible) 174 icon = ImageProvider.overlay(icon, "overlay/invisible", OverlayPosition.SOUTHEAST); 175 label.setIcon(icon); 176 label.setToolTipText(layer.getToolTipText()); 177 return label; 178 } 179 }); 180 181 final MapView mapView = mapFrame.mapView; 182 183 Collection<Layer> data = mapView.getAllLayers(); 184 for (Layer l : data) 185 model.addElement(l); 186 187 instance.setSelectedValue(mapView.getActiveLayer(), true); 188 instance.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 189 instance.addListSelectionListener(new ListSelectionListener(){ 190 public void valueChanged(ListSelectionEvent e) { 191 if (instance.getModel().getSize() == 0) 192 return; 193 if (instance.getSelectedIndex() == -1) 194 instance.setSelectedIndex(e.getFirstIndex()); 195 mapView.setActiveLayer((Layer)instance.getSelectedValue()); 196 } 197 }); 198 Layer.listeners.add(this); 199 200 instance.addMouseListener(new MouseAdapter(){ 201 private void openPopup(MouseEvent e) { 202 Point p = listScrollPane.getMousePosition(); 203 if (p == null) 204 return; // user is faster than swing with mouse movement 205 int index = instance.locationToIndex(e.getPoint()); 206 Layer layer = (Layer)instance.getModel().getElementAt(index); 207 LayerListPopup menu = new LayerListPopup(instance, layer); 208 menu.show(listScrollPane, p.x, p.y-3); 209 } 210 @Override public void mousePressed(MouseEvent e) { 211 if (e.isPopupTrigger()) 212 openPopup(e); 213 } 214 @Override public void mouseReleased(MouseEvent e) { 215 if (e.isPopupTrigger()) 216 openPopup(e); 217 } 218 @Override public void mouseClicked(MouseEvent e) { 219 if (e.getClickCount() == 2) { 220 int index = instance.locationToIndex(e.getPoint()); 221 Layer layer = (Layer)instance.getModel().getElementAt(index); 222 String current = Main.pref.get("marker.show "+layer.name,"show"); 223 Main.pref.put("marker.show "+layer.name, current.equalsIgnoreCase("show") ? "hide" : "show"); 224 layer.visible = !layer.visible; 225 Main.map.mapView.repaint(); 226 instance.repaint(); 227 } 228 } 229 }); 230 231 232 // Buttons 233 JPanel buttonPanel = new JPanel(new GridLayout(1, 5)); 234 235 ActionListener upDown = new ActionListener(){ 236 public void actionPerformed(ActionEvent e) { 237 Layer l = (Layer)instance.getSelectedValue(); 238 int sel = instance.getSelectedIndex(); 239 int selDest = e.getActionCommand().equals("up") ? sel-1 : sel+1; 240 mapView.moveLayer(l, selDest); 241 model.set(sel, model.get(selDest)); 242 model.set(selDest, l); 243 instance.setSelectedIndex(selDest); 244 updateButtonEnabled(); 245 mapView.repaint(); 246 } 247 }; 248 249 upButton = new SideButton("up", "LayerList", tr("Move the selected layer one row up."), upDown); 250 buttonPanel.add(upButton); 251 252 downButton = new SideButton("down", "LayerList", tr("Move the selected layer one row down."), upDown); 253 buttonPanel.add(downButton); 254 255 buttonPanel.add(new SideButton(new ShowHideLayerAction(null))); 256 buttonPanel.add(new SideButton(deleteAction)); 257 258 mergeButton = new SideButton("Merge", "mergedown", "LayerList", tr("Merge the layer directly below into the selected layer."), 259 new ActionListener(){ 260 public void actionPerformed(ActionEvent e) { 261 Layer lTo = (Layer)instance.getSelectedValue(); 262 Layer lFrom = (Layer)model.get(instance.getSelectedIndex()+1); 263 lTo.mergeFrom(lFrom); 264 mapView.removeLayer(lFrom); 265 &nbs