]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - src/tim/prune/load/BabelLoader.java
Moved source into separate src directory due to popular request
[GpsPrune.git] / src / tim / prune / load / BabelLoader.java
diff --git a/src/tim/prune/load/BabelLoader.java b/src/tim/prune/load/BabelLoader.java
new file mode 100644 (file)
index 0000000..7ebd7de
--- /dev/null
@@ -0,0 +1,319 @@
+package tim.prune.load;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.SwingUtilities;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import tim.prune.App;
+import tim.prune.ExternalTools;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.config.Config;
+import tim.prune.data.SourceInfo;
+import tim.prune.load.babel.BabelFilterPanel;
+import tim.prune.load.xml.XmlFileLoader;
+import tim.prune.load.xml.XmlHandler;
+import tim.prune.save.GpxExporter;
+
+/**
+ * Superclass to manage the loading of data using GpsBabel
+ * Subclasses handle either from GPS or from file
+ */
+public abstract class BabelLoader extends GenericFunction implements Runnable
+{
+       private boolean _gpsBabelChecked = false;
+       protected JDialog _dialog = null;
+       // Checkboxes for which kinds of points to load
+       protected JCheckBox _waypointCheckbox = null, _trackCheckbox = null;
+       // Checkbox to save to file or not
+       protected JCheckBox _saveCheckbox = null;
+       protected JButton _okButton = null;
+       protected JProgressBar _progressBar = null;
+       protected File _saveFile = null;
+       protected boolean _cancelled = false;
+       protected BabelFilterPanel _filterPanel = null;
+
+
+       /**
+        * Constructor
+        * @param inApp Application object to inform of data load
+        */
+       public BabelLoader(App inApp)
+       {
+               super(inApp);
+       }
+
+       /**
+        * Open the GUI to select options and start the load
+        */
+       public void begin()
+       {
+               // Check if gpsbabel looks like it's installed
+               if (_gpsBabelChecked || ExternalTools.isToolInstalled(ExternalTools.TOOL_GPSBABEL)
+                       || JOptionPane.showConfirmDialog(_dialog,
+                               I18nManager.getText("dialog.gpsload.nogpsbabel"),
+                               I18nManager.getText(getNameKey()),
+                               JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION)
+               {
+                       _gpsBabelChecked = true;
+                       // Make dialog window
+                       if (_dialog == null)
+                       {
+                               _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
+                               _dialog.setLocationRelativeTo(_parentFrame);
+                               _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+                               _dialog.getContentPane().add(makeDialogComponents());
+                               _dialog.pack();
+                       }
+                       // Initialise progress bars, buttons
+                       enableOkButton();
+                       setupProgressBar(true);
+                       initDialog(); // do any subclass-specific init here
+                       _dialog.setVisible(true);
+               }
+       }
+
+
+       /**
+        * @return a panel containing the main dialog components
+        */
+       protected abstract JPanel makeDialogComponents();
+
+
+       /** Do any subclass-specific dialog initialisation necessary */
+       protected void initDialog()
+       {
+               // GPSBabel filter, if any
+               _filterPanel.setFilterString(Config.getConfigString(Config.KEY_GPSBABEL_FILTER));
+       }
+
+       /**
+        * @param inStart true if the dialog is restarting
+        */
+       private void setupProgressBar(boolean inStart)
+       {
+               // set visibility
+               _progressBar.setVisible(!inStart);
+               // set indeterminate flags, initial value
+               _progressBar.setIndeterminate(false);
+               _progressBar.setValue(0);
+       }
+
+
+       /**
+        * Enable or disable the ok button
+        */
+       protected void enableOkButton()
+       {
+               _okButton.setEnabled(isInputOk());
+       }
+
+       /**
+        * @return true if input fields of dialog are valid
+        */
+       protected abstract boolean isInputOk();
+
+       /**
+        * Run method for performing tasks in separate thread
+        */
+       public void run()
+       {
+               _okButton.setEnabled(false);
+               setupProgressBar(false);
+               if (isInputOk())
+               {
+                       _progressBar.setIndeterminate(true);
+                       _saveFile = null;
+                       try
+                       {
+                               callGpsBabel();
+                       }
+                       catch (Exception e)
+                       {
+                               _app.showErrorMessageNoLookup(getNameKey(), e.getMessage());
+                               _cancelled = true;
+                       }
+               }
+               setupProgressBar(true);
+               enableOkButton();
+
+               // Close dialog
+               if (!_cancelled) {
+                       _dialog.dispose();
+               }
+       }
+
+
+       /**
+        * Execute the call to gpsbabel and pass the results back to the app
+        */
+       private void callGpsBabel() throws Exception
+       {
+               // Set up command to call gpsbabel
+               String[] commands = getCommandArray();
+               // Save GPS settings in config
+               saveConfigValues();
+
+               String errorMessage = "", errorMessage2 = "";
+               XmlHandler handler = null;
+               Process process = Runtime.getRuntime().exec(commands);
+               String line = null;
+
+               if (_saveFile != null)
+               {
+                       // data is being saved to file, so need to wait for it to finish
+                       process.waitFor();
+                       // try to read error message, if any
+                       try {
+                               BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+                               while ((line = r.readLine()) != null) {
+                                       errorMessage += line + "\n";
+                               }
+                               // Close error stream
+                               try {
+                                       r.close();
+                               } catch (Exception e) {}
+                       }
+                       catch (Exception e) {} // couldn't get error message
+
+                       // Trigger it to be loaded by app
+                       if (process.exitValue() == 0)
+                       {
+                               SwingUtilities.invokeLater(new Runnable() {
+                                       public void run() {
+                                               ArrayList<File> fileList = new ArrayList<File>();
+                                               fileList.add(_saveFile);
+                                               _app.loadDataFiles(fileList);
+                                       }
+                               });
+                       }
+                       else if (errorMessage.length() > 0) {
+                               throw new Exception(errorMessage);
+                       }
+                       else throw new Exception(I18nManager.getText("error.gpsload.unknown"));
+               }
+               else
+               {
+                       // Pass input stream to try to parse the xml
+                       try
+                       {
+                               XmlFileLoader xmlLoader = new XmlFileLoader(_app);
+                               SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
+                               saxParser.parse(process.getInputStream(), xmlLoader);
+                               handler = xmlLoader.getHandler();
+                               if (handler == null) {
+                                       errorMessage = "Null handler";
+                               }
+                       }
+                       catch (Exception e) {
+                               errorMessage = e.getMessage();
+                       }
+
+                       // Read the error stream to see if there's a better error message there
+                       BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+                       while ((line = r.readLine()) != null) {
+                               errorMessage2 += line + "\n";
+                       }
+                       // Close error stream
+                       try {
+                               r.close();
+                       } catch (Exception e) {}
+
+                       if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
+                       if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
+
+                       // Send data back to app
+                       _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(), null,
+                               getSourceInfo(), handler.getTrackNameList());
+               }
+       }
+
+
+       /**
+        * Get the commands to call
+        * @return String array containing commands
+        */
+       private String[] getCommandArray()
+       {
+               ArrayList<String> commandList = new ArrayList<String>();
+               // Firstly the command for gpsbabel itself
+               final String command = Config.getConfigString(Config.KEY_GPSBABEL_PATH);
+               commandList.add(command);
+               // Then whether to load waypoints or track points
+               final boolean loadWaypoints = _waypointCheckbox.isSelected();
+               final boolean loadTrack = _trackCheckbox.isSelected();
+               if (loadWaypoints) {
+                       commandList.add("-w");
+               }
+               if (loadTrack) {
+                       commandList.add("-t");
+               }
+               // Input format
+               commandList.add("-i");
+               commandList.add(getInputFormat());
+               // File path
+               commandList.add("-f");
+               commandList.add(getFilePath());
+               // Filters, if any
+               final String filter = _filterPanel.getFilterString();
+               if (filter != null && !filter.equals(""))
+               {
+                       for (String arg : filter.split(" "))
+                       {
+                               if (arg.length() > 0) {
+                                       commandList.add(arg);
+                               }
+                       }
+               }
+               // Output format
+               commandList.add("-o");
+               commandList.add("gpx");
+               // Where to
+               commandList.add("-F");
+               String whereTo = "-";
+               // Do we want to save the gpx straight to file?
+               if (_saveCheckbox.isSelected())
+               {
+                       // Select file to save to
+                       _saveFile = GpxExporter.chooseGpxFile(_parentFrame);
+                       if (_saveFile != null) {
+                               whereTo = _saveFile.getAbsolutePath();
+                       }
+               }
+               commandList.add(whereTo);
+               // Convert to string array
+               String[] args = new String[] {};
+               return commandList.toArray(args);
+       }
+
+       /**
+        * @return SourceInfo object corresponding to the load
+        */
+       protected abstract SourceInfo getSourceInfo();
+
+       /**
+        * @return complete file path or device path for gpsbabel call
+        */
+       protected abstract String getFilePath();
+
+       /**
+        * @return file name or device name
+        */
+       protected abstract String getInputFormat();
+
+       /**
+        * Save any config values necessary
+        */
+       protected abstract void saveConfigValues();
+}