package de.blau.android.filter; import java.util.Arrays; import java.util.List; import android.content.Context; import android.graphics.drawable.BitmapDrawable; import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.RelativeLayout; import de.blau.android.App; import de.blau.android.Main; import de.blau.android.R; import de.blau.android.osm.Node; import de.blau.android.osm.OsmElement; import de.blau.android.osm.Relation; import de.blau.android.osm.RelationMember; import de.blau.android.osm.Way; import de.blau.android.prefs.Preferences; import de.blau.android.presets.Preset; import de.blau.android.presets.Preset.PresetElement; import de.blau.android.presets.Preset.PresetItem; import de.blau.android.presets.PresetElementPath; import de.blau.android.util.Util; /** * Filter plus UI for filtering on presets * NOTE: the relevant ways should be processed before nodes * @author simon * */ public class PresetFilter extends Filter { /** * */ private static final long serialVersionUID = 7L; private final static String DEBUG_TAG = "PresetFilter"; private boolean enabled = true; private transient Preset preset[] = null; private transient Context context; private transient PresetElement element = null; private PresetElementPath path = null; private boolean includeWayNodes = false; private boolean inverted = false; public PresetFilter(Context context) { super(); Log.d(DEBUG_TAG, "Constructor"); init(context); // } void setPresetElement(@NonNull PresetElementPath path) { clear(); if (path != null) { this.path = path; Preset[] presets = App.getCurrentPresets(context); element = presets[0].getElementByPath(presets[0].getRootGroup(), path); if (element==null) { Log.e(DEBUG_TAG, path.toString() + " not found"); return; } Log.d(DEBUG_TAG, "Setting preset to " + element.getName() + " parent " + element.getParent()); preset = new Preset[]{new Preset(Arrays.asList(new Preset.PresetElement[]{element}))}; } if (update != null) { update.execute(); } setIcon(); } PresetElement getPresetElement() { return element; } @Override public void init(Context context) { Log.d(DEBUG_TAG, "init"); this.context = context; clear(); if (path != null) { setPresetElement(path); } } /** * @return if way nodes are incldued */ public boolean includeWayNodes() { return includeWayNodes; } /** * Include way nodes when ways are included * * @param on */ public void setIncludeWayNodes(boolean on) { Log.d(DEBUG_TAG,"set include way nodes " + on); this.includeWayNodes = on; } /** * @return is the filter inverted? */ public boolean isInverted() { return inverted; } /** * Invert the filter * * @param invert the filter if true */ public void setInverted(boolean inverted) { this.inverted = inverted; } private Include filter(OsmElement e) { Include include =Include.DONT; if (preset != null) { PresetItem item = Preset.findMatch(preset, e.getTags()); if (item != null) { include = includeWayNodes ? Include.INCLUDE_WITH_WAYNODES : Include.INCLUDE; } if (include == Include.DONT) { // check if it is a relation member List<Relation> parents = e.getParentRelations(); if (parents != null) { for (Relation r:parents) { Include relationInclude = testRelation(r, false); if (relationInclude != null && relationInclude != Include.DONT) { return relationInclude; // inherit include status from relation } } } } } return include; } @Override public boolean include(Node node, boolean selected) { // Log.d(DEBUG_TAG, "include Node " + node.getOsmId() + "?"); if (!enabled || selected) { return true; } Include include = cachedNodes.get(node); if (include != null) { // Log.d(DEBUG_TAG, "include Node " + include + " was in cache"); return include != Include.DONT; } include = filter(node); // Log.d(DEBUG_TAG, "include Node " + include); cachedNodes.put(node,include); return include != Include.DONT; } @Override public boolean include(Way way, boolean selected) { if (!enabled) { return true; } Include include = cachedWays.get(way); if (include != null) { return include != Include.DONT; } include = filter(way); if (include == Include.INCLUDE_WITH_WAYNODES) { for (Node n:way.getNodes()) { Include includeNode = cachedNodes.get(n); if (includeNode == null || (include != Include.DONT && includeNode == Include.DONT)) { // if not originally included overwrite now if (include == Include.DONT && (n.hasTags() || n.hasParentRelations())) { // no entry yet so we have to check tags and relations include(n,false); continue; } cachedNodes.put(n,include); } } } cachedWays.put(way,include); return include != Include.DONT || selected; } @Override public boolean include(Relation relation, boolean selected) { return testRelation(relation, selected) != Include.DONT; } Include testRelation(Relation relation, boolean selected) { if (!enabled || selected) { return Include.INCLUDE_WITH_WAYNODES; } Include include = cachedRelations.get(relation); if (include != null) { return include; } include = filter(relation); cachedRelations.put(relation, include); List<RelationMember> members = relation.getMembers(); if (members != null) { for (RelationMember rm:members) { OsmElement element = rm.getElement(); if (element != null) { if (element instanceof Way) { Way w = (Way)element; Include includeWay = cachedWays.get(w); if (includeWay == null || (include != Include.DONT && includeWay == Include.DONT)) { // if not originally included overwrite now if (include == Include.INCLUDE_WITH_WAYNODES) { for (Node n:w.getNodes()) { cachedNodes.put(n,include); } } cachedWays.put(w,include); } } else if (element instanceof Node) { Node n = (Node)element; Include includeNode = cachedNodes.get(n); if (includeNode == null || (include != Include.DONT && includeNode == Include.DONT)) { // if not originally included overwrite now cachedNodes.put(n,include); } } else if (element instanceof Relation) { // FIXME not clear if we really want to do this } } } } return include; } /** * Tag filter controls */ private transient FloatingActionButton presetFilterButton; private transient ViewGroup parent; private transient RelativeLayout controls; private transient Update update; @Override public void addControls(ViewGroup layout, final Update update) { Log.d(DEBUG_TAG, "adding filter controls"); this.parent = layout; this.update = update; presetFilterButton = (FloatingActionButton)parent.findViewById(R.id.tagFilterButton); final Context context = layout.getContext(); // we weren't already added ... if (presetFilterButton == null) { Preferences prefs = new Preferences(context); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); String buttonPos = layout.getContext().getString(R.string.follow_GPS_left); controls = (RelativeLayout)inflater.inflate(prefs.followGPSbuttonPosition().equals(buttonPos)?R.layout.tagfilter_controls_right:R.layout.tagfilter_controls_left, layout); presetFilterButton = (FloatingActionButton)controls.findViewById(R.id.tagFilterButton); } setIcon(); presetFilterButton.setClickable(true); presetFilterButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View b) { Log.d(DEBUG_TAG,"Button clicked"); PresetFilterActivity.start(context); } }); Util.setAlpha(presetFilterButton, Main.FABALPHA); setupControls(false); } private void setIcon() { if (element != null && presetFilterButton != null) { BitmapDrawable icon = element.getMapIcon(); if (icon != null) { presetFilterButton.setImageDrawable(icon); } else { presetFilterButton.setImageResource(R.drawable.ic_filter_list_black_36dp); } } } private void setupControls(boolean toggle) { enabled = toggle ? !enabled : enabled; update.execute(); } @Override public void removeControls() { if (parent != null && controls != null) { parent.removeView(controls); } } @Override public void hideControls() { if(presetFilterButton != null) { presetFilterButton.setImageResource(R.drawable.ic_filter_list_black_36dp); presetFilterButton.setVisibility(View.GONE); } } @Override public void showControls() { if(presetFilterButton != null) { presetFilterButton.setVisibility(View.VISIBLE); } } }