+package tim.prune.save;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import tim.prune.App;
+import tim.prune.ExternalTools;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.config.Config;
+
+/**
+ * Class to manage the loading of GPS data using GpsBabel
+ */
+public class GpsSaver extends GenericFunction implements Runnable
+{
+ private boolean _gpsBabelChecked = false;
+ private JDialog _dialog = null;
+ private JTextField _deviceField = null, _formatField = null;
+ private JTextField _trackNameField = null;
+ private JCheckBox _waypointCheckbox = null, _trackCheckbox = null;
+ private boolean _switchedWaypointsOff = false, _switchedTrackpointsOff = false;
+ private JButton _okButton = null;
+ private JProgressBar _progressBar = null;
+ private boolean _cancelled = false;
+
+
+ /**
+ * Constructor
+ * @param inApp app object
+ */
+ public GpsSaver(App inApp)
+ {
+ super(inApp);
+ }
+
+ /** get name key */
+ public String getNameKey() {
+ return "function.sendtogps";
+ }
+
+ /**
+ * 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("function.sendtogps"), true);
+ _dialog.setLocationRelativeTo(_parentFrame);
+ _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ _dialog.getContentPane().add(makeDialogComponents());
+ _dialog.pack();
+ }
+ // Initialise progress bars, buttons
+ enableCheckboxes();
+ enableOkButton();
+ setupProgressBar(true);
+ _trackNameField.requestFocus();
+ _dialog.setVisible(true);
+ }
+ }
+
+
+ /**
+ * @return a panel containing the main dialog components
+ */
+ private JPanel makeDialogComponents()
+ {
+ JPanel outerPanel = new JPanel();
+ outerPanel.setLayout(new BorderLayout());
+ // Main panel with options etc
+ JPanel mainPanel = new JPanel();
+ mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+
+ // text fields for options
+ JPanel gridPanel = new JPanel();
+ gridPanel.setLayout(new GridLayout(0, 2, 10, 3));
+ JLabel deviceLabel = new JLabel(I18nManager.getText("dialog.gpsload.device"));
+ deviceLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+ gridPanel.add(deviceLabel);
+ _deviceField = new JTextField(Config.getConfigString(Config.KEY_GPS_DEVICE), 12);
+ gridPanel.add(_deviceField);
+ JLabel formatLabel = new JLabel(I18nManager.getText("dialog.gpsload.format"));
+ formatLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+ gridPanel.add(formatLabel);
+ _formatField = new JTextField(Config.getConfigString(Config.KEY_GPS_FORMAT), 12);
+ gridPanel.add(_formatField);
+ JLabel nameLabel = new JLabel(I18nManager.getText("dialog.gpssend.trackname"));
+ nameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+ gridPanel.add(nameLabel);
+ _trackNameField = new JTextField("", 12);
+ gridPanel.add(_trackNameField);
+ gridPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
+ gridPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 20));
+ mainPanel.add(gridPanel);
+ // close dialog when escape pressed
+ KeyAdapter closer = new KeyAdapter() {
+ public void keyReleased(KeyEvent e)
+ {
+ // close dialog if escape pressed
+ if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
+ _dialog.dispose();
+ }
+ }
+ };
+ _deviceField.addKeyListener(closer);
+ _formatField.addKeyListener(closer);
+ _trackNameField.addKeyListener(closer);
+
+ // checkboxes
+ ChangeListener checkboxListener = new ChangeListener() {
+ public void stateChanged(ChangeEvent e)
+ {
+ enableOkButton();
+ }
+ };
+ _waypointCheckbox = new JCheckBox(I18nManager.getText("dialog.gpssend.sendwaypoints"), true);
+ _waypointCheckbox.addChangeListener(checkboxListener);
+ _waypointCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+ mainPanel.add(_waypointCheckbox);
+ _trackCheckbox = new JCheckBox(I18nManager.getText("dialog.gpssend.sendtracks"), true);
+ _trackCheckbox.addChangeListener(checkboxListener);
+ _trackCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+ mainPanel.add(_trackCheckbox);
+
+ // progress bar (initially invisible)
+ _progressBar = new JProgressBar(0, 10);
+ mainPanel.add(_progressBar);
+ outerPanel.add(mainPanel, BorderLayout.NORTH);
+
+ // Lower panel with ok and cancel buttons
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ _okButton = new JButton(I18nManager.getText("button.ok"));
+ _okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ // start thread to call gpsbabel
+ _cancelled = false;
+ new Thread(GpsSaver.this).start();
+ }
+ });
+ buttonPanel.add(_okButton);
+ JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _cancelled = true;
+ _dialog.dispose();
+ }
+ });
+ buttonPanel.add(cancelButton);
+ outerPanel.add(buttonPanel, BorderLayout.SOUTH);
+ return outerPanel;
+ }
+
+
+ /**
+ * @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 waypoints and trackpoints checkboxes
+ */
+ private void enableCheckboxes()
+ {
+ // Enable or disable waypoints checkbox depending on whether data is available
+ if (_waypointCheckbox.isSelected())
+ {
+ if (!_app.getTrackInfo().getTrack().hasWaypoints())
+ {
+ _waypointCheckbox.setSelected(false);
+ _switchedWaypointsOff = true;
+ }
+ else _switchedWaypointsOff = false;
+ }
+ else if (_app.getTrackInfo().getTrack().hasWaypoints() && _switchedWaypointsOff)
+ {
+ _waypointCheckbox.setSelected(true);
+ _switchedWaypointsOff = false;
+ }
+ // ... and the same for track points
+ if (_trackCheckbox.isSelected())
+ {
+ if (!_app.getTrackInfo().getTrack().hasTrackPoints())
+ {
+ _trackCheckbox.setSelected(false);
+ _switchedTrackpointsOff = true;
+ }
+ else _switchedTrackpointsOff = false;
+ }
+ else if (_app.getTrackInfo().getTrack().hasTrackPoints() && _switchedTrackpointsOff)
+ {
+ _trackCheckbox.setSelected(true);
+ _switchedTrackpointsOff = false;
+ }
+ }
+
+ /**
+ * Enable or disable the ok button
+ */
+ private void enableOkButton()
+ {
+ _okButton.setEnabled(_waypointCheckbox.isSelected() || _trackCheckbox.isSelected());
+ }
+
+
+ /**
+ * Run method for performing tasks in separate thread
+ */
+ public void run()
+ {
+ _okButton.setEnabled(false);
+ setupProgressBar(false);
+
+ _progressBar.setIndeterminate(true);
+ try
+ {
+ callGpsBabel();
+ }
+ catch (Exception e)
+ {
+ JOptionPane.showMessageDialog(_dialog, e.getMessage(),
+ I18nManager.getText("function.sendtogps"), JOptionPane.ERROR_MESSAGE);
+ _cancelled = true;
+ }
+
+ setupProgressBar(true);
+ enableOkButton();
+
+ // Close dialog
+ if (!_cancelled) {
+ _dialog.dispose();
+ }
+ }
+
+
+ /**
+ * Execute the call to gpsbabel
+ */
+ private void callGpsBabel() throws Exception
+ {
+ // Set up command to call gpsbabel
+ final String command = Config.getConfigString(Config.KEY_GPSBABEL_PATH);
+ String[] commands = null;
+ final String device = _deviceField.getText().trim();
+ final String format = _formatField.getText().trim();
+ if (_waypointCheckbox.isSelected() && _trackCheckbox.isSelected()) {
+ // Both waypoints and track points selected
+ commands = new String[] {command, "-w", "-t", "-i", "gpx", "-f", "-", "-o", format,
+ "-F", device};
+ }
+ else
+ {
+ // Only waypoints OR trackpoints selected
+ commands = new String[] {command, "-w", "-i", "gpx", "-f", "-", "-o", format,
+ "-F", device};
+ if (_trackCheckbox.isSelected()) {
+ commands[1] = "-t";
+ }
+ }
+ // Save GPS settings in config
+ Config.setConfigString(Config.KEY_GPS_DEVICE, device);
+ Config.setConfigString(Config.KEY_GPS_FORMAT, format);
+
+ String errorMessage = "";
+ Process process = Runtime.getRuntime().exec(commands);
+
+ String trackName = _trackNameField.getText();
+ if (trackName == null || trackName.equals("")) {trackName = "gpsprune";}
+ // Generate the GPX file and send to the GPS
+ OutputStreamWriter writer = new OutputStreamWriter(process.getOutputStream());
+ SettingsForExport settings = new SettingsForExport();
+ settings.setExportMissingAltitudesAsZero(true);
+ GpxExporter.exportData(writer, _app.getTrackInfo(), trackName, null, settings, null);
+ writer.close();
+
+ // Read the error stream to see if there's a better error message there
+ BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+ String line = null;
+ String errorMessage2 = "";
+ 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);}
+ }
+}