]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/save/GpxExporter.java
Version 8, September 2009
[GpsPrune.git] / tim / prune / save / GpxExporter.java
index 98619d1a81dddf0fdef65060a1969f6c582f0c25..0bd93d2f0926ad09b6cdc73b637b464f006a6011 100644 (file)
@@ -12,73 +12,82 @@ import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
 
+import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
 import javax.swing.JButton;
+import javax.swing.JCheckBox;
 import javax.swing.JDialog;
 import javax.swing.JFileChooser;
-import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JTextField;
-import javax.swing.filechooser.FileFilter;
 
+import tim.prune.App;
+import tim.prune.Config;
+import tim.prune.GenericFunction;
 import tim.prune.GpsPruner;
 import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
 import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Timestamp;
 import tim.prune.data.Track;
-import tim.prune.data.TrackInfo;
+import tim.prune.load.GenericFileFilter;
 
 /**
  * Class to export track information
  * into a specified Gpx file
  */
-public class GpxExporter implements Runnable
+public class GpxExporter extends GenericFunction implements Runnable
 {
-       private JFrame _parentFrame = null;
        private Track _track = null;
        private JDialog _dialog = null;
        private JTextField _nameField = null;
        private JTextField _descriptionField = null;
+       private PointTypeSelector _pointTypeSelector = null;
+       private JCheckBox _timestampsCheckbox = null;
        private JFileChooser _fileChooser = null;
        private File _exportFile = null;
 
        /** version number of Gpx */
-       private static final String GPX_VERSION_NUMBER = "1.1";
+       private static final String GPX_VERSION_NUMBER = "1.0";
        /** this program name */
        private static final String GPX_CREATOR = "Prune v" + GpsPruner.VERSION_NUMBER + " activityworkshop.net";
 
 
        /**
-        * Constructor giving frame and track
-        * @param inParentFrame parent frame
-        * @param inTrackInfo track info object to save
+        * Constructor
+        * @param inApp app object
         */
-       public GpxExporter(JFrame inParentFrame, TrackInfo inTrackInfo)
+       public GpxExporter(App inApp)
        {
-               _parentFrame = inParentFrame;
-               _track = inTrackInfo.getTrack();
+               super(inApp);
+               _track = inApp.getTrackInfo().getTrack();
        }
 
+       /** Get name key */
+       public String getNameKey() {
+               return "function.exportgpx";
+       }
 
        /**
         * Show the dialog to select options and export file
         */
-       public void showDialog()
+       public void begin()
        {
                // Make dialog window
                if (_dialog == null)
                {
-                       _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.exportgpx.title"), true);
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
                        _dialog.setLocationRelativeTo(_parentFrame);
                        _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                        _dialog.getContentPane().add(makeDialogComponents());
                        _dialog.pack();
                }
-               _dialog.show();
+               _pointTypeSelector.init(_app.getTrackInfo());
+               _dialog.setVisible(true);
        }
 
 
@@ -102,6 +111,13 @@ public class GpxExporter implements Runnable
                _descriptionField = new JTextField(10);
                descPanel.add(_descriptionField);
                mainPanel.add(descPanel);
+               // point type selection (track points, waypoints, photo points)
+               _pointTypeSelector = new PointTypeSelector();
+               mainPanel.add(_pointTypeSelector);
+               // checkbox for timestamps
+               _timestampsCheckbox = new JCheckBox(I18nManager.getText("dialog.exportgpx.includetimestamps"));
+               _timestampsCheckbox.setSelected(true);
+               mainPanel.add(_timestampsCheckbox);
                dialogPanel.add(mainPanel, BorderLayout.CENTER);
 
                // button panel at bottom
@@ -126,6 +142,7 @@ public class GpxExporter implements Runnable
                });
                buttonPanel.add(cancelButton);
                dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+               dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
                return dialogPanel;
        }
 
