1 package tim.prune.function.gpsies;
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;
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;
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;
45 * Function to upload track information up to Gpsies.com
47 public class UploadGpsiesFunction extends GenericFunction
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;
56 private JTextField _nameField = null;
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;
66 private JButton _uploadButton = null;
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"};
76 * @param inApp App object
78 public UploadGpsiesFunction(App inApp) {
85 public String getNameKey() {
86 return "function.uploadgpsies";
94 // Initialise dialog, show empty list
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());
104 _dialog.setVisible(true);
109 * Create dialog components
110 * @return Panel containing all gui elements in dialog
112 private Component makeDialogComponents()
114 JPanel dialogPanel = new JPanel();
115 dialogPanel.setLayout(new BorderLayout());
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() {
137 public void keyReleased(KeyEvent inE) {
139 if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {
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() {
150 public void keyPressed(KeyEvent inE) {
151 if (inE.getKeyCode() == KeyEvent.VK_TAB) {
153 if (inE.isShiftDown()) {
154 _nameField.requestFocusInWindow();
157 _privateCheckbox.requestFocusInWindow();
162 // Listen for Ctrl-backspace on password field (delete contents)
163 _passwordField.addKeyListener(new KeyAdapter() {
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("");
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);
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) {
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++)
192 _activityCheckboxes[i] = new JCheckBox(I18nManager.getText("dialog.gpsies.activity." + ACTIVITY_KEYS[i]));
193 _activityCheckboxes[i].addChangeListener(checkListener);
194 actGrid.add(_activityCheckboxes[i]);
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);
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) {
213 buttonPanel.add(_uploadButton);
214 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
215 cancelButton.addActionListener(new ActionListener() {
216 public void actionPerformed(ActionEvent e) {
220 buttonPanel.add(cancelButton);
221 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
222 dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
228 * Check the inputs and enable or disable the upload button
230 private void enableOK()
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);
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
241 for (int i=0; i<_activityCheckboxes.length; i++) {
242 ok = ok || _activityCheckboxes[i].isSelected();
246 _uploadButton.setEnabled(ok);
251 * Start the upload process (require separate thread?)
253 private void startUpload()
255 BufferedReader reader = null;
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++)
265 if (_activityCheckboxes[i].isSelected()) {
267 poster.setParameter("trackTypes", ACTIVITY_KEYS[i]);
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() {
284 GpxExporter.exportData(_writer, _app.getTrackInfo(), _nameField.getText(),
285 null, new SettingsForExport(), null);
286 } catch (IOException e) {}
288 try {_writer.close();} catch (IOException e) {}
292 poster.setParameter("formFile", "filename.gpx", iStream);
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"))
302 final int bracketPos = line.indexOf('[');
303 if (bracketPos > 0 && line.endsWith("]")) {
304 pageUrl = line.substring(bracketPos + 1, line.length()-1);
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);
318 _app.showErrorMessageNoLookup(getNameKey(), I18nManager.getText("error.gpsies.uploadnotok")
322 catch (MalformedURLException e) {}
323 catch (IOException ioe) {
324 _app.showErrorMessageNoLookup(getNameKey(), I18nManager.getText("error.gpsies.uploadfailed") + ": "
325 + ioe.getClass().getName() + " : " + ioe.getMessage());
328 try {if (reader != null) reader.close();} catch (IOException e) {}