1 package tim.prune.load;
3 import java.io.BufferedReader;
5 import java.io.InputStreamReader;
6 import java.util.ArrayList;
8 import javax.swing.JButton;
9 import javax.swing.JCheckBox;
10 import javax.swing.JDialog;
11 import javax.swing.JOptionPane;
12 import javax.swing.JPanel;
13 import javax.swing.JProgressBar;
14 import javax.swing.SwingUtilities;
15 import javax.xml.parsers.SAXParser;
16 import javax.xml.parsers.SAXParserFactory;
19 import tim.prune.ExternalTools;
20 import tim.prune.GenericFunction;
21 import tim.prune.I18nManager;
22 import tim.prune.config.Config;
23 import tim.prune.data.Altitude;
24 import tim.prune.data.SourceInfo;
25 import tim.prune.load.xml.XmlFileLoader;
26 import tim.prune.load.xml.XmlHandler;
27 import tim.prune.save.GpxExporter;
30 * Superclass to manage the loading of data using GpsBabel
31 * Subclasses handle either from GPS or from file
33 public abstract class BabelLoader extends GenericFunction implements Runnable
35 private boolean _gpsBabelChecked = false;
36 protected JDialog _dialog = null;
37 // Checkboxes for which kinds of points to load
38 protected JCheckBox _waypointCheckbox = null, _trackCheckbox = null;
39 // Checkbox to save to file or not
40 protected JCheckBox _saveCheckbox = null;
41 protected JButton _okButton = null;
42 protected JProgressBar _progressBar = null;
43 protected File _saveFile = null;
44 protected boolean _cancelled = false;
49 * @param inApp Application object to inform of data load
51 public BabelLoader(App inApp)
57 * Open the GUI to select options and start the load
61 // Check if gpsbabel looks like it's installed
62 if (_gpsBabelChecked || ExternalTools.isToolInstalled(ExternalTools.TOOL_GPSBABEL)
63 || JOptionPane.showConfirmDialog(_dialog,
64 I18nManager.getText("dialog.gpsload.nogpsbabel"),
65 I18nManager.getText(getNameKey()),
66 JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION)
68 _gpsBabelChecked = true;
72 _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
73 _dialog.setLocationRelativeTo(_parentFrame);
74 _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
75 _dialog.getContentPane().add(makeDialogComponents());
78 // Initialise progress bars, buttons
80 setupProgressBar(true);
81 initDialog(); // do any subclass-specific init here
82 _dialog.setVisible(true);
88 * @return a panel containing the main dialog components
90 protected abstract JPanel makeDialogComponents();
93 /** Do any subclass-specific dialog initialisation necessary */
94 protected void initDialog() {}
97 * @param inStart true if the dialog is restarting
99 private void setupProgressBar(boolean inStart)
102 _progressBar.setVisible(!inStart);
103 // set indeterminate flags, initial value
104 _progressBar.setIndeterminate(false);
105 _progressBar.setValue(0);
110 * Enable or disable the ok button
112 protected void enableOkButton()
114 _okButton.setEnabled(isInputOk());
118 * @return true if input fields of dialog are valid
120 protected abstract boolean isInputOk();
123 * Run method for performing tasks in separate thread
127 _okButton.setEnabled(false);
128 setupProgressBar(false);
131 _progressBar.setIndeterminate(true);
139 _app.showErrorMessageNoLookup(getNameKey(), e.getMessage());
143 setupProgressBar(true);
154 * Execute the call to gpsbabel and pass the results back to the app
156 private void callGpsBabel() throws Exception
158 // Set up command to call gpsbabel
159 String[] commands = getCommandArray();
160 // Save GPS settings in config
163 String errorMessage = "", errorMessage2 = "";
164 XmlHandler handler = null;
165 Process process = Runtime.getRuntime().exec(commands);
168 if (_saveFile != null)
170 // data is being saved to file, so need to wait for it to finish
172 // try to read error message, if any
174 BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
175 while ((line = r.readLine()) != null) {
176 errorMessage += line + "\n";
178 // Close error stream
181 } catch (Exception e) {}
183 catch (Exception e) {} // couldn't get error message
185 // Trigger it to be loaded by app
186 if (process.exitValue() == 0)
188 SwingUtilities.invokeLater(new Runnable() {
190 ArrayList<File> fileList = new ArrayList<File>();
191 fileList.add(_saveFile);
192 _app.loadDataFiles(fileList);
196 else if (errorMessage.length() > 0) {
197 throw new Exception(errorMessage);
199 else throw new Exception(I18nManager.getText("error.gpsload.unknown"));
203 // Pass input stream to try to parse the xml
206 XmlFileLoader xmlLoader = new XmlFileLoader(_app);
207 SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
208 saxParser.parse(process.getInputStream(), xmlLoader);
209 handler = xmlLoader.getHandler();
210 if (handler == null) {
211 errorMessage = "Null handler";
214 catch (Exception e) {
215 errorMessage = e.getMessage();
218 // Read the error stream to see if there's a better error message there
219 BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
220 while ((line = r.readLine()) != null) {
221 errorMessage2 += line + "\n";
223 // Close error stream
226 } catch (Exception e) {}
228 if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
229 if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
231 // Send data back to app
232 _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(), Altitude.Format.METRES,
234 handler.getTrackNameList());
240 * Get the commands to call
241 * @return String array containing commands
243 private String[] getCommandArray()
245 String[] commands = null;
246 final String command = Config.getConfigString(Config.KEY_GPSBABEL_PATH);
247 final boolean loadWaypoints = _waypointCheckbox.isSelected();
248 final boolean loadTrack = _trackCheckbox.isSelected();
249 if (loadWaypoints && loadTrack) {
250 // Both waypoints and track points selected
251 commands = new String[] {command, "-w", "-t", "-i", getInputFormat(),
252 "-f", getFilePath(), "-o", "gpx", "-F", "-"};
256 // Only waypoints OR track points selected
257 commands = new String[] {command, "-w", "-i", getInputFormat(),
258 "-f", getFilePath(), "-o", "gpx", "-F", "-"};
263 // Do we want to save the gpx straight to file?
264 if (_saveCheckbox.isSelected()) {
265 // Select file to save to
266 _saveFile = GpxExporter.chooseGpxFile(_parentFrame);
267 if (_saveFile != null) {
268 commands[commands.length-1] = _saveFile.getAbsolutePath();
275 * @return SourceInfo object corresponding to the load
277 protected abstract SourceInfo getSourceInfo();
280 * @return complete file path or device path for gpsbabel call
282 protected abstract String getFilePath();
285 * @return file name or device name
287 protected abstract String getInputFormat();
290 * Save any config values necessary
292 protected abstract void saveConfigValues();