@@ -135,22 +152,21 @@ public class GpxExporter implements Runnable
         */
        private void startExport()
        {
-               // OK pressed, so choose output file
+               // OK pressed, so check selections
+               if (!_pointTypeSelector.getAnythingSelected()) {
+                       return;
+               }
+               // Choose output file
                if (_fileChooser == null)
-                       {_fileChooser = new JFileChooser();}
-               _fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
-               _fileChooser.setFileFilter(new FileFilter() {
-                       public boolean accept(File f)
-                       {
-                               return (f != null && (f.isDirectory()
-                                       || f.getName().toLowerCase().endsWith(".gpx")));
-                       }
-                       public String getDescription()
-                       {
-                               return I18nManager.getText("dialog.exportgpx.filetype");
-                       }
-               });
-               _fileChooser.setAcceptAllFileFilterUsed(false);
+               {
+                       _fileChooser = new JFileChooser();
+                       _fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
+                       _fileChooser.setFileFilter(new GenericFileFilter("filetype.gpx", new String[] {"gpx"}));
+                       _fileChooser.setAcceptAllFileFilterUsed(false);
+                       // start from directory in config which should be set
+                       String configDir = Config.getConfigString(Config.KEY_TRACK_DIR);
+                       if (configDir != null) {_fileChooser.setCurrentDirectory(new File(configDir));}
+               }
                // Allow choose again if an existing file is selected
                boolean chooseAgain = false;
                do
@@ -196,15 +212,20 @@ public class GpxExporter implements Runnable
                {
                        // normal writing to file
                        writer = new OutputStreamWriter(new FileOutputStream(_exportFile));
+                       boolean[] saveFlags = {_pointTypeSelector.getTrackpointsSelected(), _pointTypeSelector.getWaypointsSelected(),
+                               _pointTypeSelector.getPhotopointsSelected(), _timestampsCheckbox.isSelected()};
                        // write file
-                       int numPoints = exportData(writer);
+                       final int numPoints = exportData(writer, _track, _nameField.getText(),
+                               _descriptionField.getText(), saveFlags);
 
                        // close file
                        writer.close();
-                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.ok1")
-                                + " " + numPoints + " " + I18nManager.getText("dialog.save.ok2")
-                                + " " + _exportFile.getAbsolutePath(),
-                               I18nManager.getText("dialog.save.oktitle"), JOptionPane.INFORMATION_MESSAGE);
+                       // Store directory in config for later
+                       Config.setConfigString(Config.KEY_TRACK_DIR, _exportFile.getParentFile().getAbsolutePath());
+                       // Show confirmation
+                       UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
+                                + " " + numPoints + " " + I18nManager.getText("confirm.save.ok2")
+                                + " " + _exportFile.getAbsolutePath());
                        // export successful so need to close dialog and return
                        _dialog.dispose();
                        return;
@@ -228,27 +249,36 @@ public class GpxExporter implements Runnable
        /**
         * Export the information to the given writer
         * @param inWriter writer object
+        * @param inTrack track object containing data
+        * @param inName name of track (optional)
+        * @param inDesc description of track (optional)
+        * @param inSaveFlags array of booleans to export tracks, waypoints, photos, timestamps
         * @return number of points written
+        * @throws IOException if io errors occur on write
         */
-       private int exportData(OutputStreamWriter inWriter) throws IOException
+       public static int exportData(OutputStreamWriter inWriter, Track inTrack, String inName,
+               String inDesc, boolean[] inSaveFlags) throws IOException
        {
                inWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gpx version=\"");
                inWriter.write(GPX_VERSION_NUMBER);
                inWriter.write("\" creator=\"");
                inWriter.write(GPX_CREATOR);
-               inWriter.write("\">\n");
+               inWriter.write("\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+                       + " xmlns=\"http://www.topografix.com/GPX/1/0\""
+                       + " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n");
                // Name field
-               if (_nameField != null && _nameField.getText() != null && !_nameField.getText().equals(""))
+               String trackName = "PruneTrack";
+               if (inName != null && !inName.equals(""))
                {
+                       trackName = inName;
                        inWriter.write("\t<name>");
-                       inWriter.write(_nameField.getText());
+                       inWriter.write(trackName);
                        inWriter.write("</name>\n");
                }
                // Description field
                inWriter.write("\t<desc>");
