1 package tim.prune.load;
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;
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;
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;
40 * Class to manage the loading of GPS data using GpsBabel
42 public class GpsLoader extends GenericFunction implements Runnable
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;
55 * @param inApp Application object to inform of data load
57 public GpsLoader(App inApp)
62 /** Get the name key */
63 public String getNameKey() {
64 return "function.loadfromgps";
68 * Open the GUI to select options and start the load
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)
79 _gpsBabelChecked = true;
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());
89 // Initialise progress bars, buttons
91 setupProgressBar(true);
92 _dialog.setVisible(true);
98 * @return a panel containing the main dialog components
100 private JPanel makeDialogComponents()
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));
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)
118 // close dialog if escape pressed
119 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
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);
135 ChangeListener checkboxListener = new ChangeListener() {
136 public void stateChanged(ChangeEvent e)
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);
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)
161 // start thread to call gpsbabel
163 new Thread(GpsLoader.this).start();
166 buttonPanel.add(_okButton);
167 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
168 cancelButton.addActionListener(new ActionListener() {
169 public void actionPerformed(ActionEvent e)
175 buttonPanel.add(cancelButton);
176 outerPanel.add(buttonPanel, BorderLayout.SOUTH);
182 * @param inStart true if the dialog is restarting
184 private void setupProgressBar(boolean inStart)
187 _progressBar.setVisible(!inStart);
188 // set indeterminate flags, initial value
189 _progressBar.setIndeterminate(false);
190 _progressBar.setValue(0);
195 * Enable or disable the ok button
197 private void enableOkButton()
199 _okButton.setEnabled(_waypointCheckbox.isSelected() || _trackCheckbox.isSelected());
204 * Run method for performing tasks in separate thread
208 _okButton.setEnabled(false);
209 setupProgressBar(false);
210 if (_waypointCheckbox.isSelected() || _trackCheckbox.isSelected())
212 _progressBar.setIndeterminate(true);
215 callGpsBabel(_waypointCheckbox.isSelected(), _trackCheckbox.isSelected());
219 // System.err.println("Error: " + e.getClass().getName());
220 // System.err.println("Error: " + e.getMessage());
221 _app.showErrorMessageNoLookup(getNameKey(), e.getMessage());
225 setupProgressBar(true);
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
240 private void callGpsBabel(boolean inWaypoints, boolean inTracks) throws Exception
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", "-"};
254 // Only waypoints OR track points selected
255 commands = new String[] {command, "-w", "-i", format,
256 "-f", device, "-o", "gpx", "-F", "-"};
261 // Save GPS settings in config
262 Config.setConfigString(Config.KEY_GPS_DEVICE, device);
263 Config.setConfigString(Config.KEY_GPS_FORMAT, format);
265 String errorMessage = "";
266 XmlHandler handler = null;
267 Process process = Runtime.getRuntime().exec(commands);
269 // Pass input stream to try to parse the xml
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";
280 catch (Exception e) {
281 errorMessage = e.getMessage();
284 // Read the error stream to see if there's a better error message there
285 BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
287 String errorMessage2 = "";
288 while ((line = r.readLine()) != null) {
289 errorMessage2 += line + "\n";
291 // Close error stream
294 } catch (Exception e) {}
296 if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
297 if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
299 // Send data back to app
300 _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
301 Altitude.Format.METRES, _deviceField.getText());