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