aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorrsudev <rasch@munin-soft.de>2013-11-23 22:12:24 +0100
committerrsudev <rasch@munin-soft.de>2013-11-23 22:13:06 +0100
commit652722134c0d18dbe77dd952903a71ae14755d27 (patch)
treed3613d8d906b938de5d612b5f75b3cc72605f9c2 /main
parent6240d934fc7e0d6b52fdf3b2cf21d0e72fdbf7c7 (diff)
downloadcgeo-652722134c0d18dbe77dd952903a71ae14755d27.zip
cgeo-652722134c0d18dbe77dd952903a71ae14755d27.tar.gz
cgeo-652722134c0d18dbe77dd952903a71ae14755d27.tar.bz2
Implements stable keys for opencaching waypoints
additionally extend ex- and import (gpx) to also contain visited and userdefined.
Diffstat (limited to 'main')
-rw-r--r--main/project/xsd/cgeo.xsd16
-rw-r--r--main/src/cgeo/geocaching/DataStore.java14
-rw-r--r--main/src/cgeo/geocaching/Geocache.java8
-rw-r--r--main/src/cgeo/geocaching/Waypoint.java21
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractConnector.java12
-rw-r--r--main/src/cgeo/geocaching/connector/IConnector.java19
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java18
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiClient.java1
-rw-r--r--main/src/cgeo/geocaching/export/GpxSerializer.java59
-rw-r--r--main/src/cgeo/geocaching/files/GPXParser.java57
10 files changed, 193 insertions, 32 deletions
diff --git a/main/project/xsd/cgeo.xsd b/main/project/xsd/cgeo.xsd
new file mode 100644
index 0000000..35a5983
--- /dev/null
+++ b/main/project/xsd/cgeo.xsd
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.cgeo.org/wptext/1/0" elementFormDefault="qualified">
+<xsd:annotation><xsd:documentation>
+This schema defines additional properties c:geo needs to store in a waypoint in a gpx file.
+The root element is intended to be used in the appropriate extension point in the gpx waypoint type
+(see http://www.topografix.com/GPX/1/0/gpx.xsd or http://www.topografix.com/GPX/1/1/gpx.xsd for details)
+Currently two items are defined: visited and userdefined.
+</xsd:documentation></xsd:annotation>
+<xsd:element name="cgeo">
+<xsd:complexType>
+<xsd:sequence>
+<xsd:element name="visited" type="xsd:boolean" />
+<xsd:element name="userdefined" type="xsd:boolean" />
+</xsd:sequence>
+</xsd:complexType></xsd:element>
+</xsd:schema> \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/DataStore.java b/main/src/cgeo/geocaching/DataStore.java
index a231e8b..9075d45 100644
--- a/main/src/cgeo/geocaching/DataStore.java
+++ b/main/src/cgeo/geocaching/DataStore.java
@@ -1107,7 +1107,7 @@ public class DataStore {
try {
saveAttributesWithoutTransaction(cache);
- saveOriginalWaypointsWithoutTransaction(cache);
+ saveWaypointsWithoutTransaction(cache);
saveSpoilersWithoutTransaction(cache);
saveLogsWithoutTransaction(cache.getGeocode(), cache.getLogs());
saveLogCountsWithoutTransaction(cache);
@@ -1175,7 +1175,7 @@ public class DataStore {
database.beginTransaction();
try {
- saveOriginalWaypointsWithoutTransaction(cache);
+ saveWaypointsWithoutTransaction(cache);
database.setTransactionSuccessful();
return true;
} catch (Exception e) {
@@ -1186,7 +1186,7 @@ public class DataStore {
return false;
}
- private static void saveOriginalWaypointsWithoutTransaction(final Geocache cache) {
+ private static void saveWaypointsWithoutTransaction(final Geocache cache) {
String geocode = cache.getGeocode();
List<Waypoint> waypoints = cache.getWaypoints();
@@ -1195,10 +1195,6 @@ public class DataStore {
ContentValues values = new ContentValues();
long timeStamp = System.currentTimeMillis();
for (Waypoint oneWaypoint : waypoints) {
- if (oneWaypoint.isUserDefined()) {
- currentWaypointIds.add(Integer.toString(oneWaypoint.getId()));
- continue;
- }
values.clear();
values.put("geocode", geocode);
@@ -1227,7 +1223,7 @@ public class DataStore {
/**
* remove all waypoints of the given cache, where the id is not in the given list
- *
+ *
* @param cache
* @param remainingWaypointIds
* ids of waypoints which shall not be deleted
@@ -1239,7 +1235,7 @@ public class DataStore {
/**
* Save coordinates into a ContentValues
- *
+ *
* @param values
* a ContentValues to save coordinates in
* @param oneWaypoint
diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java
index 8cfedb3..731f214 100644
--- a/main/src/cgeo/geocaching/Geocache.java
+++ b/main/src/cgeo/geocaching/Geocache.java
@@ -1771,4 +1771,12 @@ public class Geocache implements ICache, IWaypoint {
public void setLogPasswordRequired(boolean required) {
logPasswordRequired = required;
}
+
+ public String getWaypointGpxId(String prefix) {
+ return getConnector().getWaypointGpxId(prefix, geocode);
+ }
+
+ public String getWaypointPrefix(String name) {
+ return getConnector().getWaypointPrefix(name);
+ }
}
diff --git a/main/src/cgeo/geocaching/Waypoint.java b/main/src/cgeo/geocaching/Waypoint.java
index facd914..dda83d9 100644
--- a/main/src/cgeo/geocaching/Waypoint.java
+++ b/main/src/cgeo/geocaching/Waypoint.java
@@ -1,5 +1,6 @@
package cgeo.geocaching;
+import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.WaypointType;
import cgeo.geocaching.geopoint.Geopoint;
@@ -265,4 +266,24 @@ public class Waypoint implements IWaypoint {
return left.order() - right.order();
}
};
+
+ /**
+ * Delegates the creation of the waypoint-id for gpx-export to the waypoint
+ *
+ * @param prefix
+ * @return
+ */
+ public String getGpxId() {
+
+ String gpxId = prefix;
+
+ if (StringUtils.isNotBlank(geocode)) {
+ Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
+ if (cache != null) {
+ gpxId = cache.getWaypointGpxId(prefix);
+ }
+ }
+
+ return gpxId;
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java
index 3ec0580..b10366e 100644
--- a/main/src/cgeo/geocaching/connector/AbstractConnector.java
+++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java
@@ -188,4 +188,16 @@ public abstract class AbstractConnector implements IConnector {
}
return logTypes;
}
+
+ @Override
+ public String getWaypointGpxId(String prefix, String geocode) {
+ // Default: just return the prefix
+ return prefix;
+ }
+
+ @Override
+ public String getWaypointPrefix(String name) {
+ // Default: just return the name
+ return name;
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java
index 2262e47..a96ee10 100644
--- a/main/src/cgeo/geocaching/connector/IConnector.java
+++ b/main/src/cgeo/geocaching/connector/IConnector.java
@@ -215,9 +215,26 @@ public interface IConnector {
/**
* Get the list of <b>potentially</b> possible log types for a cache. Those may still be filter further during the
* actual logging activity.
- *
+ *
* @param geocache
* @return
*/
public List<LogType> getPossibleLogTypes(Geocache geocache);
+
+ /**
+ * Get the gpx id for a waypoint when exporting. For some connectors there is an inherent name logic,
+ * for others its just the 'prefix'
+ *
+ * @param prefix
+ * @return
+ */
+ public String getWaypointGpxId(String prefix, String geocode);
+
+ /**
+ * Get the 'prefix' (key) for a waypoint from the 'name' in the gpx file
+ *
+ * @param name
+ * @return
+ */
+ public String getWaypointPrefix(String name);
}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
index d5f7bf4..6a61405 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
@@ -335,4 +335,22 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
public boolean isLoggedIn() {
return Login.isActualLoginStatus();
}
+
+ @Override
+ public String getWaypointGpxId(String prefix, String geocode) {
+ String gpxId = prefix;
+ if (StringUtils.isNotBlank(geocode) && geocode.length() > 2) {
+ gpxId += geocode.substring(2);
+ }
+ return gpxId;
+ }
+
+ @Override
+ public String getWaypointPrefix(String name) {
+ String prefix = name;
+ if (StringUtils.isNotBlank(prefix) && prefix.length() >= 2) {
+ prefix = name.substring(0, 2);
+ }
+ return prefix;
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
index 686e314..24e30e7 100644
--- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
@@ -445,6 +445,7 @@ final class OkapiClient {
if (result == null) {
result = new ArrayList<Waypoint>();
}
+ wpt.setPrefix(wpt.getName());
result.add(wpt);
} catch (final JSONException e) {
Log.e("OkapiClient.parseWaypoints", e);
diff --git a/main/src/cgeo/geocaching/export/GpxSerializer.java b/main/src/cgeo/geocaching/export/GpxSerializer.java
index 3ff8879..7d6067e 100644
--- a/main/src/cgeo/geocaching/export/GpxSerializer.java
+++ b/main/src/cgeo/geocaching/export/GpxSerializer.java
@@ -33,6 +33,8 @@ public final class GpxSerializer {
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";
+ public static final String PREFIX_GSAK = "http://www.gsak.net/xmlv1/4";
+ public static final String PREFIX_CGEO = "http://www.cgeo.org/wptext/1/0";
/**
* During the export, only this number of geocaches is fully loaded into memory.
@@ -63,12 +65,15 @@ public final class GpxSerializer {
gpx.setPrefix("", PREFIX_GPX);
gpx.setPrefix("xsi", PREFIX_XSI);
gpx.setPrefix("groundspeak", PREFIX_GROUNDSPEAK);
+ gpx.setPrefix("gsak", PREFIX_GSAK);
+ gpx.setPrefix("cgeo", PREFIX_CGEO);
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");
+ PREFIX_GROUNDSPEAK + " http://www.groundspeak.com/cache/1/0/1/cache.xsd " +
+ PREFIX_GSAK + " http://www.gsak.net/xmlv1/4/gsak.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).
@@ -150,29 +155,35 @@ public final class GpxSerializer {
final List<Waypoint> waypoints = cache.getWaypoints();
final List<Waypoint> ownWaypoints = new ArrayList<Waypoint>(waypoints.size());
final List<Waypoint> originWaypoints = new ArrayList<Waypoint>(waypoints.size());
+ int maxPrefix = 0;
for (final Waypoint wp : cache.getWaypoints()) {
+
+ // Retrieve numerical prefixes to have a basis for assigning prefixes to own waypoints
+ final String prefix = wp.getPrefix();
+ if (StringUtils.isNotBlank(prefix)) {
+ 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
+ }
+ }
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);
+ writeCacheWaypoint(wp);
}
- // Prefixes must be unique. There use numeric strings as prefixes in OWN waypoints
+ // Prefixes must be unique. There use numeric strings as prefixes in OWN waypoints where they are missing
for (final Waypoint wp : ownWaypoints) {
- maxPrefix++;
- final String prefix = StringUtils.leftPad(String.valueOf(maxPrefix), 2, '0');
- writeCacheWaypoint(wp, prefix);
+ if (StringUtils.isBlank(wp.getPrefix()) || StringUtils.equalsIgnoreCase("OWN", wp.getPrefix())) {
+ maxPrefix++;
+ wp.setPrefix(StringUtils.leftPad(String.valueOf(maxPrefix), 2, '0'));
+ }
+ writeCacheWaypoint(wp);
}
}
@@ -185,7 +196,7 @@ public final class GpxSerializer {
* @param prefix
* @throws IOException
*/
- private void writeCacheWaypoint(final Waypoint wp, final String prefix) throws IOException {
+ private void writeCacheWaypoint(final Waypoint wp) throws IOException {
final Geopoint coords = wp.getCoords();
// TODO: create some extension to GPX to include waypoint without coords
if (coords != null) {
@@ -193,11 +204,27 @@ public final class GpxSerializer {
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),
+ "name", wp.getGpxId(),
"cmt", wp.getNote(),
"desc", wp.getName(),
"sym", wp.getWaypointType().toString(), //TODO: Correct identifier string
"type", "Waypoint|" + wp.getWaypointType().toString()); //TODO: Correct identifier string
+ // add parent reference the GSAK-way
+ gpx.startTag(PREFIX_GSAK, "wptExtension");
+ gpx.startTag(PREFIX_GSAK, "Parent");
+ gpx.text(wp.getGeocode());
+ gpx.endTag(PREFIX_GSAK, "Parent");
+ gpx.endTag(PREFIX_GSAK, "wptExtension");
+ if (wp.isVisited()) {
+ gpx.startTag(PREFIX_CGEO, "visited");
+ gpx.text("true");
+ gpx.endTag(PREFIX_CGEO, "visited");
+ }
+ if (wp.isUserDefined()) {
+ gpx.startTag(PREFIX_CGEO, "userdefined");
+ gpx.text("true");
+ gpx.endTag(PREFIX_CGEO, "userdefined");
+ }
gpx.endTag(PREFIX_GPX, "wpt");
}
}
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java
index e01c191..3e96291 100644
--- a/main/src/cgeo/geocaching/files/GPXParser.java
+++ b/main/src/cgeo/geocaching/files/GPXParser.java
@@ -70,9 +70,14 @@ public abstract class GPXParser extends FileParser {
* supported GSAK extension of the GPX format
*/
private static final String[] GSAK_NS = new String[] {
+ "http://www.gsak.net/xmlv1/4",
"http://www.gsak.net/xmlv1/5",
"http://www.gsak.net/xmlv1/6"
};
+ /**
+ * c:geo extensions of the gpx format
+ */
+ private static final String CGEO_NS = "http://www.cgeo.org/wptext/1/0";
private static final Pattern PATTERN_MILLISECONDS = Pattern.compile("\\.\\d{3,7}");
@@ -90,6 +95,9 @@ public abstract class GPXParser extends FileParser {
private String cmt = null;
private String desc = null;
protected final String[] userData = new String[5]; // take 5 cells, that makes indexing 1..4 easier
+ private String parentCacheCode = null;
+ private boolean wptVisited = false;
+ private boolean wptUserDefined = false;
/**
* Parser result. Maps geocode to cache.
@@ -328,20 +336,25 @@ public abstract class GPXParser extends FileParser {
private void addWaypointToCache() {
fixCache(cache);
- if (cache.getName().length() > 2) {
- final String cacheGeocodeForWaypoint = "GC" + cache.getName().substring(2).toUpperCase(Locale.US);
+ if (cache.getName().length() > 2 || StringUtils.isNotBlank(parentCacheCode)) {
+ if (StringUtils.isBlank(parentCacheCode)) {
+ parentCacheCode = "GC" + cache.getName().substring(2).toUpperCase(Locale.US);
+ }
// lookup cache for waypoint in already parsed caches
- final Geocache cacheForWaypoint = DataStore.loadCache(cacheGeocodeForWaypoint, LoadFlags.LOAD_CACHE_OR_DB);
+ final Geocache cacheForWaypoint = DataStore.loadCache(parentCacheCode, LoadFlags.LOAD_CACHE_OR_DB);
if (cacheForWaypoint != null) {
final Waypoint waypoint = new Waypoint(cache.getShortDescription(), convertWaypointSym2Type(sym), false);
+ if (wptUserDefined) {
+ waypoint.setUserDefined();
+ }
waypoint.setId(-1);
- waypoint.setGeocode(cacheGeocodeForWaypoint);
- waypoint.setPrefix(cache.getName().substring(0, 2));
+ waypoint.setGeocode(parentCacheCode);
+ waypoint.setPrefix(cacheForWaypoint.getWaypointPrefix(cache.getName()));
waypoint.setLookup("---");
// there is no lookup code in gpx file
waypoint.setCoords(cache.getCoords());
waypoint.setNote(cache.getDescription());
-
+ waypoint.setVisited(wptVisited);
final ArrayList<Waypoint> mergedWayPoints = new ArrayList<Waypoint>();
mergedWayPoints.addAll(cacheForWaypoint.getWaypoints());
@@ -480,8 +493,37 @@ public abstract class GPXParser extends FileParser {
for (int i = 2; i <= 4; i++) {
gsak.getChild(gsakNamespace, "User" + i).setEndTextElementListener(new UserDataListener(i));
}
+
+ gsak.getChild(gsakNamespace, "Parent").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String body) {
+ parentCacheCode = body;
+ }
+ });
}
+ // c:geo extensions
+ final Element cgeoVisited = cacheParent.getChild(CGEO_NS, "visited");
+
+ cgeoVisited.setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String visited) {
+ wptVisited = Boolean.valueOf(visited.trim());
+ }
+ });
+
+ final Element cgeoUserDefined = cacheParent.getChild(CGEO_NS, "userdefined");
+
+ cgeoUserDefined.setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String userDefined) {
+ wptUserDefined = Boolean.valueOf(userDefined.trim());
+ }
+ });
+
// 3 different versions of the GC schema
for (final String nsGC : GROUNDSPEAK_NAMESPACE) {
// waypoints.cache
@@ -869,6 +911,9 @@ public abstract class GPXParser extends FileParser {
name = null;
desc = null;
cmt = null;
+ parentCacheCode = null;
+ wptVisited = false;
+ wptUserDefined = false;
cache = new Geocache(this);