]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/load/GpsLoader.java
Version 6, October 2008
[GpsPrune.git] / tim / prune / load / GpsLoader.java
1 package tim.prune.load;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.FlowLayout;
6 import java.awt.GridLayout;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.io.BufferedReader;
10 import java.io.InputStreamReader;
11
12 import javax.swing.BorderFactory;
13 import javax.swing.BoxLayout;
14 import javax.swing.JButton;
15 import javax.swing.JCheckBox;
16 import javax.swing.JDialog;
17 import javax.swing.JFrame;
18 import javax.swing.JLabel;
19 import javax.swing.JOptionPane;
20 import javax.swing.JPanel;
21 import javax.swing.JProgressBar;
22 import javax.swing.JTextField;
23 import javax.swing.SwingConstants;
24 import javax.swing.event.ChangeEvent;
25 import javax.swing.event.ChangeListener;
26 import javax.xml.parsers.SAXParser;
27 import javax.xml.parsers.SAXParserFactory;
28
29 import tim.prune.App;
30 import tim.prune.Config;
31 import tim.prune.ExternalTools;
32 import tim.prune.I18nManager;
33 import tim.prune.data.Altitude;
34 import tim.prune.load.xml.XmlFileLoader;
35 import tim.prune.load.xml.XmlHandler;
36
37 /**
38  * Class to manage the loading of GPS data using GpsBabel
39  */
40 public class GpsLoader implements Runnable
41 {
42         private App _app = null;
43         private JFrame _parentFrame = null;
44         private boolean _gpsBabelChecked = false;
45         private JDialog _dialog = null;
46         private JTextField _deviceField = null, _formatField = null;
47         private JCheckBox _waypointCheckbox = null, _trackCheckbox = null;
48         private JButton _okButton = null;
49         private JProgressBar _waypointProgressBar = null, _trackProgressBar = null;
50         private boolean _cancelled = false;
51
52
53         /**
54          * Constructor
55          * @param inApp Application object to inform of data load
56          * @param inParentFrame parent frame to reference for dialogs
57          */
58         public GpsLoader(App inApp, JFrame inParentFrame)
59         {
60                 _app = inApp;
61                 _parentFrame = inParentFrame;
62         }
63
64
65         /**
66          * Open the GUI to select options and start the load
67          */
68         public void openDialog()
69         {
70                 // Check if gpsbabel looks like it's installed
71                 if (_gpsBabelChecked || ExternalTools.isGpsbabelInstalled()
72                         || JOptionPane.showConfirmDialog(_dialog,
73                                 I18nManager.getText("dialog.gpsload.nogpsbabel"),
74                                 I18nManager.getText("dialog.gpsload.title"),
75                                 JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION)
76                 {
77                         _gpsBabelChecked = true;
78                         // Make dialog window
79                         if (_dialog == null)
80                         {
81                                 _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.gpsload.title"), true);
82                                 _dialog.setLocationRelativeTo(_parentFrame);
83                                 _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
84                                 _dialog.getContentPane().add(makeDialogComponents());
85                                 _dialog.pack();
86                         }
87                         // Initialise progress bars, buttons
88                         enableOkButton();
89                         setupProgressBars(true);
90                         _dialog.show();
91                 }
92         }
93
94
95         /**
96          * @return a panel containing the main dialog components
97          */
98         private JPanel makeDialogComponents()
99         {
100                 JPanel outerPanel = new JPanel();
101                 outerPanel.setLayout(new BorderLayout());
102                 // Main panel with options etc
103                 JPanel mainPanel = new JPanel();
104                 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
105
106                 // text fields for options
107                 JPanel gridPanel = new JPanel();
108                 gridPanel.setLayout(new GridLayout(0, 2, 10, 3));
109                 JLabel deviceLabel = new JLabel(I18nManager.getText("dialog.gpsload.device"));
110                 deviceLabel.setHorizontalAlignment(SwingConstants.RIGHT);
111                 gridPanel.add(deviceLabel);
112                 _deviceField = new JTextField(Config.getGpsDevice(), 12);
113                 gridPanel.add(_deviceField);
114                 JLabel formatLabel = new JLabel(I18nManager.getText("dialog.gpsload.format"));
115                 formatLabel.setHorizontalAlignment(SwingConstants.RIGHT);
116                 gridPanel.add(formatLabel);
117                 _formatField = new JTextField(Config.getGpsFormat(), 12);
118                 gridPanel.add(_formatField);
119                 gridPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
120                 gridPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 20));
121                 mainPanel.add(gridPanel);
122
123                 // checkboxes
124                 ChangeListener checkboxListener = new ChangeListener() {
125                         public void stateChanged(ChangeEvent e)
126                         {
127                                 enableOkButton();
128                         }
129                 };
130                 _waypointCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.getwaypoints"), true);
131                 _waypointCheckbox.addChangeListener(checkboxListener);
132                 _waypointCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
133                 mainPanel.add(_waypointCheckbox);
134                 _trackCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.gettracks"), true);
135                 _trackCheckbox.addChangeListener(checkboxListener);
136                 _trackCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
137                 mainPanel.add(_trackCheckbox);
138                 // progress bars (initially invisible)
139                 _waypointProgressBar = new JProgressBar(0, 10);
140                 mainPanel.add(_waypointProgressBar);
141                 _trackProgressBar = new JProgressBar(0, 10);
142                 mainPanel.add(_trackProgressBar);
143                 outerPanel.add(mainPanel, BorderLayout.NORTH);
144
145                 // Lower panel with ok and cancel buttons
146                 JPanel buttonPanel = new JPanel();
147                 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
148                 _okButton = new JButton(I18nManager.getText("button.ok"));
149                 _okButton.addActionListener(new ActionListener() {
150                         public void actionPerformed(ActionEvent e)
151                         {
152                                 // start thread to call gpsbabel
153                                 _cancelled = false;
154                                 new Thread(GpsLoader.this).start();
155                         }
156                 });
157                 buttonPanel.add(_okButton);
158                 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
159                 cancelButton.addActionListener(new ActionListener() {
160                         public void actionPerformed(ActionEvent e)
161                         {
162                                 _cancelled = true;
163                                 _dialog.dispose();
164                         }
165                 });
166                 buttonPanel.add(cancelButton);
167                 outerPanel.add(buttonPanel, BorderLayout.SOUTH);
168                 return outerPanel;
169         }
170
171
172         /**
173          * @param inStart true if the dialog is restarting
174          */
175         private void setupProgressBars(boolean inStart)
176         {
177                 // set visibility
178                 _waypointProgressBar.setVisible(!inStart && _waypointCheckbox.isSelected());
179                 _trackProgressBar.setVisible(!inStart && _trackCheckbox.isSelected());
180                 // set indeterminate flags, initial value
181                 _waypointProgressBar.setIndeterminate(false);
182                 _waypointProgressBar.setValue(0);
183                 _trackProgressBar.setIndeterminate(false);
184                 _trackProgressBar.setValue(0);
185         }
186
187
188         /**
189          * Enable or disable the ok button
190          */
191         private void enableOkButton()
192         {
193                 _okButton.setEnabled(_waypointCheckbox.isSelected() || _trackCheckbox.isSelected());
194         }
195
196
197         /**
198          * Run method for performing tasks in separate thread
199          */
200         public void run()
201         {
202                 _okButton.setEnabled(false);
203                 setupProgressBars(false);
204                 if (_waypointCheckbox.isSelected())
205                 {
206                         _waypointProgressBar.setIndeterminate(true);
207                         _trackProgressBar.setIndeterminate(false);
208                         try
209                         {
210                                 callGpsBabel(true);
211                         }
212                         catch (Exception e)
213                         {
214                                 JOptionPane.showMessageDialog(_dialog, e.getMessage(),
215                                         I18nManager.getText("dialog.gpsload.title"), JOptionPane.ERROR_MESSAGE);
216                                 _cancelled = true;
217                         }
218                 }
219                 // Exit if cancelled or failed
220                 if (_cancelled) {
221                         setupProgressBars(true);
222                         enableOkButton();
223                         return;
224                 }
225                 if (_trackCheckbox.isSelected())
226                 {
227                         _waypointProgressBar.setIndeterminate(false);
228                         _waypointProgressBar.setValue(10);
229                         _trackProgressBar.setIndeterminate(true);
230                         try
231                         {
232                                 callGpsBabel(false);
233                         }
234                         catch (Exception e)
235                         {
236                                 JOptionPane.showMessageDialog(_dialog, e.getMessage(),
237                                         I18nManager.getText("dialog.gpsload.title"), JOptionPane.ERROR_MESSAGE);
238                                 _cancelled = true;
239                         }
240                 }
241                 setupProgressBars(true);
242                 enableOkButton();
243
244                 // Close dialog
245                 if (!_cancelled) {
246                         _dialog.dispose();
247                 }
248         }
249
250
251         /**
252          * Execute the call to gpsbabel and pass the results back to the app
253          * @param inWaypoints true to get waypoints, false to get track data
254          */
255         private void callGpsBabel(boolean inWaypoints) throws Exception
256         {
257                 // Set up command to call gpsbabel
258                 String[] commands = {"gpsbabel", null, "-i", _formatField.getText(), "-f", _deviceField.getText(), "-o", "gpx", "-F", "-"};
259                 commands[1] = inWaypoints?"-w":"-t";
260
261                 String errorMessage = "";
262                 XmlHandler handler = null;
263                 Process process = Runtime.getRuntime().exec(commands);
264
265                 // Pass input stream to try to parse the xml
266                 try
267                 {
268                         XmlFileLoader xmlLoader = new XmlFileLoader(_app, _parentFrame);
269                         SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
270                         saxParser.parse(process.getInputStream(), xmlLoader);
271                         handler = xmlLoader.getHandler();
272                         if (handler == null) {
273                                 errorMessage = "Null handler";
274                         }
275                 }
276                 catch (Exception e) {
277                         errorMessage = e.getMessage();
278                 }
279
280                 // Read the error stream to see if there's a better error message there
281                 BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
282                 String line = null;
283                 String errorMessage2 = "";
284                 while ((line = r.readLine()) != null) {
285                         errorMessage2 += line + "\n";
286                 }
287                 if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
288                 if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
289
290                 // Send data back to app
291                 boolean append = _waypointCheckbox.isSelected() && !inWaypoints;
292                 _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
293                         Altitude.FORMAT_METRES, _deviceField.getText(), append);
294         }
295 }