diff options
Diffstat (limited to 'main/src/cgeo/geocaching/export')
| -rw-r--r-- | main/src/cgeo/geocaching/export/FieldnoteExport.java | 52 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/export/GpxExport.java | 240 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/export/GpxSerializer.java | 255 |
3 files changed, 290 insertions, 257 deletions
diff --git a/main/src/cgeo/geocaching/export/FieldnoteExport.java b/main/src/cgeo/geocaching/export/FieldnoteExport.java index a42a48a..9d0310c 100644 --- a/main/src/cgeo/geocaching/export/FieldnoteExport.java +++ b/main/src/cgeo/geocaching/export/FieldnoteExport.java @@ -9,6 +9,8 @@ import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.settings.Settings; +import cgeo.geocaching.ui.Formatter; import cgeo.geocaching.utils.AsyncTaskWithProgress; import cgeo.geocaching.utils.IOUtils; import cgeo.geocaching.utils.Log; @@ -70,21 +72,18 @@ class FieldnoteExport extends AbstractExport { } private Dialog getExportOptionsDialog(final Geocache[] caches, final Activity activity) { - AlertDialog.Builder builder = new AlertDialog.Builder(activity); + final AlertDialog.Builder builder = new AlertDialog.Builder(activity); // AlertDialog has always dark style, so we have to apply it as well always - View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.fieldnote_export_dialog, null); + final View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.fieldnote_export_dialog, null); builder.setView(layout); final CheckBox uploadOption = (CheckBox) layout.findViewById(R.id.upload); final CheckBox onlyNewOption = (CheckBox) layout.findViewById(R.id.onlynew); - uploadOption.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - onlyNewOption.setEnabled(uploadOption.isChecked()); - } - }); + if (Settings.getFieldnoteExportDate() > 0) { + onlyNewOption.setText(getString(R.string.export_fieldnotes_onlynew) + "\n(" + Formatter.formatShortDateTime(activity, Settings.getFieldnoteExportDate()) + ')'); + } builder.setPositiveButton(R.string.export, new DialogInterface.OnClickListener() { @@ -132,13 +131,16 @@ class FieldnoteExport extends AbstractExport { final StringBuilder fieldNoteBuffer = new StringBuilder(); try { int i = 0; - for (Geocache cache : caches) { + for (final Geocache cache : caches) { if (cache.isLogOffline()) { - appendFieldNote(fieldNoteBuffer, cache, cgData.loadLogOffline(cache.getGeocode())); + final LogEntry log = cgData.loadLogOffline(cache.getGeocode()); + if (!onlyNew || onlyNew && log.date > Settings.getFieldnoteExportDate()) { + appendFieldNote(fieldNoteBuffer, cache, log); + } publishProgress(++i); } } - } catch (Exception e) { + } catch (final Exception e) { Log.e("FieldnoteExport.ExportTask generation", e); return false; } @@ -151,17 +153,17 @@ class FieldnoteExport extends AbstractExport { exportLocation.mkdirs(); - SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); + final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); exportFile = new File(exportLocation.toString() + '/' + fileNameDateFormat.format(new Date()) + ".txt"); Writer fileWriter = null; BufferedOutputStream buffer = null; try { - OutputStream os = new FileOutputStream(exportFile); + final OutputStream os = new FileOutputStream(exportFile); buffer = new BufferedOutputStream(os); fileWriter = new OutputStreamWriter(buffer, CharEncoding.UTF_16); fileWriter.write(fieldNoteBuffer.toString()); - } catch (IOException e) { + } catch (final IOException e) { Log.e("FieldnoteExport.ExportTask export", e); return false; } finally { @@ -181,17 +183,11 @@ class FieldnoteExport extends AbstractExport { } final String uri = "http://www.geocaching.com/my/uploadfieldnotes.aspx"; - String page = Network.getResponseData(Network.getRequest(uri)); + final String page = Login.getRequestLogged(uri, null); - if (!Login.getLoginStatus(page)) { - // Login.isActualLoginStatus() was wrong, we are not logged in - final StatusCode loginState = Login.login(); - if (loginState == StatusCode.NO_ERROR) { - page = Network.getResponseData(Network.getRequest(uri)); - } else { - Log.e("FieldnoteExport.ExportTask upload: No login (error: " + loginState + ')'); - return false; - } + if (StringUtils.isBlank(page)) { + Log.e("FieldnoteExport.ExportTask get page: No data from server"); + return false; } final String[] viewstates = Login.getViewstates(page); @@ -201,10 +197,6 @@ class FieldnoteExport extends AbstractExport { "__EVENTARGUMENT", "", "ctl00$ContentBody$btnUpload", "Upload Field Note"); - if (onlyNew) { - uploadParams.put("ctl00$ContentBody$chkSuppressDate", "on"); - } - Login.putViewstates(uploadParams, viewstates); Network.getResponseData(Network.postRequest(uri, uploadParams, "ctl00$ContentBody$FieldNoteLoader", "text/plain", exportFile)); @@ -222,9 +214,7 @@ class FieldnoteExport extends AbstractExport { protected void onPostExecuteInternal(Boolean result) { if (null != activity) { if (result) { - // if (onlyNew) { - // // update last export time in settings when doing it ourself (currently we use the date check from gc.com) - // } + Settings.setFieldnoteExportDate(System.currentTimeMillis()); ActivityMixin.showToast(activity, getName() + ' ' + getString(R.string.export_exportedto) + ": " + exportFile.toString()); diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java index 0ba1a3c..61be3c5 100644 --- a/main/src/cgeo/geocaching/export/GpxExport.java +++ b/main/src/cgeo/geocaching/export/GpxExport.java @@ -1,24 +1,12 @@ package cgeo.geocaching.export; import cgeo.geocaching.Geocache; -import cgeo.geocaching.LogEntry; +import cgeo.geocaching.settings.Settings; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; -import cgeo.geocaching.Waypoint; -import cgeo.geocaching.cgData; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.activity.ActivityMixin; -import cgeo.geocaching.enumerations.CacheAttribute; -import cgeo.geocaching.enumerations.LoadFlags; -import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.utils.AsyncTaskWithProgress; -import cgeo.geocaching.utils.TextUtils; import cgeo.geocaching.utils.Log; -import cgeo.geocaching.utils.XmlUtils; -import cgeo.org.kxml2.io.KXmlSerializer; - -import org.apache.commons.lang3.StringUtils; -import org.xmlpull.v1.XmlSerializer; import android.app.Activity; import android.app.AlertDialog; @@ -39,22 +27,11 @@ import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Locale; -import java.util.Set; class GpxExport extends AbstractExport { - private static final SimpleDateFormat dateFormatZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); - public static final String PREFIX_XSI = "http://www.w3.org/2001/XMLSchema-instance"; - public static final String PREFIX_GPX = "http://www.topografix.com/GPX/1/0"; - public static final String PREFIX_GROUNDSPEAK = "http://www.groundspeak.com/cache/1/0"; - - /** - * During the export, only this number of geocaches is fully loaded into memory. - */ - public static final int CACHES_PER_BATCH = 100; protected GpxExport() { super(getString(R.string.export_gpx)); @@ -62,7 +39,7 @@ class GpxExport extends AbstractExport { @Override public void export(final List<Geocache> caches, final Activity activity) { - String[] geocodes = getGeocodes(caches); + final String[] geocodes = getGeocodes(caches); if (null == activity) { // No activity given, so no user interaction possible. // Start export with default parameters. @@ -75,10 +52,10 @@ class GpxExport extends AbstractExport { } private Dialog getExportDialog(final String[] geocodes, final Activity activity) { - AlertDialog.Builder builder = new AlertDialog.Builder(activity); + final AlertDialog.Builder builder = new AlertDialog.Builder(activity); // AlertDialog has always dark style, so we have to apply it as well always - View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.gpx_export_dialog, null); + final View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.gpx_export_dialog, null); builder.setView(layout); final TextView text = (TextView) layout.findViewById(R.id.info); @@ -108,7 +85,7 @@ class GpxExport extends AbstractExport { } private static String[] getGeocodes(final List<Geocache> caches) { - ArrayList<String> allGeocodes = new ArrayList<String>(caches.size()); + final ArrayList<String> allGeocodes = new ArrayList<String>(caches.size()); for (final Geocache geocache : caches) { allGeocodes.add(geocache.getGeocode()); } @@ -117,7 +94,6 @@ class GpxExport extends AbstractExport { protected class ExportTask extends AsyncTaskWithProgress<String, File> { private final Activity activity; - private int countExported = 0; /** * Instantiates and configures the task for exporting field notes. @@ -137,7 +113,7 @@ class GpxExport extends AbstractExport { return null; } - List<String> allGeocodes = new ArrayList<String>(Arrays.asList(geocodes)); + final List<String> allGeocodes = new ArrayList<String>(Arrays.asList(geocodes)); setMessage(cgeoapplication.getInstance().getResources().getQuantityString(R.plurals.cache_counts, allGeocodes.size(), allGeocodes.size())); @@ -148,38 +124,21 @@ class GpxExport extends AbstractExport { final File exportLocation = new File(Settings.getGpxExportDir()); exportLocation.mkdirs(); - final XmlSerializer gpx = new KXmlSerializer(); writer = new BufferedWriter(new FileWriter(exportFile)); - gpx.setOutput(writer); + new GpxSerializer().writeGPX(allGeocodes, writer, new GpxSerializer.ProgressListener() { - gpx.startDocument("UTF-8", true); - gpx.setPrefix("", PREFIX_GPX); - gpx.setPrefix("xsi", PREFIX_XSI); - gpx.setPrefix("groundspeak", PREFIX_GROUNDSPEAK); - gpx.startTag(PREFIX_GPX, "gpx"); - gpx.attribute("", "version", "1.0"); - gpx.attribute("", "creator", "c:geo - http://www.cgeo.org/"); - gpx.attribute(PREFIX_XSI, "schemaLocation", - PREFIX_GPX + " http://www.topografix.com/GPX/1/0/gpx.xsd " + - PREFIX_GROUNDSPEAK + " http://www.groundspeak.com/cache/1/0/1/cache.xsd"); - - // Split the overall set of geocodes into small chunks. That is a compromise between memory efficiency (because - // we don't load all caches fully into memory) and speed (because we don't query each cache separately). - while (!allGeocodes.isEmpty()) { - final List<String> batch = allGeocodes.subList(0, Math.min(CACHES_PER_BATCH, allGeocodes.size())); - exportBatch(gpx, batch); - batch.clear(); - } - - gpx.endTag(PREFIX_GPX, "gpx"); - gpx.endDocument(); + @Override + public void publishProgress(int countExported) { + ExportTask.this.publishProgress(countExported); + } + }); } catch (final Exception e) { Log.e("GpxExport.ExportTask export", e); if (writer != null) { try { writer.close(); - } catch (IOException e1) { + } catch (final IOException e1) { // Ignore double error } } @@ -194,184 +153,13 @@ class GpxExport extends AbstractExport { return exportFile; } - private void exportBatch(final XmlSerializer gpx, Collection<String> geocodesOfBatch) throws IOException { - Set<Geocache> caches = cgData.loadCaches(geocodesOfBatch, LoadFlags.LOAD_ALL_DB_ONLY); - for (Geocache cache : caches) { - gpx.startTag(PREFIX_GPX, "wpt"); - gpx.attribute("", "lat", Double.toString(cache.getCoords().getLatitude())); - gpx.attribute("", "lon", Double.toString(cache.getCoords().getLongitude())); - - final Date hiddenDate = cache.getHiddenDate(); - if (hiddenDate != null) { - XmlUtils.simpleText(gpx, PREFIX_GPX, "time", dateFormatZ.format(hiddenDate)); - } - - XmlUtils.multipleTexts(gpx, PREFIX_GPX, - "name", cache.getGeocode(), - "desc", cache.getName(), - "url", cache.getUrl(), - "urlname", cache.getName(), - "sym", cache.isFound() ? "Geocache Found" : "Geocache", - "type", "Geocache|" + cache.getType().pattern); - - gpx.startTag(PREFIX_GROUNDSPEAK, "cache"); - gpx.attribute("", "id", cache.getCacheId()); - gpx.attribute("", "available", !cache.isDisabled() ? "True" : "False"); - gpx.attribute("", "archives", cache.isArchived() ? "True" : "False"); - - XmlUtils.multipleTexts(gpx, PREFIX_GROUNDSPEAK, - "name", cache.getName(), - "placed_by", cache.getOwnerDisplayName(), - "owner", cache.getOwnerUserId(), - "type", cache.getType().pattern, - "container", cache.getSize().id, - "difficulty", Float.toString(cache.getDifficulty()), - "terrain", Float.toString(cache.getTerrain()), - "country", cache.getLocation(), - "state", "", - "encoded_hints", cache.getHint()); - - writeAttributes(gpx, cache); - - gpx.startTag(PREFIX_GROUNDSPEAK, "short_description"); - gpx.attribute("", "html", TextUtils.containsHtml(cache.getShortDescription()) ? "True" : "False"); - gpx.text(cache.getShortDescription()); - gpx.endTag(PREFIX_GROUNDSPEAK, "short_description"); - - gpx.startTag(PREFIX_GROUNDSPEAK, "long_description"); - gpx.attribute("", "html", TextUtils.containsHtml(cache.getDescription()) ? "True" : "False"); - gpx.text(cache.getDescription()); - gpx.endTag(PREFIX_GROUNDSPEAK, "long_description"); - - writeLogs(gpx, cache); - - gpx.endTag(PREFIX_GROUNDSPEAK, "cache"); - gpx.endTag(PREFIX_GPX, "wpt"); - - writeWaypoints(gpx, cache); - - countExported++; - publishProgress(countExported); - } - } - - private void writeWaypoints(final XmlSerializer gpx, final Geocache cache) throws IOException { - List<Waypoint> waypoints = cache.getWaypoints(); - List<Waypoint> ownWaypoints = new ArrayList<Waypoint>(waypoints.size()); - List<Waypoint> originWaypoints = new ArrayList<Waypoint>(waypoints.size()); - for (Waypoint wp : cache.getWaypoints()) { - if (wp.isUserDefined()) { - ownWaypoints.add(wp); - } else { - originWaypoints.add(wp); - } - } - int maxPrefix = 0; - for (Waypoint wp : originWaypoints) { - String prefix = wp.getPrefix(); - try { - final int numericPrefix = Integer.parseInt(prefix); - maxPrefix = Math.max(numericPrefix, maxPrefix); - } catch (NumberFormatException ex) { - // ignore non numeric prefix, as it should be unique in the list of non-own waypoints already - } - writeCacheWaypoint(gpx, wp, prefix); - } - // Prefixes must be unique. There use numeric strings as prefixes in OWN waypoints - for (Waypoint wp : ownWaypoints) { - maxPrefix++; - String prefix = StringUtils.leftPad(String.valueOf(maxPrefix), 2, '0'); - writeCacheWaypoint(gpx, wp, prefix); - } - } - - /** - * Writes one waypoint entry for cache waypoint. - * - * @param cache - * The - * @param wp - * @param prefix - * @throws IOException - */ - private void writeCacheWaypoint(final XmlSerializer gpx, final Waypoint wp, final String prefix) throws IOException { - final Geopoint coords = wp.getCoords(); - // TODO: create some extension to GPX to include waypoint without coords - if (coords != null) { - gpx.startTag(PREFIX_GPX, "wpt"); - gpx.attribute("", "lat", Double.toString(coords.getLatitude())); - gpx.attribute("", "lon", Double.toString(coords.getLongitude())); - XmlUtils.multipleTexts(gpx, PREFIX_GPX, - "name", prefix + wp.getGeocode().substring(2), - "cmt", wp.getNote(), - "desc", wp.getName(), - "sym", wp.getWaypointType().toString(), //TODO: Correct identifier string - "type", "Waypoint|" + wp.getWaypointType().toString()); //TODO: Correct identifier string - gpx.endTag(PREFIX_GPX, "wpt"); - } - } - - private void writeLogs(final XmlSerializer gpx, final Geocache cache) throws IOException { - if (cache.getLogs().isEmpty()) { - return; - } - gpx.startTag(PREFIX_GROUNDSPEAK, "logs"); - - for (LogEntry log : cache.getLogs()) { - gpx.startTag(PREFIX_GROUNDSPEAK, "log"); - gpx.attribute("", "id", Integer.toString(log.id)); - - XmlUtils.multipleTexts(gpx, PREFIX_GROUNDSPEAK, - "date", dateFormatZ.format(new Date(log.date)), - "type", log.type.type); - - gpx.startTag(PREFIX_GROUNDSPEAK, "finder"); - gpx.attribute("", "id", ""); - gpx.text(log.author); - gpx.endTag(PREFIX_GROUNDSPEAK, "finder"); - - gpx.startTag(PREFIX_GROUNDSPEAK, "text"); - gpx.attribute("", "encoded", "False"); - gpx.text(log.log); - gpx.endTag(PREFIX_GROUNDSPEAK, "text"); - - gpx.endTag(PREFIX_GROUNDSPEAK, "log"); - } - - gpx.endTag(PREFIX_GROUNDSPEAK, "logs"); - } - - private void writeAttributes(final XmlSerializer gpx, final Geocache cache) throws IOException { - if (cache.getAttributes().isEmpty()) { - return; - } - //TODO: Attribute conversion required: English verbose name, gpx-id - gpx.startTag(PREFIX_GROUNDSPEAK, "attributes"); - - for (String attribute : cache.getAttributes()) { - final CacheAttribute attr = CacheAttribute.getByRawName(CacheAttribute.trimAttributeName(attribute)); - if (attr == null) { - continue; - } - final boolean enabled = CacheAttribute.isEnabled(attribute); - - gpx.startTag(PREFIX_GROUNDSPEAK, "attribute"); - gpx.attribute("", "id", Integer.toString(attr.gcid)); - gpx.attribute("", "inc", enabled ? "1" : "0"); - gpx.text(attr.getL10n(enabled)); - gpx.endTag(PREFIX_GROUNDSPEAK, "attribute"); - } - - gpx.endTag(PREFIX_GROUNDSPEAK, "attributes"); - } - @Override protected void onPostExecuteInternal(final File exportFile) { if (null != activity) { if (exportFile != null) { ActivityMixin.showToast(activity, getName() + ' ' + getString(R.string.export_exportedto) + ": " + exportFile.toString()); if (Settings.getShareAfterExport()) { - Intent shareIntent = new Intent(); + final Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(exportFile)); shareIntent.setType("application/xml"); diff --git a/main/src/cgeo/geocaching/export/GpxSerializer.java b/main/src/cgeo/geocaching/export/GpxSerializer.java new file mode 100644 index 0000000..2d25296 --- /dev/null +++ b/main/src/cgeo/geocaching/export/GpxSerializer.java @@ -0,0 +1,255 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.LogEntry; +import cgeo.geocaching.Waypoint; +import cgeo.geocaching.cgData; +import cgeo.geocaching.enumerations.CacheAttribute; +import cgeo.geocaching.enumerations.LoadFlags; +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.utils.TextUtils; +import cgeo.geocaching.utils.XmlUtils; +import cgeo.org.kxml2.io.KXmlSerializer; + +import org.apache.commons.lang3.StringUtils; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +public final class GpxSerializer { + + private static final SimpleDateFormat dateFormatZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); + public static final String PREFIX_XSI = "http://www.w3.org/2001/XMLSchema-instance"; + public static final String PREFIX_GPX = "http://www.topografix.com/GPX/1/0"; + public static final String PREFIX_GROUNDSPEAK = "http://www.groundspeak.com/cache/1/0"; + + /** + * During the export, only this number of geocaches is fully loaded into memory. + */ + public static final int CACHES_PER_BATCH = 100; + + /** + * counter for exported caches, used for progress reporting + */ + private int countExported; + private ProgressListener progressListener; + private final XmlSerializer gpx = new KXmlSerializer(); + + protected static interface ProgressListener { + + void publishProgress(int countExported); + + } + + public void writeGPX(List<String> allGeocodesIn, Writer writer, final ProgressListener progressListener) throws IOException { + // create a copy of the geocode list, as we need to modify it, but it might be immutable + final ArrayList<String> allGeocodes = new ArrayList<String>(allGeocodesIn); + + this.progressListener = progressListener; + gpx.setOutput(writer); + + gpx.startDocument("UTF-8", true); + gpx.setPrefix("", PREFIX_GPX); + gpx.setPrefix("xsi", PREFIX_XSI); + gpx.setPrefix("groundspeak", PREFIX_GROUNDSPEAK); + gpx.startTag(PREFIX_GPX, "gpx"); + gpx.attribute("", "version", "1.0"); + gpx.attribute("", "creator", "c:geo - http://www.cgeo.org/"); + gpx.attribute(PREFIX_XSI, "schemaLocation", + PREFIX_GPX + " http://www.topografix.com/GPX/1/0/gpx.xsd " + + PREFIX_GROUNDSPEAK + " http://www.groundspeak.com/cache/1/0/1/cache.xsd"); + + // Split the overall set of geocodes into small chunks. That is a compromise between memory efficiency (because + // we don't load all caches fully into memory) and speed (because we don't query each cache separately). + while (!allGeocodes.isEmpty()) { + final List<String> batch = allGeocodes.subList(0, Math.min(CACHES_PER_BATCH, allGeocodes.size())); + exportBatch(gpx, batch); + batch.clear(); + } + + gpx.endTag(PREFIX_GPX, "gpx"); + gpx.endDocument(); + } + + private void exportBatch(final XmlSerializer gpx, Collection<String> geocodesOfBatch) throws IOException { + final Set<Geocache> caches = cgData.loadCaches(geocodesOfBatch, LoadFlags.LOAD_ALL_DB_ONLY); + for (final Geocache cache : caches) { + gpx.startTag(PREFIX_GPX, "wpt"); + gpx.attribute("", "lat", Double.toString(cache.getCoords().getLatitude())); + gpx.attribute("", "lon", Double.toString(cache.getCoords().getLongitude())); + + final Date hiddenDate = cache.getHiddenDate(); + if (hiddenDate != null) { + XmlUtils.simpleText(gpx, PREFIX_GPX, "time", dateFormatZ.format(hiddenDate)); + } + + XmlUtils.multipleTexts(gpx, PREFIX_GPX, + "name", cache.getGeocode(), + "desc", cache.getName(), + "url", cache.getUrl(), + "urlname", cache.getName(), + "sym", cache.isFound() ? "Geocache Found" : "Geocache", + "type", "Geocache|" + cache.getType().pattern); + + gpx.startTag(PREFIX_GROUNDSPEAK, "cache"); + gpx.attribute("", "id", cache.getCacheId()); + gpx.attribute("", "available", !cache.isDisabled() ? "True" : "False"); + gpx.attribute("", "archives", cache.isArchived() ? "True" : "False"); + + XmlUtils.multipleTexts(gpx, PREFIX_GROUNDSPEAK, + "name", cache.getName(), + "placed_by", cache.getOwnerDisplayName(), + "owner", cache.getOwnerUserId(), + "type", cache.getType().pattern, + "container", cache.getSize().id, + "difficulty", Float.toString(cache.getDifficulty()), + "terrain", Float.toString(cache.getTerrain()), + "country", cache.getLocation(), + "state", "", + "encoded_hints", cache.getHint()); + + writeAttributes(cache); + + gpx.startTag(PREFIX_GROUNDSPEAK, "short_description"); + gpx.attribute("", "html", TextUtils.containsHtml(cache.getShortDescription()) ? "True" : "False"); + gpx.text(cache.getShortDescription()); + gpx.endTag(PREFIX_GROUNDSPEAK, "short_description"); + + gpx.startTag(PREFIX_GROUNDSPEAK, "long_description"); + gpx.attribute("", "html", TextUtils.containsHtml(cache.getDescription()) ? "True" : "False"); + gpx.text(cache.getDescription()); + gpx.endTag(PREFIX_GROUNDSPEAK, "long_description"); + + writeLogs(cache); + + gpx.endTag(PREFIX_GROUNDSPEAK, "cache"); + gpx.endTag(PREFIX_GPX, "wpt"); + + writeWaypoints(cache); + + countExported++; + if (progressListener != null) { + progressListener.publishProgress(countExported); + } + } + } + + private void writeWaypoints(final Geocache cache) throws IOException { + final List<Waypoint> waypoints = cache.getWaypoints(); + final List<Waypoint> ownWaypoints = new ArrayList<Waypoint>(waypoints.size()); + final List<Waypoint> originWaypoints = new ArrayList<Waypoint>(waypoints.size()); + for (final Waypoint wp : cache.getWaypoints()) { + if (wp.isUserDefined()) { + ownWaypoints.add(wp); + } else { + originWaypoints.add(wp); + } + } + int maxPrefix = 0; + for (final Waypoint wp : originWaypoints) { + final String prefix = wp.getPrefix(); + try { + final int numericPrefix = Integer.parseInt(prefix); + maxPrefix = Math.max(numericPrefix, maxPrefix); + } catch (final NumberFormatException ex) { + // ignore non numeric prefix, as it should be unique in the list of non-own waypoints already + } + writeCacheWaypoint(wp, prefix); + } + // Prefixes must be unique. There use numeric strings as prefixes in OWN waypoints + for (final Waypoint wp : ownWaypoints) { + maxPrefix++; + final String prefix = StringUtils.leftPad(String.valueOf(maxPrefix), 2, '0'); + writeCacheWaypoint(wp, prefix); + } + } + + /** + * Writes one waypoint entry for cache waypoint. + * + * @param cache + * The + * @param wp + * @param prefix + * @throws IOException + */ + private void writeCacheWaypoint(final Waypoint wp, final String prefix) throws IOException { + final Geopoint coords = wp.getCoords(); + // TODO: create some extension to GPX to include waypoint without coords + if (coords != null) { + gpx.startTag(PREFIX_GPX, "wpt"); + gpx.attribute("", "lat", Double.toString(coords.getLatitude())); + gpx.attribute("", "lon", Double.toString(coords.getLongitude())); + XmlUtils.multipleTexts(gpx, PREFIX_GPX, + "name", prefix + wp.getGeocode().substring(2), + "cmt", wp.getNote(), + "desc", wp.getName(), + "sym", wp.getWaypointType().toString(), //TODO: Correct identifier string + "type", "Waypoint|" + wp.getWaypointType().toString()); //TODO: Correct identifier string + gpx.endTag(PREFIX_GPX, "wpt"); + } + } + + private void writeLogs(final Geocache cache) throws IOException { + if (cache.getLogs().isEmpty()) { + return; + } + gpx.startTag(PREFIX_GROUNDSPEAK, "logs"); + + for (final LogEntry log : cache.getLogs()) { + gpx.startTag(PREFIX_GROUNDSPEAK, "log"); + gpx.attribute("", "id", Integer.toString(log.id)); + + XmlUtils.multipleTexts(gpx, PREFIX_GROUNDSPEAK, + "date", dateFormatZ.format(new Date(log.date)), + "type", log.type.type); + + gpx.startTag(PREFIX_GROUNDSPEAK, "finder"); + gpx.attribute("", "id", ""); + gpx.text(log.author); + gpx.endTag(PREFIX_GROUNDSPEAK, "finder"); + + gpx.startTag(PREFIX_GROUNDSPEAK, "text"); + gpx.attribute("", "encoded", "False"); + gpx.text(log.log); + gpx.endTag(PREFIX_GROUNDSPEAK, "text"); + + gpx.endTag(PREFIX_GROUNDSPEAK, "log"); + } + + gpx.endTag(PREFIX_GROUNDSPEAK, "logs"); + } + + private void writeAttributes(final Geocache cache) throws IOException { + if (cache.getAttributes().isEmpty()) { + return; + } + //TODO: Attribute conversion required: English verbose name, gpx-id + gpx.startTag(PREFIX_GROUNDSPEAK, "attributes"); + + for (final String attribute : cache.getAttributes()) { + final CacheAttribute attr = CacheAttribute.getByRawName(CacheAttribute.trimAttributeName(attribute)); + if (attr == null) { + continue; + } + final boolean enabled = CacheAttribute.isEnabled(attribute); + + gpx.startTag(PREFIX_GROUNDSPEAK, "attribute"); + gpx.attribute("", "id", Integer.toString(attr.gcid)); + gpx.attribute("", "inc", enabled ? "1" : "0"); + gpx.text(attr.getL10n(enabled)); + gpx.endTag(PREFIX_GROUNDSPEAK, "attribute"); + } + + gpx.endTag(PREFIX_GROUNDSPEAK, "attributes"); + } + +} |
