Changeset 1169 in josm for trunk/src/org/openstreetmap/josm/tools
- Timestamp:
- 2008-12-23T15:07:05+01:00 (16 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/tools
- Files:
-
- 23 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/tools/AudioPlayer.java
r891 r1169 18 18 /** 19 19 * Creates and controls a separate audio player thread. 20 * 20 * 21 21 * @author David Earl <david@frankieandshadow.com> 22 22 * … … 24 24 public class AudioPlayer extends Thread { 25 25 26 27 28 private enum State { INITIALIZING, NOTPLAYING, PLAYING, PAUSED, INTERRUPTED } 29 26 private static AudioPlayer audioPlayer = null; 27 28 private enum State { INITIALIZING, NOTPLAYING, PLAYING, PAUSED, INTERRUPTED } 29 private State state; 30 30 private enum Command { PLAY, PAUSE } 31 31 private enum Result { WAITING, OK, FAILED } … … 33 33 private double leadIn; // seconds 34 34 private double calibration; // ratio of purported duration of samples to true duration 35 36 private double bytesPerSecond; 37 38 39 40 41 * Passes information from the control thread to the playing thread 42 43 44 45 46 47 48 49 50 51 52 * Called to execute the commands in the other thread 53 54 55 56 57 this.speed = speed; 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 * Plays a WAV audio file from the beginning. See also the variant which doesn't 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 * gets the singleton object, and if this is the first time, creates it along with 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 AudioFormataudioFormat = null;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 case PLAY: 266 267 268 if (playingUrl != command.url() || 269 stateChange != State.PAUSED || 270 offset != 0.0) 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 /* skip doesn't seem to want to skip big chunks, so 291 * reduce it to smaller ones 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 audioFormat = new AudioFormat(audioFormat.getEncoding(), 307 audioFormat.getSampleRate() * (float) (speed * calibration), 308 audioFormat.getSampleSizeInBits(), 309 audioFormat.getChannels(), 310 audioFormat.getFrameSize(), 311 audioFormat.getFrameRate() * (float) (speed * calibration), 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 JOptionPane.showMessageDialog(Main.parent, 336 337 338 35 private double position; // seconds 36 private double bytesPerSecond; 37 private static long chunk = 4000; /* bytes */ 38 private double speed = 1.0; 39 40 /** 41 * Passes information from the control thread to the playing thread 42 */ 43 private class Execute { 44 private Command command; 45 private Result result; 46 private Exception exception; 47 private URL url; 48 private double offset; // seconds 49 private double speed; // ratio 50 51 /* 52 * Called to execute the commands in the other thread 53 */ 54 protected void play(URL url, double offset, double speed) throws Exception { 55 this.url = url; 56 this.offset = offset; 57 this.speed = speed; 58 command = Command.PLAY; 59 result = Result.WAITING; 60 send(); 61 } 62 protected void pause() throws Exception { 63 command = Command.PAUSE; 64 send(); 65 } 66 private void send() throws Exception { 67 result = Result.WAITING; 68 interrupt(); 69 while (result == Result.WAITING) { sleep(10); /* yield(); */ } 70 if (result == Result.FAILED) { throw exception; } 71 } 72 private void possiblyInterrupt() throws InterruptedException { 73 if (interrupted() || result == Result.WAITING) 74 throw new InterruptedException(); 75 } 76 protected void failed (Exception e) { 77 exception = e; 78 result = Result.FAILED; 79 state = State.NOTPLAYING; 80 } 81 protected void ok (State newState) { 82 result = Result.OK; 83 state = newState; 84 } 85 protected double offset() { 86 return offset; 87 } 88 protected double speed() { 89 return speed; 90 } 91 protected URL url() { 92 return url; 93 } 94 protected Command command() { 95 return command; 96 } 97 } 98 99 private Execute command; 100 101 /** 102 * Plays a WAV audio file from the beginning. See also the variant which doesn't 103 * start at the beginning of the stream 104 * @param url The resource to play, which must be a WAV file or stream 105 * @throws audio fault exception, e.g. can't open stream, unhandleable audio format 106 */ 107 public static void play(URL url) throws Exception { 108 AudioPlayer.get().command.play(url, 0.0, 1.0); 109 } 110 111 /** 112 * Plays a WAV audio file from a specified position. 113 * @param url The resource to play, which must be a WAV file or stream 114 * @param seconds The number of seconds into the audio to start playing 115 * @throws audio fault exception, e.g. can't open stream, unhandleable audio format 116 */ 117 public static void play(URL url, double seconds) throws Exception { 118 AudioPlayer.get().command.play(url, seconds, 1.0); 119 } 120 121 /** 122 * Plays a WAV audio file from a specified position at variable speed. 123 * @param url The resource to play, which must be a WAV file or stream 124 * @param seconds The number of seconds into the audio to start playing 125 * @param speed Rate at which audio playes (1.0 = real time, > 1 is faster) 126 * @throws audio fault exception, e.g. can't open stream, unhandleable audio format 127 */ 128 public static void play(URL url, double seconds, double speed) throws Exception { 129 AudioPlayer.get().command.play(url, seconds, speed); 130 } 131 132 /** 133 * Pauses the currently playing audio stream. Does nothing if nothing playing. 134 * @throws audio fault exception, e.g. can't open stream, unhandleable audio format 135 */ 136 public static void pause() throws Exception { 137 AudioPlayer.get().command.pause(); 138 } 139 140 /** 141 * To get the Url of the playing or recently played audio. 142 * @return url - could be null 143 */ 144 public static URL url() { 145 return AudioPlayer.get().playingUrl; 146 } 147 148 /** 149 * Whether or not we are paused. 150 * @return boolean whether or not paused 151 */ 152 public static boolean paused() { 153 return AudioPlayer.get().state == State.PAUSED; 154 } 155 156 /** 157 * Whether or not we are playing. 158 * @return boolean whether or not playing 159 */ 160 public static boolean playing() { 161 return AudioPlayer.get().state == State.PLAYING; 162 } 163 164 /** 165 * How far we are through playing, in seconds. 166 * @return double seconds 167 */ 168 public static double position() { 169 return AudioPlayer.get().position; 170 } 171 172 /** 173 * Speed at which we will play. 174 * @return double, speed multiplier 175 */ 176 public static double speed() { 177 return AudioPlayer.get().speed; 178 } 179 180 /** 181 * gets the singleton object, and if this is the first time, creates it along with 182 * the thread to support audio 183 */ 184 private static AudioPlayer get() { 185 if (audioPlayer != null) 186 return audioPlayer; 187 try { 188 audioPlayer = new AudioPlayer(); 189 return audioPlayer; 190 } catch (Exception ex) { 191 return null; 192 } 193 } 194 195 private AudioPlayer() { 196 state = State.INITIALIZING; 197 command = new Execute(); 198 playingUrl = null; 199 try { 200 leadIn = Double.parseDouble(Main.pref.get("audio.leadin", "1.0" /* default, seconds */)); 201 } catch (NumberFormatException e) { 202 leadIn = 1.0; // failed to parse 203 } 204 try { 205 calibration = Double.parseDouble(Main.pref.get("audio.calibration", "1.0" /* default, ratio */)); 206 } catch (NumberFormatException e) { 207 calibration = 1.0; // failed to parse 208 } 209 start(); 210 while (state == State.INITIALIZING) { yield(); } 211 } 212 213 /** 214 * Starts the thread to actually play the audio, per Thread interface 215 * Not to be used as public, though Thread interface doesn't allow it to be made private 216 */ 217 @Override public void run() { 218 /* code running in separate thread */ 219 220 playingUrl = null; 221 AudioInputStream audioInputStream = null; 222 SourceDataLine audioOutputLine = null; 223 AudioFormat audioFormat = null; 224 byte[] abData = new byte[(int)chunk]; 225 226 for (;;) { 227 try { 228 switch (state) { 229 case INITIALIZING: 230 // we're ready to take interrupts 231 state = State.NOTPLAYING; 232 break; 233 case NOTPLAYING: 234 case PAUSED: 235 sleep(200); 236 break; 237 case PLAYING: 238 command.possiblyInterrupt(); 239 for(;;) { 240 int nBytesRead = 0; 241 nBytesRead = audioInputStream.read(abData, 0, abData.length); 242 position += nBytesRead / bytesPerSecond; 243 command.possiblyInterrupt(); 244 if (nBytesRead < 0) { break; } 245 audioOutputLine.write(abData, 0, nBytesRead); // => int nBytesWritten 246 command.possiblyInterrupt(); 247 } 248 // end of audio, clean up 249 audioOutputLine.drain(); 250 audioOutputLine.close(); 251 audioOutputLine = null; 252 audioInputStream.close(); 253 audioInputStream = null; 254 playingUrl = null; 255 state = State.NOTPLAYING; 256 command.possiblyInterrupt(); 257 break; 258 } 259 } catch (InterruptedException e) { 260 interrupted(); // just in case we get an interrupt 261 State stateChange = state; 262 state = State.INTERRUPTED; 263 try { 264 switch (command.command()) { 265 case PLAY: 266 double offset = command.offset(); 267 speed = command.speed(); 268 if (playingUrl != command.url() || 269 stateChange != State.PAUSED || 270 offset != 0.0) 271 { 272 if (audioInputStream != null) { 273 audioInputStream.close(); 274 audioInputStream = null; 275 } 276 playingUrl = command.url(); 277 audioInputStream = AudioSystem.getAudioInputStream(playingUrl); 278 audioFormat = audioInputStream.getFormat(); 279 long nBytesRead = 0; 280 position = 0.0; 281 offset -= leadIn; 282 double calibratedOffset = offset * calibration; 283 bytesPerSecond = audioFormat.getFrameRate() /* frames per second */ 284 * audioFormat.getFrameSize() /* bytes per frame */; 285 if (speed * bytesPerSecond > 256000.0) 286 speed = 256000 / bytesPerSecond; 287 if (calibratedOffset > 0.0) { 288 long bytesToSkip = (long)( 289 calibratedOffset /* seconds (double) */ * bytesPerSecond); 290 /* skip doesn't seem to want to skip big chunks, so 291 * reduce it to smaller ones 292 */ 293 // audioInputStream.skip(bytesToSkip); 294 while (bytesToSkip > chunk) { 295 nBytesRead = audioInputStream.skip(chunk); 296 if (nBytesRead <= 0) 297 throw new IOException(tr("This is after the end of the recording")); 298 bytesToSkip -= nBytesRead; 299 } 300 if (bytesToSkip > 0) 301 audioInputStream.skip(bytesToSkip); 302 position = offset; 303 } 304 if (audioOutputLine != null) 305 audioOutputLine.close(); 306 audioFormat = new AudioFormat(audioFormat.getEncoding(), 307 audioFormat.getSampleRate() * (float) (speed * calibration), 308 audioFormat.getSampleSizeInBits(), 309 audioFormat.getChannels(), 310 audioFormat.getFrameSize(), 311 audioFormat.getFrameRate() * (float) (speed * calibration), 312 audioFormat.isBigEndian()); 313 DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); 314 audioOutputLine = (SourceDataLine) AudioSystem.getLine(info); 315 audioOutputLine.open(audioFormat); 316 audioOutputLine.start(); 317 } 318 stateChange = State.PLAYING; 319 break; 320 case PAUSE: 321 stateChange = State.PAUSED; 322 break; 323 } 324 command.ok(stateChange); 325 } catch (Exception startPlayingException) { 326 command.failed(startPlayingException); // sets state 327 } 328 } catch (Exception e) { 329 state = State.NOTPLAYING; 330 } 331 } 332 } 333 334 public static void audioMalfunction(Exception ex) { 335 JOptionPane.showMessageDialog(Main.parent, 336 "<html><p>" + tr(ex.getMessage()) + "</p></html>", 337 tr("Error playing sound"), JOptionPane.ERROR_MESSAGE); 338 } 339 339 } -
trunk/src/org/openstreetmap/josm/tools/AutoCompleteComboBox.java
r741 r1169 17 17 public class AutoCompleteComboBox extends JComboBox { 18 18 19 20 21 22 23 24 25 26 19 /** 20 * Auto-complete a JComboBox. 21 * 22 * Inspired by http://www.orbital-computer.de/JComboBox/ 23 */ 24 private class AutoCompleteComboBoxDocument extends PlainDocument { 25 private JComboBox comboBox; 26 private boolean selecting = false; 27 27 28 29 30 28 public AutoCompleteComboBoxDocument(final JComboBox comboBox) { 29 this.comboBox = comboBox; 30 } 31 31 32 33 34 35 36 32 @Override public void remove(int offs, int len) throws BadLocationException { 33 if (selecting) 34 return; 35 super.remove(offs, len); 36 } 37 37 38 39 40 41 42 38 @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { 39 if(selecting || (offs == 0 && str.equals(getText(0, getLength())))) 40 return; 41 boolean initial = (offs == 0 && getLength() == 0 && str.length() > 1); 42 super.insertString(offs, str, a); 43 43 44 45 46 47 48 44 // return immediately when selecting an item 45 // Note: this is done after calling super method because we need 46 // ActionListener informed 47 if (selecting) 48 return; 49 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 50 int size = getLength(); 51 int start = offs+str.length(); 52 int end = start; 53 String curText = getText(0, size); 54 // lookup and select a matching item 55 Object item = lookupItem(curText); 56 setSelectedItem(item); 57 if(initial) 58 start = 0; 59 if (item != null) { 60 String newText = item.toString(); 61 if(!newText.equals(curText)) 62 { 63 selecting = true; 64 super.remove(0, size); 65 super.insertString(0, newText, a); 66 selecting = false; 67 start = size; 68 end = getLength(); 69 } 70 } 71 JTextComponent editor = (JTextComponent)comboBox.getEditor().getEditorComponent(); 72 editor.setSelectionStart(start); 73 editor.setSelectionEnd(end); 74 } 75 75 76 77 78 79 80 76 private void setSelectedItem(Object item) { 77 selecting = true; 78 comboBox.setSelectedItem(item); 79 selecting = false; 80 } 81 81 82 83 84 85 86 87 88 89 90 91 82 private Object lookupItem(String pattern) { 83 ComboBoxModel model = comboBox.getModel(); 84 for (int i = 0, n = model.getSize(); i < n; i++) { 85 Object currentItem = model.getElementAt(i); 86 if (currentItem.toString().startsWith(pattern)) 87 return currentItem; 88 } 89 return null; 90 } 91 } 92 92 93 94 95 96 93 public AutoCompleteComboBox() { 94 JTextComponent editor = (JTextComponent) this.getEditor().getEditorComponent(); 95 editor.setDocument(new AutoCompleteComboBoxDocument(this)); 96 } 97 97 98 99 100 101 102 103 104 98 public void setPossibleItems(Collection<String> elems) { 99 DefaultComboBoxModel model = (DefaultComboBoxModel)this.getModel(); 100 Object oldValue = this.getEditor().getItem(); 101 model.removeAllElements(); 102 for (String elem : elems) model.addElement(elem); 103 this.getEditor().setItem(oldValue); 104 } 105 105 } -
trunk/src/org/openstreetmap/josm/tools/BugReportExceptionHandler.java
r1032 r1169 39 39 public final class BugReportExceptionHandler implements Thread.UncaughtExceptionHandler { 40 40 41 42 43 44 45 46 47 48 49 50 51 41 public void uncaughtException(Thread t, Throwable e) { 42 e.printStackTrace(); 43 if (Main.parent != null) { 44 if (e instanceof OutOfMemoryError) { 45 // do not translate the string, as translation may raise an exception 46 JOptionPane.showMessageDialog(Main.parent, "JOSM is out of memory. " + 47 "Strange things may happen.\nPlease restart JOSM with the -Xmx###M option,\n" + 48 "where ### is the the number of MB assigned to JOSM (e.g. 256).\n" + 49 "Currently, " + Runtime.getRuntime().maxMemory()/1024/1024 + " MB are available to JOSM."); 50 return; 51 } 52 52 53 53 PluginProxy plugin = null; 54 54 55 56 57 55 // Check for an explicit problem when calling a plugin function 56 if (e instanceof PluginException) 57 plugin = ((PluginException)e).plugin; 58 58 59 60 59 if (plugin == null) 60 plugin = guessPlugin(e); 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 88 89 90 62 if (plugin != null) { 63 int answer = JOptionPane.showConfirmDialog( 64 Main.parent, tr("An unexpected exception occurred that may have come from the ''{0}'' plugin.", 65 plugin.info.name) + "\n"+ (plugin.info.author != null ? 66 tr("According to the information within the plugin, the author is {0}.", 67 plugin.info.author) : "") + "\n" + 68 tr("Try updating to the newest version of this plugin before reporting a bug.") + "\n" + 69 tr("Should the plugin be disabled?"), 70 tr("Disable plugin"), 71 JOptionPane.YES_NO_OPTION); 72 if (answer == JOptionPane.OK_OPTION) { 73 LinkedList<String> plugins = new LinkedList<String>(Arrays.asList(Main.pref.get("plugins").split(","))); 74 if (plugins.contains(plugin.info.name)) { 75 while (plugins.remove(plugin.info.name)) {} 76 String p = ""; 77 for (String s : plugins) 78 p += ","+s; 79 if (p.length() > 0) 80 p = p.substring(1); 81 Main.pref.put("plugins", p); 82 JOptionPane.showMessageDialog(Main.parent, 83 tr("The plugin has been removed from the configuration. Please restart JOSM to unload the plugin.")); 84 } else { 85 JOptionPane.showMessageDialog(Main.parent, 86 tr("The plugin could not be removed. Please tell the people you got JOSM from about the problem.")); 87 } 88 return; 89 } 90 } 91 91 92 93 94 95 96 97 98 99 100 101 92 Object[] options = new String[]{tr("Do nothing"), tr("Report Bug")}; 93 int answer = JOptionPane.showOptionDialog(Main.parent, tr("An unexpected exception occurred.\n\n" + 94 "This is always a coding error. If you are running the latest\n" + 95 "version of JOSM, please consider being kind and file a bug report."), 96 tr("Unexpected Exception"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, 97 null, options, options[0]); 98 if (answer == 1) { 99 try { 100 StringWriter stack = new StringWriter(); 101 e.printStackTrace(new PrintWriter(stack)); 102 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 103 URL revUrl = Main.class.getResource("/REVISION"); 104 StringBuilder sb = new StringBuilder(); 105 if (revUrl == null) { 106 sb.append(tr("Development version. Unknown revision.")); 107 File f = new File("org/openstreetmap/josm/Main.class"); 108 if (!f.exists()) 109 f = new File("bin/org/openstreetmap/josm/Main.class"); 110 if (!f.exists()) 111 f = new File("build/org/openstreetmap/josm/Main.class"); 112 if (f.exists()) { 113 DateFormat sdf = SimpleDateFormat.getDateTimeInstance(); 114 sb.append("\nMain.class build on "+sdf.format(new Date(f.lastModified()))); 115 sb.append("\n"); 116 } 117 } else { 118 BufferedReader in = new BufferedReader(new InputStreamReader(revUrl.openStream())); 119 for (String line = in.readLine(); line != null; line = in.readLine()) { 120 sb.append(line); 121 sb.append('\n'); 122 } 123 } 124 sb.append("\n"+stack.getBuffer().toString()); 125 125 126 127 128 129 130 131 132 133 134 135 136 126 JPanel p = new JPanel(new GridBagLayout()); 127 p.add(new JLabel(tr("<html>Please report a ticket at {0}<br>" + 128 "Include your steps to get to the error (as detailed as possible)!<br>" + 129 "Be sure to include the following information:</html>", "http://josm.openstreetmap.de/newticket")), GBC.eol()); 130 try { 131 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(sb.toString()), new ClipboardOwner(){ 132 public void lostOwnership(Clipboard clipboard, Transferable contents) {} 133 }); 134 p.add(new JLabel(tr("(The text has already been copied to your clipboard.)")), GBC.eop()); 135 } 136 catch (RuntimeException x) {} 137 137 138 139 140 141 138 JTextArea info = new JTextArea(sb.toString(), 20, 60); 139 info.setCaretPosition(0); 140 info.setEditable(false); 141 p.add(new JScrollPane(info), GBC.eop()); 142 142 143 144 145 146 147 148 149 143 JOptionPane.showMessageDialog(Main.parent, p); 144 } catch (Exception e1) { 145 e1.printStackTrace(); 146 } 147 } 148 } 149 } 150 150 151 152 153 154 155 156 157 151 private PluginProxy guessPlugin(Throwable e) { 152 String name = guessPluginName(e); 153 for (PluginProxy p : Main.plugins) 154 if (p.info.name.equals(name)) 155 return p; 156 return null; 157 } 158 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 159 /** 160 * Analyze the stack of the argument and return a name of a plugin, if 161 * some known problem pattern has been found or <code>null</code>, if 162 * the stack does not contain plugin-code. 163 * 164 * Note: This heuristic is not meant as discrimination against specific 165 * plugins, but only to stop the flood of similar bug reports about plugins. 166 * Of course, plugin writers are free to install their own version of 167 * an exception handler with their email address listed to receive 168 * bug reports ;-). 169 */ 170 private String guessPluginName(Throwable e) { 171 for (StackTraceElement element : e.getStackTrace()) { 172 String c = element.getClassName(); 173 173 174 175 176 177 178 179 180 181 182 183 184 185 174 if (c.contains("wmsplugin.") || c.contains(".WMSLayer")) 175 return "wmsplugin"; 176 if (c.contains("landsat.") || c.contains(".LandsatLayer")) 177 return "landsat"; 178 if (c.contains("livegps.")) 179 return "livegps"; 180 if (c.contains("mappaint.")) 181 return "mappaint"; 182 if (c.contains("annotationtester.")) 183 return "annotation-tester"; 184 if (c.startsWith("UtilsPlugin.")) 185 return "UtilsPlugin"; 186 186 187 188 189 190 191 192 193 194 195 187 if (c.startsWith("org.openstreetmap.josm.plugins.")) { 188 String p = c.substring("org.openstreetmap.josm.plugins.".length()); 189 if (p.indexOf('.') != -1 && p.matches("[a-z].*")) { 190 return p.substring(0,p.indexOf('.')); 191 } 192 } 193 } 194 return null; 195 } 196 196 } -
trunk/src/org/openstreetmap/josm/tools/ColorHelper.java
r885 r1169 8 8 */ 9 9 public class ColorHelper { 10 11 public static Color html2color(String html) {12 if (html.length() > 0 && html.charAt(0) == '#')13 html = html.substring(1);14 else if (html.length() != 6 && html.length() != 8)15 return null;16 try {17 return new Color(18 Integer.parseInt(html.substring(0,2),16),19 Integer.parseInt(html.substring(2,4),16),20 Integer.parseInt(html.substring(4,6),16),21 (html.length() == 8 ? Integer.parseInt(html.substring(6,8),16) : 255));22 } catch (NumberFormatException e) {23 return null;24 }25 }26 10 27 private static String int2hex(int i) { 28 String s = Integer.toHexString(i / 16) + Integer.toHexString(i % 16); 29 return s.toUpperCase(); 30 } 31 32 public static String color2html(Color col) { 33 return "#"+int2hex(col.getRed())+int2hex(col.getGreen())+int2hex(col.getBlue()); 34 } 11 public static Color html2color(String html) { 12 if (html.length() > 0 && html.charAt(0) == '#') 13 html = html.substring(1); 14 else if (html.length() != 6 && html.length() != 8) 15 return null; 16 try { 17 return new Color( 18 Integer.parseInt(html.substring(0,2),16), 19 Integer.parseInt(html.substring(2,4),16), 20 Integer.parseInt(html.substring(4,6),16), 21 (html.length() == 8 ? Integer.parseInt(html.substring(6,8),16) : 255)); 22 } catch (NumberFormatException e) { 23 return null; 24 } 25 } 26 27 private static String int2hex(int i) { 28 String s = Integer.toHexString(i / 16) + Integer.toHexString(i % 16); 29 return s.toUpperCase(); 30 } 31 32 public static String color2html(Color col) { 33 return "#"+int2hex(col.getRed())+int2hex(col.getGreen())+int2hex(col.getBlue()); 34 } 35 35 } -
trunk/src/org/openstreetmap/josm/tools/DateParser.java
r627 r1169 8 8 /** 9 9 * Tries to parse a date as good as it can. 10 * 10 * 11 11 * @author Immanuel.Scholz 12 12 */ 13 13 public class DateParser { 14 15 16 14 public static Date parse(String d) throws ParseException { 15 return new PrimaryDateParser().parse(d); 16 } 17 17 } -
trunk/src/org/openstreetmap/josm/tools/Destroyable.java
r627 r1169 6 6 * been removed) have an definite set of actions to execute. This is the "destructor" interface called 7 7 * on those objects. 8 * 8 * 9 9 * @author immanuel.scholz 10 10 */ 11 11 public interface Destroyable { 12 12 13 14 15 16 13 /** 14 * Called when the object has been destroyed. 15 */ 16 public void destroy(); 17 17 } -
trunk/src/org/openstreetmap/josm/tools/DontShowAgainInfo.java
r1004 r1169 16 16 public class DontShowAgainInfo { 17 17 18 19 20 18 public static boolean show(String prefKey, String msg) { 19 return show(prefKey, new JLabel(msg), true, JOptionPane.OK_CANCEL_OPTION, JOptionPane.OK_OPTION); 20 } 21 21 22 23 24 22 public static boolean show(String prefKey, String msg, Boolean state) { 23 return show(prefKey, new JLabel(msg), state, JOptionPane.OK_CANCEL_OPTION, JOptionPane.OK_OPTION); 24 } 25 25 26 27 28 26 public static boolean show(String prefKey, Container msg) { 27 return show(prefKey, msg, true, JOptionPane.OK_CANCEL_OPTION, JOptionPane.OK_OPTION); 28 } 29 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 30 public static boolean show(String prefKey, Container msg, Boolean state, int options, int true_option) { 31 if (!Main.pref.getBoolean("message."+prefKey)) { 32 JCheckBox dontshowagain = new JCheckBox(tr("Do not show again")); 33 dontshowagain.setSelected(Main.pref.getBoolean("message."+prefKey, state)); 34 JPanel all = new JPanel(new GridBagLayout()); 35 all.add(msg, GBC.eop()); 36 all.add(dontshowagain, GBC.eol()); 37 int answer = JOptionPane.showConfirmDialog(Main.parent, all, tr("Information"), options); 38 if (answer != true_option) 39 return false; 40 Main.pref.put("message."+prefKey, dontshowagain.isSelected()); 41 } 42 return true; 43 } 44 44 } -
trunk/src/org/openstreetmap/josm/tools/ExifReader.java
r627 r1169 18 18 public class ExifReader { 19 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 20 @SuppressWarnings("unchecked") public static Date readTime(File filename) throws ParseException { 21 Date date = null; 22 try { 23 Metadata metadata = JpegMetadataReader.readMetadata(filename); 24 for (Iterator<Directory> dirIt = metadata.getDirectoryIterator(); dirIt.hasNext();) { 25 for (Iterator<Tag> tagIt = dirIt.next().getTagIterator(); tagIt.hasNext();) { 26 Tag tag = tagIt.next(); 27 if (tag.getTagType() == 0x9003) 28 return DateParser.parse(tag.getDescription()); 29 if (tag.getTagType() == 0x132 || tag.getTagType() == 0x9004) 30 date = DateParser.parse(tag.getDescription()); 31 } 32 } 33 } catch (ParseException e) { 34 throw e; 35 35 } catch (Exception e) { 36 36 e.printStackTrace(); 37 37 } 38 39 38 return date; 39 } 40 40 } -
trunk/src/org/openstreetmap/josm/tools/FallbackDateParser.java
r627 r1169 13 13 * based on similar code in JOSM. This class is not threadsafe, a separate 14 14 * instance must be created per thread. 15 * 15 * 16 16 * @author Brett Henderson 17 17 */ 18 18 public class FallbackDateParser { 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 * 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 19 20 private static final String[] formats = { 21 "yyyy-MM-dd'T'HH:mm:ss'Z'", 22 "yyyy-MM-dd'T'HH:mm:ssZ", 23 "yyyy-MM-dd'T'HH:mm:ss", 24 "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", 25 "yyyy-MM-dd'T'HH:mm:ss.SSSZ", 26 "yyyy-MM-dd HH:mm:ss", 27 "MM/dd/yyyy HH:mm:ss", 28 "MM/dd/yyyy'T'HH:mm:ss.SSS'Z'", 29 "MM/dd/yyyy'T'HH:mm:ss.SSSZ", 30 "MM/dd/yyyy'T'HH:mm:ss.SSS", 31 "MM/dd/yyyy'T'HH:mm:ssZ", 32 "MM/dd/yyyy'T'HH:mm:ss", 33 "yyyy:MM:dd HH:mm:ss" 34 }; 35 36 37 private List<DateFormat> dateParsers; 38 private int activeDateParser; 39 40 41 /** 42 * Creates a new instance. 43 */ 44 public FallbackDateParser() { 45 // Build a list of candidate date parsers. 46 dateParsers = new ArrayList<DateFormat>(formats.length); 47 for (int i = 0; i < formats.length; i++) { 48 dateParsers.add(new SimpleDateFormat(formats[i])); 49 } 50 51 // We haven't selected a date parser yet. 52 activeDateParser = -1; 53 } 54 55 56 /** 57 * Attempts to parse the specified date. 58 * 59 * @param date 60 * The date to parse. 61 * @return The date. 62 * @throws ParseException 63 * Occurs if the date does not match any of the supported date 64 * formats. 65 */ 66 public Date parse(String date) throws ParseException { 67 String correctedDate; 68 69 // Try to fix ruby's broken xmlschema - format 70 // Replace this: 71 // 2007-02-12T18:43:01+00:00 72 // With this: 73 // 2007-02-12T18:43:01+0000 74 if (date.length() == 25 && date.charAt(22) == ':') { 75 correctedDate = date.substring(0, 22) + date.substring(23, 25); 76 } else { 77 correctedDate = date; 78 } 79 80 // If we have previously successfully used a date parser, we'll try it 81 // first. 82 if (activeDateParser >= 0) { 83 try { 84 return dateParsers.get(activeDateParser).parse(correctedDate); 85 } catch (ParseException e) { 86 // The currently active parser didn't work, so we must clear it 87 // and find a new appropriate parser. 88 activeDateParser = -1; 89 } 90 } 91 92 // Try the date parsers one by one until a suitable format is found. 93 for (int i = 0; i < dateParsers.size(); i++) { 94 try { 95 Date result; 96 97 // Attempt to parse with the current parser, if successful we 98 // store its index for next time. 99 result = dateParsers.get(i).parse(correctedDate); 100 activeDateParser = i; 101 102 return result; 103 104 } catch (ParseException pe) { 105 // Ignore parsing errors and try the next pattern. 106 } 107 } 108 109 throw new ParseException("The date string (" + date + ") could not be parsed.", 0); 110 } 111 111 } -
trunk/src/org/openstreetmap/josm/tools/GBC.java
r627 r1169 12 12 * A wrapper for GridBagConstraints which has sane default static creators and 13 13 * member functions to chain calling. 14 * 14 * 15 15 * @author imi 16 16 */ 17 17 public class GBC extends GridBagConstraints { 18 18 19 20 21 22 19 /** 20 * Use public static creator functions to create an GBC. 21 */ 22 private GBC() {} 23 23 24 25 26 27 28 29 30 31 32 24 /** 25 * Create a standard constraint (which is not the last). 26 * @return A standard constraint with no filling. 27 */ 28 public static GBC std() { 29 GBC c = new GBC(); 30 c.anchor = WEST; 31 return c; 32 } 33 33 34 35 36 37 38 39 40 41 42 34 /** 35 * Create the constraint for the last elements on a line. 36 * @return A constraint which indicates the last item on a line. 37 */ 38 public static GBC eol() { 39 GBC c = std(); 40 c.gridwidth = REMAINDER; 41 return c; 42 } 43 43 44 45 46 47 48 49 50 51 44 /** 45 * Create the constraint for the last elements on a line and on a paragraph. 46 * This is merely a shortcut for eol().insets(0,0,0,10) 47 * @return A constraint which indicates the last item on a line. 48 */ 49 public static GBC eop() { 50 return eol().insets(0,0,0,10); 51 } 52 52 53 54 55 56 57 58 59 53 /** 54 * Try to fill both, horizontal and vertical 55 * @return This constraint for chaining. 56 */ 57 public GBC fill() { 58 return fill(BOTH); 59 } 60 60 61 62 63 64 65 66 67 68 69 70 71 72 73 61 /** 62 * Set fill to the given value 63 * @param value The filling value, either NONE, HORIZONTAL, VERTICAL or BOTH 64 * @return This constraint for chaining. 65 */ 66 public GBC fill(int value) { 67 fill = value; 68 if (value == HORIZONTAL || value == BOTH) 69 weightx = 1.0; 70 if (value == VERTICAL || value == BOTH) 71 weighty = 1.0; 72 return this; 73 } 74 74 75 76 77 78 79 80 81 82 83 75 /** 76 * Set the anchor of this GBC to a. 77 * @param a The new anchor, e.g. GBC.CENTER or GBC.EAST. 78 * @return This constraint for chaining. 79 */ 80 public GBC anchor(int a) { 81 anchor = a; 82 return this; 83 } 84 84 85 86 87 * @param leftThe left space of the insets88 * @param topThe top space of the insets89 * @param rightThe right space of the insets90 * @param bottomThe bottom space of the insets91 92 93 94 95 96 85 /** 86 * Adds insets to this GBC. 87 * @param left The left space of the insets 88 * @param top The top space of the insets 89 * @param right The right space of the insets 90 * @param bottom The bottom space of the insets 91 * @return This constraint for chaining. 92 */ 93 public GBC insets(int left, int top, int right, int bottom) { 94 insets = new Insets(top, left, bottom, right); 95 return this; 96 } 97 97 98 99 100 101 *horizontal strut.102 103 *vertical strut.104 105 106 107 108 109 98 /** 99 * This is a helper to easily create a glue with a minimum default value. 100 * @param x If higher than 0, this will be a horizontal glue with x as minimum 101 * horizontal strut. 102 * @param y If higher than 0, this will be a vertical glue with y as minimum 103 * vertical strut. 104 */ 105 public static Component glue(int x, int y) { 106 short maxx = x > 0 ? Short.MAX_VALUE : 0; 107 short maxy = y > 0 ? Short.MAX_VALUE : 0; 108 return new Box.Filler(new Dimension(x,y), new Dimension(x,y), new Dimension(maxx,maxy)); 109 } 110 110 } -
trunk/src/org/openstreetmap/josm/tools/I18n.java
r1065 r1169 10 10 /** 11 11 * Internationalisation support. 12 * 12 * 13 13 * @author Immanuel.Scholz 14 14 */ 15 15 public class I18n { 16 16 17 18 17 /* Base name for translation data. Used for detecting available translations */ 18 private static final String TR_BASE = "org.openstreetmap.josm.i18n.Translation_"; 19 19 20 21 22 23 24 20 /** 21 * Set by MainApplication. Changes here later will probably mess up everything, because 22 * many strings are already loaded. 23 */ 24 public static org.xnap.commons.i18n.I18n i18n; 25 25 26 27 28 29 30 26 public static final String tr(String text, Object... objects) { 27 if (i18n == null) 28 return MessageFormat.format(text, objects); 29 return i18n.tr(text, objects); 30 } 31 31 32 33 34 35 36 32 public static final String tr(String text) { 33 if (i18n == null) 34 return text; 35 return i18n.tr(text); 36 } 37 37 38 39 40 38 public static final String marktr(String text) { 39 return text; 40 } 41 41 42 43 44 45 46 42 public static final String trn(String text, String pluralText, long n, Object... objects) { 43 if (i18n == null) 44 return n == 1 ? tr(text, objects) : tr(pluralText, objects); 45 return i18n.trn(text, pluralText, n, objects); 46 } 47 47 48 49 50 51 52 48 public static final String trn(String text, String pluralText, long n) { 49 if (i18n == null) 50 return n == 1 ? tr(text) : tr(pluralText); 51 return i18n.trn(text, pluralText, n); 52 } 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 54 /** 55 * Get a list of all available JOSM Translations. 56 * @return an array of locale objects. 57 */ 58 public static final Locale[] getAvailableTranslations() { 59 Vector<Locale> v = new Vector<Locale>(); 60 Locale[] l = Locale.getAvailableLocales(); 61 for (int i = 0; i < l.length; i++) { 62 String cn = TR_BASE + l[i]; 63 try { 64 Class.forName(cn); 65 v.add(l[i]); 66 } catch (ClassNotFoundException e) { 67 } 68 } 69 l = new Locale[v.size()]; 70 l = v.toArray(l); 71 Arrays.sort(l, new Comparator<Locale>() { 72 public int compare(Locale o1, Locale o2) { 73 return o1.toString().compareTo(o2.toString()); 74 } 75 }); 76 return l; 77 } 78 78 } -
trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
r991 r1169 32 32 public class ImageProvider { 33 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 * @param subdirThe position of the directory, e.g. "layer"55 * @param nameThe icons name (without the ending of ".png")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 34 /** 35 * Position of an overlay icon 36 * @author imi 37 */ 38 public static enum OverlayPosition {NORTHWEST, NORTHEAST, SOUTHWEST, SOUTHEAST} 39 40 /** 41 * The icon cache 42 */ 43 private static Map<String, Image> cache = new HashMap<String, Image>(); 44 45 /** 46 * Add here all ClassLoader whose ressource should be searched. 47 * Plugin's class loaders are added by main. 48 */ 49 public static final List<ClassLoader> sources = new LinkedList<ClassLoader>(); 50 51 /** 52 * Return an image from the specified location. 53 * 54 * @param subdir The position of the directory, e.g. "layer" 55 * @param name The icons name (without the ending of ".png") 56 * @return The requested Image. 57 */ 58 public static ImageIcon get(String subdir, String name) { 59 ImageIcon icon = getIfAvailable(subdir, name); 60 if (icon == null) { 61 String ext = name.indexOf('.') != -1 ? "" : ".png"; 62 throw new NullPointerException("/images/"+subdir+name+ext+" not found"); 63 } 64 return icon; 65 } 66 67 public static ImageIcon getIfAvailable(String subdir, String name) 68 { 69 return getIfAvailable((Collection<String>)null, null, subdir, name); 70 } 71 public static final ImageIcon getIfAvailable(String[] dirs, String id, String subdir, String name) 72 { 73 return getIfAvailable(Arrays.asList(dirs), id, subdir, name); 74 } 75 76 /** 77 * Like {@link #get(String)}, but does not throw and return <code>null</code> 78 * in case of nothing is found. Use this, if the image to retrieve is optional. 79 */ 80 public static ImageIcon getIfAvailable(Collection<String> dirs, String id, String subdir, String name) 81 { 82 if (name == null) 83 return null; 84 if (subdir == null) 85 subdir = ""; 86 else if (!subdir.equals("")) 87 subdir += "/"; 88 String ext = name.indexOf('.') != -1 ? "" : ".png"; 89 String full_name = subdir+name+ext; 90 String cache_name = full_name; 91 /* cache separately */ 92 if(dirs != null && dirs.size() > 0) 93 cache_name = "id:"+id+":"+full_name; 94 95 Image img = cache.get(cache_name); 96 if (img == null) { 97 // getImageUrl() does a ton of "stat()" calls and gets expensive 98 // and redundant when you have a whole ton of objects. So, 99 // index the cache by the name of the icon we're looking for 100 // and don't bother to create a URL unless we're actually 101 // creating the image. 102 URL path = getImageUrl(full_name, dirs); 103 if (path == null) 104 return null; 105 img = Toolkit.getDefaultToolkit().createImage(path); 106 cache.put(cache_name, img); 107 } 108 109 return new ImageIcon(img); 110 } 111 112 private static URL getImageUrl(String path, String name) 113 { 114 if(path.startsWith("resource://")) 115 { 116 String p = path.substring("resource://".length()); 117 for (ClassLoader source : sources) 118 { 119 URL res; 120 if ((res = source.getResource(p+name)) != null) 121 return res; 122 } 123 } 124 else 125 { 126 try { 127 File f = new File(path, name); 128 if(f.exists()) 129 return f.toURI().toURL(); 130 } catch (MalformedURLException e) {} 131 } 132 return null; 133 } 134 135 private static URL getImageUrl(String imageName, Collection<String> dirs) 136 { 137 URL u; 138 // Try passed directories first 139 if(dirs != null) 140 { 141 for (String name : dirs) 142 { 143 u = getImageUrl(name, imageName); 144 if(u != null) return u; 145 } 146 } 147 // Try user-preference directory 148 u = getImageUrl(Main.pref.getPreferencesDir()+"images", imageName); 149 if(u != null) return u; 150 151 // Try plugins and josm classloader 152 u = getImageUrl("resource://images/", imageName); 153 if(u != null) return u; 154 155 // Try all other ressource directories 156 for (String location : Main.pref.getAllPossiblePreferenceDirs()) 157 { 158 u = getImageUrl(location+"images", imageName); 159 if(u != null) return u; 160 u = getImageUrl(location, imageName); 161 if(u != null) return u; 162 } 163 return null; 164 } 165 166 /** 167 * Shortcut for get("", name); 168 */ 169 public static ImageIcon get(String name) { 170 return get("", name); 171 } 172 173 public static Cursor getCursor(String name, String overlay) { 174 ImageIcon img = get("cursor",name); 175 if (overlay != null) 176 img = overlay(img, "cursor/modifier/"+overlay, OverlayPosition.SOUTHEAST); 177 Cursor c = Toolkit.getDefaultToolkit().createCustomCursor(img.getImage(), 178 name.equals("crosshair") ? new Point(10,10) : new Point(3,2), "Cursor"); 179 return c; 180 } 181 182 /** 183 * @return an icon that represent the overlay of the two given icons. The 184 * second icon is layed on the first relative to the given position. 185 */ 186 public static ImageIcon overlay(Icon ground, String overlayImage, OverlayPosition pos) { 187 GraphicsConfiguration conf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); 188 int w = ground.getIconWidth(); 189 int h = ground.getIconHeight(); 190 ImageIcon overlay = ImageProvider.get(overlayImage); 191 int wo = overlay.getIconWidth(); 192 int ho = overlay.getIconHeight(); 193 BufferedImage img = conf.createCompatibleImage(w,h, Transparency.TRANSLUCENT); 194 Graphics g = img.createGraphics(); 195 ground.paintIcon(null, g, 0, 0); 196 int x = 0, y = 0; 197 switch (pos) { 198 case NORTHWEST: 199 x = 0; 200 y = 0; 201 break; 202 case NORTHEAST: 203 x = w-wo; 204 y = 0; 205 break; 206 case SOUTHWEST: 207 x = 0; 208 y = h-ho; 209 break; 210 case SOUTHEAST: 211 x = w-wo; 212 y = h-ho; 213 break; 214 } 215 overlay.paintIcon(null, g, x, y); 216 return new ImageIcon(img); 217 } 218 219 static { 220 try { 221 sources.add(ClassLoader.getSystemClassLoader()); 222 } catch (SecurityException ex) { 223 sources.add(ImageProvider.class.getClassLoader()); 224 } 225 } 226 226 } -
trunk/src/org/openstreetmap/josm/tools/OpenBrowser.java
r1023 r1169 19 19 public class OpenBrowser { 20 20 21 22 23 24 25 26 27 28 29 30 31 32 33 21 /** 22 * @return <code>null</code> for success or a string in case of an error. 23 */ 24 public static String displayUrl(String url) { 25 if (Main.applet) { 26 try { 27 JApplet applet = (JApplet) Main.parent; 28 applet.getAppletContext().showDocument(new URL(url)); 29 return null; 30 } catch (MalformedURLException mue) { 31 return mue.getMessage(); 32 } 33 } 34 34 35 36 37 38 39 40 41 35 try { 36 Main.platform.openUrl(url); 37 } catch (IOException e) { 38 return e.getMessage(); 39 } 40 return null; 41 } 42 42 43 43 } -
trunk/src/org/openstreetmap/josm/tools/Pair.java
r627 r1169 6 6 */ 7 7 public final class Pair<A,B> { 8 9 8 public A a; 9 public B b; 10 10 11 12 13 14 11 public Pair(A a, B b) { 12 this.a = a; 13 this.b = b; 14 } 15 15 16 17 18 16 @Override public int hashCode() { 17 return a.hashCode() ^ b.hashCode(); 18 } 19 19 20 21 22 23 20 @Override public boolean equals(Object o) { 21 return o == null ? o == null : o instanceof Pair 22 && a.equals(((Pair<?,?>) o).a) && b.equals(((Pair<?,?>) o).b); 23 } 24 24 25 26 27 28 29 30 25 public static <T> ArrayList<T> toArrayList(Pair<T, T> p) { 26 ArrayList<T> l = new ArrayList<T>(2); 27 l.add(p.a); 28 l.add(p.b); 29 return l; 30 } 31 31 32 33 34 35 36 37 38 39 32 public static <T> Pair<T,T> sort(Pair<T,T> p) { 33 if (p.b.hashCode() < p.a.hashCode()) { 34 T tmp = p.a; 35 p.a = p.b; 36 p.b = tmp; 37 } 38 return p; 39 } 40 40 } -
trunk/src/org/openstreetmap/josm/tools/PlatformHook.java
r1084 r1169 29 29 */ 30 30 public interface PlatformHook { 31 32 33 34 35 36 37 38 39 31 /** 32 * The preStartupHook will be called extremly early. It is 33 * guaranteed to be called before the GUI setup has started. 34 * 35 * Reason: On OSX we need to inform the Swing libraries 36 * that we want to be integrated with the OS before we setup 37 * our GUI. 38 */ 39 public void preStartupHook(); 40 40 41 42 43 44 45 46 47 48 41 /** 42 * The startupHook will be called early, but after the GUI 43 * setup has started. 44 * 45 * Reason: On OSX we need to register some callbacks with the 46 * OS, so we'll receive events from the system menu. 47 */ 48 public void startupHook(); 49 49 50 51 52 53 54 50 /** 51 * The openURL hook will be used to open an URL in the 52 * default webbrowser. 53 */ 54 public void openUrl(String url) throws IOException; 55 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 56 /** 57 * The initShortcutGroups hook will be called by the 58 * Shortcut class if it detects that there are no 59 * groups in teh config file. So that will happen 60 * once on each JOSM installation only. 61 * 62 * Please note that ShorCut will load its config on demand, 63 * that is, at the moment the first shortcut is registered. 64 * 65 * In this hook, you have to fill the preferences with 66 * data, not the internal structures! Also, do not try 67 * to register any shortcuts from within. 68 */ 69 public void initShortcutGroups(); 70 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 71 /** 72 * The initSystemShortcuts hook will be called by the 73 * Shortcut class after the modifier groups have been read 74 * from the config, but before any shortcuts are read from 75 * it or registered from within the application. 76 * 77 * Plese note that you are not allowed to register any 78 * shortuts from this hook, but only "systemCuts"! 79 * 80 * BTW: SystemCuts should be named "system:<whatever>", 81 * and it'd be best if sou'd recycle the names already used 82 * by the Windows and OSX hooks. Especially the later has 83 * really many of them. 84 * 85 * You should also register any and all shortcuts that the 86 * operation system handles itself to block JOSM from trying 87 * to use them---as that would just not work. Call setAutomatic 88 * on them to prevent the keyboard preferences from allowing the 89 * user to change them. 90 */ 91 public void initSystemShortcuts(); 92 92 93 94 95 96 97 98 99 100 101 102 103 104 93 /** 94 * The makeTooltip hook will be called whenever a tooltip for 95 * a menu or button is created. 96 * 97 * Tooltips are usually not system dependent, unless the 98 * JVM is to dumb to provide correct names for all the keys. 99 * 100 * Another reason not to use the implementation in the *nix 101 * hook are LAFs that don't understand HTML, such as the OSX 102 * LAFs. 103 */ 104 public String makeTooltip(String name, Shortcut sc); 105 105 } -
trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java
r1084 r1169 16 16 */ 17 17 public class PlatformHookOsx extends PlatformHookUnixoid implements PlatformHook, InvocationHandler { 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 18 private static PlatformHookOsx ivhandler = new PlatformHookOsx(); 19 public void preStartupHook(){ 20 // This will merge our MenuBar into the system menu. 21 // MUST be set before Swing is initialized! 22 // And will not work when one of the system independet LAFs is used. 23 // They just insist on painting themselves... 24 System.setProperty("apple.laf.useScreenMenuBar", "true"); 25 } 26 public void startupHook() { 27 // Here we register callbacks for the menu entries in the system menu 28 try { 29 Class Ccom_apple_eawt_Application = Class.forName("com.apple.eawt.Application"); 30 Object Ocom_apple_eawt_Application = Ccom_apple_eawt_Application.getConstructor((Class[])null).newInstance((Object[])null); 31 Class Ccom_apple_eawt_ApplicationListener = Class.forName("com.apple.eawt.ApplicationListener"); 32 Method MaddApplicationListener = Ccom_apple_eawt_Application.getDeclaredMethod("addApplicationListener", new Class[] { Ccom_apple_eawt_ApplicationListener }); 33 Object Oproxy = Proxy.newProxyInstance(PlatformHookOsx.class.getClassLoader(), new Class[] { Ccom_apple_eawt_ApplicationListener }, ivhandler); 34 MaddApplicationListener.invoke(Ocom_apple_eawt_Application, new Object[] { Oproxy }); 35 Method MsetEnabledPreferencesMenu = Ccom_apple_eawt_Application.getDeclaredMethod("setEnabledPreferencesMenu", new Class[] { boolean.class }); 36 MsetEnabledPreferencesMenu.invoke(Ocom_apple_eawt_Application, new Object[] { Boolean.TRUE }); 37 } catch (Exception ex) { 38 // Oops, what now? 39 // We'll just ignore this for now. The user will still be able to close JOSM 40 // by closing all its windows. 41 System.out.println("Failed to register with OSX: " + ex); 42 } 43 } 44 public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { 45 Boolean handled = Boolean.TRUE; 46 //System.out.println("Going to handle method "+method+" (short: "+method.getName()+") with event "+args[0]); 47 if (method.getName().equals("handleQuit")) { 48 handled = !Main.main.breakBecauseUnsavedChanges(); 49 } else if (method.getName().equals("handleAbout")) { 50 Main.main.menu.about.actionPerformed(null); 51 } else if (method.getName().equals("handlePreferences")) { 52 Main.main.menu.preferences.actionPerformed(null); 53 } else { 54 return null; 55 } 56 if (args[0] != null) { 57 try { 58 args[0].getClass().getDeclaredMethod("setHandled", new Class[] { boolean.class }).invoke(args[0], new Object[] { handled }); 59 } catch (Exception ex) { 60 System.out.println("Failed to report handled event: " + ex); 61 } 62 } 63 return null; 64 } 65 public void openUrl(String url) throws IOException { 66 // Ain't that KISS? 67 Runtime.getRuntime().exec("open " + url); 68 } 69 public void initShortcutGroups() { 70 // Everything but Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU is guesswork. 71 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_NONE), Integer.toString(-1)); 72 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY), Integer.toString(KeyEvent.CTRL_DOWN_MASK)); 73 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU), Integer.toString(KeyEvent.META_DOWN_MASK)); 74 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT), Integer.toString(0)); 75 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 76 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_DIRECT), Integer.toString(0)); 77 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MNEMONIC),Integer.toString(KeyEvent.ALT_DOWN_MASK)); 78 79 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_NONE), Integer.toString(-1)); 80 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 81 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MENU), Integer.toString(KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 82 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_EDIT), Integer.toString(KeyEvent.SHIFT_DOWN_MASK)); 83 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_LAYER), Integer.toString(KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 84 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT), Integer.toString(KeyEvent.SHIFT_DOWN_MASK)); 85 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MNEMONIC), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 86 87 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_NONE), Integer.toString(-1)); 88 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_HOTKEY), Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)); 89 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MENU), Integer.toString(KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)); 90 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_EDIT), Integer.toString(KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 91 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_LAYER), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 92 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_DIRECT), Integer.toString(KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)); 93 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MNEMONIC), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 94 } 95 public void initSystemShortcuts() { 96 // Yeah, it's a long, long list. And people always complain that OSX has no shortcuts. 97 Shortcut.registerSystemShortcut("apple-reserved-01", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK).setAutomatic(); // Show or hide the Spotlight search field (when multiple languages are installed, may rotate through enabled script systems). 98 Shortcut.registerSystemShortcut("apple-reserved-02", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Apple reserved. 99 Shortcut.registerSystemShortcut("apple-reserved-03", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Show the Spotlight search results window (when multiple languages are installed, may rotate through keyboard layouts and input methods within a script). 100 Shortcut.registerSystemShortcut("apple-reserved-04", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // | Apple reserved. 101 Shortcut.registerSystemShortcut("apple-reserved-05", "reserved", KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Navigate through controls in a reverse direction. See "Keyboard Focus and Navigation." 102 Shortcut.registerSystemShortcut("apple-reserved-06", "reserved", KeyEvent.VK_TAB, KeyEvent.META_DOWN_MASK).setAutomatic(); // Move forward to the next most recently used application in a list of open applications. 103 Shortcut.registerSystemShortcut("apple-reserved-07", "reserved", KeyEvent.VK_TAB, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move backward through a list of open applications (sorted by recent use). 104 Shortcut.registerSystemShortcut("apple-reserved-08", "reserved", KeyEvent.VK_TAB, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the next grouping of controls in a dialog or the next table (when Tab moves to the next cell). See Accessibility Overview. 105 Shortcut.registerSystemShortcut("apple-reserved-09", "reserved", KeyEvent.VK_TAB, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move focus to the previous grouping of controls. See Accessibility Overview. 106 Shortcut.registerSystemShortcut("apple-reserved-10", "reserved", KeyEvent.VK_ESCAPE, KeyEvent.META_DOWN_MASK).setAutomatic(); // Open Front Row. 107 Shortcut.registerSystemShortcut("apple-reserved-11", "reserved", KeyEvent.VK_ESCAPE, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Open the Force Quit dialog. 108 Shortcut.registerSystemShortcut("apple-reserved-12", "reserved", KeyEvent.VK_F1, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Toggle full keyboard access on or off. See Accessibility Overview. 109 Shortcut.registerSystemShortcut("apple-reserved-13", "reserved", KeyEvent.VK_F2, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the menu bar. See Accessibility Overview. 110 Shortcut.registerSystemShortcut("apple-reserved-14", "reserved", KeyEvent.VK_F3, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the Dock. See Accessibility Overview. 111 Shortcut.registerSystemShortcut("apple-reserved-15", "reserved", KeyEvent.VK_F4, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the active (or next) window. See Accessibility Overview. 112 Shortcut.registerSystemShortcut("apple-reserved-16", "reserved", KeyEvent.VK_F4, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move focus to the previously active window. See Accessibility Overview. 113 Shortcut.registerSystemShortcut("apple-reserved-17", "reserved", KeyEvent.VK_F5, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the toolbar. See Accessibility Overview. 114 Shortcut.registerSystemShortcut("apple-reserved-18", "reserved", KeyEvent.VK_F5, KeyEvent.META_DOWN_MASK).setAutomatic(); // Turn VoiceOver on or off. See Accessibility Overview. 115 Shortcut.registerSystemShortcut("apple-reserved-19", "reserved", KeyEvent.VK_F6, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the first (or next) panel. See Accessibility Overview. 116 Shortcut.registerSystemShortcut("apple-reserved-20", "reserved", KeyEvent.VK_F6, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move focus to the previous panel. See Accessibility Overview. 117 Shortcut.registerSystemShortcut("apple-reserved-21", "reserved", KeyEvent.VK_F7, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Temporarily override the current keyboard access mode in windows and dialogs. See Accessibility Overview. 118 Shortcut.registerSystemShortcut("apple-reserved-22", "reserved", KeyEvent.VK_F9, 0).setAutomatic(); // Tile or untile all open windows. 119 Shortcut.registerSystemShortcut("apple-reserved-23", "reserved", KeyEvent.VK_F10, 0).setAutomatic(); // Tile or untile all open windows in the currently active application. 120 Shortcut.registerSystemShortcut("apple-reserved-24", "reserved", KeyEvent.VK_F11, 0).setAutomatic(); // Hide or show all open windows. 121 Shortcut.registerSystemShortcut("apple-reserved-25", "reserved", KeyEvent.VK_F12, 0).setAutomatic(); // Hide or display Dashboard. 122 Shortcut.registerSystemShortcut("apple-reserved-26", "reserved", KeyEvent.VK_DEAD_GRAVE, KeyEvent.META_DOWN_MASK).setAutomatic(); // Activate the next open window in the frontmost application. See "Window Layering." 123 Shortcut.registerSystemShortcut("apple-reserved-27", "reserved", KeyEvent.VK_DEAD_GRAVE, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Activate the previous open window in the frontmost application. See "Window Layering." 124 Shortcut.registerSystemShortcut("apple-reserved-28", "reserved", KeyEvent.VK_DEAD_GRAVE, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Move focus to the window drawer. 125 Shortcut.registerSystemShortcut("apple-reserved-29", "reserved", KeyEvent.VK_MINUS, KeyEvent.META_DOWN_MASK).setAutomatic(); // Decrease the size of the selected item (equivalent to the Smaller command). See "The Format Menu." 126 Shortcut.registerSystemShortcut("apple-reserved-30", "reserved", KeyEvent.VK_MINUS, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Zoom out when screen zooming is on. See Accessibility Overview. 127 128 Shortcut.registerSystemShortcut("system:align-left", "reserved", KeyEvent.VK_OPEN_BRACKET, KeyEvent.META_DOWN_MASK); // Left-align a selection (equivalent to the Align Left command). See "The Format Menu." 129 Shortcut.registerSystemShortcut("system:align-right","reserved", KeyEvent.VK_CLOSE_BRACKET, KeyEvent.META_DOWN_MASK); // Right-align a selection (equivalent to the Align Right command). See "The Format Menu." 130 // I found no KeyEvent for | 131 //Shortcut.registerSystemCut("system:align-center", "reserved", '|', KeyEvent.META_DOWN_MASK); // Center-align a selection (equivalent to the Align Center command). See "The Format Menu." 132 Shortcut.registerSystemShortcut("system:spelling", "reserved", KeyEvent.VK_COLON, KeyEvent.META_DOWN_MASK); // Display the Spelling window (equivalent to the Spelling command). See "The Edit Menu." 133 Shortcut.registerSystemShortcut("system:spellcheck", "reserved", KeyEvent.VK_SEMICOLON, KeyEvent.META_DOWN_MASK); // Find misspelled words in the document (equivalent to the Check Spelling command). See "The Edit Menu." 134 Shortcut.registerSystemShortcut("system:preferences", "reserved", KeyEvent.VK_COMMA, KeyEvent.META_DOWN_MASK).setAutomatic(); // Open the application's preferences window (equivalent to the Preferences command). See "The Application Menu." 135 136 Shortcut.registerSystemShortcut("apple-reserved-31", "reserved", KeyEvent.VK_COMMA, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Decrease screen contrast. See Accessibility Overview. 137 Shortcut.registerSystemShortcut("apple-reserved-32", "reserved", KeyEvent.VK_PERIOD, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Increase screen contrast. See Accessibility Overview. 138 139 // I found no KeyEvent for ? 140 //Shortcut.registerSystemCut("system:help", "reserved", '?', KeyEvent.META_DOWN_MASK).setAutomatic(); // Open the application's help in Help Viewer. See "The Help Menu." 141 142 Shortcut.registerSystemShortcut("apple-reserved-33", "reserved", KeyEvent.VK_SLASH, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Turn font smoothing on or off. 143 Shortcut.registerSystemShortcut("apple-reserved-34", "reserved", KeyEvent.VK_EQUALS, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Increase the size of the selected item (equivalent to the Bigger command). See "The Format Menu." 144 Shortcut.registerSystemShortcut("apple-reserved-35", "reserved", KeyEvent.VK_EQUALS, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Zoom in when screen zooming is on. See Accessibility Overview. 145 Shortcut.registerSystemShortcut("apple-reserved-36", "reserved", KeyEvent.VK_3, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Capture the screen to a file. 146 Shortcut.registerSystemShortcut("apple-reserved-37", "reserved", KeyEvent.VK_3, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Capture the screen to the Clipboard. 147 Shortcut.registerSystemShortcut("apple-reserved-38", "reserved", KeyEvent.VK_4, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Capture a selection to a file. 148 Shortcut.registerSystemShortcut("apple-reserved-39", "reserved", KeyEvent.VK_4, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Capture a selection to the Clipboard. 149 Shortcut.registerSystemShortcut("apple-reserved-40", "reserved", KeyEvent.VK_8, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Turn screen zooming on or off. See Accessibility Overview. 150 Shortcut.registerSystemShortcut("apple-reserved-41", "reserved", KeyEvent.VK_8, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Invert the screen colors. See Accessibility Overview. 151 152 Shortcut.registerSystemShortcut("system:selectall", "reserved", KeyEvent.VK_A, KeyEvent.META_DOWN_MASK); // Highlight every item in a document or window, or all characters in a text field (equivalent to the Select All command). See "The Edit Menu." 153 Shortcut.registerSystemShortcut("system:bold", "reserved", KeyEvent.VK_B, KeyEvent.META_DOWN_MASK); // Boldface the selected text or toggle boldfaced text on and off (equivalent to the Bold command). See "The Edit Menu." 154 Shortcut.registerSystemShortcut("system:copy", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK); // Duplicate the selected data and store on the Clipboard (equivalent to the Copy command). See "The Edit Menu." 155 Shortcut.registerSystemShortcut("system:colors", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Display the Colors window (equivalent to the Show Colors command). See "The Format Menu." 156 Shortcut.registerSystemShortcut("system:copystyle", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Copy the style of the selected text (equivalent to the Copy Style command). See "The Format Menu." 157 Shortcut.registerSystemShortcut("system:copyformat", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Copy the formatting settings of the selected item and store on the Clipboard (equivalent to the Copy Ruler command). See "The Format Menu." 158 159 Shortcut.registerSystemShortcut("apple-reserved-42", "reserved", KeyEvent.VK_D, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Show or hide the Dock. See "The Dock." 160 161 Shortcut.registerSystemShortcut("system:dictionarylookup", "reserved", KeyEvent.VK_D, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK); // Display the definition of the selected word in the Dictionary application. 162 Shortcut.registerSystemShortcut("system:findselected", "reserved", KeyEvent.VK_E, KeyEvent.META_DOWN_MASK); // Use the selection for a find operation. See "Find Windows." 163 Shortcut.registerSystemShortcut("system:find", "reserved", KeyEvent.VK_F, KeyEvent.META_DOWN_MASK); // Open a Find window (equivalent to the Find command). See "The Edit Menu." 164 Shortcut.registerSystemShortcut("system:search", "reserved", KeyEvent.VK_F, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Jump to the search field control. See "Search Fields." 165 Shortcut.registerSystemShortcut("system:findnext", "reserved", KeyEvent.VK_G, KeyEvent.META_DOWN_MASK); // Find the next occurrence of the selection (equivalent to the Find Next command). See "The Edit Menu." 166 Shortcut.registerSystemShortcut("system:findprev", "reserved", KeyEvent.VK_G, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Find the previous occurrence of the selection (equivalent to the Find Previous command). See "The Edit Menu." 167 Shortcut.registerSystemShortcut("system:hide", "reserved", KeyEvent.VK_H, KeyEvent.META_DOWN_MASK).setAutomatic(); // Hide the windows of the currently running application (equivalent to the Hide ApplicationName command). See "The Application Menu." 168 Shortcut.registerSystemShortcut("system:hideothers", "reserved", KeyEvent.VK_H, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Hide the windows of all other running applications (equivalent to the Hide Others command). See "The Application Menu." 169 // What about applications that have italic text AND info windows? 170 //Shortcut.registerSystemCut("system:italic", "reserved", KeyEvent.VK_I, KeyEvent.META_DOWN_MASK); // Italicize the selected text or toggle italic text on or off (equivalent to the Italic command). See "The Format Menu." 171 Shortcut.registerSystemShortcut("system:info", "reserved", KeyEvent.VK_I, KeyEvent.META_DOWN_MASK); // Display an Info window. See "Inspector Windows." 172 Shortcut.registerSystemShortcut("system:inspector", "reserved", KeyEvent.VK_I, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Display an inspector window. See "Inspector Windows." 173 Shortcut.registerSystemShortcut("system:toselection", "reserved", KeyEvent.VK_J, KeyEvent.META_DOWN_MASK); // Scroll to a selection. 174 Shortcut.registerSystemShortcut("system:minimize", "reserved", KeyEvent.VK_M, KeyEvent.META_DOWN_MASK); // Minimize the active window to the Dock (equivalent to the Minimize command). See "The Window Menu." 175 Shortcut.registerSystemShortcut("system:minimizeall", "reserved", KeyEvent.VK_M, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Minimize all windows of the active application to the Dock (equivalent to the Minimize All command). See "The Window Menu." 176 Shortcut.registerSystemShortcut("system:new", "reserved", KeyEvent.VK_N, KeyEvent.META_DOWN_MASK); // Open a new document (equivalent to the New command). See "The File Menu." 177 Shortcut.registerSystemShortcut("system:open", "reserved", KeyEvent.VK_O, KeyEvent.META_DOWN_MASK); // Display a dialog for choosing a document to open (equivalent to the Open command). See "The File Menu." 178 Shortcut.registerSystemShortcut("system:print", "reserved", KeyEvent.VK_P, KeyEvent.META_DOWN_MASK); // Display the Print dialog (equivalent to the Print command). See "The File Menu." 179 Shortcut.registerSystemShortcut("system:printsetup", "reserved", KeyEvent.VK_P, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Display a dialog for specifying printing parameters (equivalent to the Page Setup command). See "The File Menu." 180 Shortcut.registerSystemShortcut("system:menuexit", "reserved", KeyEvent.VK_Q, KeyEvent.META_DOWN_MASK).setAutomatic(); // Quit the application (equivalent to the Quit command). See "The Application Menu." 181 182 Shortcut.registerSystemShortcut("apple-reserved-43", "reserved", KeyEvent.VK_Q, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Log out the current user (equivalent to the Log Out command). 183 Shortcut.registerSystemShortcut("apple-reserved-44", "reserved", KeyEvent.VK_Q, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Log out the current user without confirmation. 184 185 Shortcut.registerSystemShortcut("system:save", "reserved", KeyEvent.VK_S, KeyEvent.META_DOWN_MASK); // Save the active document (equivalent to the Save command). See "The File Menu." 186 Shortcut.registerSystemShortcut("system:saveas", "reserved", KeyEvent.VK_S, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Display the Save dialog (equivalent to the Save As command). See "The File Menu." 187 Shortcut.registerSystemShortcut("system:fonts", "reserved", KeyEvent.VK_T, KeyEvent.META_DOWN_MASK); // Display the Fonts window (equivalent to the Show Fonts command). See "The Format Menu." 188 Shortcut.registerSystemShortcut("system:toggletoolbar", "reserved", KeyEvent.VK_T, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Show or hide a toolbar (equivalent to the Show/Hide Toolbar command). See "The View Menu" and "Toolbars." 189 Shortcut.registerSystemShortcut("system:underline", "reserved", KeyEvent.VK_U, KeyEvent.META_DOWN_MASK); // Underline the selected text or turn underlining on or off (equivalent to the Underline command). See "The Format Menu." 190 Shortcut.registerSystemShortcut("system:paste", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK); // Insert the Clipboard contents at the insertion point (equivalent to the Paste command). See "The File Menu." 191 Shortcut.registerSystemShortcut("system:pastestyle", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Apply the style of one object to the selected object (equivalent to the Paste Style command). See "The Format Menu." 192 Shortcut.registerSystemShortcut("system:pastemwithoutstyle", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Apply the style of the surrounding text to the inserted object (equivalent to the Paste and Match Style command). See "The Edit Menu." 193 Shortcut.registerSystemShortcut("system:pasteformatting", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK); // Apply formatting settings to the selected object (equivalent to the Paste Ruler command). See "The Format Menu." 194 Shortcut.registerSystemShortcut("system:closewindow", "reserved", KeyEvent.VK_W, KeyEvent.META_DOWN_MASK); // Close the active window (equivalent to the Close command). See "The File Menu." 195 Shortcut.registerSystemShortcut("system:closefile", "reserved", KeyEvent.VK_W, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Close a file and its associated windows (equivalent to the Close File command). See "The File Menu." 196 Shortcut.registerSystemShortcut("system:closeallwindows", "reserved", KeyEvent.VK_W, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Close all windows in the application (equivalent to the Close All command). See "The File Menu." 197 Shortcut.registerSystemShortcut("system:cut", "reserved", KeyEvent.VK_X, KeyEvent.META_DOWN_MASK); // Remove the selection and store on the Clipboard (equivalent to the Cut command). See "The Edit Menu." 198 Shortcut.registerSystemShortcut("system:undo", "reserved", KeyEvent.VK_Z, KeyEvent.META_DOWN_MASK); // Reverse the effect of the user's previous operation (equivalent to the Undo command). See "The Edit Menu." 199 Shortcut.registerSystemShortcut("system:redo", "reserved", KeyEvent.VK_Z, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Reverse the effect of the last Undo command (equivalent to the Redo command). See "The Edit Menu." 200 201 Shortcut.registerSystemShortcut("apple-reserved-45", "reserved", KeyEvent.VK_RIGHT, KeyEvent.META_DOWN_MASK).setAutomatic(); // Change the keyboard layout to current layout of Roman script. 202 //Shortcut.registerSystemCut("apple-reserved-46", "reserved", KeyEvent.VK_RIGHT, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the next semantic unit, typically the end of the current line. 203 //Shortcut.registerSystemCut("apple-reserved-47", "reserved", KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection one character to the right. 204 //Shortcut.registerSystemCut("apple-reserved-48", "reserved", KeyEvent.VK_RIGHT, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the end of the current word, then to the end of the next word. 205 206 Shortcut.registerSystemShortcut("system:movefocusright", "reserved", KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview. 207 208 Shortcut.registerSystemShortcut("apple-reserved-49", "reserved", KeyEvent.VK_LEFT, KeyEvent.META_DOWN_MASK).setAutomatic(); // Change the keyboard layout to current layout of system script. 209 //Shortcut.registerSystemCut("apple-reserved-50", "reserved", KeyEvent.VK_LEFT, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the previous semantic unit, typically the beginning of the current line. 210 //Shortcut.registerSystemCut("apple-reserved-51", "reserved", KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection one character to the left. 211 //Shortcut.registerSystemCut("apple-reserved-52", "reserved", KeyEvent.VK_LEFT, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the beginning of the current word, then to the beginning of the previous word. 212 213 Shortcut.registerSystemShortcut("system:movefocusleft", "reserved", KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview. 214 215 //Shortcut.registerSystemCut("apple-reserved-53", "reserved", KeyEvent.VK_UP, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection upward in the next semantic unit, typically the beginning of the document. 216 //Shortcut.registerSystemCut("apple-reserved-54", "reserved", KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the line above, to the nearest character boundary at the same horizontal location. 217 //Shortcut.registerSystemCut("apple-reserved-55", "reserved", KeyEvent.VK_UP, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the beginning of the current paragraph, then to the beginning of the next paragraph. 218 219 Shortcut.registerSystemShortcut("system:movefocusup", "reserved", KeyEvent.VK_UP, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview. 220 221 //Shortcut.registerSystemCut("apple-reserved-56", "reserved", KeyEvent.VK_DOWN, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection downward in the next semantic unit, typically the end of the document. 222 //Shortcut.registerSystemCut("apple-reserved-57", "reserved", KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the line below, to the nearest character boundary at the same horizontal location. 223 //Shortcut.registerSystemCut("apple-reserved-58", "reserved", KeyEvent.VK_DOWN, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the end of the current paragraph, then to the end of the next paragraph (include the blank line between paragraphs in cut, copy, and paste operations). 224 225 Shortcut.registerSystemShortcut("system:movefocusdown", "reserved", KeyEvent.VK_DOWN, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview. 226 227 Shortcut.registerSystemShortcut("system:about", "reserved", 0, -1).setAutomatic(); // About 228 } 229 public String makeTooltip(String name, Shortcut sc) { 230 String lafid = UIManager.getLookAndFeel().getID(); 231 boolean canHtml = true; 232 // "Mac" is the native LAF, "Aqua" is Quaqua. Both use native menus with native tooltips. 233 if (lafid.contains("Mac") || lafid.contains("Aqua")) { 234 canHtml = false; 235 } 236 String result = ""; 237 if (canHtml) result += "<html>"; 238 result += name; 239 if (sc != null && sc.getKeyText().length() != 0) { 240 result += " "; 241 if (canHtml) result += "<font size='-2'>"; 242 result += "("+sc.getKeyText()+")"; 243 if (canHtml) result += "</font>"; 244 } 245 if (canHtml) result += " </html>"; 246 return result; 247 } 248 248 } -
trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java
r1084 r1169 15 15 */ 16 16 public class PlatformHookUnixoid implements PlatformHook { 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 17 public void preStartupHook(){ 18 } 19 public void startupHook() { 20 } 21 public void openUrl(String url) throws IOException { 22 String[] programs = {"gnome-open", "kfmclient openURL", "firefox"}; 23 for (String program : programs) { 24 try { 25 Runtime.getRuntime().exec(program+" "+url); 26 return; 27 } catch (IOException e) { 28 } 29 } 30 } 31 public void initShortcutGroups() { 32 // This is the Windows list. Someone should look over it and make it more "*nix"... 33 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_NONE), Integer.toString(-1)); 34 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY), Integer.toString(KeyEvent.CTRL_DOWN_MASK)); 35 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU), Integer.toString(KeyEvent.CTRL_DOWN_MASK)); 36 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT), Integer.toString(0)); 37 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 38 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_DIRECT), Integer.toString(0)); 39 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MNEMONIC),Integer.toString(KeyEvent.ALT_DOWN_MASK)); 40 40 41 42 43 44 45 46 47 41 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_NONE), Integer.toString(-1)); 42 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 43 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MENU), Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 44 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_EDIT), Integer.toString(KeyEvent.SHIFT_DOWN_MASK)); 45 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_LAYER), Integer.toString(KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 46 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT), Integer.toString(KeyEvent.SHIFT_DOWN_MASK)); 47 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MNEMONIC), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 48 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 49 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_NONE), Integer.toString(-1)); 50 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_HOTKEY), Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)); 51 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MENU), Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)); 52 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_EDIT), Integer.toString(KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 53 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_LAYER), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 54 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_DIRECT), Integer.toString(KeyEvent.CTRL_DOWN_MASK)); 55 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MNEMONIC), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 56 } 57 public void initSystemShortcuts() { 58 // TODO: Insert system shortcuts here. See Windows and espacially OSX to see how to. 59 } 60 /** 61 * This should work for all platforms. Yeah, should. 62 * See PlatformHook.java for a list of reasons why 63 * this is implemented here... 64 */ 65 public String makeTooltip(String name, Shortcut sc) { 66 String result = ""; 67 result += "<html>"; 68 result += name; 69 if (sc != null && sc.getKeyText().length() != 0) { 70 result += " "; 71 result += "<font size='-2'>"; 72 result += "("+sc.getKeyText()+")"; 73 result += "</font>"; 74 } 75 result += " </html>"; 76 return result; 77 } 78 78 } -
trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java
r1084 r1169 14 14 */ 15 15 public class PlatformHookWindows extends PlatformHookUnixoid implements PlatformHook { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 16 public void preStartupHook(){ 17 } 18 public void startupHook() { 19 } 20 public void openUrl(String url) throws IOException { 21 Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url); 22 } 23 public void initShortcutGroups() { 24 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_NONE), Integer.toString(-1)); 25 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY), Integer.toString(KeyEvent.CTRL_DOWN_MASK)); 26 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU), Integer.toString(KeyEvent.CTRL_DOWN_MASK)); 27 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT), Integer.toString(0)); 28 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 29 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_DIRECT), Integer.toString(0)); 30 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MNEMONIC),Integer.toString(KeyEvent.ALT_DOWN_MASK)); 31 31 32 33 34 35 36 37 38 32 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_NONE), Integer.toString(-1)); 33 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 34 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MENU), Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 35 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_EDIT), Integer.toString(KeyEvent.SHIFT_DOWN_MASK)); 36 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_LAYER), Integer.toString(KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 37 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT), Integer.toString(KeyEvent.SHIFT_DOWN_MASK)); 38 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MNEMONIC), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 39 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 40 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_NONE), Integer.toString(-1)); 41 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_HOTKEY), Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)); 42 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MENU), Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)); 43 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_EDIT), Integer.toString(KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); 44 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_LAYER), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 45 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_DIRECT), Integer.toString(KeyEvent.CTRL_DOWN_MASK)); 46 Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MNEMONIC), Integer.toString(KeyEvent.ALT_DOWN_MASK)); 47 } 48 public void initSystemShortcuts() { 49 // This list if far from complete! 50 Shortcut.registerSystemShortcut("system:exit", "unused", KeyEvent.VK_F4, KeyEvent.ALT_DOWN_MASK).setAutomatic(); // items with automatic shortcuts will not be added to the menu bar at all 51 Shortcut.registerSystemShortcut("system:menuexit", "unused", KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK); 52 Shortcut.registerSystemShortcut("system:copy", "unused", KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK); 53 Shortcut.registerSystemShortcut("system:paste", "unused", KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK); 54 Shortcut.registerSystemShortcut("system:cut", "unused", KeyEvent.VK_X, KeyEvent.CTRL_DOWN_MASK); 55 Shortcut.registerSystemShortcut("system:duplicate", "unused", KeyEvent.VK_D, KeyEvent.CTRL_DOWN_MASK); // not really system, but to avoid odd results 56 Shortcut.registerSystemShortcut("system:help", "unused", KeyEvent.VK_F1, 0); 57 } 58 58 } 59 59 -
trunk/src/org/openstreetmap/josm/tools/PrimaryDateParser.java
r627 r1169 15 15 * based on similar code in JOSM. This class is not threadsafe, a separate 16 16 * instance must be created per thread. 17 * 17 * 18 18 * @author Brett Henderson 19 19 */ 20 20 public class PrimaryDateParser { 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 * 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 21 private DatatypeFactory datatypeFactory; 22 private FallbackDateParser fallbackDateParser; 23 private Calendar calendar; 24 25 26 /** 27 * Creates a new instance. 28 */ 29 public PrimaryDateParser() { 30 // Build an xml data type factory. 31 try { 32 datatypeFactory = DatatypeFactory.newInstance(); 33 34 } catch (DatatypeConfigurationException e) { 35 throw new RuntimeException("Unable to instantiate xml datatype factory.", e); 36 } 37 38 fallbackDateParser = new FallbackDateParser(); 39 40 calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); 41 } 42 43 44 private boolean isDateInShortStandardFormat(String date) { 45 char[] dateChars; 46 // We can only parse the date if it is in a very specific format. 47 // eg. 2007-09-23T08:25:43Z 48 49 if (date.length() != 20) { 50 return false; 51 } 52 53 dateChars = date.toCharArray(); 54 55 // Make sure any fixed characters are in the correct place. 56 if (dateChars[4] != '-') { 57 return false; 58 } 59 if (dateChars[7] != '-') { 60 return false; 61 } 62 if (dateChars[10] != 'T') { 63 return false; 64 } 65 if (dateChars[13] != ':') { 66 return false; 67 } 68 if (dateChars[16] != ':') { 69 return false; 70 } 71 if (dateChars[19] != 'Z') { 72 return false; 73 } 74 75 // Ensure all remaining characters are numbers. 76 for (int i = 0; i < 4; i++) { 77 if (dateChars[i] < '0' || dateChars[i] > '9') { 78 return false; 79 } 80 } 81 for (int i = 5; i < 7; i++) { 82 if (dateChars[i] < '0' || dateChars[i] > '9') { 83 return false; 84 } 85 } 86 for (int i = 8; i < 10; i++) { 87 if (dateChars[i] < '0' || dateChars[i] > '9') { 88 return false; 89 } 90 } 91 for (int i = 11; i < 13; i++) { 92 if (dateChars[i] < '0' || dateChars[i] > '9') { 93 return false; 94 } 95 } 96 for (int i = 14; i < 16; i++) { 97 if (dateChars[i] < '0' || dateChars[i] > '9') { 98 return false; 99 } 100 } 101 for (int i = 17; i < 19; i++) { 102 if (dateChars[i] < '0' || dateChars[i] > '9') { 103 return false; 104 } 105 } 106 107 // No problems found so it is in the special case format. 108 return true; 109 } 110 111 112 private boolean isDateInLongStandardFormat(String date) { 113 char[] dateChars; 114 // We can only parse the date if it is in a very specific format. 115 // eg. 2007-09-23T08:25:43.000Z 116 117 if (date.length() != 24) { 118 return false; 119 } 120 121 dateChars = date.toCharArray(); 122 123 // Make sure any fixed characters are in the correct place. 124 if (dateChars[4] != '-') { 125 return false; 126 } 127 if (dateChars[7] != '-') { 128 return false; 129 } 130 if (dateChars[10] != 'T') { 131 return false; 132 } 133 if (dateChars[13] != ':') { 134 return false; 135 } 136 if (dateChars[16] != ':') { 137 return false; 138 } 139 if (dateChars[19] != '.') { 140 return false; 141 } 142 if (dateChars[23] != 'Z') { 143 return false; 144 } 145 146 // Ensure all remaining characters are numbers. 147 for (int i = 0; i < 4; i++) { 148 if (dateChars[i] < '0' || dateChars[i] > '9') { 149 return false; 150 } 151 } 152 for (int i = 5; i < 7; i++) { 153 if (dateChars[i] < '0' || dateChars[i] > '9') { 154 return false; 155 } 156 } 157 for (int i = 8; i < 10; i++) { 158 if (dateChars[i] < '0' || dateChars[i] > '9') { 159 return false; 160 } 161 } 162 for (int i = 11; i < 13; i++) { 163 if (dateChars[i] < '0' || dateChars[i] > '9') { 164 return false; 165 } 166 } 167 for (int i = 14; i < 16; i++) { 168 if (dateChars[i] < '0' || dateChars[i] > '9') { 169 return false; 170 } 171 } 172 for (int i = 17; i < 19; i++) { 173 if (dateChars[i] < '0' || dateChars[i] > '9') { 174 return false; 175 } 176 } 177 for (int i = 20; i < 23; i++) { 178 if (dateChars[i] < '0' || dateChars[i] > '9') { 179 return false; 180 } 181 } 182 183 // No problems found so it is in the special case format. 184 return true; 185 } 186 187 188 private Date parseShortStandardDate(String date) { 189 int year; 190 int month; 191 int day; 192 int hour; 193 int minute; 194 int second; 195 196 year = Integer.parseInt(date.substring(0, 4)); 197 month = Integer.parseInt(date.substring(5, 7)); 198 day = Integer.parseInt(date.substring(8, 10)); 199 hour = Integer.parseInt(date.substring(11, 13)); 200 minute = Integer.parseInt(date.substring(14, 16)); 201 second = Integer.parseInt(date.substring(17, 19)); 202 203 calendar.clear(); 204 calendar.set(Calendar.YEAR, year); 205 calendar.set(Calendar.MONTH, month - 1); 206 calendar.set(Calendar.DAY_OF_MONTH, day); 207 calendar.set(Calendar.HOUR_OF_DAY, hour); 208 calendar.set(Calendar.MINUTE, minute); 209 calendar.set(Calendar.SECOND, second); 210 211 return calendar.getTime(); 212 } 213 214 215 private Date parseLongStandardDate(String date) { 216 int year; 217 int month; 218 int day; 219 int hour; 220 int minute; 221 int second; 222 int millisecond; 223 224 year = Integer.parseInt(date.substring(0, 4)); 225 month = Integer.parseInt(date.substring(5, 7)); 226 day = Integer.parseInt(date.substring(8, 10)); 227 hour = Integer.parseInt(date.substring(11, 13)); 228 minute = Integer.parseInt(date.substring(14, 16)); 229 second = Integer.parseInt(date.substring(17, 19)); 230 millisecond = Integer.parseInt(date.substring(20, 23)); 231 232 calendar.clear(); 233 calendar.set(Calendar.YEAR, year); 234 calendar.set(Calendar.MONTH, month - 1); 235 calendar.set(Calendar.DAY_OF_MONTH, day); 236 calendar.set(Calendar.HOUR_OF_DAY, hour); 237 calendar.set(Calendar.MINUTE, minute); 238 calendar.set(Calendar.SECOND, second); 239 calendar.set(Calendar.MILLISECOND, millisecond); 240 241 return calendar.getTime(); 242 } 243 244 245 /** 246 * Attempts to parse the specified date. 247 * 248 * @param date 249 * The date to parse. 250 * @return The date. 251 * @throws ParseException 252 * Occurs if the date does not match any of the supported date 253 * formats. 254 */ 255 public Date parse(String date) throws ParseException { 256 try { 257 if (isDateInShortStandardFormat(date)) { 258 return parseShortStandardDate(date); 259 } else if (isDateInLongStandardFormat(date)) { 260 return parseLongStandardDate(date); 261 } else { 262 return datatypeFactory.newXMLGregorianCalendar(date).toGregorianCalendar().getTime(); 263 } 264 265 } catch (IllegalArgumentException e) { 266 return fallbackDateParser.parse(date); 267 } 268 } 269 269 } -
trunk/src/org/openstreetmap/josm/tools/Shortcut.java
r1157 r1169 139 139 */ 140 140 public KeyStroke getKeyStroke() { 141 if (assignedModifier != -1) 142 return KeyStroke.getKeyStroke(assignedKey, assignedModifier); 141 if (assignedModifier != -1) 142 return KeyStroke.getKeyStroke(assignedKey, assignedModifier); 143 143 return null; 144 144 } … … 351 351 System.err.println("CONFLICT WITH SYSTEM KEY "+shortText); 352 352 return null; 353 } 353 } 354 354 potentialShortcut = new Shortcut(shortText, longText, key, GROUP_RESERVED, key, modifier, true, false); 355 355 shortcuts.put(shortText, potentialShortcut); … … 441 441 // a lengthy warning message 442 442 private static void displayWarning(Shortcut conflictsWith, Shortcut potentialShortcut, String shortText, String longText) { 443 JOptionPane.showMessageDialog(Main.parent, 443 JOptionPane.showMessageDialog(Main.parent, 444 444 tr("Setting the keyboard shortcut ''{0}'' for the action ''{1}'' ({2}) failed\n"+ 445 445 "because the shortcut is already taken by the action ''{3}'' ({4}).\n\n", -
trunk/src/org/openstreetmap/josm/tools/UrlLabel.java
r627 r1169 12 12 public class UrlLabel extends JEditorPane implements HyperlinkListener { 13 13 14 14 private final String url; 15 15 16 17 18 16 public UrlLabel(String url) { 17 this (url, url); 18 } 19 19 20 21 22 23 24 25 26 27 28 20 public UrlLabel(String url, String description) { 21 this.url = url; 22 setContentType("text/html"); 23 setText("<html><a href=\""+url+"\">"+description+"</a></html>"); 24 setToolTipText(url); 25 setEditable(false); 26 setOpaque(false); 27 addHyperlinkListener(this); 28 } 29 29 30 31 32 33 34 30 public void hyperlinkUpdate(HyperlinkEvent e) { 31 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { 32 OpenBrowser.displayUrl(url); 33 } 34 } 35 35 } -
trunk/src/org/openstreetmap/josm/tools/WikiReader.java
r740 r1169 14 14 public class WikiReader { 15 15 16 17 16 public static final String JOSM_EXTERN = "http://josm-extern."; 17 private final String baseurl; 18 18 19 20 19 public WikiReader(String baseurl) { 20 this.baseurl = baseurl; 21 21 } 22 22 23 24 25 26 27 28 29 30 31 32 23 /** 24 * Read the page specified by the url and return the content. 25 * 26 * If the url is within the baseurl path, parse it as an trac wikipage and 27 * replace relative pathes etc.. 28 * 29 * @return Either the string of the content of the wiki page. 30 * @throws IOException Throws, if the page could not be loaded. 31 */ 32 public String read(String url) throws IOException { 33 33 BufferedReader in = new BufferedReader(new InputStreamReader(new URL(url).openStream(), "utf-8")); 34 34 if (url.startsWith(baseurl)) 35 35 return readFromTrac(in, url); 36 36 return readNormal(in); 37 }38 39 private String readNormal(BufferedReader in) throws IOException {40 StringBuilder b = new StringBuilder("<html>");41 for (String line = in.readLine(); line != null; line = in.readLine()) {42 line = adjustText(line);43 b.append(line);44 b.append("\n");45 }46 return b.toString();47 37 } 48 38 49 private String readFromTrac(BufferedReader in, String url) throws IOException { 39 private String readNormal(BufferedReader in) throws IOException { 40 StringBuilder b = new StringBuilder("<html>"); 41 for (String line = in.readLine(); line != null; line = in.readLine()) { 42 line = adjustText(line); 43 b.append(line); 44 b.append("\n"); 45 } 46 return b.toString(); 47 } 48 49 private String readFromTrac(BufferedReader in, String url) throws IOException { 50 50 boolean inside = false; 51 51 StringBuilder b = new StringBuilder("<html>"); 52 52 for (String line = in.readLine(); line != null; line = in.readLine()) { 53 54 55 56 57 58 59 60 61 62 63 64 65 53 if (line.contains("<div id=\"searchable\">")) 54 inside = true; 55 else if (line.contains("<div class=\"buttons\">")) 56 inside = false; 57 if (inside) { 58 line = line.replaceAll("<img src=\"/", "<img src=\""+baseurl+"/"); 59 line = line.replaceAll("href=\"/", "href=\""+baseurl+"/"); 60 if (!line.contains("$")) 61 line = line.replaceAll("<p>Describe \"([^\"]+)\" here</p>", "<p>Describe \"$1\" <a href=\""+JOSM_EXTERN+url.substring(7)+"\">here</a></p>"); 62 line = adjustText(line); 63 b.append(line); 64 b.append("\n"); 65 } 66 66 } 67 67 b.append("</html>"); … … 69 69 } 70 70 71 72 73 71 private String adjustText(String text) { 72 text = text.replaceAll(" />", ">"); 73 return text; 74 74 } 75 75 } -
trunk/src/org/openstreetmap/josm/tools/XmlObjectParser.java
r1163 r1169 31 31 32 32 public static final String lang = Main.getLanguageCode(); 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 return s != null && 155 !s.equals("0") && 156 !s.startsWith("off") && 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 33 public static class Uniform<T> implements Iterable<T>{ 34 private Iterator<Object> iterator; 35 /** 36 * @param klass This has to be specified since generics are ereased from 37 * class files so the JVM cannot deduce T itself. 38 */ 39 public Uniform(Reader input, String tagname, Class<T> klass) { 40 XmlObjectParser parser = new XmlObjectParser(); 41 parser.map(tagname, klass); 42 parser.start(input); 43 iterator = parser.iterator(); 44 } 45 public Iterator<T> iterator() { 46 return new Iterator<T>(){ 47 public boolean hasNext() {return iterator.hasNext();} 48 @SuppressWarnings("unchecked") public T next() {return (T)iterator.next();} 49 public void remove() {iterator.remove();} 50 }; 51 } 52 } 53 54 private class Parser extends DefaultHandler { 55 Stack<Object> current = new Stack<Object>(); 56 String characters = ""; 57 @Override public void startElement(String ns, String lname, String qname, Attributes a) throws SAXException { 58 if (mapping.containsKey(qname)) { 59 Class<?> klass = mapping.get(qname).klass; 60 try { 61 current.push(klass.newInstance()); 62 } catch (Exception e) { 63 throw new SAXException(e); 64 } 65 for (int i = 0; i < a.getLength(); ++i) 66 setValue(a.getQName(i), a.getValue(i)); 67 if (mapping.get(qname).onStart) 68 report(); 69 if (mapping.get(qname).both) 70 { 71 try { 72 queue.put(current.peek()); 73 } catch (InterruptedException e) { 74 } 75 } 76 } 77 } 78 @Override public void endElement(String ns, String lname, String qname) throws SAXException { 79 if (mapping.containsKey(qname) && !mapping.get(qname).onStart) 80 report(); 81 else if (characters != null && !current.isEmpty()) { 82 setValue(qname, characters.trim()); 83 characters = ""; 84 } 85 } 86 @Override public void characters(char[] ch, int start, int length) { 87 String s = new String(ch, start, length); 88 characters += s; 89 } 90 91 private void report() { 92 try { 93 queue.put(current.pop()); 94 } catch (InterruptedException e) { 95 } 96 characters = ""; 97 } 98 99 private Object getValueForClass(Class<?> klass, String value) { 100 if (klass == Boolean.TYPE) 101 return parseBoolean(value); 102 else if (klass == Integer.TYPE || klass == Long.TYPE) 103 return Long.parseLong(value); 104 else if (klass == Float.TYPE || klass == Double.TYPE) 105 return Double.parseDouble(value); 106 return value; 107 } 108 109 private void setValue(String fieldName, String value) throws SAXException { 110 if (fieldName.equals("class") || fieldName.equals("default") || fieldName.equals("throw") || fieldName.equals("new") || fieldName.equals("null")) 111 fieldName += "_"; 112 try { 113 Object c = current.peek(); 114 Field f = null; 115 try { 116 f = c.getClass().getField(fieldName); 117 } catch (NoSuchFieldException e) { 118 if(fieldName.startsWith(lang)) 119 { 120 String locfieldName = "locale_" + 121 fieldName.substring(lang.length()); 122 try { 123 f = c.getClass().getField(locfieldName); 124 } catch (NoSuchFieldException ex) { 125 } 126 } 127 } 128 if (f != null && Modifier.isPublic(f.getModifiers())) 129 f.set(c, getValueForClass(f.getType(), value)); 130 else { 131 if(fieldName.startsWith(lang)) 132 { 133 int l = lang.length(); 134 fieldName = "set" + fieldName.substring(l,l+1).toUpperCase() + fieldName.substring(l+1); 135 } 136 else 137 { 138 fieldName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1); 139 } 140 Method[] methods = c.getClass().getDeclaredMethods(); 141 for (Method m : methods) { 142 if (m.getName().equals(fieldName) && m.getParameterTypes().length == 1) { 143 m.invoke(c, new Object[]{getValueForClass(m.getParameterTypes()[0], value)}); 144 return; 145 } 146 } 147 } 148 } catch (Exception e) { 149 e.printStackTrace(); // SAXException does not dump inner exceptions. 150 throw new SAXException(e); 151 } 152 } 153 private boolean parseBoolean(String s) { 154 return s != null && 155 !s.equals("0") && 156 !s.startsWith("off") && 157 !s.startsWith("false") && 158 !s.startsWith("no"); 159 } 160 } 161 162 private static class Entry { 163 Class<?> klass; 164 boolean onStart; 165 boolean both; 166 public Entry(Class<?> klass, boolean onStart, boolean both) { 167 super(); 168 this.klass = klass; 169 this.onStart = onStart; 170 this.both = both; 171 } 172 } 173 174 private Map<String, Entry> mapping = new HashMap<String, Entry>(); 175 private Parser parser; 176 177 /** 178 * The queue of already parsed items from the parsing thread. 179 */ 180 private BlockingQueue<Object> queue = new ArrayBlockingQueue<Object>(10); 181 182 /** 183 * This stores one item retrieved from the queue to give hasNext a chance. 184 * So this is also the object that will be returned on the next call to next(). 185 */ 186 private Object lookAhead = null; 187 188 /** 189 * This object represent the end of the stream (null is not allowed as 190 * member in class Queue). 191 */ 192 private Object EOS = new Object(); 193 194 public XmlObjectParser() { 195 parser = new Parser(); 196 } 197 198 public Iterable<Object> start(final Reader in) { 199 new Thread(){ 200 @Override public void run() { 201 try { 202 SAXParserFactory.newInstance().newSAXParser().parse(new InputSource(in), parser); 203 } catch (Exception e) { 204 try { 205 queue.put(e); 206 } catch (InterruptedException e1) { 207 } 208 } 209 parser = null; 210 try { 211 queue.put(EOS); 212 } catch (InterruptedException e) { 213 } 214 } 215 }.start(); 216 return this; 217 } 218 219 public void map(String tagName, Class<?> klass) { 220 mapping.put(tagName, new Entry(klass,false,false)); 221 } 222 223 public void mapOnStart(String tagName, Class<?> klass) { 224 mapping.put(tagName, new Entry(klass,true,false)); 225 } 226 227 public void mapBoth(String tagName, Class<?> klass) { 228 mapping.put(tagName, new Entry(klass,false,true)); 229 } 230 231 /** 232 * @return The next object from the xml stream or <code>null</code>, 233 * if no more objects. 234 */ 235 public Object next() throws SAXException { 236 fillLookAhead(); 237 if (lookAhead == EOS) 238 throw new NoSuchElementException(); 239 Object o = lookAhead; 240 lookAhead = null; 241 return o; 242 } 243 244 private void fillLookAhead() throws SAXException { 245 if (lookAhead != null) 246 return; 247 try { 248 lookAhead = queue.take(); 249 if (lookAhead instanceof SAXException) 250 throw (SAXException)lookAhead; 251 else if (lookAhead instanceof RuntimeException) 252 throw (RuntimeException)lookAhead; 253 else if (lookAhead instanceof Exception) 254 throw new SAXException((Exception)lookAhead); 255 } catch (InterruptedException e) { 256 throw new RuntimeException("XmlObjectParser must not be interrupted.", e); 257 } 258 } 259 260 public boolean hasNext() throws SAXException { 261 fillLookAhead(); 262 262 return lookAhead != EOS; 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 263 } 264 265 public Iterator<Object> iterator() { 266 return new Iterator<Object>(){ 267 public boolean hasNext() { 268 try { 269 return XmlObjectParser.this.hasNext(); 270 } catch (SAXException e) { 271 e.printStackTrace(); 272 throw new RuntimeException(e); 273 } 274 } 275 public Object next() { 276 try { 277 return XmlObjectParser.this.next(); 278 } catch (SAXException e) { 279 e.printStackTrace(); 280 throw new RuntimeException(e); 281 } 282 } 283 public void remove() { 284 throw new UnsupportedOperationException(); 285 } 286 }; 287 } 288 288 }
Note:
See TracChangeset
for help on using the changeset viewer.