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.SourceInfo;
24 import tim.prune.load.babel.BabelFilterPanel;
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;
45 protected BabelFilterPanel _filterPanel = null;
50 * @param inApp Application object to inform of data load
52 public BabelLoader(App inApp)
58 * Open the GUI to select options and start the load
62 // Check if gpsbabel looks like it's installed
63 if (_gpsBabelChecked || ExternalTools.isToolInstalled(ExternalTools.TOOL_GPSBABEL)
64 || JOptionPane.showConfirmDialog(_dialog,
65 I18nManager.getText("dialog.gpsload.nogpsbabel"),
66 I18nManager.getText(getNameKey()),
67 JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION)
69 _gpsBabelChecked = true;
73 _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
74 _dialog.setLocationRelativeTo(_parentFrame);
75 _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
76 _dialog.getContentPane().add(makeDialogComponents());
79 // Initialise progress bars, buttons
81 setupProgressBar(true);
82 initDialog(); // do any subclass-specific init here
83 _dialog.setVisible(true);
89 * @return a panel containing the main dialog components
91 protected abstract JPanel makeDialogComponents();
94 /** Do any subclass-specific dialog initialisation necessary */
95 protected void initDialog()
97 // GPSBabel filter, if any
98 _filterPanel.setFilterString(Config.getConfigString(Config.KEY_GPSBABEL_FILTER));
102 * @param inStart true if the dialog is restarting
104 private void setupProgressBar(boolean inStart)
107 _progressBar.setVisible(!inStart);
108 // set indeterminate flags, initial value
109 _progressBar.setIndeterminate(false);
110 _progressBar.setValue(0);
115 * Enable or disable the ok button
117 protected void enableOkButton()
119 _okButton.setEnabled(isInputOk());
123 * @return true if input fields of dialog are valid
125 protected abstract boolean isInputOk();
128 * Run method for performing tasks in separate thread
132 _okButton.setEnabled(false);
133 setupProgressBar(false);
136 _progressBar.setIndeterminate(true);
144 _app.showErrorMessageNoLookup(getNameKey(), e.getMessage());
148 setupProgressBar(true);
159 * Execute the call to gpsbabel and pass the results back to the app
161 private void callGpsBabel() throws Exception
163 // Set up command to call gpsbabel
164 String[] commands = getCommandArray();
165 // Save GPS settings in config
168 String errorMessage = "", errorMessage2 = "";
169 XmlHandler handler = null;
170 Process process = Runtime.getRuntime().exec(commands);
173 if (_saveFile != null)
175 // data is being saved to file, so need to wait for it to finish
177 // try to read error message, if any
179 BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
180 while ((line = r.readLine()) != null) {
181 errorMessage += line + "\n";
183 // Close error stream
186 } catch (Exception e) {}
188 catch (Exception e) {} // couldn't get error message
190 // Trigger it to be loaded by app
191 if (process.exitValue() == 0)
193 SwingUtilities.invokeLater(new Runnable() {
195 ArrayList<File> fileList = new ArrayList<File>();
196 fileList.add(_saveFile);
197 _app.loadDataFiles(fileList);
201 else if (errorMessage.length() > 0) {
202 throw new Exception(errorMessage);
204 else throw new Exception(I18nManager.getText("error.gpsload.unknown"));
208 // Pass input stream to try to parse the xml
211 XmlFileLoader xmlLoader = new XmlFileLoader(_app);
212 SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
213 saxParser.parse(process.getInputStream(), xmlLoader);
214 handler = xmlLoader.getHandler();
215 if (handler == null) {
216 errorMessage = "Null handler";
219 catch (Exception e) {
220 errorMessage = e.getMessage();
223 // Read the error stream to see if there's a better error message there
224 BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
225 while ((line = r.readLine()) != null) {
226 errorMessage2 += line + "\n";
228 // Close error stream
231 } catch (Exception e) {}
233 if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
234 if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
236 // Send data back to app
237 _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(), null,
238 getSourceInfo(), handler.getTrackNameList());
244 * Get the commands to call
245 * @return String array containing commands
247 private String[] getCommandArray()
249 ArrayList<String> commandList = new ArrayList<String>();
250 // Firstly the command for gpsbabel itself
251 final String command = Config.getConfigString(Config.KEY_GPSBABEL_PATH);
252 commandList.add(command);
253 // Then whether to load waypoints or track points
254 final boolean loadWaypoints = _waypointCheckbox.isSelected();
255 final boolean loadTrack = _trackCheckbox.isSelected();
257 commandList.add("-w");
260 commandList.add("-t");
263 commandList.add("-i");
264 commandList.add(getInputFormat());
266 commandList.add("-f");
267 commandList.add(getFilePath());
269 final String filter = _filterPanel.getFilterString();
270 if (filter != null && !filter.equals(""))
272 for (String arg : filter.split(" "))
274 if (arg.length() > 0) {
275 commandList.add(arg);
280 commandList.add("-o");
281 commandList.add("gpx");
283 commandList.add("-F");
284 String whereTo = "-";
285 // Do we want to save the gpx straight to file?
286 if (_saveCheckbox.isSelected())
288 // Select file to save to
289 _saveFile = GpxExporter.chooseGpxFile(_parentFrame);
290 if (_saveFile != null) {
291 whereTo = _saveFile.getAbsolutePath();
294 commandList.add(whereTo);
295 // Convert to string array
296 String[] args = new String[] {};
297 return commandList.toArray(args);
301 * @return SourceInfo object corresponding to the load
303 protected abstract SourceInfo getSourceInfo();
306 * @return complete file path or device path for gpsbabel call
308 protected abstract String getFilePath();
311 * @return file name or device name
313 protected abstract String getInputFormat();
316 * Save any config values necessary
318 protected abstract void saveConfigValues();