]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/load/GpsLoader.java
Version 8, September 2009
[GpsPrune.git] / tim / prune / load / GpsLoader.java
1 package tim.prune.load;
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
14 import javax.swing.BorderFactory;
15 import javax.swing.BoxLayout;
16 import javax.swing.JButton;
17 import javax.swing.JCheckBox;
18 import javax.swing.JDialog;
19 import javax.swing.JLabel;
20 import javax.swing.JOptionPane;
21 import javax.swing.JPanel;
22 import javax.swing.JProgressBar;
23 import javax.swing.JTextField;
24 import javax.swing.SwingConstants;
25 import javax.swing.event.ChangeEvent;
26 import javax.swing.event.ChangeListener;
27 import javax.xml.parsers.SAXParser;
28 import javax.xml.parsers.SAXParserFactory;
29
30 import tim.prune.App;
31 import tim.prune.Config;
32 import tim.prune.ExternalTools;
33 import tim.prune.GenericFunction;
34 import tim.prune.I18nManager;
35 import tim.prune.data.Altitude;
36 import tim.prune.load.xml.XmlFileLoader;
37 import tim.prune.load.xml.XmlHandler;
38
39 /**
40  * Class to manage the loading of GPS data using GpsBabel
41  */
42 public class GpsLoader extends GenericFunction implements Runnable
43 {
44         private boolean _gpsBabelChecked = false;
45         private JDialog _dialog = null;
46         private JTextField _deviceField = null, _formatField = null;
47         private JCheckBox _waypointCheckbox = null, _trackCheckbox = null;
48         private JButton _okButton = null;
49         private JProgressBar _progressBar = null;
50         private boolean _cancelled = false;
51
52
53         /**
54          * Constructor
55          * @param inApp Application object to inform of data load
56          */
57         public GpsLoader(App inApp)
58         {
59                 super(inApp);
60         }
61
62         /** Get the name key */
63         public String getNameKey() {
64                 return "function.loadfromgps";
65         }
66
67         /**
68          * Open the GUI to select options and start the load
69          */
70         public void begin()
71         {
72                 // Check if gpsbabel looks like it's installed
73                 if (_gpsBabelChecked || ExternalTools.isToolInstalled(ExternalTools.TOOL_GPSBABEL)
74                         || JOptionPane.showConfirmDialog(_dialog,
75                                 I18nManager.getText("dialog.gpsload.nogpsbabel"),
76                                 I18nManager.getText(getNameKey()),
77                                 JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION)
78                 {
79                         _gpsBabelChecked = true;
80                         // Make dialog window
81                         if (_dialog == null)
82                         {
83                                 _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
84                                 _dialog.setLocationRelativeTo(_parentFrame);
85                                 _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
86                                 _dialog.getContentPane().add(makeDialogComponents());
87                                 _dialog.pack();
88                         }
89                         // Initialise progress bars, buttons
90                         enableOkButton();
91                         setupProgressBar(true);
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                 _deviceField.addKeyListener(new KeyAdapter() {
116                         public void keyReleased(KeyEvent e)
117                         {
118                                 // close dialog if escape pressed
119                                 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
120                                         _dialog.dispose();
121                                 }
122                         }
123                 });
124                 gridPanel.add(_deviceField);
125                 JLabel formatLabel = new JLabel(I18nManager.getText("dialog.gpsload.format"));
126                 formatLabel.setHorizontalAlignment(SwingConstants.RIGHT);
127                 gridPanel.add(formatLabel);
128                 _formatField = new JTextField(Config.getConfigString(Config.KEY_GPS_FORMAT), 12);
129                 gridPanel.add(_formatField);
130                 gridPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
131                 gridPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 20));
132                 mainPanel.add(gridPanel);
133
134                 // checkboxes
135                 ChangeListener checkboxListener = new ChangeListener() {
136                         public void stateChanged(ChangeEvent e)
137                         {
138                                 enableOkButton();
139                         }
140                 };
141                 _waypointCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.getwaypoints"), true);
142                 _waypointCheckbox.addChangeListener(checkboxListener);
143                 _waypointCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
144                 mainPanel.add(_waypointCheckbox);
145                 _trackCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.gettracks"), true);
146                 _trackCheckbox.addChangeListener(checkboxListener);
147                 _trackCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
148                 mainPanel.add(_trackCheckbox);
149                 // progress bar (initially invisible)
150                 _progressBar = new JProgressBar(0, 10);
151                 mainPanel.add(_progressBar);
152                 outerPanel.add(mainPanel, BorderLayout.NORTH);
153
154                 // Lower panel with ok and cancel buttons
155                 JPanel buttonPanel = new JPanel();
156                 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
157                 _okButton = new JButton(I18nManager.getText("button.ok"));
158                 _okButton.addActionListener(new ActionListener() {
159                         public void actionPerformed(ActionEvent e)
160                         {
161                                 // start thread to call gpsbabel
162                                 _cancelled = false;
163                                 new Thread(GpsLoader.this).start();
164                         }
165                 });
166                 buttonPanel.add(_okButton);
167                 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
168                 cancelButton.addActionListener(new ActionListener() {
169                         public void actionPerformed(ActionEvent e)
170                         {
171                                 _cancelled = true;
172                                 _dialog.dispose();
173                         }
174                 });
175                 buttonPanel.add(cancelButton);
176                 outerPanel.add(buttonPanel, BorderLayout.SOUTH);
177                 return outerPanel;
178         }
179
180
181         /**
182          * @param inStart true if the dialog is restarting
183          */
184         private void setupProgressBar(boolean inStart)
185         {
186                 // set visibility
187                 _progressBar.setVisible(!inStart);
188                 // set indeterminate flags, initial value
189                 _progressBar.setIndeterminate(false);
190                 _progressBar.setValue(0);
191         }
192
193
194         /**
195          * Enable or disable the ok button
196          */
197         private void enableOkButton()
198         {
199                 _okButton.setEnabled(_waypointCheckbox.isSelected() || _trackCheckbox.isSelected());
200         }
201
202
203         /**
204          * Run method for performing tasks in separate thread
205          */
206         public void run()
207         {
208                 _okButton.setEnabled(false);
209                 setupProgressBar(false);
210                 if (_waypointCheckbox.isSelected() || _trackCheckbox.isSelected())
211                 {
212                         _progressBar.setIndeterminate(true);
213                         try
214                         {
215                                 callGpsBabel(_waypointCheckbox.isSelected(), _trackCheckbox.isSelected());
216                         }
217                         catch (Exception e)
218                         {
219                                 // System.err.println("Error: " + e.getClass().getName());
220                                 // System.err.println("Error: " + e.getMessage());
221                                 _app.showErrorMessageNoLookup(getNameKey(), e.getMessage());
222                                 _cancelled = true;
223                         }
224                 }
225                 setupProgressBar(true);
226                 enableOkButton();
227
228                 // Close dialog
229                 if (!_cancelled) {
230                         _dialog.dispose();
231                 }
232         }
233
234
235         /**
236          * Execute the call to gpsbabel and pass the results back to the app
237          * @param inWaypoints true to load waypoints
238          * @param inTracks true to load track points
239          */
240         private void callGpsBabel(boolean inWaypoints, boolean inTracks) throws Exception
241         {
242                 // Set up command to call gpsbabel
243                 String[] commands = null;
244                 final String device = _deviceField.getText().trim();
245                 final String format = _formatField.getText().trim();
246                 final String command = Config.getConfigString(Config.KEY_GPSBABEL_PATH);
247                 if (inWaypoints && inTracks) {
248                         // Both waypoints and track points selected
249                         commands = new String[] {command, "-w", "-t", "-i", format,
250                                 "-f", device, "-o", "gpx", "-F", "-"};
251                 }
252                 else
253                 {
254                         // Only waypoints OR track points selected
255                         commands = new String[] {command, "-w", "-i", format,
256                                 "-f", device, "-o", "gpx", "-F", "-"};
257                         if (inTracks) {
258                                 commands[1] = "-t";
259                         }
260                 }
261                 // Save GPS settings in config
262                 Config.setConfigString(Config.KEY_GPS_DEVICE, device);
263                 Config.setConfigString(Config.KEY_GPS_FORMAT, format);
264
265                 String errorMessage = "";
266                 XmlHandler handler = null;
267                 Process process = Runtime.getRuntime().exec(commands);
268
269                 // Pass input stream to try to parse the xml
270                 try
271                 {
272                         XmlFileLoader xmlLoader = new XmlFileLoader(_app);
273                         SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
274                         saxParser.parse(process.getInputStream(), xmlLoader);
275                         handler = xmlLoader.getHandler();
276                         if (handler == null) {
277                                 errorMessage = "Null handler";
278                         }
279                 }
280                 catch (Exception e) {
281                         errorMessage = e.getMessage();
282                 }
283
284                 // Read the error stream to see if there's a better error message there
285                 BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
286                 String line = null;
287                 String errorMessage2 = "";
288                 while ((line = r.readLine()) != null) {
289                         errorMessage2 += line + "\n";
290                 }
291                 // Close error stream
292                 try {
293                         r.close();
294                 } catch (Exception e) {}
295
296                 if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
297                 if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
298
299                 // Send data back to app
300                 _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
301                         Altitude.Format.METRES, _deviceField.getText());
302         }
303 }