]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - src/tim/prune/function/gpsies/UploadGpsiesFunction.java
Moved source into separate src directory due to popular request
[GpsPrune.git] / src / tim / prune / function / gpsies / UploadGpsiesFunction.java
diff --git a/src/tim/prune/function/gpsies/UploadGpsiesFunction.java b/src/tim/prune/function/gpsies/UploadGpsiesFunction.java
new file mode 100644 (file)
index 0000000..3cef9db
--- /dev/null
@@ -0,0 +1,332 @@
+package tim.prune.function.gpsies;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.border.EtchedBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.function.browser.BrowserLauncher;
+import tim.prune.gui.GuiGridLayout;
+import tim.prune.save.GpxExporter;
+import tim.prune.save.SettingsForExport;
+
+/**
+ * Function to upload track information up to Gpsies.com
+ */
+public class UploadGpsiesFunction extends GenericFunction
+{
+       /** Dialog object */
+       private JDialog _dialog = null;
+       /** Edit box for user name */
+       private JTextField _usernameField = null;
+       /** Edit box for password */
+       private JPasswordField _passwordField = null;
+       /** Name of track */
+       private JTextField _nameField = null;
+       /** Description */
+       private JTextArea _descField = null;
+       /** Private checkbox */
+       private JCheckBox _privateCheckbox = null;
+       /** Activity checkboxes */
+       private JCheckBox[] _activityCheckboxes = null;
+       /** Writer object for GPX export */
+       private OutputStreamWriter _writer = null;
+       /** upload button */
+       private JButton _uploadButton = null;
+
+       /** URL to post form to */
+       private static final String GPSIES_URL = "http://www.gpsies.com/upload.do";
+       /** Keys for describing activities */
+       private static final String[] ACTIVITY_KEYS = {"trekking", "walking", "jogging",
+               "biking", "motorbiking", "snowshoe", "sailing", "skating"};
+
+       /**
+        * Constructor
+        * @param inApp App object
+        */
+       public UploadGpsiesFunction(App inApp) {
+               super(inApp);
+       }
+
+       /**
+        * @return name key
+        */
+       public String getNameKey() {
+               return "function.uploadgpsies";
+       }
+
+       /**
+        * Begin the function
+        */
+       public void begin()
+       {
+               // Initialise dialog, show empty list
+               if (_dialog == null)
+               {
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
+                       _dialog.setLocationRelativeTo(_parentFrame);
+                       _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+                       _dialog.getContentPane().add(makeDialogComponents());
+                       _dialog.pack();
+               }
+               // Show dialog
+               _dialog.setVisible(true);
+       }
+
+
+       /**
+        * Create dialog components
+        * @return Panel containing all gui elements in dialog
+        */
+       private Component makeDialogComponents()
+       {
+               JPanel dialogPanel = new JPanel();
+               dialogPanel.setLayout(new BorderLayout());
+
+               JPanel gridPanel = new JPanel();
+               GuiGridLayout grid = new GuiGridLayout(gridPanel);
+               grid.add(new JLabel(I18nManager.getText("dialog.gpsies.username")));
+               _usernameField = new JTextField(15);
+               grid.add(_usernameField);
+               grid.add(new JLabel(I18nManager.getText("dialog.gpsies.password")));
+               _passwordField = new JPasswordField(15);
+               grid.add(_passwordField);
+               // Track name and description
+               grid.add(new JLabel(I18nManager.getText("dialog.gpsies.column.name")));
+               _nameField = new JTextField(15);
+               grid.add(_nameField);
+               grid.add(new JLabel(I18nManager.getText("dialog.gpsies.description")));
+               _descField = new JTextArea(5, 15);
+               _descField.setLineWrap(true);
+               _descField.setWrapStyleWord(true);
+               grid.add(new JScrollPane(_descField));
+               // Listener on all these text fields to enable/disable the ok button
+               KeyAdapter keyListener = new KeyAdapter() {
+                       /** Key released */
+                       public void keyReleased(KeyEvent inE) {
+                               enableOK();
+                               if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {
+                                       _dialog.dispose();
+                               }
+                       }
+               };
+               _usernameField.addKeyListener(keyListener);
+               _passwordField.addKeyListener(keyListener);
+               _nameField.addKeyListener(keyListener);
+               // Listen for tabs on description field, to change focus not enter tabs
+               _descField.addKeyListener(new KeyAdapter() {
+                       /** Key pressed */
+                       public void keyPressed(KeyEvent inE) {
+                               if (inE.getKeyCode() == KeyEvent.VK_TAB) {
+                                       inE.consume();
+                                       if (inE.isShiftDown()) {
+                                               _nameField.requestFocusInWindow();
+                                       }
+                                       else {
+                                               _privateCheckbox.requestFocusInWindow();
+                                       }
+                               }
+                       }
+               });
+               // Listen for Ctrl-backspace on password field (delete contents)
+               _passwordField.addKeyListener(new KeyAdapter() {
+                       /** Key released */
+                       public void keyReleased(KeyEvent inE) {
+                               if (inE.isControlDown() && (inE.getKeyCode() == KeyEvent.VK_BACK_SPACE
+                                       || inE.getKeyCode() == KeyEvent.VK_DELETE)) {
+                                       _passwordField.setText("");
+                               }
+                       }
+               });
+               // Checkbox for private / public
+               grid.add(new JLabel(I18nManager.getText("dialog.gpsies.keepprivate")));
+               _privateCheckbox = new JCheckBox();
+               _privateCheckbox.setSelected(true);
+               grid.add(_privateCheckbox);
+
+               // panel for activity type checkboxes
+               JPanel activityPanel = new JPanel();
+               activityPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
+               ChangeListener checkListener = new ChangeListener() {
+                       public void stateChanged(ChangeEvent arg0) {
+                               enableOK();
+                       }
+               };
+               // Why not a simple grid layout here?
+               GuiGridLayout actGrid = new GuiGridLayout(activityPanel, new double[] {1.0, 1.0}, new boolean[] {false, false});
+               final int numActivities = ACTIVITY_KEYS.length;
+               _activityCheckboxes = new JCheckBox[numActivities];
+               for (int i=0; i<numActivities; i++)
+               {
+                       _activityCheckboxes[i] = new JCheckBox(I18nManager.getText("dialog.gpsies.activity." + ACTIVITY_KEYS[i]));
+                       _activityCheckboxes[i].addChangeListener(checkListener);
+                       actGrid.add(_activityCheckboxes[i]);
+               }
+               grid.add(new JLabel(I18nManager.getText("dialog.gpsies.activities")));
+               grid.add(activityPanel);
+               JPanel midPanel = new JPanel();
+               midPanel.setLayout(new BoxLayout(midPanel, BoxLayout.Y_AXIS));
+               midPanel.add(gridPanel);
+               dialogPanel.add(midPanel, BorderLayout.CENTER);
+
+               // button panel at bottom
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               _uploadButton = new JButton(I18nManager.getText("button.upload"));
+               _uploadButton.setEnabled(false);
+               _uploadButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               startUpload();
+                       }
+               });
+               buttonPanel.add(_uploadButton);
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               _dialog.dispose();
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+               dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
+               return dialogPanel;
+       }
+
+
+       /**
+        * Check the inputs and enable or disable the upload button
+        */
+       private void enableOK()
+       {
+               // Check for lengths of input fields - only username, password and filename are required
+               boolean ok = (_usernameField.getText().length() > 0 && _nameField.getText().length() > 0);
+               if (ok) {
+                       // also check password field
+                       char[] pass = _passwordField.getPassword();
+                       ok = pass.length > 0;
+                       for (int i=0; i<pass.length; i++) {pass[i] = '0';} // recommended by javadoc
+                       if (ok) {
+                               ok = false;
+                               for (int i=0; i<_activityCheckboxes.length; i++) {
+                                       ok = ok || _activityCheckboxes[i].isSelected();
+                               }
+                       }
+               }
+               _uploadButton.setEnabled(ok);
+       }
+
+
+       /**
+        * Start the upload process (require separate thread?)
+        */
+       private void startUpload()
+       {
+               BufferedReader reader = null;
+               try
+               {
+                       FormPoster poster = new FormPoster(new URL(GPSIES_URL));
+                       poster.setParameter("device", "Prune");
+                       poster.setParameter("username", _usernameField.getText());
+                       poster.setParameter("password", new String(_passwordField.getPassword()));
+                       boolean hasActivity = false;
+                       for (int i=0; i<ACTIVITY_KEYS.length; i++)
+                       {
+                               if (_activityCheckboxes[i].isSelected()) {
+                                       hasActivity = true;
+                                       poster.setParameter("trackTypes", ACTIVITY_KEYS[i]);
+                               }
+                       }
+                       if (!hasActivity) {poster.setParameter("trackTypes", "walking");} // default if none given
+                       poster.setParameter("filename", _nameField.getText());
+                       poster.setParameter("fileDescription", _descField.getText());
+                       poster.setParameter("startpointCountry", "DE");
+                       poster.setParameter("endpointCountry", "DE"); // both those will be corrected by gpsies
+                       poster.setParameter("status", (_privateCheckbox.isSelected()?"3":"1"));
+                       poster.setParameter("submit", "speichern"); // required
+                       // Use Pipes to connect the GpxExporter's output with the FormPoster's input
+                       PipedInputStream iStream = new PipedInputStream();
+                       PipedOutputStream oStream = new PipedOutputStream(iStream);
+                       _writer = new OutputStreamWriter(oStream);
+                       new Thread(new Runnable() {
+                               public void run() {
+                                       try {
+                                               GpxExporter.exportData(_writer, _app.getTrackInfo(), _nameField.getText(),
+                                                       null, new SettingsForExport(), null);
+                                       } catch (IOException e) {}
+                                       finally {
+                                               try {_writer.close();} catch (IOException e) {}
+                                       }
+                               }
+                       }).start();
+                       poster.setParameter("formFile", "filename.gpx", iStream);
+
+                       BufferedInputStream answer = new BufferedInputStream(poster.post());
+                       int response = poster.getResponseCode();
+                       reader = new BufferedReader(new InputStreamReader(answer));
+                       String line = reader.readLine();
+                       // Try to extract gpsies page url from the returned message
+                       String pageUrl = null;
+                       if (response == 200 && line.substring(0, 2).toUpperCase().equals("OK"))
+                       {
+                               final int bracketPos = line.indexOf('[');
+                               if (bracketPos > 0 && line.endsWith("]")) {
+                                       pageUrl = line.substring(bracketPos + 1, line.length()-1);
+                               }
+                       }
+                       if (pageUrl != null)
+                       {
+                               // OK received and managed to extract a Url from the return message.
+                               int userChoice = JOptionPane.showConfirmDialog(_app.getFrame(),
+                                       I18nManager.getText("dialog.gpsies.confirmopenpage"),
+                                       I18nManager.getText(getNameKey()), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
+                               if (userChoice == JOptionPane.OK_OPTION) {
+                                       BrowserLauncher.launchBrowser(pageUrl);
+                               }
+                       }
+                       else {
+                               _app.showErrorMessageNoLookup(getNameKey(), I18nManager.getText("error.gpsies.uploadnotok")
+                                       + ": " + line);
+                       }
+               }
+               catch (MalformedURLException e) {}
+               catch (IOException ioe) {
+                       _app.showErrorMessageNoLookup(getNameKey(), I18nManager.getText("error.gpsies.uploadfailed") + ": "
+                               + ioe.getClass().getName() + " : " + ioe.getMessage());
+               }
+               finally {
+                       try {if (reader != null) reader.close();} catch (IOException e) {}
+               }
+               _dialog.dispose();
+       }
+}