Ticket #1876: Re-Write Direct Upload.patch

File Re-Write Direct Upload.patch, 24.7 KB (added by xeen, 4 years ago)

Rewrites most of DirectUpload. Improved layout a bit. Dialog now modal because it makes more sense the way it works now. Fixes #1873, too.

  • DirectUpload/src/org/openstreetmap/josm/plugins/DirectUpload/UploadDataGui.java

     
    88 
    99package org.openstreetmap.josm.plugins.DirectUpload; 
    1010 
    11 import java.awt.BorderLayout; 
    12 import java.awt.Container; 
     11import static org.openstreetmap.josm.tools.I18n.tr; 
     12 
    1313import java.awt.Dimension; 
    14 import java.awt.event.ItemEvent; 
     14import java.awt.event.ActionEvent; 
    1515import java.awt.GridBagLayout; 
    16 import java.awt.GridBagConstraints; 
    17 import java.awt.Toolkit; 
    1816import java.io.BufferedOutputStream; 
    19 import java.io.DataOutputStream; 
     17import java.io.ByteArrayInputStream; 
     18import java.io.ByteArrayOutputStream; 
     19import java.io.InputStream; 
    2020import java.io.IOException; 
    21 import java.io.UnsupportedEncodingException; 
     21import java.io.OutputStream; 
    2222import java.lang.String; 
    2323import java.net.HttpURLConnection; 
    24 import java.net.MalformedURLException; 
    2524import java.net.URL; 
    2625import java.nio.ByteBuffer; 
    2726import java.nio.CharBuffer; 
    2827import java.nio.charset.Charset; 
    2928import java.nio.charset.CharsetEncoder; 
    30 import java.nio.charset.CharacterCodingException; 
    3129import java.text.DateFormat; 
     30import java.text.DecimalFormat; 
    3231import java.text.SimpleDateFormat; 
    3332import java.util.Date; 
    34 import java.util.logging.Level; 
    35 import java.util.logging.Logger; 
    3633 
    37 import javax.swing.BorderFactory; 
    38 import javax.swing.Box; 
    3934import javax.swing.JButton; 
    4035import javax.swing.JCheckBox; 
    4136import javax.swing.JLabel; 
    42 import javax.swing.JOptionPane; 
    4337import javax.swing.JPanel; 
    44 import javax.swing.JScrollPane; 
    45 import javax.swing.JTextArea; 
    4638import javax.swing.JTextField; 
    47 import javax.swing.UIManager; 
    4839 
    49 import org.openstreetmap.josm.Main; 
    5040import org.openstreetmap.josm.data.gpx.GpxData; 
    51 import org.openstreetmap.josm.io.GpxWriter; 
     41import org.openstreetmap.josm.gui.ExtendedDialog; 
     42import org.openstreetmap.josm.gui.JMultilineLabel; 
     43import org.openstreetmap.josm.gui.layer.GpxLayer; 
    5244import org.openstreetmap.josm.gui.layer.Layer; 
    53 import org.openstreetmap.josm.gui.layer.GpxLayer; 
    5445import org.openstreetmap.josm.gui.MapView; 
    5546import org.openstreetmap.josm.gui.PleaseWaitRunnable; 
     47import org.openstreetmap.josm.io.GpxWriter; 
     48import org.openstreetmap.josm.Main; 
    5649import org.openstreetmap.josm.tools.Base64; 
    5750import org.openstreetmap.josm.tools.GBC; 
    58 import static org.openstreetmap.josm.tools.I18n.tr; 
    5951 
    6052/** 
    6153 * 
    62  * @author  subhodip 
     54 * @author  subhodip, xeen 
    6355 */ 
    64 public class UploadDataGui extends javax.swing.JFrame { 
    65     private JTextArea OutputDisplay = new JTextArea(); 
     56public 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(""); 
    6663    private JTextField descriptionField = new JTextField(); 
    6764    private JTextField tagsField = new JTextField(); 
    6865    private JCheckBox publicCheckbox = new JCheckBox(); 
    69     private JButton OkButton = new JButton(); 
    70  
    71     public static final String API_VERSION = "0.5"; 
     66     
     67    // Constants used when generating upload request 
     68    private static final String API_VERSION = "0.5"; 
    7269    private static final String BOUNDARY = "----------------------------d10f7aa230e8"; 
    7370    private static final String LINE_END = "\r\n"; 
     71    private static final String uploadTraceText = tr("Upload Trace"); 
    7472 
     73    // Filename and current date. Date will be used as fallback if filename not available 
    7574    private String datename = new SimpleDateFormat("yyMMddHHmmss").format(new Date()); 
     75    private String filename = ""; 
     76     
     77    private boolean cancelled = false; 
    7678 
    77     /** Creates new form UploadDataGui */ 
    7879    public UploadDataGui() { 
    79         setTitle(tr("Upload Traces")); 
    80         initComponents(); 
     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()); 
    8195    } 
    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  
     96     
     97    /** 
     98     * Sets up the dialog window elements 
     99     * @return JPanel with components 
     100     */ 
     101    private JPanel initComponents() { 
    117102        publicCheckbox.setText(tr("Public")); 
    118103        publicCheckbox.setToolTipText(tr("Selected makes your trace public in openstreetmap.org")); 
    119104 
     
    126111        JPanel p = new JPanel(); 
    127112        p.setLayout(new GridBagLayout()); 
    128113 
    129         p.add(OutputDisplay, GBC.eol().fill()); 
     114        OutputDisplay.setMaxWidth(findMaxDialogSize().width-10); 
     115        p.add(OutputDisplay, GBC.eol()); 
    130116 
    131         p.add(tagsLabel, GBC.std().insets(0,10,0,0)); 
     117        p.add(tagsLabel, GBC.eol().insets(0,10,0,0)); 
    132118        p.add(tagsField, GBC.eol().fill(GBC.HORIZONTAL)); 
    133119 
    134         p.add(descriptionLabel, GBC.std().insets(0,10,0,0)); 
     120        p.add(descriptionLabel, GBC.eol().insets(0,10,0,0)); 
    135121        p.add(descriptionField, GBC.eol().fill(GBC.HORIZONTAL)); 
    136122 
    137123        p.add(publicCheckbox, GBC.eol()); 
    138124 
    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() { 
    147133        // If no GPX layer is selected, select one for the user if there is only one GPX layer 
    148134        if(Main.map != null && Main.map.mapView != null) { 
    149135            MapView mv=Main.map.mapView; 
     
    161147 
    162148            if(mv.getActiveLayer() instanceof GpxLayer) { 
    163149                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())); 
    165154            } 
    166155        } 
    167  
    168         boolean x=checkForGPXLayer(); 
    169156    } 
    170157 
    171     public void upload(String username, String password, String description, String tags, Boolean isPublic, GpxData gpxData) throws IOException { 
     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 { 
    172166        if(checkForErrors(username, password, description, gpxData)) 
    173167            return; 
    174                  
    175         OkButton.setEnabled(false); 
    176                  
     168         
     169        // Clean description/tags from disallowed chars 
    177170        description = description.replaceAll("[&?/\\\\]"," "); 
    178171        tags = tags.replaceAll("[&?/\\\\.,;]"," "); 
    179172         
     173        // Set progress dialog to indeterminate while connecting 
    180174        Main.pleaseWaitDlg.progress.setValue(0); 
    181175        Main.pleaseWaitDlg.setIndeterminate(true);  
    182176        Main.pleaseWaitDlg.currentAction.setText(tr("Connecting...")); 
    183         // We don't support cancellation yet, so do not advertise it 
    184         Main.pleaseWaitDlg.cancel.setEnabled(false); 
    185177 
    186178        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); 
    192186             
    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()); 
    197189             
    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);  
    202192             
    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) {} 
    211196             
    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")); 
    219207            } 
    220             out.close(); 
    221             connect.disconnect(); 
    222              
    223             OkButton.setEnabled(!success); 
    224              
    225         } catch(UnsupportedEncodingException ignore) { 
    226         } catch (MalformedURLException e) { 
     208        } catch(Exception e) { 
    227209            OutputDisplay.setText(tr("Error while uploading")); 
    228210            e.printStackTrace(); 
    229211        } 
    230212    } 
    231213     
    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) { 
    233333        String errors=""; 
    234334        if(description == null || description.length() == 0) 
    235335            errors += tr("No description provided. Please provide some description."); 
     
    237337        if(gpxData == null) 
    238338            errors += tr("No GPX layer selected. Cannot upload a trace."); 
    239339 
    240         if(username == null || username.length()==0) 
     340        if(username == null || username.length() == 0) 
    241341            errors += tr("No username provided."); 
    242342 
    243         if(password == null || password.length()==0) 
     343        if(password == null || password.length() == 0) 
    244344            errors += tr("No password provided."); 
    245345 
    246346        OutputDisplay.setText(errors); 
    247347        return errors.length() > 0; 
    248348    } 
    249349 
     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     */ 
    250355    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)) { 
    252360            OutputDisplay.setText(tr("No GPX layer selected. Cannot upload a trace.")); 
    253361            return true; 
    254362        } 
    255363        return false; 
    256364    } 
    257365 
    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() { 
    259371        if(checkForGPXLayer()) return; 
     372         
     373        // Disable Upload button so users can't just upload that track again 
     374        buttons.get(0).setEnabled(false); 
    260375 
    261376        PleaseWaitRunnable uploadTask = new PleaseWaitRunnable(tr("Uploading GPX Track")){ 
    262377            @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(), 
    267379                         tagsField.getText(), 
    268380                         publicCheckbox.isSelected(), 
    269381                         ((GpxLayer)Main.map.mapView.getActiveLayer()).data 
    270382                  ); 
    271383            } 
    272             @Override protected void finish() { 
    273                 setAlwaysOnTop(true); 
    274             } 
     384            @Override protected void finish() {} 
    275385            @Override protected void cancel() { 
     386                cancelled = true; 
    276387            } 
    277388        }; 
    278389         
    279390        Main.worker.execute(uploadTask); 
    280391    } 
    281  
    282     private void CancelButtonActionPerformed(java.awt.event.ActionEvent evt) { 
    283         dispose(); 
     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); 
    284406    } 
    285407 
    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); 
     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); 
    295424    } 
    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); 
     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) {} 
    305435    } 
     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); 
     480    } 
    306481}