Changeset 13820 in osm for applications/editors/josm/plugins/DirectUpload
- Timestamp:
- 2009-02-21T14:52:35+01:00 (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/DirectUpload/src/org/openstreetmap/josm/plugins/DirectUpload/UploadDataGui.java
r13634 r13820 9 9 package org.openstreetmap.josm.plugins.DirectUpload; 10 10 11 import java.awt.BorderLayout;12 import java.awt.Container; 11 import static org.openstreetmap.josm.tools.I18n.tr; 12 13 13 import java.awt.Dimension; 14 import java.awt.event. ItemEvent;14 import java.awt.event.ActionEvent; 15 15 import java.awt.GridBagLayout; 16 import java.awt.GridBagConstraints;17 import java.awt.Toolkit;18 16 import java.io.BufferedOutputStream; 19 import java.io.DataOutputStream; 17 import java.io.ByteArrayInputStream; 18 import java.io.ByteArrayOutputStream; 19 import java.io.InputStream; 20 20 import java.io.IOException; 21 import java.io. UnsupportedEncodingException;21 import java.io.OutputStream; 22 22 import java.lang.String; 23 23 import java.net.HttpURLConnection; 24 import java.net.MalformedURLException;25 24 import java.net.URL; 26 25 import java.nio.ByteBuffer; … … 28 27 import java.nio.charset.Charset; 29 28 import java.nio.charset.CharsetEncoder; 30 import java.nio.charset.CharacterCodingException;31 29 import java.text.DateFormat; 30 import java.text.DecimalFormat; 32 31 import java.text.SimpleDateFormat; 33 32 import java.util.Date; 34 import java.util.logging.Level; 35 import java.util.logging.Logger; 36 37 import javax.swing.BorderFactory; 38 import javax.swing.Box; 33 39 34 import javax.swing.JButton; 40 35 import javax.swing.JCheckBox; 41 36 import javax.swing.JLabel; 42 import javax.swing.JOptionPane;43 37 import javax.swing.JPanel; 44 import javax.swing.JScrollPane;45 import javax.swing.JTextArea;46 38 import javax.swing.JTextField; 47 import javax.swing.UIManager; 48 49 import org.openstreetmap.josm.Main; 39 50 40 import org.openstreetmap.josm.data.gpx.GpxData; 51 import org.openstreetmap.josm.io.GpxWriter; 41 import org.openstreetmap.josm.gui.ExtendedDialog; 42 import org.openstreetmap.josm.gui.JMultilineLabel; 43 import org.openstreetmap.josm.gui.layer.GpxLayer; 52 44 import org.openstreetmap.josm.gui.layer.Layer; 53 import org.openstreetmap.josm.gui.layer.GpxLayer;54 45 import org.openstreetmap.josm.gui.MapView; 55 46 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 47 import org.openstreetmap.josm.io.GpxWriter; 48 import org.openstreetmap.josm.Main; 56 49 import org.openstreetmap.josm.tools.Base64; 57 50 import org.openstreetmap.josm.tools.GBC; 58 import static org.openstreetmap.josm.tools.I18n.tr;59 51 60 52 /** 61 53 * 62 * @author subhodip 54 * @author subhodip, xeen 63 55 */ 64 public class UploadDataGui extends javax.swing.JFrame { 65 private JTextArea OutputDisplay = new JTextArea(); 56 public class UploadDataGui extends ExtendedDialog { 57 // User for log in when uploading trace 58 private String username = Main.pref.get("osm-server.username"); 59 private String password = Main.pref.get("osm-server.password"); 60 61 // Fields are declared here for easy access 62 private JMultilineLabel OutputDisplay = new JMultilineLabel(""); 66 63 private JTextField descriptionField = new JTextField(); 67 64 private JTextField tagsField = new JTextField(); 68 65 private JCheckBox publicCheckbox = new JCheckBox(); 69 private JButton OkButton = new JButton();70 71 p ublicstatic final String API_VERSION = "0.5";66 67 // Constants used when generating upload request 68 private static final String API_VERSION = "0.5"; 72 69 private static final String BOUNDARY = "----------------------------d10f7aa230e8"; 73 70 private static final String LINE_END = "\r\n"; 74 71 private static final String uploadTraceText = tr("Upload Trace"); 72 73 // Filename and current date. Date will be used as fallback if filename not available 75 74 private String datename = new SimpleDateFormat("yyMMddHHmmss").format(new Date()); 76 77 /** Creates new form UploadDataGui */ 75 private String filename = ""; 76 77 private boolean cancelled = false; 78 78 79 public UploadDataGui() { 79 setTitle(tr("Upload Traces")); 80 initComponents(); 81 } 82 83 private void initComponents() { 84 setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); 85 setAlwaysOnTop(true); 86 setPreferredSize(new Dimension(350,200)); 87 88 // Display Center Screen 89 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 90 Dimension labelSize = getPreferredSize(); 91 setLocation(screenSize.width / 2 - (labelSize.width / 2), screenSize.height / 2 - (labelSize.height / 2)); 92 93 OutputDisplay.setBackground(UIManager.getColor("Panel.background")); 94 OutputDisplay.setBorder(BorderFactory.createEmptyBorder(0,0,0,0)); 95 OutputDisplay.setEditable(false); 96 OutputDisplay.setFont(new JLabel().getFont()); 97 OutputDisplay.setLineWrap(true); 98 OutputDisplay.setWrapStyleWord(true); 99 100 JScrollPane jScrollPane1 = new JScrollPane(); 101 jScrollPane1.setViewportView(OutputDisplay); 102 103 OkButton.setText(tr("Upload GPX track")); 104 OkButton.addActionListener(new java.awt.event.ActionListener() { 105 public void actionPerformed(java.awt.event.ActionEvent evt) { 106 OkButtonActionPerformed(evt); 107 } 108 }); 109 110 JButton CancelButton = new JButton(tr("Cancel")); 111 CancelButton.addActionListener(new java.awt.event.ActionListener() { 112 public void actionPerformed(java.awt.event.ActionEvent evt) { 113 CancelButtonActionPerformed(evt); 114 } 115 }); 116 80 // Initalizes ExtendedDialog 81 super(Main.parent, 82 tr("Upload Traces"), 83 new String[] {uploadTraceText, tr("Cancel")}, 84 true 85 ); 86 JPanel content = initComponents(); 87 autoSelectTrace(); 88 89 contentConstraints = GBC.eol().fill().insets(5,10,5,0); 90 setupDialog(content, new String[] { "uploadtrace.png", "cancel.png" }); 91 92 buttons.get(0).setEnabled(!checkForGPXLayer()); 93 94 setSize(findMaxDialogSize()); 95 } 96 97 /** 98 * Sets up the dialog window elements 99 * @return JPanel with components 100 */ 101 private JPanel initComponents() { 117 102 publicCheckbox.setText(tr("Public")); 118 103 publicCheckbox.setToolTipText(tr("Selected makes your trace public in openstreetmap.org")); … … 127 112 p.setLayout(new GridBagLayout()); 128 113 129 p.add(OutputDisplay, GBC.eol().fill()); 130 131 p.add(tagsLabel, GBC.std().insets(0,10,0,0)); 114 OutputDisplay.setMaxWidth(findMaxDialogSize().width-10); 115 p.add(OutputDisplay, GBC.eol()); 116 117 p.add(tagsLabel, GBC.eol().insets(0,10,0,0)); 132 118 p.add(tagsField, GBC.eol().fill(GBC.HORIZONTAL)); 133 119 134 p.add(descriptionLabel, GBC. std().insets(0,10,0,0));120 p.add(descriptionLabel, GBC.eol().insets(0,10,0,0)); 135 121 p.add(descriptionField, GBC.eol().fill(GBC.HORIZONTAL)); 136 122 137 123 p.add(publicCheckbox, GBC.eol()); 138 124 139 p.add(CancelButton, GBC.std());140 p.add(OkButton, GBC.eol().fill(GBC.HORIZONTAL));141 142 getContentPane().setLayout(new GridBagLayout());143 getContentPane().add(p, GBC.eol().insets(10,10,10,10).fill());144 145 pack();146 125 return p; 126 } 127 128 /** 129 * This function will automatically select a GPX layer if it's the only one. 130 * If a GPX layer is found, its filename will be parsed and displayed 131 */ 132 private void autoSelectTrace() { 147 133 // If no GPX layer is selected, select one for the user if there is only one GPX layer 148 134 if(Main.map != null && Main.map.mapView != null) { … … 162 148 if(mv.getActiveLayer() instanceof GpxLayer) { 163 149 GpxData data=((GpxLayer)Main.map.mapView.getActiveLayer()).data; 164 descriptionField.setText(data.storageFile.getName().replaceAll("[&?/\\\\]"," ").replaceAll("(\\.[^.]*)$","")); 150 filename = data.storageFile.getName() 151 .replaceAll("[&?/\\\\]"," ").replaceAll("(\\.[^.]*)$",""); 152 descriptionField.setText(getFilename()); 153 OutputDisplay.setText(tr("Selected track: {0}", getFilename())); 165 154 } 166 155 } 167 168 boolean x=checkForGPXLayer(); 169 } 170 171 public void upload(String username, String password, String description, String tags, Boolean isPublic, GpxData gpxData) throws IOException { 156 } 157 158 /** 159 * This is the actual workhorse that manages the upload. 160 * @param String Description of the GPX track being uploaded 161 * @param String Tags assosciated with the GPX track being uploaded 162 * @param boolean Shall the GPX track be public 163 * @param GpxData The GPX Data to upload 164 */ 165 private void upload(String description, String tags, Boolean isPublic, GpxData gpxData) throws IOException { 172 166 if(checkForErrors(username, password, description, gpxData)) 173 167 return; 174 175 OkButton.setEnabled(false); 176 168 169 // Clean description/tags from disallowed chars 177 170 description = description.replaceAll("[&?/\\\\]"," "); 178 171 tags = tags.replaceAll("[&?/\\\\.,;]"," "); 179 172 173 // Set progress dialog to indeterminate while connecting 180 174 Main.pleaseWaitDlg.progress.setValue(0); 181 175 Main.pleaseWaitDlg.setIndeterminate(true); 182 176 Main.pleaseWaitDlg.currentAction.setText(tr("Connecting...")); 183 // We don't support cancellation yet, so do not advertise it184 Main.pleaseWaitDlg.cancel.setEnabled(false);185 177 186 178 try { 187 URL url = new URL("http://www.openstreetmap.org/api/" + API_VERSION + "/gpx/create"); 188 HttpURLConnection connect = (HttpURLConnection) url.openConnection(); 189 connect.setConnectTimeout(15000); 190 connect.setRequestMethod("POST"); 191 connect.setDoOutput(true); 179 // Generate data for upload 180 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 181 writeGpxFile(baos, "file", gpxData); 182 writeField(baos, "description", description); 183 writeField(baos, "tags", (tags != null && tags.length() > 0) ? tags : ""); 184 writeField(baos, "public", isPublic ? "1" : "0"); 185 writeString(baos, "--" + BOUNDARY + "--" + LINE_END); 192 186 193 CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); 194 String auth = username + ":" + password; 195 ByteBuffer bytes = encoder.encode(CharBuffer.wrap(auth)); 196 connect.addRequestProperty("Authorization", "Basic " + Base64.encode(bytes)); 187 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 188 HttpURLConnection conn = setupConnection(baos.size()); 197 189 198 connect.addRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); 199 connect.addRequestProperty("Connection", "close"); // counterpart of keep-alive 200 connect.addRequestProperty("Expect", ""); 201 connect.connect(); 190 Main.pleaseWaitDlg.progress.setMaximum(baos.size()); 191 Main.pleaseWaitDlg.setIndeterminate(false); 202 192 203 Main.pleaseWaitDlg.currentAction.setText(tr("Uploading GPX track...")); 204 DataOutputStream out = new DataOutputStream(new BufferedOutputStream(connect.getOutputStream())); 205 writeContentDispositionGpxData(out, "file", gpxData); 206 writeContentDisposition(out, "description", description); 207 writeContentDisposition(out, "tags", (tags != null && tags.length() > 0) ? tags : ""); 208 writeContentDisposition(out, "public", isPublic ? "1" : "0"); 209 out.writeBytes("--" + BOUNDARY + "--" + LINE_END); 210 out.flush(); 193 try { 194 flushToServer(bais, conn.getOutputStream()); 195 } catch(Exception e) {} 211 196 212 String returnMsg = connect.getResponseMessage(); 213 boolean success = returnMsg.equals("OK"); 214 OutputDisplay.setText(success ? tr("GPX upload was successful") : returnMsg); 215 216 if (connect.getResponseCode() != 200) { 217 if (connect.getHeaderField("Error") != null) 218 returnMsg += "\n" + connect.getHeaderField("Error"); 197 if(cancelled) { 198 conn.disconnect(); 199 OutputDisplay.setText(tr("Upload cancelled")); 200 buttons.get(0).setEnabled(true); 201 cancelled = false; 202 } else { 203 boolean success = finishUpConnection(conn); 204 buttons.get(0).setEnabled(!success); 205 if(success) 206 buttons.get(1).setText(tr("Close")); 219 207 } 220 out.close(); 221 connect.disconnect(); 222 223 OkButton.setEnabled(!success); 224 225 } catch(UnsupportedEncodingException ignore) { 226 } catch (MalformedURLException e) { 208 } catch(Exception e) { 227 209 OutputDisplay.setText(tr("Error while uploading")); 228 210 e.printStackTrace(); … … 230 212 } 231 213 232 private boolean checkForErrors(String username, String password, String description, GpxData gpxData) { 214 /** 215 * This function sets up the upload URL and logs in using the username and password given 216 * in the preferences. 217 * @param int The length of the content to be sent to the server 218 * @return HttpURLConnection The set up conenction 219 */ 220 private HttpURLConnection setupConnection(int contentLength) throws Exception { 221 // Encode username and password 222 CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); 223 String auth = username + ":" + password; 224 ByteBuffer bytes = encoder.encode(CharBuffer.wrap(auth)); 225 226 // Upload URL 227 URL url = new URL("http://www.openstreetmap.org/api/" + API_VERSION + "/gpx/create"); 228 229 // Set up connection and log in 230 HttpURLConnection c = (HttpURLConnection) url.openConnection(); 231 c.setFixedLengthStreamingMode(contentLength); 232 c.setConnectTimeout(15000); 233 c.setRequestMethod("POST"); 234 c.setDoOutput(true); 235 c.addRequestProperty("Authorization", "Basic " + Base64.encode(bytes)); 236 c.addRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); 237 c.addRequestProperty("Connection", "close"); // counterpart of keep-alive 238 c.addRequestProperty("Expect", ""); 239 c.connect(); 240 241 return c; 242 } 243 244 /** 245 * This function checks if the given connection finished up fine, closes it and returns the result. 246 * It also posts the result (or errors) to OutputDisplay. 247 248 * @param HttpURLConnection The connection to check/finish up 249 */ 250 private boolean finishUpConnection(HttpURLConnection c) throws Exception { 251 String returnMsg = c.getResponseMessage(); 252 boolean success = returnMsg.equals("OK"); 253 254 if (c.getResponseCode() != 200) { 255 if (c.getHeaderField("Error") != null) 256 returnMsg += "\n" + c.getHeaderField("Error"); 257 } 258 259 OutputDisplay.setText(success 260 ? tr("GPX upload was successful") 261 : tr("Upload failed. Server returned the following message: ") + returnMsg); 262 263 c.disconnect(); 264 return success; 265 } 266 267 /** 268 * Uploads a given InputStream to a given OutputStream and sets progress 269 * @param InputSteam 270 * @param OutputStream 271 */ 272 private void flushToServer(InputStream in, OutputStream out) throws Exception { 273 // Upload in 10 kB chunks 274 byte[] buffer = new byte[10000]; 275 int nread; 276 int cur = 0; 277 synchronized (in) { 278 while ((nread = in.read(buffer, 0, buffer.length)) >= 0) { 279 out.write(buffer, 0, nread); 280 cur += nread; 281 out.flush(); 282 Main.pleaseWaitDlg.progress.setValue(cur); 283 Main.pleaseWaitDlg.currentAction.setText(getProgressText(cur)); 284 285 if(cancelled) 286 break; 287 } 288 } 289 if(!cancelled) 290 out.flush(); 291 Main.pleaseWaitDlg.currentAction.setText("Waiting for server reply..."); 292 buffer = null; 293 } 294 295 /** 296 * Generates the output string displayed in the PleaseWaitDialog. 297 * @param int Bytes already uploaded 298 * @return String Message 299 */ 300 private String getProgressText(int cur) { 301 int max = Main.pleaseWaitDlg.progress.getMaximum(); 302 int percent = Math.round(cur * 100 / max); 303 return tr("Uploading GPX track: {0}% ({1} of {2})", 304 percent, formatBytes(cur), formatBytes(max)); 305 } 306 307 /** 308 * Nicely calculates given bytes into MB, kB and B (with units) 309 * @param int Bytes 310 * @return String 311 */ 312 private String formatBytes(int bytes) { 313 return (bytes > 1000 * 1000 314 // Rounds to 2 decimal places 315 ? new DecimalFormat("0.00") 316 .format((double)Math.round(bytes/(1000*10))/100) + " MB" 317 : (bytes > 1000 318 ? Math.round(bytes/1000) + " kB" 319 : bytes + " B")); 320 } 321 322 /** 323 * Checks for common errors and displays them in OutputDisplay if it finds any. 324 * Returns whether errors have been found or not. 325 * @param String OSM username 326 * @param String OSM password 327 * @param String GPX track description 328 * @param GpxData the GPX data to upload 329 * @return boolean true if errors have been found 330 */ 331 private boolean checkForErrors(String username, String password, 332 String description, GpxData gpxData) { 233 333 String errors=""; 234 334 if(description == null || description.length() == 0) … … 238 338 errors += tr("No GPX layer selected. Cannot upload a trace."); 239 339 240 if(username == null || username.length() ==0)340 if(username == null || username.length() == 0) 241 341 errors += tr("No username provided."); 242 342 243 if(password == null || password.length() ==0)343 if(password == null || password.length() == 0) 244 344 errors += tr("No password provided."); 245 345 … … 248 348 } 249 349 350 /** 351 * Checks if a GPX layer is selected and returns the result. Also writes an error 352 * message to OutputDisplay if result is false. 353 * @return boolean True, if /no/ GPX layer is selected 354 */ 250 355 private boolean checkForGPXLayer() { 251 if(Main.map == null || Main.map.mapView == null || Main.map.mapView.getActiveLayer() == null || !(Main.map.mapView.getActiveLayer() instanceof GpxLayer)) { 356 if(Main.map == null 357 || Main.map.mapView == null 358 || Main.map.mapView.getActiveLayer() == null 359 || !(Main.map.mapView.getActiveLayer() instanceof GpxLayer)) { 252 360 OutputDisplay.setText(tr("No GPX layer selected. Cannot upload a trace.")); 253 361 return true; … … 256 364 } 257 365 258 private void OkButtonActionPerformed(java.awt.event.ActionEvent evt) { 366 367 /** 368 * This creates the uploadTask that does the actual work and hands it to the main.worker to be executed. 369 */ 370 private void setupUpload() { 259 371 if(checkForGPXLayer()) return; 372 373 // Disable Upload button so users can't just upload that track again 374 buttons.get(0).setEnabled(false); 260 375 261 376 PleaseWaitRunnable uploadTask = new PleaseWaitRunnable(tr("Uploading GPX Track")){ 262 377 @Override protected void realRun() throws IOException { 263 setAlwaysOnTop(false); 264 upload(Main.pref.get("osm-server.username"), 265 Main.pref.get("osm-server.password"), 266 descriptionField.getText(), 378 upload(descriptionField.getText(), 267 379 tagsField.getText(), 268 380 publicCheckbox.isSelected(), … … 270 382 ); 271 383 } 272 @Override protected void finish() { 273 setAlwaysOnTop(true); 274 } 384 @Override protected void finish() {} 275 385 @Override protected void cancel() { 386 cancelled = true; 276 387 } 277 388 }; … … 279 390 Main.worker.execute(uploadTask); 280 391 } 281 282 private void CancelButtonActionPerformed(java.awt.event.ActionEvent evt) { 283 dispose(); 284 } 285 286 private void writeContentDisposition(DataOutputStream out, String name, String value) throws IOException { 287 out.writeBytes("--" + BOUNDARY + LINE_END); 288 out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"" + LINE_END); 289 out.writeBytes(LINE_END); 290 // DataOutputStream's "writeUTF" method is unsuitable here because it adds two 291 // char length bytes in front 292 byte[] temp=value.getBytes("UTF-8"); 293 out.write(temp, 0, temp.length); 294 out.writeBytes(LINE_END); 295 } 296 297 private void writeContentDispositionGpxData(DataOutputStream out, String name, GpxData gpxData) throws IOException { 298 out.writeBytes("--" + BOUNDARY + LINE_END); 299 out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + datename +".gpx" + "\"" + LINE_END); 300 out.writeBytes("Content-Type: application/octet-stream" + LINE_END); 301 out.writeBytes(LINE_END); 302 new GpxWriter(out).write(gpxData); 303 out.flush(); 304 out.writeBytes(LINE_END); 392 393 /** 394 * Writes textfields (like in webbrowser) to the given ByteArrayOutputStream 395 * @param ByteArrayOutputStream 396 * @param String The name of the "textbox" 397 * @param String The value to write 398 */ 399 private void writeField(ByteArrayOutputStream baos, String name, String value) throws IOException { 400 writeBoundary(baos); 401 writeString(baos, "Content-Disposition: form-data; name=\"" + name + "\""); 402 writeLineEnd(baos); 403 writeLineEnd(baos); 404 baos.write(value.getBytes("UTF-8")); 405 writeLineEnd(baos); 406 } 407 408 /** 409 * Writes gpxData (= file field in webbrowser) to the given ByteArrayOutputStream 410 * @param ByteArrayOutputStream 411 * @param String The name of the "upload field" 412 * @param GpxData The GPX data to upload 413 */ 414 private void writeGpxFile(ByteArrayOutputStream baos, String name, GpxData gpxData) throws IOException { 415 writeBoundary(baos); 416 writeString(baos, "Content-Disposition: form-data; name=\"" + name + "\"; "); 417 writeString(baos, "filename=\"" + getFilename() + ".gpx" + "\""); 418 writeLineEnd(baos); 419 writeString(baos, "Content-Type: application/octet-stream"); 420 writeLineEnd(baos); 421 writeLineEnd(baos); 422 new GpxWriter(baos).write(gpxData); 423 writeLineEnd(baos); 424 } 425 426 /** 427 * Writes a String to the given ByteArrayOutputStream 428 * @param ByteArrayOutputStream 429 * @param String 430 */ 431 private void writeString(ByteArrayOutputStream baos, String s) { 432 try { 433 baos.write(s.getBytes()); 434 } catch(Exception e) {} 435 } 436 437 /** 438 * Writes a newline to the given ByteArrayOutputStream 439 * @param ByteArrayOutputStream 440 */ 441 private void writeLineEnd(ByteArrayOutputStream baos) { 442 writeString(baos, LINE_END); 443 } 444 445 /** 446 * Writes a boundary line to the given ByteArrayOutputStream 447 * @param ByteArrayOutputStream 448 */ 449 private void writeBoundary(ByteArrayOutputStream baos) { 450 writeString(baos, "--" + BOUNDARY); 451 writeLineEnd(baos); 452 } 453 454 /** 455 * Returns the filename of the GPX file to be upload. If not available, returns current date 456 * as an alternative 457 * @param String 458 */ 459 private String getFilename() { 460 return filename.equals("") ? datename : filename; 461 } 462 463 /** 464 * Defines a default size for the dialog 465 */ 466 @Override protected Dimension findMaxDialogSize() { 467 setResizable(false); 468 return new Dimension(300, 230); 469 } 470 471 /** 472 * Overrides the default actions. Will not close the window when upload trace is clicked 473 */ 474 @Override protected void buttonAction(ActionEvent evt) { 475 String a = evt.getActionCommand(); 476 if(uploadTraceText.equals(a)) 477 setupUpload(); 478 else 479 setVisible(false); 305 480 } 306 481 }
Note:
See TracChangeset
for help on using the changeset viewer.