import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
-import java.nio.charset.Charset;
import javax.swing.BorderFactory;
import javax.swing.Box;
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
import tim.prune.config.Config;
-import tim.prune.data.Altitude;
import tim.prune.data.AudioClip;
import tim.prune.data.Coordinate;
import tim.prune.data.DataPoint;
import tim.prune.data.RecentFile;
import tim.prune.data.Timestamp;
import tim.prune.data.TrackInfo;
+import tim.prune.data.UnitSetLibrary;
import tim.prune.gui.DialogCloser;
import tim.prune.load.GenericFileFilter;
import tim.prune.save.xml.GpxCacherList;
private JPanel _encodingsPanel = null;
private JRadioButton _useSystemRadio = null, _forceUtf8Radio = null;
private File _exportFile = null;
- private static String _systemEncoding = null;
/** this program name */
private static final String GPX_CREATOR = "GpsPrune v" + GpsPrune.VERSION_NUMBER + " activityworkshop.net";
_dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
_dialog.setLocationRelativeTo(_parentFrame);
_dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- _systemEncoding = getSystemEncoding();
_dialog.getContentPane().add(makeDialogComponents());
_dialog.pack();
}
_pointTypeSelector.init(_app.getTrackInfo());
- _encodingsPanel.setVisible(!isSystemUtf8());
- if (!isSystemUtf8()) {
+ _encodingsPanel.setVisible(!XmlUtils.isSystemUtf8());
+ if (!XmlUtils.isSystemUtf8())
+ {
+ String systemEncoding = XmlUtils.getSystemEncoding();
_useSystemRadio.setText(I18nManager.getText("dialog.exportgpx.encoding.system")
- + " (" + (_systemEncoding == null ? "unknown" : _systemEncoding) + ")");
+ + " (" + (systemEncoding == null ? "unknown" : systemEncoding) + ")");
}
_dialog.setVisible(true);
}
mainPanel.add(checkPanel);
// panel for selecting character encoding
_encodingsPanel = new JPanel();
- if (!isSystemUtf8())
+ if (!XmlUtils.isSystemUtf8())
{
// only add this panel if system isn't utf8 (or can't be identified yet)
_encodingsPanel.setBorder(BorderFactory.createCompoundBorder(
*/
public void run()
{
+ // Instantiate source file cachers in case we want to copy output
+ GpxCacherList gpxCachers = null;
+ if (_copySourceCheckbox.isSelected()) {
+ gpxCachers = new GpxCacherList(_trackInfo.getFileInfo());
+ }
OutputStreamWriter writer = null;
try
{
_pointTypeSelector.getJustSelection(), _timestampsCheckbox.isSelected()};
// write file
final int numPoints = exportData(writer, _trackInfo, _nameField.getText(),
- _descriptionField.getText(), saveFlags, _copySourceCheckbox.isSelected());
+ _descriptionField.getText(), saveFlags, gpxCachers);
// close file
writer.close();
* @param inName name of track (optional)
* @param inDesc description of track (optional)
* @param inSaveFlags array of booleans to export tracks, waypoints, photos, audios, selection, timestamps
- * @param inUseCopy true to copy source if available
+ * @param inGpxCachers list of Gpx cachers containing input data
* @return number of points written
* @throws IOException if io errors occur on write
*/
public static int exportData(OutputStreamWriter inWriter, TrackInfo inInfo, String inName,
- String inDesc, boolean[] inSaveFlags, boolean inUseCopy) throws IOException
+ String inDesc, boolean[] inSaveFlags, GpxCacherList inGpxCachers) throws IOException
{
- // Instantiate source file cachers in case we want to copy output
- GpxCacherList gpxCachers = null;
- if (inUseCopy) gpxCachers = new GpxCacherList(inInfo.getFileInfo());
// Write or copy headers
inWriter.write(getXmlHeaderString(inWriter));
- inWriter.write(getGpxHeaderString(gpxCachers));
+ final String gpxHeader = getGpxHeaderString(inGpxCachers);
+ final boolean isVersion1_1 = (gpxHeader.toUpperCase().indexOf("GPX/1/1") > 0);
+ inWriter.write(gpxHeader);
// Name field
- String trackName = "GpsPruneTrack";
- if (inName != null && !inName.equals(""))
- {
- trackName = inName;
- inWriter.write("\t<name>");
- inWriter.write(trackName);
- inWriter.write("</name>\n");
- }
- // Description field
- inWriter.write("\t<desc>");
- inWriter.write((inDesc != null && !inDesc.equals(""))?inDesc:"Export from GpsPrune");
- inWriter.write("</desc>\n");
+ String trackName = (inName != null && !inName.equals("")) ? inName : "GpsPruneTrack";
+ writeNameAndDescription(inWriter, inName, inDesc, isVersion1_1);
int i = 0;
DataPoint point = null;
// Make a wpt element for each waypoint
if (point.isWaypoint() && exportWaypoints)
{
- String pointSource = (inUseCopy?getPointSource(gpxCachers, point):null);
- if (pointSource != null) {
+ String pointSource = (inGpxCachers == null? null : getPointSource(inGpxCachers, point));
+ if (pointSource != null)
+ {
+ // If timestamp checkbox is off, strip time
+ if (!exportTimestamps) {
+ pointSource = stripTime(pointSource);
+ }
+ inWriter.write('\t');
inWriter.write(pointSource);
inWriter.write('\n');
}
{
// Output all route points (if any)
numSaved += writeTrackPoints(inWriter, inInfo, exportSelection, exportTrackpoints, exportPhotos,
- exportAudios, exportTimestamps, true, gpxCachers, "<rtept", "\t<rte><number>1</number>\n",
+ exportAudios, exportTimestamps, true, inGpxCachers, "<rtept", "\t<rte><number>1</number>\n",
null, "\t</rte>\n");
// Output all track points, if any
- String trackStart = "\t<trk><name>" + trackName + "</name><number>1</number><trkseg>\n";
+ String trackStart = "\t<trk>\n\t\t<name>" + trackName + "</name>\n\t\t<number>1</number>\n\t\t<trkseg>\n";
numSaved += writeTrackPoints(inWriter, inInfo, exportSelection, exportTrackpoints, exportPhotos,
- exportAudios, exportTimestamps, false, gpxCachers, "<trkpt", trackStart,
- "\t</trkseg>\n\t<trkseg>\n", "\t</trkseg></trk>\n");
+ exportAudios, exportTimestamps, false, inGpxCachers, "<trkpt", trackStart,
+ "\t</trkseg>\n\t<trkseg>\n", "\t\t</trkseg>\n\t</trk>\n");
}
inWriter.write("</gpx>\n");
}
+ /**
+ * Write the name and description according to the GPX version number
+ * @param inWriter writer object
+ * @param inName name, or null if none supplied
+ * @param inDesc description, or null if none supplied
+ * @param inIsVersion1_1 true if gpx version 1.1, false for version 1.0
+ */
+ private static void writeNameAndDescription(OutputStreamWriter inWriter,
+ String inName, String inDesc, boolean inIsVersion1_1) throws IOException
+ {
+ String desc = (inDesc != null && !inDesc.equals("")) ? inDesc : "Export from GpsPrune";
+ // Position of name and description fields needs to be different for GPX1.0 and GPX1.1
+ if (inIsVersion1_1)
+ {
+ // GPX 1.1 has the name and description inside a metadata tag
+ inWriter.write("\t<metadata>\n");
+ }
+ if (inName != null && !inName.equals(""))
+ {
+ if (inIsVersion1_1) {inWriter.write('\t');}
+ inWriter.write("\t<name>");
+ inWriter.write(inName);
+ inWriter.write("</name>\n");
+ }
+ if (inIsVersion1_1) {inWriter.write('\t');}
+ inWriter.write("\t<desc>");
+ inWriter.write(desc);
+ inWriter.write("</desc>\n");
+ if (inIsVersion1_1)
+ {
+ inWriter.write("\t</metadata>\n");
+ }
+ }
+
/**
* Loop through the track outputting the relevant track points
* @param inWriter writer object for output
// get the source from the point (if any)
String pointSource = getPointSource(inCachers, point);
// Clear point source if it's the wrong type of point (eg changed from waypoint or route point)
- if (pointSource != null && !pointSource.toLowerCase().startsWith(inPointTag)) {pointSource = null;}
+ if (pointSource != null && !pointSource.trim().toLowerCase().startsWith(inPointTag)) {
+ pointSource = null;
+ }
if (pointSource != null || !inOnlyCopies)
{
// restart track segment if necessary
inWriter.write(inSegmentTag);
}
if (numSaved == 0) {inWriter.write(inStartTag);}
- if (pointSource != null) {
+ if (pointSource != null)
+ {
+ // If timestamps checkbox is off, strip the time
+ if (!exportTimestamps) {
+ pointSource = stripTime(pointSource);
+ }
inWriter.write(pointSource);
inWriter.write('\n');
}
// Point has been modified - maybe it's possible to modify the source
source = replaceGpxTags(source, "lat=\"", "\"", inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
source = replaceGpxTags(source, "lon=\"", "\"", inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
- source = replaceGpxTags(source, "<ele>", "</ele>", inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
+ source = replaceGpxTags(source, "<ele>", "</ele>", inPoint.getAltitude().getStringValue(UnitSetLibrary.UNITS_METRES));
source = replaceGpxTags(source, "<time>", "</time>", inPoint.getTimestamp().getText(Timestamp.FORMAT_ISO_8601));
if (inPoint.isWaypoint())
{
*/
private static String getXmlHeaderString(OutputStreamWriter inWriter)
{
- return "<?xml version=\"1.0\" encoding=\"" + getEncoding(inWriter) + "\"?>\n";
+ return "<?xml version=\"1.0\" encoding=\"" + XmlUtils.getEncoding(inWriter) + "\"?>\n";
}
- /**
- * Get the default system encoding using a writer
- * @param inWriter writer object
- * @return string defining encoding
- */
- private static String getEncoding(OutputStreamWriter inWriter)
- {
- String encoding = inWriter.getEncoding();
- try {
- encoding = Charset.forName(encoding).name();
- }
- catch (Exception e) {} // ignore failure to find encoding
- // Hack to fix bugs with Mac OSX (which reports MacRoman but is actually UTF-8)
- if (encoding == null || encoding.toLowerCase().startsWith("macroman")) {
- encoding = "UTF-8";
- }
- return encoding;
- }
-
-
- /**
- * Use a temporary file to obtain the name of the default system encoding
- * @return name of default system encoding, or null if write failed
- */
- private static String getSystemEncoding()
- {
- File tempFile = null;
- String encoding = null;
- try
- {
- tempFile = File.createTempFile("prune", null);
- OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(tempFile));
- encoding = getEncoding(writer);
- writer.close();
- }
- catch (IOException e) {} // value stays null
- // Delete temp file
- if (tempFile != null && tempFile.exists()) {
- if (!tempFile.delete()) {
- System.err.println("Cannot delete temp file: " + tempFile.getAbsolutePath());
- }
- }
- // If writing failed (eg permissions) then just ask system for default
- if (encoding == null) encoding = Charset.defaultCharset().name();
- return encoding;
- }
-
- /**
- * Creates temp file if necessary to check system encoding
- * @return true if system uses UTF-8 by default
- */
- private static boolean isSystemUtf8()
- {
- if (_systemEncoding == null) _systemEncoding = getSystemEncoding();
- return (_systemEncoding != null && _systemEncoding.toUpperCase().equals("UTF-8"));
- }
-
/**
* Get the header string for the gpx tag
* @param inCachers cacher list to ask for headers, if available
if (inCachers != null) {gpxHeader = inCachers.getFirstHeader();}
if (gpxHeader == null || gpxHeader.length() < 5)
{
+ // TODO: Consider changing this to default to GPX 1.1
// Create default (1.0) header
gpxHeader = "<gpx version=\"1.0\" creator=\"" + GPX_CREATOR
+ "\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
if (inPoint.hasAltitude())
{
inWriter.write("\t\t<ele>");
- inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
+ inWriter.write("" + inPoint.getAltitude().getStringValue(UnitSetLibrary.UNITS_METRES));
inWriter.write("</ele>\n");
}
// timestamp if available (point might have timestamp and then be turned into a waypoint)
boolean inExportPhoto, boolean inExportAudio)
throws IOException
{
- inWriter.write("\t\t<trkpt lat=\"");
+ inWriter.write("\t\t\t<trkpt lat=\"");
inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
inWriter.write("\" lon=\"");
inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
- inWriter.write("\">");
+ inWriter.write("\">\n");
// altitude
if (inPoint.hasAltitude())
{
- inWriter.write("<ele>");
- inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
- inWriter.write("</ele>");
+ inWriter.write("\t\t\t\t<ele>");
+ inWriter.write("" + inPoint.getAltitude().getStringValue(UnitSetLibrary.UNITS_METRES));
+ inWriter.write("</ele>\n");
}
// timestamp if available (and selected)
if (inPoint.hasTimestamp() && inTimestamps)
{
- inWriter.write("<time>");
+ inWriter.write("\t\t\t\t<time>");
inWriter.write(inPoint.getTimestamp().getText(Timestamp.FORMAT_ISO_8601));
- inWriter.write("</time>");
+ inWriter.write("</time>\n");
}
// photo, audio
if (inPoint.getPhoto() != null && inExportPhoto) {
if (inPoint.getAudio() != null && inExportAudio) {
inWriter.write(makeMediaLink(inPoint.getAudio()));
}
- inWriter.write("</trkpt>\n");
+ inWriter.write("\t\t\t</trkpt>\n");
}
// No link available, must have been loaded from zip file - no link possible
return "";
}
+
+
+ /**
+ * Strip the time from a GPX point source string
+ * @param inPointSource point source to copy
+ * @return point source with timestamp removed
+ */
+ private static String stripTime(String inPointSource)
+ {
+ return inPointSource.replaceAll("[ \t]*<time>.*?</time>", "");
+ }
}