]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/load/BabelLoader.java
Version 13, August 2011
[GpsPrune.git] / tim / prune / load / BabelLoader.java
1 package tim.prune.load;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.InputStreamReader;
6 import java.util.ArrayList;
7
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;
17
18 import tim.prune.App;
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;
28
29 /**
30  * Superclass to manage the loading of data using GpsBabel
31  * Subclasses handle either from GPS or from file
32  */
33 public abstract class BabelLoader extends GenericFunction implements Runnable
34 {
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
46
47         /**
48          * Constructor
49          * @param inApp Application object to inform of data load
50          */
51         public BabelLoader(App inApp)
52         {
53                 super(inApp);
54         }
55
56         /**
57          * Open the GUI to select options and start the load
58          */
59         public void begin()
60         {
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)
67                 {
68                         _gpsBabelChecked = true;
69                         // Make dialog window
70                         if (_dialog == null)
71                         {
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());
76                                 _dialog.pack();
77                         }
78                         // Initialise progress bars, buttons
79                         enableOkButton();
80                         setupProgressBar(true);
81                         initDialog(); // do any subclass-specific init here
82                         _dialog.setVisible(true);
83                 }
84         }
85
86
87         /**
88          * @return a panel containing the main dialog components
89          */
90         protected abstract JPanel makeDialogComponents();
91
92
93         /** Do any subclass-specific dialog initialisation necessary */
94         protected void initDialog() {}
95
96         /**
97          * @param inStart true if the dialog is restarting
98          */
99         private void setupProgressBar(boolean inStart)
100         {
101                 // set visibility
102                 _progressBar.setVisible(!inStart);
103                 // set indeterminate flags, initial value
104                 _progressBar.setIndeterminate(false);
105                 _progressBar.setValue(0);
106         }
107
108
109         /**
110          * Enable or disable the ok button
111          */
112         protected void enableOkButton()
113         {
114                 _okButton.setEnabled(isInputOk());
115         }
116
117         /**
118          * @return true if input fields of dialog are valid
119          */
120         protected abstract boolean isInputOk();
121
122         /**
123          * Run method for performing tasks in separate thread
124          */
125         public void run()
126         {
127                 _okButton.setEnabled(false);
128                 setupProgressBar(false);
129                 if (isInputOk())
130                 {
131                         _progressBar.setIndeterminate(true);
132                         _saveFile = null;
133                         try
134                         {
135                                 callGpsBabel();
136                         }
137                         catch (Exception e)
138                         {
139                                 _app.showErrorMessageNoLookup(getNameKey(), e.getMessage());
140                                 _cancelled = true;
141                         }
142                 }
143                 setupProgressBar(true);
144                 enableOkButton();
145
146                 // Close dialog
147                 if (!_cancelled) {
148                         _dialog.dispose();
149                 }
150         }
151
152
153         /**
154          * Execute the call to gpsbabel and pass the results back to the app
155          */
156         private void callGpsBabel() throws Exception
157         {
158                 // Set up command to call gpsbabel
159                 String[] commands = getCommandArray();
160                 // Save GPS settings in config
161                 saveConfigValues();
162
163                 String errorMessage = "", errorMessage2 = "";
164                 XmlHandler handler = null;
165                 Process process = Runtime.getRuntime().exec(commands);
166                 String line = null;
167
168                 if (_saveFile != null)
169                 {
170                         // data is being saved to file, so need to wait for it to finish
171                         process.waitFor();
172                         // try to read error message, if any
173                         try {
174                                 BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
175                                 while ((line = r.readLine()) != null) {
176                                         errorMessage += line + "\n";
177                                 }
178                                 // Close error stream
179                                 try {
180                                         r.close();
181                                 } catch (Exception e) {}
182                         }
183                         catch (Exception e) {} // couldn't get error message
184
185                         // Trigger it to be loaded by app
186                         if (process.exitValue() == 0)
187                         {
188                                 SwingUtilities.invokeLater(new Runnable() {
189                                         public void run() {
190                                                 ArrayList<File> fileList = new ArrayList<File>();
191                                                 fileList.add(_saveFile);
192                                                 _app.loadDataFiles(fileList);
193                                         }
194                                 });
195                         }
196                         else if (errorMessage.length() > 0) {
197                                 throw new Exception(errorMessage);
198                         }
199                         else throw new Exception(I18nManager.getText("error.gpsload.unknown"));
200                 }
201                 else
202                 {
203                         // Pass input stream to try to parse the xml
204                         try
205                         {
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";
212                                 }
213                         }
214                         catch (Exception e) {
215                                 errorMessage = e.getMessage();
216                         }
217
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";
222                         }
223                         // Close error stream
224                         try {
225                                 r.close();
226                         } catch (Exception e) {}
227
228                         if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
229                         if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
230
231                         // Send data back to app
232                         _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(), Altitude.Format.METRES,
233                                 getSourceInfo(),
234                                 handler.getTrackNameList());
235                 }
236         }
237
238
239         /**
240          * Get the commands to call
241          * @return String array containing commands
242          */
243         private String[] getCommandArray()
244         {
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", "-"};
253                 }
254                 else
255                 {
256                         // Only waypoints OR track points selected
257                         commands = new String[] {command, "-w", "-i", getInputFormat(),
258                                 "-f", getFilePath(), "-o", "gpx", "-F", "-"};
259                         if (loadTrack) {
260                                 commands[1] = "-t";
261                         }
262                 }
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();
269                         }
270                 }
271                 return commands;
272         }
273
274         /**
275          * @return SourceInfo object corresponding to the load
276          */
277         protected abstract SourceInfo getSourceInfo();
278
279         /**
280          * @return complete file path or device path for gpsbabel call
281          */
282         protected abstract String getFilePath();
283
284         /**
285          * @return file name or device name
286          */
287         protected abstract String getInputFormat();
288
289         /**
290          * Save any config values necessary
291          */
292         protected abstract void saveConfigValues();
293 }