]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/load/BabelLoader.java
7ebd7deadc73a50023cb5baecc76936296a3eae9
[GpsPrune.git] / src / 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.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;
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         protected BabelFilterPanel _filterPanel = null;
46
47
48         /**
49          * Constructor
50          * @param inApp Application object to inform of data load
51          */
52         public BabelLoader(App inApp)
53         {
54                 super(inApp);
55         }
56
57         /**
58          * Open the GUI to select options and start the load
59          */
60         public void begin()
61         {
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)
68                 {
69                         _gpsBabelChecked = true;
70                         // Make dialog window
71                         if (_dialog == null)
72                         {
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());
77                                 _dialog.pack();
78                         }
79                         // Initialise progress bars, buttons
80                         enableOkButton();
81                         setupProgressBar(true);
82                         initDialog(); // do any subclass-specific init here
83                         _dialog.setVisible(true);
84                 }
85         }
86
87
88         /**
89          * @return a panel containing the main dialog components
90          */
91         protected abstract JPanel makeDialogComponents();
92
93
94         /** Do any subclass-specific dialog initialisation necessary */
95         protected void initDialog()
96         {
97                 // GPSBabel filter, if any
98                 _filterPanel.setFilterString(Config.getConfigString(Config.KEY_GPSBABEL_FILTER));
99         }
100
101         /**
102          * @param inStart true if the dialog is restarting
103          */
104         private void setupProgressBar(boolean inStart)
105         {
106                 // set visibility
107                 _progressBar.setVisible(!inStart);
108                 // set indeterminate flags, initial value
109                 _progressBar.setIndeterminate(false);
110                 _progressBar.setValue(0);
111         }
112
113
114         /**
115          * Enable or disable the ok button
116          */
117         protected void enableOkButton()
118         {
119                 _okButton.setEnabled(isInputOk());
120         }
121
122         /**
123          * @return true if input fields of dialog are valid
124          */
125         protected abstract boolean isInputOk();
126
127         /**
128          * Run method for performing tasks in separate thread
129          */
130         public void run()
131         {
132                 _okButton.setEnabled(false);
133                 setupProgressBar(false);
134                 if (isInputOk())
135                 {
136                         _progressBar.setIndeterminate(true);
137                         _saveFile = null;
138                         try
139                         {
140                                 callGpsBabel();
141                         }
142                         catch (Exception e)
143                         {
144                                 _app.showErrorMessageNoLookup(getNameKey(), e.getMessage());
145                                 _cancelled = true;
146                         }
147                 }
148                 setupProgressBar(true);
149                 enableOkButton();
150
151                 // Close dialog
152                 if (!_cancelled) {
153                         _dialog.dispose();
154                 }
155         }
156
157
158         /**
159          * Execute the call to gpsbabel and pass the results back to the app
160          */
161         private void callGpsBabel() throws Exception
162         {
163                 // Set up command to call gpsbabel
164                 String[] commands = getCommandArray();
165                 // Save GPS settings in config
166                 saveConfigValues();
167
168                 String errorMessage = "", errorMessage2 = "";
169                 XmlHandler handler = null;
170                 Process process = Runtime.getRuntime().exec(commands);
171                 String line = null;
172
173                 if (_saveFile != null)
174                 {
175                         // data is being saved to file, so need to wait for it to finish
176                         process.waitFor();
177                         // try to read error message, if any
178                         try {
179                                 BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
180                                 while ((line = r.readLine()) != null) {
181                                         errorMessage += line + "\n";
182                                 }
183                                 // Close error stream
184                                 try {
185                                         r.close();
186                                 } catch (Exception e) {}
187                         }
188                         catch (Exception e) {} // couldn't get error message
189
190                         // Trigger it to be loaded by app
191                         if (process.exitValue() == 0)
192                         {
193                                 SwingUtilities.invokeLater(new Runnable() {
194                                         public void run() {
195                                                 ArrayList<File> fileList = new ArrayList<File>();
196                                                 fileList.add(_saveFile);
197                                                 _app.loadDataFiles(fileList);
198                                         }
199                                 });
200                         }
201                         else if (errorMessage.length() > 0) {
202                                 throw new Exception(errorMessage);
203                         }
204                         else throw new Exception(I18nManager.getText("error.gpsload.unknown"));
205                 }
206                 else
207                 {
208                         // Pass input stream to try to parse the xml
209                         try
210                         {
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";
217                                 }
218                         }
219                         catch (Exception e) {
220                                 errorMessage = e.getMessage();
221                         }
222
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";
227                         }
228                         // Close error stream
229                         try {
230                                 r.close();
231                         } catch (Exception e) {}
232
233                         if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
234                         if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
235
236                         // Send data back to app
237                         _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(), null,
238                                 getSourceInfo(), handler.getTrackNameList());
239                 }
240         }
241
242
243         /**
244          * Get the commands to call
245          * @return String array containing commands
246          */
247         private String[] getCommandArray()
248         {
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();
256                 if (loadWaypoints) {
257                         commandList.add("-w");
258                 }
259                 if (loadTrack) {
260                         commandList.add("-t");
261                 }
262                 // Input format
263                 commandList.add("-i");
264                 commandList.add(getInputFormat());
265                 // File path
266                 commandList.add("-f");
267                 commandList.add(getFilePath());
268                 // Filters, if any
269                 final String filter = _filterPanel.getFilterString();
270                 if (filter != null && !filter.equals(""))
271                 {
272                         for (String arg : filter.split(" "))
273                         {
274                                 if (arg.length() > 0) {
275                                         commandList.add(arg);
276                                 }
277                         }
278                 }
279                 // Output format
280                 commandList.add("-o");
281                 commandList.add("gpx");
282                 // Where to
283                 commandList.add("-F");
284                 String whereTo = "-";
285                 // Do we want to save the gpx straight to file?
286                 if (_saveCheckbox.isSelected())
287                 {
288                         // Select file to save to
289                         _saveFile = GpxExporter.chooseGpxFile(_parentFrame);
290                         if (_saveFile != null) {
291                                 whereTo = _saveFile.getAbsolutePath();
292                         }
293                 }
294                 commandList.add(whereTo);
295                 // Convert to string array
296                 String[] args = new String[] {};
297                 return commandList.toArray(args);
298         }
299
300         /**
301          * @return SourceInfo object corresponding to the load
302          */
303         protected abstract SourceInfo getSourceInfo();
304
305         /**
306          * @return complete file path or device path for gpsbabel call
307          */
308         protected abstract String getFilePath();
309
310         /**
311          * @return file name or device name
312          */
313         protected abstract String getInputFormat();
314
315         /**
316          * Save any config values necessary
317          */
318         protected abstract void saveConfigValues();
319 }