-               if (_descriptionField != null && _descriptionField.getText() != null && !_descriptionField.getText().equals(""))
-               {
-                       inWriter.write(_descriptionField.getText());
+               if (inDesc != null && !inDesc.equals("")) {
+                       inWriter.write(inDesc);
                }
                else
                {
@@ -259,67 +289,87 @@ public class GpxExporter implements Runnable
                int i = 0;
                DataPoint point = null;
                boolean hasTrackpoints = false;
+               final boolean exportTrackpoints = inSaveFlags[0];
+               final boolean exportWaypoints = inSaveFlags[1];
+               final boolean exportPhotos = inSaveFlags[2];
+               final boolean exportTimestamps = inSaveFlags[3];
                // Loop over waypoints
-               int numPoints = _track.getNumPoints();
+               final int numPoints = inTrack.getNumPoints();
+               int numSaved = 0;
                for (i=0; i<numPoints; i++)
                {
-                       point = _track.getPoint(i);
-                       // Make a blob for each waypoint
+                       point = inTrack.getPoint(i);
+                       // Make a wpt element for each waypoint
                        if (point.isWaypoint())
                        {
-                               exportWaypoint(point, inWriter);
+                               if (exportWaypoints) {
+                                       exportWaypoint(point, inWriter, exportTimestamps);
+                                       numSaved++;
+                               }
                        }
                        else
                        {
                                hasTrackpoints = true;
                        }
                }
-               // Make a line for the track, if there is one
-               // TODO: Look at segments of track, and split into separate track segments in Gpx if necessary
+               // Output the track, if there is one
                if (hasTrackpoints)
                {
-                       inWriter.write("\t<trk><trkseg>\n");
+                       boolean firstPoint = true;
+                       inWriter.write("\t<trk><name>" + trackName + "</name><number>1</number><trkseg>\n");
                        // Loop over track points
                        for (i=0; i<numPoints; i++)
                        {
-                               point = _track.getPoint(i);
+                               point = inTrack.getPoint(i);
+                               // restart track segment if necessary
+                               if (point.getSegmentStart() && !firstPoint) {
+                                       inWriter.write("\t</trkseg>\n\t<trkseg>\n");
+                               }
                                if (!point.isWaypoint())
                                {
-                                       exportTrackpoint(point, inWriter);
+                                       if ((point.getPhoto()==null && exportTrackpoints) || (point.getPhoto()!=null && exportPhotos))
+                                       {
+                                               // export the point
+                                               exportTrackpoint(point, inWriter, exportTimestamps);
+                                               numSaved++;
+                                               firstPoint = false;
+                                       }
                                }
                        }
                        inWriter.write("\t</trkseg></trk>\n");
                }
                inWriter.write("</gpx>\n");
-               return numPoints;
+               return numSaved;
        }
 
-
        /**
         * Export the specified waypoint into the file
         * @param inPoint waypoint to export
         * @param inWriter writer object
+        * @param inTimestamps true to export timestamps too
         * @throws IOException on write failure
         */
-       private void exportWaypoint(DataPoint inPoint, Writer inWriter) throws IOException
+       private static void exportWaypoint(DataPoint inPoint, Writer inWriter, boolean inTimestamps)
+               throws IOException
        {
                inWriter.write("\t<wpt lat=\"");
-               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write("\" lon=\"");
-               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write("\">\n");
-               inWriter.write("\t\t<name>");
-               inWriter.write(inPoint.getWaypointName().trim());
-               inWriter.write("</name>\n");
                // altitude if available
                if (inPoint.hasAltitude())
                {
                        inWriter.write("\t\t<ele>");
-                       inWriter.write("" + inPoint.getAltitude().getValue(Altitude.FORMAT_METRES));
+                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
                        inWriter.write("</ele>\n");
                }
-               // timestamp if available (point might have altitude and then be turned into a waypoint)
-               if (inPoint.hasTimestamp())
+               // write waypoint name after elevation
+               inWriter.write("\t\t<name>");
+               inWriter.write(inPoint.getWaypointName().trim());
+               inWriter.write("</name>\n");
+               // timestamp if available (point might have timestamp and then be turned into a waypoint)
+               if (inPoint.hasTimestamp() && inTimestamps)
                {
                        inWriter.write("\t\t<time>");
                        inWriter.write(inPoint.getTimestamp().getText(Timestamp.FORMAT_ISO_8601));
@@ -334,23 +384,25 @@ public class GpxExporter implements Runnable
         * Export the specified trackpoint into the file
         * @param inPoint trackpoint to export
         * @param inWriter writer object
+        * @param inTimestamps true to export timestamps too
         */
-       private void exportTrackpoint(DataPoint inPoint, Writer inWriter) throws IOException
+       private static void exportTrackpoint(DataPoint inPoint, Writer inWriter, boolean inTimestamps)
+               throws IOException
        {
                inWriter.write("\t\t<trkpt lat=\"");
-               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write("\" lon=\"");
-               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write("\">");
                // altitude
                if (inPoint.hasAltitude())
                {
                        inWriter.write("<ele>");
-                       inWriter.write("" + inPoint.getAltitude().getValue(Altitude.FORMAT_METRES));
+                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
                        inWriter.write("</ele>");
                }
-               // timestamp if available
-               if (inPoint.hasTimestamp())
+               // timestamp if available (and selected)
+               if (inPoint.hasTimestamp() && inTimestamps)
                {
                        inWriter.write("<time>");
                        inWriter.write(inPoint.getTimestamp().getText(Timestamp.FORMAT_ISO_8601));