aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorrsudev <rasch@munin-soft.de>2011-08-31 09:45:04 -0700
committerrsudev <rasch@munin-soft.de>2011-08-31 09:45:04 -0700
commitcd51f9ec96c1842ca15343491c93de2cb50f5bb9 (patch)
treebc3b828e6b6c96b08352334085afe274fad8e483 /src
parentd0dbb9cf45719b69b691d7b13b79c1ed9befab7e (diff)
parentf083df4fd71ba7da380254dc3d79c4f95628fce1 (diff)
downloadcgeo-cd51f9ec96c1842ca15343491c93de2cb50f5bb9.zip
cgeo-cd51f9ec96c1842ca15343491c93de2cb50f5bb9.tar.gz
cgeo-cd51f9ec96c1842ca15343491c93de2cb50f5bb9.tar.bz2
Merge pull request #327 from koem/master
GPX import of attributes (fix for #299)
Diffstat (limited to 'src')
-rw-r--r--src/cgeo/geocaching/cgData.java14
-rw-r--r--src/cgeo/geocaching/cgeodetail.java95
-rw-r--r--src/cgeo/geocaching/files/GPXParser.java164
3 files changed, 243 insertions, 30 deletions
diff --git a/src/cgeo/geocaching/cgData.java b/src/cgeo/geocaching/cgData.java
index ab24864..a8c6eda 100644
--- a/src/cgeo/geocaching/cgData.java
+++ b/src/cgeo/geocaching/cgData.java
@@ -35,7 +35,7 @@ public class cgData {
private cgDbHelper dbHelper = null;
private SQLiteDatabase databaseRO = null;
private SQLiteDatabase databaseRW = null;
- private static final int dbVersion = 55;
+ private static final int dbVersion = 56;
private static final String dbName = "data";
private static final String dbTableCaches = "cg_caches";
private static final String dbTableLists = "cg_lists";
@@ -778,6 +778,18 @@ public class cgData {
}
}
+
+ // make all internal attribute names lowercase
+ // @see issue #299
+ if (oldVersion < 56) { // update to 56
+ try {
+ db.execSQL("update " + dbTableAttributes + " set attribute = " +
+ "lower(attribute) where attribute like \"%_yes\" " +
+ "or attribute like \"%_no\"");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 56: " + e.toString());
+ }
+ }
}
db.setTransactionSuccessful();
diff --git a/src/cgeo/geocaching/cgeodetail.java b/src/cgeo/geocaching/cgeodetail.java
index e4d748c..48b6430 100644
--- a/src/cgeo/geocaching/cgeodetail.java
+++ b/src/cgeo/geocaching/cgeodetail.java
@@ -86,9 +86,15 @@ public class cgeodetail extends AbstractActivity {
private ProgressDialog watchlistDialog = null; // progress dialog for watchlist add/remove
private Thread watchlistThread = null; // thread for watchlist add/remove
private HashMap<Integer, String> calendars = new HashMap<Integer, String>();
+
private ViewGroup attributeIconsLayout; // layout for attribute icons
private ViewGroup attributeDescriptionsLayout; // layout for attribute descriptions
private boolean attributesShowAsIcons = true; // default: show icons
+ /** <code>noAttributeImagesFound</code>
+ * This will be the case if the cache was imported with an older version of c:geo.
+ * These older versions parsed the attribute description from the tooltip in the web
+ * page and put them into the DB. No icons can be matched for these. */
+ private boolean noAttributeIconsFound = false;
private int attributeBoxMaxWidth;
private Handler storeCacheHandler = new Handler() {
@@ -801,7 +807,8 @@ public class cgeodetail extends AbstractActivity {
// cache attributes
if (cache.attributes != null && cache.attributes.size() > 0) {
- final LinearLayout attribBox = (LinearLayout) findViewById(R.id.attributes_innerbox);
+ final LinearLayout attribBox = (LinearLayout) findViewById(
+ R.id.attributes_innerbox);
// maximum width for attribute icons is screen width - paddings of parents
attributeBoxMaxWidth = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
@@ -827,10 +834,18 @@ public class cgeodetail extends AbstractActivity {
} );
// icons or text?
- if (attributesShowAsIcons)
+ //
+ // also show icons when noAttributeImagesFound == true. Explanation:
+ // 1. no icons could be found in the first invocation of this method
+ // 2. user refreshes cache from web
+ // 3. now this method is called again
+ // 4. attributeShowAsIcons is false but noAttributeImagesFound is true
+ // => try to show them now
+ if (attributesShowAsIcons || noAttributeIconsFound) {
showAttributeIcons(attribBox, attributeBoxMaxWidth);
- else
+ } else {
showAttributeDescriptions(attribBox);
+ }
findViewById(R.id.attributes_box).setVisibility(View.VISIBLE);
}
@@ -1926,8 +1941,14 @@ public class cgeodetail extends AbstractActivity {
* and makes it visible
*/
private void showAttributeIcons(LinearLayout attribBox, int parentWidth) {
- if (attributeIconsLayout == null)
+ if (attributeIconsLayout == null) {
attributeIconsLayout = createAttributeIconsLayout(parentWidth);
+ // no matching icons found? show text
+ if (noAttributeIconsFound) {
+ showAttributeDescriptions(attribBox);
+ return;
+ }
+ }
attribBox.removeAllViews();
attribBox.addView(attributeIconsLayout);
attributesShowAsIcons = true;
@@ -1938,8 +1959,9 @@ public class cgeodetail extends AbstractActivity {
* and makes it visible
*/
private void showAttributeDescriptions(LinearLayout attribBox) {
- if (attributeDescriptionsLayout == null)
+ if (attributeDescriptionsLayout == null) {
attributeDescriptionsLayout = createAttributeDescriptionsLayout();
+ }
attribBox.removeAllViews();
attribBox.addView(attributeDescriptionsLayout);
attributesShowAsIcons = false;
@@ -1949,10 +1971,17 @@ public class cgeodetail extends AbstractActivity {
* toggle attribute descriptions and icons
*/
private void toggleAttributeDisplay(LinearLayout attribBox, int parentWidth) {
- if (attributesShowAsIcons)
+ // Don't toggle when there are no icons to show.
+ if (noAttributeIconsFound) {
+ return;
+ }
+
+ // toggle
+ if (attributesShowAsIcons) {
showAttributeDescriptions(attribBox);
- else
+ } else {
showAttributeIcons(attribBox, parentWidth);
+ }
}
private ViewGroup createAttributeIconsLayout(int parentWidth) {
@@ -1963,11 +1992,14 @@ public class cgeodetail extends AbstractActivity {
LinearLayout attributeRow = newAttributeIconsRow();
rows.addView(attributeRow);
+ noAttributeIconsFound = true;
+
for(String attributeName : cache.attributes) {
boolean strikethru = attributeName.endsWith("_no");
// cut off _yes / _no
- if (attributeName.endsWith("_no") || attributeName.endsWith("_yes"))
+ if (attributeName.endsWith("_no") || attributeName.endsWith("_yes")) {
attributeName = attributeName.substring(0, attributeName.lastIndexOf("_"));
+ }
// check if another attribute icon fits in this row
attributeRow.measure(0, 0);
int rowWidth = attributeRow.getMeasuredWidth();
@@ -1981,26 +2013,30 @@ public class cgeodetail extends AbstractActivity {
// dynamically search icon of the attribute
Drawable d = null;
- int id = res.getIdentifier("attribute_" + attributeName, "drawable", base.context.getPackageName());
- if (id > 0)
+ int id = res.getIdentifier("attribute_" + attributeName, "drawable",
+ base.context.getPackageName());
+ if (id > 0) {
+ noAttributeIconsFound = false;
d = res.getDrawable(id);
- else
+ iv.setImageDrawable(d);
+ // strike through?
+ if (strikethru) {
+ // generate strikethru image with same properties as attribute image
+ ImageView strikethruImage = new ImageView(this);
+ strikethruImage.setLayoutParams(iv.getLayoutParams());
+ d = res.getDrawable(R.drawable.attribute__strikethru);
+ strikethruImage.setImageDrawable(d);
+ fl.addView(strikethruImage);
+ }
+ } else {
d = res.getDrawable(R.drawable.attribute_icon_not_found);
- iv.setImageDrawable(d);
-
- // strike through?
- if (strikethru) {
- // generate strikethru image with same properties as attribute image
- ImageView strikethruImage = new ImageView(this);
- strikethruImage.setLayoutParams(iv.getLayoutParams());
- d = res.getDrawable(R.drawable.attribute__strikethru);
- strikethruImage.setImageDrawable(d);
- fl.addView(strikethruImage);
- }
+ iv.setImageDrawable(d);
+ }
+
attributeRow.addView(fl);
}
- return rows;
+ return rows;
}
private LinearLayout newAttributeIconsRow() {
@@ -2012,7 +2048,8 @@ public class cgeodetail extends AbstractActivity {
}
private ViewGroup createAttributeDescriptionsLayout() {
- final LinearLayout descriptions = (LinearLayout) inflater.inflate(R.layout.attribute_descriptions, null);
+ final LinearLayout descriptions = (LinearLayout) inflater.inflate(
+ R.layout.attribute_descriptions, null);
TextView attribView = (TextView) descriptions.getChildAt(0);
StringBuilder buffer = new StringBuilder();
@@ -2021,18 +2058,20 @@ public class cgeodetail extends AbstractActivity {
attribute = cache.attributes.get(i);
// dynamically search for a translation of the attribute
- int id = res.getIdentifier("attribute_" + attribute, "string", base.context.getPackageName());
+ int id = res.getIdentifier("attribute_" + attribute, "string",
+ base.context.getPackageName());
if (id > 0) {
String translated = res.getString(id);
if (translated != null && translated.length() > 0) {
attribute = translated;
}
}
- if (buffer.length() > 0) {
- buffer.append('\n');
- }
+ if (buffer.length() > 0) buffer.append('\n');
buffer.append(attribute);
}
+
+ if (noAttributeIconsFound)
+ buffer.append("\n\n").append(res.getString(R.string.cache_attributes_no_icons));
attribView.setText(buffer);
diff --git a/src/cgeo/geocaching/files/GPXParser.java b/src/cgeo/geocaching/files/GPXParser.java
index c96e30c..14607bf 100644
--- a/src/cgeo/geocaching/files/GPXParser.java
+++ b/src/cgeo/geocaching/files/GPXParser.java
@@ -23,6 +23,7 @@ import android.sax.RootElement;
import android.sax.StartElementListener;
import android.util.Log;
import android.util.Xml;
+import cgeo.geocaching.R;
import cgeo.geocaching.cgBase;
import cgeo.geocaching.cgCache;
import cgeo.geocaching.cgLog;
@@ -54,12 +55,129 @@ public abstract class GPXParser extends FileParser {
private cgCache cache = new cgCache();
private cgTrackable trackable = new cgTrackable();
private cgLog log = new cgLog();
+ private CacheAttribute cacheAttribute = null;
private String type = null;
private String sym = null;
private String name = null;
private String cmt = null;
private String desc = null;
+
+ private class CacheAttribute {
+ // List of cache attributes matching IDs used in GPX files.
+ // The ID is represented by the position of the String in the array.
+ // Strings are not used as text but as resource IDs of strings, just to be aware of changes
+ // made in strings.xml which then will lead to compile errors here and not to runtime errors.
+ private final int[] CACHE_ATTRIBUTES = {
+ -1, // 0
+ R.string.attribute_dogs_yes, // 1
+ R.string.attribute_fee_yes, // 2
+ R.string.attribute_rappelling_yes, // 3
+ R.string.attribute_boat_yes, // 4
+ R.string.attribute_scuba_yes, // 5
+ R.string.attribute_kids_yes, // 6
+ R.string.attribute_onehour_yes, // 7
+ R.string.attribute_scenic_yes, // 8
+ R.string.attribute_hiking_yes, // 9
+ R.string.attribute_climbing_yes, // 10
+ R.string.attribute_wading_yes, // 11
+ R.string.attribute_swimming_yes, // 12
+ R.string.attribute_available_yes, // 13
+ R.string.attribute_night_yes, // 14
+ R.string.attribute_winter_yes, // 15
+ -1, // 16
+ R.string.attribute_poisonoak_yes, // 17
+ R.string.attribute_dangerousanimals_yes, // 18
+ R.string.attribute_ticks_yes, // 19
+ R.string.attribute_mine_yes, // 20
+ R.string.attribute_cliff_yes, // 21
+ R.string.attribute_hunting_yes, // 22
+ R.string.attribute_danger_yes, // 23
+ R.string.attribute_wheelchair_yes, // 24
+ R.string.attribute_parking_yes, // 25
+ R.string.attribute_public_yes, // 26
+ R.string.attribute_water_yes, // 27
+ R.string.attribute_restrooms_yes, // 28
+ R.string.attribute_phone_yes, // 29
+ R.string.attribute_picnic_yes, // 30
+ R.string.attribute_camping_yes, // 31
+ R.string.attribute_bicycles_yes, // 32
+ R.string.attribute_motorcycles_yes, // 33
+ R.string.attribute_quads_yes, // 34
+ R.string.attribute_jeeps_yes, // 35
+ R.string.attribute_snowmobiles_yes, // 36
+ R.string.attribute_horses_yes, // 37
+ R.string.attribute_campfires_yes, // 38
+ R.string.attribute_thorn_yes, // 39
+ R.string.attribute_stealth_yes, // 40
+ R.string.attribute_stroller_yes, // 41
+ R.string.attribute_firstaid_yes, // 42
+ R.string.attribute_cow_yes, // 43
+ R.string.attribute_flashlight_yes, // 44
+ R.string.attribute_landf_yes, // 45
+ R.string.attribute_rv_yes, // 46
+ R.string.attribute_field_puzzle_yes, // 47
+ R.string.attribute_uv_yes, // 48
+ R.string.attribute_snowshoes_yes, // 49
+ R.string.attribute_skiis_yes, // 50
+ R.string.attribute_s_tool_yes, // 51
+ R.string.attribute_nightcache_yes, // 52
+ R.string.attribute_parkngrab_yes, // 53
+ R.string.attribute_abandonedbuilding_yes, // 54
+ R.string.attribute_hike_short_yes, // 55
+ R.string.attribute_hike_med_yes, // 56
+ R.string.attribute_hike_long_yes, // 57
+ R.string.attribute_fuel_yes, // 58
+ R.string.attribute_food_yes, // 59
+ R.string.attribute_wirelessbeacon_yes, // 60
+ R.string.attribute_partnership_yes, // 61
+ R.string.attribute_seasonal_yes, // 62
+ R.string.attribute_touristok_yes, // 63
+ R.string.attribute_treeclimbing_yes, // 64
+ R.string.attribute_frontyard_yes, // 65
+ R.string.attribute_teamwork_yes, // 66
+ };
+ private static final String YES = "_yes";
+ private static final String NO = "_no";
+ private final Pattern BASENAME_PATTERN = Pattern.compile("^.*attribute_(.*)(_yes|_no)");
+
+ private Boolean active = null; // for yes/no
+ private String baseName; // "food", "parkngrab", ...
+
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+ // map GPX-Attribute-Id to baseName
+ public void setBaseName(int id) {
+ this.baseName = null;
+ // get String out of array
+ if (CACHE_ATTRIBUTES.length <= id)
+ return;
+ int stringId = CACHE_ATTRIBUTES[id];
+ if (stringId == -1)
+ return; // id not found
+ // get text for string
+ String stringName = null;
+ try {
+ stringName = app.getResources().getResourceName(stringId);
+ } catch (NullPointerException e) {
+ return;
+ }
+ if (stringName == null)
+ return;
+ // cut out baseName
+ Matcher m = BASENAME_PATTERN.matcher(stringName);
+ if (! m.matches())
+ return;
+ this.baseName = m.group(1);
+ }
+ // @return baseName + "_yes" or "_no" e.g. "food_no" or "uv_yes"
+ public String getInternalId() {
+ if (baseName == null || active == null)
+ return null;
+ return baseName + (active ? YES : NO);
+ }
+ }
public GPXParser(cgeoapplication appIn, int listIdIn, cgSearch searchIn, String namespaceIn, String versionIn) {
app = appIn;
@@ -278,7 +396,51 @@ public abstract class GPXParser extends FileParser {
}
});
- // waypoint.cache.difficulty
+ // waypoint.cache.attributes
+ // @see issue #299
+
+ // <groundspeak:attributes>
+ // <groundspeak:attribute id="32" inc="1">Bicycles</groundspeak:attribute>
+ // <groundspeak:attribute id="13" inc="1">Available at all times</groundspeak:attribute>
+ // where inc = 0 => _no, inc = 1 => _yes
+ // IDs see array CACHE_ATTRIBUTES
+ final Element gcAttributes = gcCache.getChild(nsGC, "attributes");
+
+ // waypoint.cache.attribute
+ final Element gcAttribute = gcAttributes.getChild(nsGC, "attribute");
+
+ gcAttribute.setStartElementListener(new StartElementListener() {
+ @Override
+ public void start(Attributes attrs) {
+ cacheAttribute = new CacheAttribute();
+ try {
+ if (attrs.getIndex("id") > -1) {
+ cacheAttribute.setBaseName(Integer.parseInt(attrs.getValue("id")));
+ }
+ if (attrs.getIndex("inc") > -1) {
+ cacheAttribute.setActive(Integer.parseInt(attrs.getValue("inc")) != 0);
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ });
+
+ gcAttribute.setEndElementListener(new EndElementListener() {
+ @Override
+ public void end() {
+ if (cacheAttribute != null) {
+ String internalId = cacheAttribute.getInternalId();
+ if (internalId != null) {
+ if (cache.attributes == null)
+ cache.attributes = new ArrayList<String>();
+ cache.attributes.add(internalId);
+ }
+ }
+ }
+ });
+
+ // waypoint.cache.difficulty
gcCache.getChild(nsGC, "difficulty").setEndTextElementListener(new EndTextElementListener() {
@Override