]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/function/gpsies/UploadGpsiesFunction.java
Version 11, August 2010
[GpsPrune.git] / tim / prune / function / gpsies / UploadGpsiesFunction.java
1 package tim.prune.function.gpsies;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.FlowLayout;
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8 import java.awt.event.KeyAdapter;
9 import java.awt.event.KeyEvent;
10 import java.io.BufferedInputStream;
11 import java.io.BufferedReader;
12 import java.io.IOException;
13 import java.io.InputStreamReader;
14 import java.io.OutputStreamWriter;
15 import java.io.PipedInputStream;
16 import java.io.PipedOutputStream;
17 import java.net.MalformedURLException;
18 import java.net.URL;
19
20 import javax.swing.BorderFactory;
21 import javax.swing.BoxLayout;
22 import javax.swing.JButton;
23 import javax.swing.JCheckBox;
24 import javax.swing.JDialog;
25 import javax.swing.JLabel;
26 import javax.swing.JOptionPane;
27 import javax.swing.JPanel;
28 import javax.swing.JPasswordField;
29 import javax.swing.JScrollPane;
30 import javax.swing.JTextArea;
31 import javax.swing.JTextField;
32 import javax.swing.border.EtchedBorder;
33 import javax.swing.event.ChangeEvent;
34 import javax.swing.event.ChangeListener;
35
36 import tim.prune.App;
37 import tim.prune.GenericFunction;
38 import tim.prune.I18nManager;
39 import tim.prune.function.browser.BrowserLauncher;
40 import tim.prune.gui.GuiGridLayout;
41 import tim.prune.save.GpxExporter;
42
43 /**
44  * Function to upload track information up to Gpsies.com
45  */
46 public class UploadGpsiesFunction extends GenericFunction
47 {
48         /** Dialog object */
49         private JDialog _dialog = null;
50         /** Edit box for user name */
51         private JTextField _usernameField = null;
52         /** Edit box for password */
53         private JPasswordField _passwordField = null;
54         /** Name of track */
55         private JTextField _nameField = null;
56         /** Description */
57         private JTextArea _descField = null;
58         /** Private checkbox */
59         private JCheckBox _privateCheckbox = null;
60         /** Activity checkboxes */
61         private JCheckBox[] _activityCheckboxes = null;
62         /** Writer object for GPX export */
63         private OutputStreamWriter _writer = null;
64         /** upload button */
65         private JButton _uploadButton = null;
66
67         /** URL to post form to */
68         private static final String GPSIES_URL = "http://www.gpsies.com/upload.do";
69         /** Keys for describing activities */
70         private static final String[] ACTIVITY_KEYS = {"trekking", "walking", "jogging",
71                 "biking", "motorbiking", "snowshoe", "sailing", "skating"};
72
73         /**
74          * Constructor
75          * @param inApp App object
76          */
77         public UploadGpsiesFunction(App inApp) {
78                 super(inApp);
79         }
80
81         /**
82          * @return name key
83          */
84         public String getNameKey() {
85                 return "function.uploadgpsies";
86         }
87
88         /**
89          * Begin the function
90          */
91         public void begin()
92         {
93                 // Initialise dialog, show empty list
94                 if (_dialog == null)
95                 {
96                         _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
97                         _dialog.setLocationRelativeTo(_parentFrame);
98                         _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
99                         _dialog.getContentPane().add(makeDialogComponents());
100                         _dialog.pack();
101                 }
102                 // Show dialog
103                 _dialog.setVisible(true);
104         }
105
106
107         /**
108          * Create dialog components
109          * @return Panel containing all gui elements in dialog
110          */
111         private Component makeDialogComponents()
112         {
113                 JPanel dialogPanel = new JPanel();
114                 dialogPanel.setLayout(new BorderLayout());
115
116                 JPanel gridPanel = new JPanel();
117                 GuiGridLayout grid = new GuiGridLayout(gridPanel);
118                 grid.add(new JLabel(I18nManager.getText("dialog.gpsies.username")));
119                 _usernameField = new JTextField(15);
120                 grid.add(_usernameField);
121                 grid.add(new JLabel(I18nManager.getText("dialog.gpsies.password")));
122                 _passwordField = new JPasswordField(15);
123                 grid.add(_passwordField);
124                 // Track name and description
125                 grid.add(new JLabel(I18nManager.getText("dialog.gpsies.column.name")));
126                 _nameField = new JTextField(15);
127                 grid.add(_nameField);
128                 grid.add(new JLabel(I18nManager.getText("dialog.gpsies.description")));
129                 _descField = new JTextArea(5, 15);
130                 _descField.setLineWrap(true);
131                 _descField.setWrapStyleWord(true);
132                 grid.add(new JScrollPane(_descField));
133                 // Listener on all these text fields to enable/disable the ok button
134                 KeyAdapter keyListener = new KeyAdapter() {
135                         /** Key released */
136                         public void keyReleased(KeyEvent inE) {
137                                 enableOK();
138                                 if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {
139                                         _dialog.dispose();
140                                 }
141                         }
142                 };
143                 _usernameField.addKeyListener(keyListener);
144                 _passwordField.addKeyListener(keyListener);
145                 _nameField.addKeyListener(keyListener);
146                 // Listen for tabs on description field, to change focus not enter tabs
147                 _descField.addKeyListener(new KeyAdapter() {
148                         /** Key pressed */
149                         public void keyPressed(KeyEvent inE) {
150                                 if (inE.getKeyCode() == KeyEvent.VK_TAB) {
151                                         inE.consume();
152                                         if (inE.isShiftDown()) {
153                                                 _nameField.requestFocusInWindow();
154                                         }
155                                         else {
156                                                 _privateCheckbox.requestFocusInWindow();
157                                         }
158                                 }
159                         }
160                 });
161                 // Listen for Ctrl-backspace on password field (delete contents)
162                 _passwordField.addKeyListener(new KeyAdapter() {
163                         /** Key released */
164                         public void keyReleased(KeyEvent inE) {
165                                 if (inE.isControlDown() && (inE.getKeyCode() == KeyEvent.VK_BACK_SPACE
166                                         || inE.getKeyCode() == KeyEvent.VK_DELETE)) {
167                                         _passwordField.setText("");
168                                 }
169                         }
170                 });
171                 // Checkbox for private / public
172                 grid.add(new JLabel(I18nManager.getText("dialog.gpsies.keepprivate")));
173                 _privateCheckbox = new JCheckBox();
174                 _privateCheckbox.setSelected(true);
175                 grid.add(_privateCheckbox);
176
177                 // panel for activity type checkboxes
178                 JPanel activityPanel = new JPanel();
179                 activityPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
180                 ChangeListener checkListener = new ChangeListener() {
181                         public void stateChanged(ChangeEvent arg0) {
182                                 enableOK();
183                         }
184                 };
185                 GuiGridLayout actGrid = new GuiGridLayout(activityPanel, true);
186                 final int numActivities = ACTIVITY_KEYS.length;
187                 _activityCheckboxes = new JCheckBox[numActivities];
188                 for (int i=0; i<numActivities; i++)
189                 {
190                         _activityCheckboxes[i] = new JCheckBox(I18nManager.getText("dialog.gpsies.activity." + ACTIVITY_KEYS[i]));
191                         _activityCheckboxes[i].addChangeListener(checkListener);
192                         actGrid.add(_activityCheckboxes[i]);
193                 }
194                 grid.add(new JLabel(I18nManager.getText("dialog.gpsies.activities")));
195                 grid.add(activityPanel);
196                 JPanel midPanel = new JPanel();
197                 midPanel.setLayout(new BoxLayout(midPanel, BoxLayout.Y_AXIS));
198                 midPanel.add(gridPanel);
199                 dialogPanel.add(midPanel, BorderLayout.CENTER);
200
201                 // button panel at bottom
202                 JPanel buttonPanel = new JPanel();
203                 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
204                 _uploadButton = new JButton(I18nManager.getText("button.upload"));
205                 _uploadButton.setEnabled(false);
206                 _uploadButton.addActionListener(new ActionListener() {
207                         public void actionPerformed(ActionEvent e) {
208                                 startUpload();
209                         }
210                 });
211                 buttonPanel.add(_uploadButton);
212                 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
213                 cancelButton.addActionListener(new ActionListener() {
214                         public void actionPerformed(ActionEvent e) {
215                                 _dialog.dispose();
216                         }
217                 });
218                 buttonPanel.add(cancelButton);
219                 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
220                 dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
221                 return dialogPanel;
222         }
223
224
225         /**
226          * Check the inputs and enable or disable the upload button
227          */
228         private void enableOK()
229         {
230                 // Check for lengths of input fields - only username, password and filename are required
231                 boolean ok = (_usernameField.getText().length() > 0 && _nameField.getText().length() > 0);
232                 if (ok) {
233                         // also check password field
234                         char[] pass = _passwordField.getPassword();
235                         ok = pass.length > 0;
236                         for (int i=0; i<pass.length; i++) {pass[i] = '0';} // recommended by javadoc
237                         if (ok) {
238                                 ok = false;
239                                 for (int i=0; i<_activityCheckboxes.length; i++) {
240                                         ok = ok || _activityCheckboxes[i].isSelected();
241                                 }
242                         }
243                 }
244                 _uploadButton.setEnabled(ok);
245         }
246
247
248         /**
249          * Start the upload process (require separate thread?)
250          */
251         private void startUpload()
252         {
253                 try
254                 {
255                         FormPoster poster = new FormPoster(new URL(GPSIES_URL));
256                         poster.setParameter("device", "Prune");
257                         poster.setParameter("username", _usernameField.getText());
258                         poster.setParameter("password", new String(_passwordField.getPassword()));
259                         boolean hasActivity = false;
260                         for (int i=0; i<ACTIVITY_KEYS.length; i++)
261                         {
262                                 if (_activityCheckboxes[i].isSelected()) {
263                                         hasActivity = true;
264                                         poster.setParameter("trackTypes", ACTIVITY_KEYS[i]);
265                                 }
266                         }
267                         if (!hasActivity) {poster.setParameter("trackTypes", "walking");} // default if none given
268                         poster.setParameter("filename", _nameField.getText());
269                         poster.setParameter("fileDescription", _descField.getText());
270                         poster.setParameter("startpointCountry", "DE");
271                         poster.setParameter("endpointCountry", "DE"); // both those will be corrected by gpsies
272                         poster.setParameter("status", (_privateCheckbox.isSelected()?"3":"1"));
273                         poster.setParameter("submit", "speichern"); // required
274                         // Use Pipes to connect the GpxExporter's output with the FormPoster's input
275                         PipedInputStream iStream = new PipedInputStream();
276                         PipedOutputStream oStream = new PipedOutputStream(iStream);
277                         _writer = new OutputStreamWriter(oStream);
278                         new Thread(new Runnable() {
279                                 public void run() {
280                                         boolean[] saveFlags = {true, true, true, false, true}; // export everything
281                                         try {
282                                                 GpxExporter.exportData(_writer, _app.getTrackInfo(), _nameField.getText(), null, saveFlags, false);
283                                                 _writer.close();
284                                         } catch (IOException e) {
285                                                 e.printStackTrace();
286                                         }
287                                 }
288                         }).start();
289                         poster.setParameter("formFile", "filename.gpx", iStream);
290
291                         BufferedInputStream answer = new BufferedInputStream(poster.post());
292                         int response = poster.getResponseCode();
293                         BufferedReader reader = new BufferedReader(new InputStreamReader(answer));
294                         String line = reader.readLine();
295                         // Try to extract gpsies page url from the returned message
296                         String pageUrl = null;
297                         if (response == 200 && line.substring(0, 2).toUpperCase().equals("OK"))
298                         {
299                                 final int bracketPos = line.indexOf('[');
300                                 if (bracketPos > 0 && line.endsWith("]")) {
301                                         pageUrl = line.substring(bracketPos + 1, line.length()-1);
302                                 }
303                         }
304                         if (pageUrl != null)
305                         {
306                                 // OK received and managed to extract a Url from the return message.
307                                 int userChoice = JOptionPane.showConfirmDialog(_app.getFrame(),
308                                         I18nManager.getText("dialog.gpsies.confirmopenpage"),
309                                         I18nManager.getText(getNameKey()), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
310                                 if (userChoice == JOptionPane.OK_OPTION) {
311                                         BrowserLauncher.launchBrowser(pageUrl);
312                                 }
313                         }
314                         else {
315                                 _app.showErrorMessageNoLookup(getNameKey(), I18nManager.getText("error.gpsies.uploadnotok")
316                                         + ": " + line);
317                         }
318                 }
319                 catch (MalformedURLException e) {}
320                 catch (IOException ioe) {
321                         _app.showErrorMessageNoLookup(getNameKey(), I18nManager.getText("error.gpsies.uploadfailed") + ": "
322                                 + ioe.getClass().getName() + " : " + ioe.getMessage());
323                 }
324                 _dialog.dispose();
325         }
326 }