diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cgeo/geocaching/cgData.java | 14 | ||||
| -rw-r--r-- | src/cgeo/geocaching/cgeodetail.java | 95 | ||||
| -rw-r--r-- | src/cgeo/geocaching/files/GPXParser.java | 164 |
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 |
