Changeset 1169 in josm
- Timestamp:
- 2008-12-23T15:07:05+01:00 (14 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 * @returnAn read-only text area with the content of "resource"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 public void actionPerformed(ActionEvent e) { 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