]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/save/GpsSaver.java
Version 18.4, April 2016
[GpsPrune.git] / tim / prune / save / GpsSaver.java
1 package tim.prune.save;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.FlowLayout;
6 import java.awt.GridLayout;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.awt.event.KeyAdapter;
10 import java.awt.event.KeyEvent;
11 import java.io.BufferedReader;
12 import java.io.InputStreamReader;
13 import java.io.OutputStreamWriter;
14
15 import javax.swing.BorderFactory;
16 import javax.swing.BoxLayout;
17 import javax.swing.JButton;
18 import javax.swing.JCheckBox;
19 import javax.swing.JDialog;
20 import javax.swing.JLabel;
21 import javax.swing.JOptionPane;
22 import javax.swing.JPanel;
23 import javax.swing.JProgressBar;
24 import javax.swing.JTextField;
25 import javax.swing.SwingConstants;
26 import javax.swing.event.ChangeEvent;
27 import javax.swing.event.ChangeListener;
28
29 import tim.prune.App;
30 import tim.prune.ExternalTools;
31 import tim.prune.GenericFunction;
32 import tim.prune.I18nManager;
33 import tim.prune.config.Config;
34
35 /**
36  * Class to manage the loading of GPS data using GpsBabel
37  */
38 public class GpsSaver extends GenericFunction implements Runnable
39 {
40         private boolean _gpsBabelChecked = false;
41         private JDialog _dialog = null;
42         private JTextField _deviceField = null, _formatField = null;
43         private JTextField _trackNameField = null;
44         private JCheckBox _waypointCheckbox = null, _trackCheckbox = null;
45         private boolean _switchedWaypointsOff = false, _switchedTrackpointsOff = false;
46         private JButton _okButton = null;
47         private JProgressBar _progressBar = null;
48         private boolean _cancelled = false;
49
50
51         /**
52          * Constructor
53          * @param inApp app object
54          */
55         public GpsSaver(App inApp)
56         {
57                 super(inApp);
58         }
59
60         /** get name key */
61         public String getNameKey() {
62                 return "function.sendtogps";
63         }
64
65         /**
66          * Open the GUI to select options and start the load
67          */
68         public void begin()
69         {
70                 // Check if gpsbabel looks like it's installed
71                 if (_gpsBabelChecked || ExternalTools.isToolInstalled(ExternalTools.TOOL_GPSBABEL)
72                         || JOptionPane.showConfirmDialog(_dialog,
73                                 I18nManager.getText("dialog.gpsload.nogpsbabel"),
74                                 I18nManager.getText(getNameKey()),
75                                 JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION)
76                 {
77                         _gpsBabelChecked = true;
78                         // Make dialog window
79                         if (_dialog == null)
80                         {
81                                 _dialog = new JDialog(_parentFrame, I18nManager.getText("function.sendtogps"), true);
82                                 _dialog.setLocationRelativeTo(_parentFrame);
83                                 _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
84                                 _dialog.getContentPane().add(makeDialogComponents());
85                                 _dialog.pack();
86                         }
87                         // Initialise progress bars, buttons
88                         enableCheckboxes();
89                         enableOkButton();
90                         setupProgressBar(true);
91                         _trackNameField.requestFocus();
92                         _dialog.setVisible(true);
93                 }
94         }
95
96
97         /**
98          * @return a panel containing the main dialog components
99          */
100         private JPanel makeDialogComponents()
101         {
102                 JPanel outerPanel = new JPanel();
103                 outerPanel.setLayout(new BorderLayout());
104                 // Main panel with options etc
105                 JPanel mainPanel = new JPanel();
106                 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
107
108                 // text fields for options
109                 JPanel gridPanel = new JPanel();
110                 gridPanel.setLayout(new GridLayout(0, 2, 10, 3));
111                 JLabel deviceLabel = new JLabel(I18nManager.getText("dialog.gpsload.device"));
112                 deviceLabel.setHorizontalAlignment(SwingConstants.RIGHT);
113                 gridPanel.add(deviceLabel);
114                 _deviceField = new JTextField(Config.getConfigString(Config.KEY_GPS_DEVICE), 12);
115                 gridPanel.add(_deviceField);
116                 JLabel formatLabel = new JLabel(I18nManager.getText("dialog.gpsload.format"));
117                 formatLabel.setHorizontalAlignment(SwingConstants.RIGHT);
118                 gridPanel.add(formatLabel);
119                 _formatField = new JTextField(Config.getConfigString(Config.KEY_GPS_FORMAT), 12);
120                 gridPanel.add(_formatField);
121                 JLabel nameLabel = new JLabel(I18nManager.getText("dialog.gpssend.trackname"));
122                 nameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
123                 gridPanel.add(nameLabel);
124                 _trackNameField = new JTextField("", 12);
125                 gridPanel.add(_trackNameField);
126                 gridPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
127                 gridPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 20));
128                 mainPanel.add(gridPanel);
129                 // close dialog when escape pressed
130                 KeyAdapter closer = new KeyAdapter() {
131                         public void keyReleased(KeyEvent e)
132                         {
133                                 // close dialog if escape pressed
134                                 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
135                                         _dialog.dispose();
136                                 }
137                         }
138                 };
139                 _deviceField.addKeyListener(closer);
140                 _formatField.addKeyListener(closer);
141                 _trackNameField.addKeyListener(closer);
142
143                 // checkboxes
144                 ChangeListener checkboxListener = new ChangeListener() {
145                         public void stateChanged(ChangeEvent e)
146                         {
147                                 enableOkButton();
148                         }
149                 };
150                 _waypointCheckbox = new JCheckBox(I18nManager.getText("dialog.gpssend.sendwaypoints"), true);
151                 _waypointCheckbox.addChangeListener(checkboxListener);
152                 _waypointCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
153                 mainPanel.add(_waypointCheckbox);
154                 _trackCheckbox = new JCheckBox(I18nManager.getText("dialog.gpssend.sendtracks"), true);
155                 _trackCheckbox.addChangeListener(checkboxListener);
156                 _trackCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
157                 mainPanel.add(_trackCheckbox);
158
159                 // progress bar (initially invisible)
160                 _progressBar = new JProgressBar(0, 10);
161                 mainPanel.add(_progressBar);
162                 outerPanel.add(mainPanel, BorderLayout.NORTH);
163
164                 // Lower panel with ok and cancel buttons
165                 JPanel buttonPanel = new JPanel();
166                 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
167                 _okButton = new JButton(I18nManager.getText("button.ok"));
168                 _okButton.addActionListener(new ActionListener() {
169                         public void actionPerformed(ActionEvent e)
170                         {
171                                 // start thread to call gpsbabel
172                                 _cancelled = false;
173                                 new Thread(GpsSaver.this).start();
174                         }
175                 });
176                 buttonPanel.add(_okButton);
177                 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
178                 cancelButton.addActionListener(new ActionListener() {
179                         public void actionPerformed(ActionEvent e)
180                         {
181                                 _cancelled = true;
182                                 _dialog.dispose();
183                         }
184                 });
185                 buttonPanel.add(cancelButton);
186                 outerPanel.add(buttonPanel, BorderLayout.SOUTH);
187                 return outerPanel;
188         }
189
190
191         /**
192          * @param inStart true if the dialog is restarting
193          */
194         private void setupProgressBar(boolean inStart)
195         {
196                 // set visibility
197                 _progressBar.setVisible(!inStart);
198                 // set indeterminate flags, initial value
199                 _progressBar.setIndeterminate(false);
200                 _progressBar.setValue(0);
201         }
202
203         /**
204          * Enable or disable the waypoints and trackpoints checkboxes
205          */
206         private void enableCheckboxes()
207         {
208                 // Enable or disable waypoints checkbox depending on whether data is available
209                 if (_waypointCheckbox.isSelected())
210                 {
211                         if (!_app.getTrackInfo().getTrack().hasWaypoints())
212                         {
213                                 _waypointCheckbox.setSelected(false);
214                                 _switchedWaypointsOff = true;
215                         }
216                         else _switchedWaypointsOff = false;
217                 }
218                 else if (_app.getTrackInfo().getTrack().hasWaypoints() && _switchedWaypointsOff)
219                 {
220                         _waypointCheckbox.setSelected(true);
221                         _switchedWaypointsOff = false;
222                 }
223                 // ... and the same for track points
224                 if (_trackCheckbox.isSelected())
225                 {
226                         if (!_app.getTrackInfo().getTrack().hasTrackPoints())
227                         {
228                                 _trackCheckbox.setSelected(false);
229                                 _switchedTrackpointsOff = true;
230                         }
231                         else _switchedTrackpointsOff = false;
232                 }
233                 else if (_app.getTrackInfo().getTrack().hasTrackPoints() && _switchedTrackpointsOff)
234                 {
235                         _trackCheckbox.setSelected(true);
236                         _switchedTrackpointsOff = false;
237                 }
238         }
239
240         /**
241          * Enable or disable the ok button
242          */
243         private void enableOkButton()
244         {
245                 _okButton.setEnabled(_waypointCheckbox.isSelected() || _trackCheckbox.isSelected());
246         }
247
248
249         /**
250          * Run method for performing tasks in separate thread
251          */
252         public void run()
253         {
254                 _okButton.setEnabled(false);
255                 setupProgressBar(false);
256
257                 _progressBar.setIndeterminate(true);
258                 try
259                 {
260                         callGpsBabel();
261                 }
262                 catch (Exception e)
263                 {
264                         JOptionPane.showMessageDialog(_dialog, e.getMessage(),
265                                 I18nManager.getText("function.sendtogps"), JOptionPane.ERROR_MESSAGE);
266                         _cancelled = true;
267                 }
268
269                 setupProgressBar(true);
270                 enableOkButton();
271
272                 // Close dialog
273                 if (!_cancelled) {
274                         _dialog.dispose();
275                 }
276         }
277
278
279         /**
280          * Execute the call to gpsbabel
281          */
282         private void callGpsBabel() throws Exception
283         {
284                 // Set up command to call gpsbabel
285                 final String command = Config.getConfigString(Config.KEY_GPSBABEL_PATH);
286                 String[] commands = null;
287                 final String device = _deviceField.getText().trim();
288                 final String format = _formatField.getText().trim();
289                 if (_waypointCheckbox.isSelected() && _trackCheckbox.isSelected()) {
290                         // Both waypoints and track points selected
291                         commands = new String[] {command, "-w", "-t", "-i", "gpx", "-f", "-", "-o", format,
292                                 "-F", device};
293                 }
294                 else
295                 {
296                         // Only waypoints OR trackpoints selected
297                         commands = new String[] {command, "-w", "-i", "gpx", "-f", "-", "-o", format,
298                                 "-F", device};
299                         if (_trackCheckbox.isSelected()) {
300                                 commands[1] = "-t";
301                         }
302                 }
303                 // Save GPS settings in config
304                 Config.setConfigString(Config.KEY_GPS_DEVICE, device);
305                 Config.setConfigString(Config.KEY_GPS_FORMAT, format);
306
307                 String errorMessage = "";
308                 Process process = Runtime.getRuntime().exec(commands);
309
310                 String trackName = _trackNameField.getText();
311                 if (trackName == null || trackName.equals("")) {trackName = "gpsprune";}
312                 // Generate the GPX file and send to the GPS
313                 OutputStreamWriter writer = new OutputStreamWriter(process.getOutputStream());
314                 boolean[] saveFlags = {true, true, true, true, false, true}; // export everything
315                 GpxExporter.exportData(writer, _app.getTrackInfo(), trackName, null, saveFlags, null);
316                 writer.close();
317
318                 // Read the error stream to see if there's a better error message there
319                 BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
320                 String line = null;
321                 String errorMessage2 = "";
322                 while ((line = r.readLine()) != null) {
323                         errorMessage2 += line + "\n";
324                 }
325                 // Close error stream
326                 try {
327                         r.close();
328                 } catch (Exception e) {}
329                 if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
330                 if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
331         }
332 }