aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main/src/cgeo/geocaching/cgCache.java87
-rw-r--r--main/src/cgeo/geocaching/cgeoapplication.java12
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCParser.java6
-rw-r--r--main/src/cgeo/geocaching/export/GpxExport.java5
-rw-r--r--main/src/cgeo/geocaching/files/GPXParser.java2
-rw-r--r--main/src/cgeo/geocaching/utils/LazyInitializedList.java68
-rw-r--r--tests/res/raw/lazy.gpx188
-rw-r--r--tests/src/cgeo/geocaching/files/GPXParserTest.java21
-rw-r--r--tests/src/cgeo/geocaching/utils/LazyInitializedListTest.java27
9 files changed, 368 insertions, 48 deletions
diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java
index 461a15e..b38992f 100644
--- a/main/src/cgeo/geocaching/cgCache.java
+++ b/main/src/cgeo/geocaching/cgCache.java
@@ -22,6 +22,7 @@ import cgeo.geocaching.enumerations.WaypointType;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.network.HtmlImage;
import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.LazyInitializedList;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.LogTemplateProvider;
import cgeo.geocaching.utils.LogTemplateProvider.LogContext;
@@ -94,10 +95,25 @@ public class cgCache implements ICache, IWaypoint {
private float myVote = 0; // valid ratings are larger than zero
private int inventoryItems = 0;
private boolean onWatchlist = false;
- private List<String> attributes = null;
- private List<cgWaypoint> waypoints = null;
+ private LazyInitializedList<String> attributes = new LazyInitializedList<String>() {
+ @Override
+ protected List<String> loadFromDatabase() {
+ return cgeoapplication.getInstance().loadAttributes(geocode);
+ }
+ };
+ private LazyInitializedList<cgWaypoint> waypoints = new LazyInitializedList<cgWaypoint>() {
+ @Override
+ protected List<cgWaypoint> loadFromDatabase() {
+ return cgeoapplication.getInstance().loadWaypoints(geocode);
+ }
+ };
private List<cgImage> spoilers = null;
- private List<LogEntry> logs = null;
+ private LazyInitializedList<LogEntry> logs = new LazyInitializedList<LogEntry>() {
+ @Override
+ protected List<LogEntry> loadFromDatabase() {
+ return cgeoapplication.getInstance().loadLogs(geocode);
+ }
+ };
private List<cgTrackable> inventory = null;
private Map<LogType, Integer> logCounts = new HashMap<LogType, Integer>();
private boolean logOffline = false;
@@ -253,14 +269,16 @@ public class cgCache implements ICache, IWaypoint {
if (myVote == 0) {
myVote = other.myVote;
}
- if (attributes == null) {
- attributes = other.attributes;
+ if (attributes.isEmpty()) {
+ attributes.set(other.attributes.get());
}
- if (waypoints == null) {
- waypoints = other.waypoints;
+ if (waypoints.isEmpty()) {
+ waypoints.set(other.waypoints.get());
}
else {
- cgWaypoint.mergeWayPoints(waypoints, other.getWaypoints(), waypoints == null || waypoints.isEmpty());
+ ArrayList<cgWaypoint> newPoints = new ArrayList<cgWaypoint>(waypoints.get());
+ cgWaypoint.mergeWayPoints(newPoints, other.getWaypoints(), false);
+ waypoints.set(newPoints);
}
if (spoilers == null) {
spoilers = other.spoilers;
@@ -273,8 +291,8 @@ public class cgCache implements ICache, IWaypoint {
inventory = other.inventory;
inventoryItems = other.inventoryItems;
}
- if (CollectionUtils.isEmpty(logs)) { // keep last known logs if none
- logs = other.logs;
+ if (logs.isEmpty()) { // keep last known logs if none
+ logs.set(other.logs.get());
}
if (logCounts.size() == 0) {
logCounts = other.logCounts;
@@ -674,10 +692,7 @@ public class cgCache implements ICache, IWaypoint {
@Override
public List<String> getAttributes() {
- if (attributes == null) {
- return Collections.emptyList();
- }
- return Collections.unmodifiableList(attributes);
+ return Collections.unmodifiableList(attributes.get());
}
@Override
@@ -900,10 +915,7 @@ public class cgCache implements ICache, IWaypoint {
* @return always non <code>null</code>
*/
public List<cgWaypoint> getWaypoints() {
- if (waypoints == null) {
- return Collections.emptyList();
- }
- return Collections.unmodifiableList(waypoints);
+ return Collections.unmodifiableList(waypoints.get());
}
/**
@@ -915,7 +927,7 @@ public class cgCache implements ICache, IWaypoint {
* @return <code>true</code> if waypoints successfully added to waypoint database
*/
public boolean setWaypoints(List<cgWaypoint> waypoints, boolean saveToDatabase) {
- this.waypoints = waypoints;
+ this.waypoints.set(waypoints);
finalDefined = false;
if (waypoints != null) {
for (cgWaypoint waypoint : waypoints) {
@@ -929,8 +941,11 @@ public class cgCache implements ICache, IWaypoint {
return saveToDatabase && cgeoapplication.getInstance().saveWaypoints(this);
}
+ /**
+ * @return never <code>null</code>, but an empty collection instead
+ */
public List<LogEntry> getLogs() {
- return getLogs(true);
+ return Collections.unmodifiableList(getLogs(true));
}
/**
@@ -939,14 +954,11 @@ public class cgCache implements ICache, IWaypoint {
* @return the logs with all entries or just the entries of the friends, never <code>null</code>
*/
public List<LogEntry> getLogs(boolean allLogs) {
- if (logs == null) {
- return Collections.emptyList();
- }
if (allLogs) {
- return logs;
+ return logs.get();
}
ArrayList<LogEntry> friendLogs = new ArrayList<LogEntry>();
- for (LogEntry log : logs) {
+ for (LogEntry log : logs.get()) {
if (log.friend) {
friendLogs.add(log);
}
@@ -959,7 +971,7 @@ public class cgCache implements ICache, IWaypoint {
* the log entries
*/
public void setLogs(List<LogEntry> logs) {
- this.logs = logs;
+ this.logs.set(logs);
}
public boolean isLogOffline() {
@@ -1056,7 +1068,7 @@ public class cgCache implements ICache, IWaypoint {
}
public void setAttributes(List<String> attributes) {
- this.attributes = attributes;
+ this.attributes.set(attributes);
}
public void setSpoilers(List<cgImage> spoilers) {
@@ -1122,10 +1134,6 @@ public class cgCache implements ICache, IWaypoint {
* @return <code>true</code> if waypoint successfully added to waypoint database
*/
public boolean addOrChangeWaypoint(final cgWaypoint waypoint, boolean saveToDatabase) {
- if (null == waypoints) {
- waypoints = new ArrayList<cgWaypoint>();
- }
-
waypoint.setGeocode(geocode);
if (waypoint.getId() <= 0) { // this is a new waypoint
@@ -1147,7 +1155,7 @@ public class cgCache implements ICache, IWaypoint {
}
public boolean hasWaypoints() {
- return CollectionUtils.isNotEmpty(waypoints);
+ return !waypoints.isEmpty();
}
public boolean hasFinalDefined() {
@@ -1263,7 +1271,7 @@ public class cgCache implements ICache, IWaypoint {
* @return waypoint or <code>null</code> if index is out of range
*/
public cgWaypoint getWaypoint(final int index) {
- return waypoints != null && index >= 0 && index < waypoints.size() ? waypoints.get(index) : null;
+ return index >= 0 && index < waypoints.size() ? waypoints.get(index) : null;
}
/**
@@ -1314,27 +1322,18 @@ public class cgCache implements ICache, IWaypoint {
}
public void addAttribute(final String attribute) {
- if (attributes == null) {
- attributes = new ArrayList<String>();
- }
attributes.add(attribute);
}
public boolean hasAttributes() {
- return attributes != null && attributes.size() > 0;
+ return !attributes.isEmpty();
}
public void prependLog(final LogEntry log) {
- if (logs == null) {
- logs = new ArrayList<LogEntry>();
- }
- logs.add(0, log);
+ logs.prepend(log);
}
public void appendLog(final LogEntry log) {
- if (logs == null) {
- logs = new ArrayList<LogEntry>();
- }
logs.add(log);
}
diff --git a/main/src/cgeo/geocaching/cgeoapplication.java b/main/src/cgeo/geocaching/cgeoapplication.java
index 572420d..9e221cd 100644
--- a/main/src/cgeo/geocaching/cgeoapplication.java
+++ b/main/src/cgeo/geocaching/cgeoapplication.java
@@ -489,4 +489,16 @@ public class cgeoapplication extends Application {
return storage.getTrackableCodes();
}
+ public List<LogEntry> loadLogs(final String geocode) {
+ return storage.loadLogs(geocode);
+ }
+
+ public List<String> loadAttributes(final String geocode) {
+ return storage.loadAttributes(geocode);
+ }
+
+ public List<cgWaypoint> loadWaypoints(final String geocode) {
+ return storage.loadWaypoints(geocode);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java
index 218d4fc..778db24 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCParser.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java
@@ -498,6 +498,7 @@ public abstract class GCParser {
if (null != attributesPre) {
final Matcher matcherAttributesInside = GCConstants.PATTERN_ATTRIBUTESINSIDE.matcher(attributesPre);
+ final ArrayList<String> attributes = new ArrayList<String>();
while (matcherAttributesInside.find()) {
if (matcherAttributesInside.groupCount() > 1 && !matcherAttributesInside.group(2).equalsIgnoreCase("blank")) {
// by default, use the tooltip of the attribute
@@ -512,9 +513,10 @@ public abstract class GCParser {
attribute = imageName.substring(start + 1, end).replace('-', '_').toLowerCase();
}
}
- cache.addAttribute(attribute);
+ attributes.add(attribute);
}
}
+ cache.setAttributes(attributes);
}
} catch (Exception e) {
// failed to parse cache attributes
@@ -1634,7 +1636,7 @@ public abstract class GCParser {
if (allLogs.contains(log)) {
allLogs.get(allLogs.indexOf(log)).friend = true;
} else {
- allLogs.add(log);
+ cache.appendLog(log);
}
}
}
diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java
index 73287da..a97bf0a 100644
--- a/main/src/cgeo/geocaching/export/GpxExport.java
+++ b/main/src/cgeo/geocaching/export/GpxExport.java
@@ -351,12 +351,13 @@ class GpxExport extends AbstractExport {
}
private void writeLogs(final cgCache cache) throws IOException {
- if (cache.getLogs().size() <= 0) {
+ final List<LogEntry> logs = cache.getLogs();
+ if (logs.size() <= 0) {
return;
}
gpx.write("<groundspeak:logs>");
- for (LogEntry log : cache.getLogs()) {
+ for (LogEntry log : logs) {
gpx.write("<groundspeak:log id=\"");
gpx.write(Integer.toString(log.id));
gpx.write("\">");
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java
index ea26a66..a6a285f 100644
--- a/main/src/cgeo/geocaching/files/GPXParser.java
+++ b/main/src/cgeo/geocaching/files/GPXParser.java
@@ -855,6 +855,8 @@ public abstract class GPXParser extends FileParser {
cache = new cgCache();
cache.setReliableLatLon(true);
+ cache.setAttributes(new ArrayList<String>());
+ cache.setWaypoints(new ArrayList<cgWaypoint>(), false);
for (int i = 0; i < userData.length; i++) {
userData[i] = null;
}
diff --git a/main/src/cgeo/geocaching/utils/LazyInitializedList.java b/main/src/cgeo/geocaching/utils/LazyInitializedList.java
new file mode 100644
index 0000000..6061394
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/LazyInitializedList.java
@@ -0,0 +1,68 @@
+package cgeo.geocaching.utils;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public abstract class LazyInitializedList<ElementType> implements Iterable<ElementType> {
+
+ private List<ElementType> list;
+
+ public List<ElementType> get() {
+ initializeList();
+ return list;
+ }
+
+ private void initializeList() {
+ if (list == null) {
+ list = loadFromDatabase();
+ }
+ }
+
+ protected abstract List<ElementType> loadFromDatabase();
+
+ public void add(final ElementType element) {
+ initializeList();
+ list.add(element);
+ }
+
+ public void prepend(final ElementType element) {
+ initializeList();
+ list.add(0, element);
+ }
+
+ public void set(final List<ElementType> elements) {
+ list = new ArrayList<ElementType>(elements);
+ }
+
+ public boolean isEmpty() {
+ initializeList();
+ return list.isEmpty();
+ }
+
+ public ElementType remove(final int index) {
+ initializeList();
+ return list.remove(index);
+ }
+
+ public void add(int index, final ElementType element) {
+ initializeList();
+ list.add(index, element);
+ }
+
+ public int size() {
+ initializeList();
+ return list.size();
+ }
+
+ @Override
+ public Iterator<ElementType> iterator() {
+ initializeList();
+ return list.iterator();
+ }
+
+ public ElementType get(final int index) {
+ initializeList();
+ return list.get(index);
+ }
+}
diff --git a/tests/res/raw/lazy.gpx b/tests/res/raw/lazy.gpx
new file mode 100644
index 0000000..5186abc
--- /dev/null
+++ b/tests/res/raw/lazy.gpx
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ manually created GPX file
+-->
+<gpx xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" creator="Groundspeak Pocket Query" xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0 http://www.groundspeak.com/cache/1/0/cache.xsd" xmlns="http://www.topografix.com/GPX/1/0">
+ <name>Testdata</name>
+ <desc>Geocache file generated by Groundspeak</desc>
+ <author>Groundspeak</author>
+ <email>contact@groundspeak.com</email>
+ <time>2011-09-16T21:13:25.1723847Z</time>
+ <keywords>cache, geocache, groundspeak</keywords>
+ <bounds minlat="49.3187" minlon="8.54565" maxlat="49.3187" maxlon="8.54565" />
+ <wpt lat="49.3187" lon="8.54565">
+ <time>2011-08-05T07:00:00Z</time>
+ <name>GC31J2H</name>
+ <desc>Hockenheimer City-Brunnen by vptsz, Multi-cache (2/1)</desc>
+ <url>http://www.geocaching.com/seek/cache_details.aspx?guid=0eba627b-bc4c-4e37-9bae-80dad5b97815</url>
+ <urlname>Hockenheimer City-Brunnen</urlname>
+ <sym>Geocache Found</sym>
+ <type>Geocache|Multi-cache</type>
+ <groundspeak:cache id="2406611" available="True" archived="False" xmlns:groundspeak="http://www.groundspeak.com/cache/1/0">
+<groundspeak:attributes>
+<groundspeak:attribute id="3" inc="1">Climbing gear</groundspeak:attribute>
+<groundspeak:attribute id="5" inc="1">Scuba gear</groundspeak:attribute>
+<groundspeak:attribute id="18" inc="1">Snakes</groundspeak:attribute>
+<groundspeak:attribute id="20" inc="1">Abandoned mines</groundspeak:attribute>
+<groundspeak:attribute id="21" inc="1">Cliff / falling rocks</groundspeak:attribute>
+<groundspeak:attribute id="43" inc="1">Watch for livestock</groundspeak:attribute>
+</groundspeak:attributes>
+ <groundspeak:name>Hockenheimer City-Brunnen</groundspeak:name>
+ <groundspeak:placed_by>vptsz</groundspeak:placed_by>
+ <groundspeak:owner id="3639006">vptsz</groundspeak:owner>
+ <groundspeak:type>Multi-cache</groundspeak:type>
+ <groundspeak:container>Small</groundspeak:container>
+ <groundspeak:difficulty>2</groundspeak:difficulty>
+ <groundspeak:terrain>1</groundspeak:terrain>
+ <groundspeak:country>Germany</groundspeak:country>
+ <groundspeak:state>Baden-Württemberg</groundspeak:state>
+ <groundspeak:short_description html="False">Kurzer informativer Multi entlang der Brunnen und einer Reihe von sehenswerten Gebäuden in der Hockenheimer Innenstadt. Ortskundige haben einen kleinen Heimvorteil. Dennoch müssen auch sie an allen Stationen die Frage beantworten, um zum Final gelangen zu können.</groundspeak:short_description>
+ <groundspeak:long_description html="False">Cachemobile können kostenfrei am Messplatz geparkt werden. Von da aus geht es in einem Rundweg durch die Hockenheimer "City". Die Stationen liegen an und um sehenswerte Brunnen.
+
+1. Station: Brunnen an der Kraichbachbrücke (N 49° 19.122 E 008° 32.739)
+
+Der Kraichbach fließt, bewacht von den Blicken des Brückenheiligen Nepomuk, durch Hockenheims Innenstadt. Renaturierungs- und Hochwasserschutzmaßnahmen beeinflussten den Verlauf des Baches und werden ihn auch künftig weiter verändern. Dieses Gebäude am Bach beherbergte einst das Rheintal Radio und bis 2011 die Hockenheimer Tageszeitung.
+
+Frage: Wann wurde Nepomuk erneuert?
+
+Jahreszahl = ABCD
+
+2. Station: Brunnen an der Fortuna-Kreuzung (N 49° 19.ADD E 008° 32.BCA)
+
+Die versetzte Straßenkreuzung Untere/Obere Hauptstraße wird von den Hockenheimern Fortuna-Kreuzung genannt. Dort, wo heute das Sparkassengebäude steht, stand früher das Gasthaus Fortuna, in dessen Mauern ehemals die älteste Brauerei (es gab hier mal 8 Brauereien!) untergebracht war.
+
+Nebenan findet man das Wirtshaus Zum Güldnen Engel. Es ist eines der traditionsreichsten Häuser in Hockenheim. Im unteren Teil des Hauses befindet sich eine Eisdiele - unsere Lieblingseisdiele! Diese lädt an warmen Tagen zum Verweilen und Erfrischen ein.
+
+Frage: Wann wurde der Güldene Engel errichtet?
+
+Quersumme der Jahreszahl = E
+
+3. Station: Brunnen auf dem Marktplatz (N 49° 19.(102+E) E 008° (2*E+1).0AD)
+
+Eingerahmt von der ev. Kirche, der Pestalozzischule und der Stadthalle liegt der Hockenheimer Marktplatz. Wenn auch der Wochenmarkt seit einiger Zeit sein neues Zuhause auf dem Platz an der Zehntscheuer hat, bietet der Marktplatz Raum für allerlei Veranstaltungen. Hier sei besonders der Hockenheimer Advent (am 1. Adventswochenende) hervorzuheben. Erwähnenswert ist an dieser Stelle auch die links von der Kirche gelegene Brauerei zum Stadtpark.
+
+Frage: Wie viele rote Steine befinden sich oben an der höchsten Säule des Brunnens?
+
+Anzahl rote Steine = F
+
+4. Station: Brunnen an der Zehntscheuer (N 49° 19.08(F-6) E 008° 32.8(2*F+1)
+
+Das Gebäude der Zehntscheuer wurde 2010 am jetzigen Standort wieder eröffnet. Die Scheuer stand früher in der Zähringerstraße - zwischen Karlsruherstraße und Ebertpark, dort wurde sie abgetragen und auf dem Patz hinter dem katholischen Gemeindehaus St. Christopherus mit neuen Elementen wieder aufgebaut. Die Zehntscheuer beherbergt seit ihrem Umzug die Bücherei und das Tabakmuseum. Auf dem Platz zwischen Brunnen und Zehntscheuer findet mittwochs und samstags der Hockenheimer Wochenmarkt statt.
+
+Was ist eine Zehntscheuer? In der Zehntscheuer mussten die Bauern jährlich den "Zehnt" an ihre Herren abliefern. Der Zehnt waren Naturalabgaben, vor allem Getreide und Gemüse, aber auch Heu oder Vieh. Diese Abgaben wurden in der Zehntscheuer aufbewahrt.
+
+Frage: Wie viele rot umrahmte Fenster befinden sich an der vom Brunnen aus gesehen Stirnseite der Zehntscheuer?
+
+Anzahl Fenster = G
+
+5. Station: Mühlenbrunnen (N 49° 19.0(30+G) E 008° 32.B0(G-D)
+
+In früheren Jahren standen in Hockenheim am Kraichbach drei Mühlen. Die letzte der Hockenheimer Mühlen wurden in den 1960er Jahren von der Stadt abrissen - heute steht an dieser Stelle ein Wohnblock. Nur der Brunnen erinnert noch an die einstigen Mühlen in der Stadt.
+
+Frage: Wie viele Mäuse ärgern den Müller?
+
+Anzahl Mäuse = H
+
+6. Final
+
+Wenn Ihr alle Fragen richtig beantwortet habt, dann könnt Ihr den Final hier finden:
+
+N 049° 1(D*H)(A+B)(B*C+D-A) E 008° 3(E+F)(G*H)
+
+Auf dem Weg dorthin passiert Ihr einen ehemals belebten und seinerzeit nett ausgestatteten Ort, der auch einen tollen Brunnen beherbergte. Mittlerweile ist es eher ein "Lost Place", aber wir hoffen, dass er im Laufe der Zeit erneuert werden wird.
+
+Inhalt: Die Box beeinhaltet Logbuch und Stift. Für die ersten Finder haben wir als Goodie zwei TBs und einen Original Apple-Ohrhörer (neu) hineingelegt.
+
+Viel Spaß beim Suchen,
+vptsz
+
+P.S.: Bitte die Dose vorsichtig bergen und sorgfältig wiederverstecken. Es muss kein Privatgelände betreten werden. Erhöhte Muggelgefahr!
+
+Additional Waypoints
+0031J2H - Parkplatz
+N 49° 19.051 E 008° 32.705
+Kostenfreies Parken (je nach Parkreihe Parkscheibe erforderlich)
+0131J2H - Brunnen1
+N/S __ ° __ . ___ W/E ___ ° __ . ___
+Wann wurde Nepomuk erneuert?
+Jahreszahl = ABCD
+0231J2H - Brunnen2
+N/S __ ° __ . ___ W/E ___ ° __ . ___
+Wann wurde der Güldene Engel errichtet?
+Quersumme der Jahreszahl = E
+0331J2H - Brunnen3
+N/S __ ° __ . ___ W/E ___ ° __ . ___
+Wie viele rote Steine befinden sich oben an der höchsten Säulen des Brunnens?
+Anzahl rote Steine = F
+0431J2H - Brunnen4
+N/S __ ° __ . ___ W/E ___ ° __ . ___
+Wie viele rot umrahmte Fenster befinden sich an der vom Brunnen aus gesehenen Stirnseite der Zehntscheuer?
+Anzahl Fenster = G
+0531J2H - Brunnen5
+N/S __ ° __ . ___ W/E ___ ° __ . ___
+Frage: Wie viele Mäuse ärgern den Müller?
+Anzahl Mäuse = H
+FN31J2H - Final
+N/S __ ° __ . ___ W/E ___ ° __ . ___
+
+</groundspeak:long_description>
+ <groundspeak:encoded_hints>Station3: Der zerbrochene Stein zählt doppelt.
+Final: Oben neben dem Tor</groundspeak:encoded_hints>
+ <groundspeak:logs>
+ <groundspeak:log id="186806513">
+ <groundspeak:date>2011-09-16T19:00:00Z</groundspeak:date>
+ <groundspeak:type>Found it</groundspeak:type>
+ <groundspeak:finder id="429672">hanslinde</groundspeak:finder>
+ <groundspeak:text encoded="False">Jetzt kennen wir aber Hockenheim schon ganz gut, denn noch nicht so lange her,
+waren wir als "Pilger" unterwegs und heute spazierten wir wieder zu netten
+Plätzen in Hockenheim und diese City-Brunnen Runde hat uns gut gefallen [:D]!
+Der letzte Brunnen war uns schon sehr bekannt [;)], aber der ist so nett
+gemacht, dass wir hier wieder etwas verweilten.
+Beim Final wurden wir schnell fündig und trugen uns gerne ins Logbuch ein [^].
+Vielen Dank für diese Stadtführung und sonnige Grüße von hanslinde</groundspeak:text>
+ </groundspeak:log>
+ <groundspeak:log id="186713161">
+ <groundspeak:date>2011-09-15T19:00:00Z</groundspeak:date>
+ <groundspeak:type>Found it</groundspeak:type>
+ <groundspeak:finder id="1493325">Ute und Conny</groundspeak:finder>
+ <groundspeak:text encoded="False">heute nachmittag habe ich mir mal die Hockenheimer Brunnen angesehen. Gleich an der ersten Stage hat es Nepomuk wohl nicht mehr gefallen und er ist ca. 20m Richtung Rhein gewandert. Dort konnte ich ihn allerdings antreffen und anschließend meine Tour fortsetzen. Am besten hat mir der letzte Brunnen gefallen. Das Final fand ich dann um 13.20h und verewigte mich im Logbuch.
+Danke für Cache #2045
+Ute und Conny</groundspeak:text>
+ </groundspeak:log>
+ <groundspeak:log id="186235831">
+ <groundspeak:date>2011-09-11T19:00:00Z</groundspeak:date>
+ <groundspeak:type>Found it</groundspeak:type>
+ <groundspeak:finder id="1083716">Badner-Bub</groundspeak:finder>
+ <groundspeak:text encoded="False">Die schöne Runde haben wir gerade noch vor dem Sturm abgeschlossem. Da bin ich froh, dass ich den Rechenfehler noch rechtzeitig behoben habe. Danke für ne nette Runde.
+TFTC</groundspeak:text>
+ </groundspeak:log>
+ <groundspeak:log id="185959809">
+ <groundspeak:date>2011-09-11T19:00:00Z</groundspeak:date>
+ <groundspeak:type>Found it</groundspeak:type>
+ <groundspeak:finder id="3751187">AnSiVa</groundspeak:finder>
+ <groundspeak:text encoded="False">Danke für den interessanten Multi.
+Hat alle prima gepaßt. Beim Final kamen erst Zweifel auf aber dann hatten wir ihn. Ein schönes Plätzchen.</groundspeak:text>
+ </groundspeak:log>
+ <groundspeak:log id="185945356">
+ <groundspeak:date>2011-09-11T19:00:00Z</groundspeak:date>
+ <groundspeak:type>Found it</groundspeak:type>
+ <groundspeak:finder id="1931031">B39</groundspeak:finder>
+ <groundspeak:text encoded="False">#550 Schöne Runde durch Hockenheim. Trotz Unklarheit über die Anzahl der zerbrochenen roten Steinen mit Hilfe des Hints gut gefunden. TFTC B39
+IN: TB + Coin</groundspeak:text>
+ </groundspeak:log>
+ <groundspeak:log id="185890848">
+ <groundspeak:date>2011-09-11T07:00:00Z</groundspeak:date>
+ <groundspeak:type>Found it</groundspeak:type>
+ <groundspeak:finder id="2557167">Geoteufel</groundspeak:finder>
+ <groundspeak:text encoded="False">Sehr schöne Runde und wir haben wieder etwas Neues über Hockenheim gelernt. Super Tarnung.
+TFTC, Geoteufel</groundspeak:text>
+ </groundspeak:log>
+ </groundspeak:logs>
+ <groundspeak:travelbugs>
+ <groundspeak:travelbug id="1729111" ref="TB29V2P">
+ <groundspeak:name>2008 NCOG Horse Race: Cache or Charge?</groundspeak:name>
+ </groundspeak:travelbug>
+ </groundspeak:travelbugs>
+ </groundspeak:cache>
+ </wpt>
+</gpx> \ No newline at end of file
diff --git a/tests/src/cgeo/geocaching/files/GPXParserTest.java b/tests/src/cgeo/geocaching/files/GPXParserTest.java
index 4b4f286..6f8a76d 100644
--- a/tests/src/cgeo/geocaching/files/GPXParserTest.java
+++ b/tests/src/cgeo/geocaching/files/GPXParserTest.java
@@ -7,6 +7,7 @@ import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
+import cgeo.geocaching.enumerations.LoadFlags.LoadFlag;
import cgeo.geocaching.enumerations.WaypointType;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.test.AbstractResourceInstrumentationTestCase;
@@ -18,6 +19,7 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -253,4 +255,23 @@ public class GPXParserTest extends AbstractResourceInstrumentationTestCase {
assertTrue(codes.contains("GC2KN6K"));
assertTrue(codes.contains("GC1T3MK"));
}
+
+ public void testLazyLogLoading() throws IOException, ParserException {
+ // this test should be in CacheTest, but it is easier to create here due to the GPX import abilities
+ final String geocode = "GC31J2H";
+ removeCacheCompletely(geocode);
+ final List<cgCache> caches = readGPX10(R.raw.lazy);
+ assertEquals(1, caches.size());
+ cgeoapplication.getInstance().removeAllFromCache();
+
+ // load only the minimum cache, it has several members missing
+ final cgCache minimalCache = cgeoapplication.getInstance().loadCache(geocode, EnumSet.of(LoadFlag.LOAD_DB_MINIMAL));
+
+ // now check that we load lazy members on demand
+ assertFalse(minimalCache.getAttributes().isEmpty());
+ assertFalse(minimalCache.getLogs().isEmpty());
+
+ removeCacheCompletely(geocode);
+ }
+
}
diff --git a/tests/src/cgeo/geocaching/utils/LazyInitializedListTest.java b/tests/src/cgeo/geocaching/utils/LazyInitializedListTest.java
new file mode 100644
index 0000000..1d0767e
--- /dev/null
+++ b/tests/src/cgeo/geocaching/utils/LazyInitializedListTest.java
@@ -0,0 +1,27 @@
+package cgeo.geocaching.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class LazyInitializedListTest extends TestCase {
+ public static void testAccess() {
+ final LazyInitializedList<String> list = new LazyInitializedList<String>() {
+ @Override
+ protected List<String> loadFromDatabase() {
+ return new ArrayList<String>();
+ }
+ };
+ assertTrue(list.isEmpty());
+ list.add("Test");
+ assertFalse(list.isEmpty());
+ assertEquals(1, list.size());
+ int iterations = 0;
+ for (String element : list) {
+ assertEquals("Test", element);
+ iterations++;
+ }
+ assertEquals(1, iterations);
+ }
+}