Changeset 5437 in josm


Ignore:
Timestamp:
Aug 12, 2012 11:43:00 PM (10 months ago)
Author:
bastiK
Message:

fixed #7948 - inverted filter "child type:way" disables untagged nodes of ways

Location:
trunk/src/org/openstreetmap/josm/data
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/Preferences.java

    r5412 r5437  
    106106    protected final SortedMap<String, List<Map<String,String>>> listOfStructsDefaults = new TreeMap<String, List<Map<String,String>>>(); 
    107107 
     108    /** 
     109     * Interface for a preference value 
     110     * 
     111     * @param <T> the data type for the value 
     112     */ 
    108113    public interface Setting<T> { 
     114        /** 
     115         * Returns the value of this setting. 
     116         * 
     117         * @return the value of this setting 
     118         */ 
    109119        T getValue(); 
     120 
     121        /** 
     122         * Enable usage of the visitor pattern. 
     123         * 
     124         * @param visitor the visitor 
     125         */ 
    110126        void visit(SettingVisitor visitor); 
     127 
     128        /** 
     129         * Returns a setting whose value is null. 
     130         * 
     131         * Cannot be static, because there is no static inheritance. 
     132         * @return a Setting object that isn't null itself, but returns null 
     133         * for {@link #getValue()} 
     134         */ 
    111135        Setting<T> getNullInstance(); 
    112136    } 
     
    448472     * operating systems and hardware, this shouldn't be a performance problem. 
    449473     * @param key the unique identifier for the setting 
    450      * @param value the value of the setting. Can be null or "" wich both removes 
     474     * @param value the value of the setting. Can be null or "" which both removes 
    451475     *  the key-value entry. 
    452476     * @return if true, something has changed (i.e. value is different than before) 
  • trunk/src/org/openstreetmap/josm/data/osm/FilterMatcher.java

    r5423 r5437  
    4444 */ 
    4545public class FilterMatcher { 
     46 
     47    /** 
     48     * Describes quality of the filtering. 
     49     * 
     50     * Depending on the context, this can either refer to disabled or 
     51     * to hidden primitives. 
     52     * 
     53     * The distinction is necessary, because untagged nodes should only 
     54     * "inherit" their filter property from the parent way, when the 
     55     * parent way is hidden (or disabled) "explicitly" (i.e. by a non-inverted 
     56     * filter). This way, filters like 
     57     * <code>["child type:way", inverted, Add]</code> show the 
     58     * untagged way nodes, as intended. 
     59     * 
     60     * This information is only needed for ways and relations, so nodes are 
     61     * either <code>NOT_FILTERED</code> or <code>PASSIV</code>. 
     62     */ 
     63    public enum FilterType { 
     64        /** no filter applies */ 
     65        NOT_FILTERED, 
     66        /** at least one non-inverted filter applies */ 
     67        EXPLICIT, 
     68        /** at least one filter applies, but they are all inverted filters */ 
     69        PASSIV 
     70    } 
    4671 
    4772    private static class FilterInfo { 
     
    102127    } 
    103128 
    104     private boolean getState(OsmPrimitive primitive, boolean hidden) { 
    105         return hidden?primitive.isDisabledAndHidden():primitive.isDisabled(); 
    106     } 
    107  
     129    /** 
     130     * Check if primitive is filtered. 
     131     * @param primitive the primitive to check 
     132     * @param hidden the minimum level required for the primitive to count as filtered 
     133     * @return when hidden is true, returns whether the primitive is hidden 
     134     * when hidden is false, returns whether the primitive is disabled or hidden 
     135     */ 
     136    private boolean isFiltered(OsmPrimitive primitive, boolean hidden) { 
     137        return hidden ? primitive.isDisabledAndHidden() : primitive.isDisabled(); 
     138    } 
     139 
     140    /** 
     141     * Check if primitive is hidden explicitly. 
     142     * Only used for ways and relations. 
     143     * @param primitive the primitive to check 
     144     * @param hidden the level where the check is performed 
     145     * @return true, if at least one non-inverted filter applies to the primitive 
     146     */ 
     147    private boolean isFilterExplicit(OsmPrimitive primitive, boolean hidden) { 
     148        return hidden ? primitive.getHiddenType() : primitive.getDisabledType(); 
     149    } 
     150 
     151    /** 
     152     * Check if all parent ways are filtered. 
     153     * @param primitive the primitive to check 
     154     * @param hidden parameter that indicates the minimum level of filtering: 
     155     * true when objects need to be hidden to count as filtered and 
     156     * false when it suffices to be disabled to count as filtered 
     157     * @return true if (a) there is at least one parent way 
     158     * (b) all parent ways are filtered at least at the level indicated by the 
     159     * parameter <code>hidden</code> and 
     160     * (c) at least one of the parent ways is explicitly filtered 
     161     */ 
    108162    private boolean allParentWaysFiltered(OsmPrimitive primitive, boolean hidden) { 
    109163        List<OsmPrimitive> refs = primitive.getReferrers(); 
    110         boolean foundWay = false; 
    111  
     164        boolean isExplicit = false; 
    112165        for (OsmPrimitive p: refs) { 
    113166            if (p instanceof Way) { 
    114                 foundWay = true; 
    115                 if (!getState(p, hidden)) 
     167                if (!isFiltered(p, hidden)) 
    116168                    return false; 
    117             } 
    118         } 
    119  
    120         return foundWay; 
     169                isExplicit |= isFilterExplicit(p, hidden); 
     170            } 
     171        } 
     172        return isExplicit; 
    121173    } 
    122174 
     
    124176        List<OsmPrimitive> refs = primitive.getReferrers(); 
    125177        for (OsmPrimitive p: refs) { 
    126             if (p instanceof Way && !getState(p, hidden)) 
     178            if (p instanceof Way && !isFiltered(p, hidden)) 
    127179                return true; 
    128180        } 
     
    131183    } 
    132184 
    133     private boolean test(List<FilterInfo> filters, OsmPrimitive primitive, boolean hidden) { 
     185    private FilterType test(List<FilterInfo> filters, OsmPrimitive primitive, boolean hidden) { 
    134186 
    135187        if (primitive.isIncomplete()) 
    136             return false; 
    137  
    138         boolean selected = false; 
     188            return FilterType.NOT_FILTERED; 
     189 
     190        boolean filtered = false; 
    139191        // If the primitive is "explicitly" hidden by a non-inverted filter. 
    140192        // Only interesting for nodes. 
    141         boolean explicitlyHidden = false; 
     193        boolean explicitlyFiltered = false; 
    142194 
    143195        for (FilterInfo fi: filters) { 
    144196            if (fi.isDelete) { 
    145                 if (selected && fi.match.match(primitive)) { 
    146                     selected = false; 
     197                if (filtered && fi.match.match(primitive)) { 
     198                    filtered = false; 
    147199                } 
    148200            } else { 
    149                 if ((!selected || (!explicitlyHidden && !fi.isInverted)) && fi.match.match(primitive)) { 
    150                     selected = true; 
     201                if ((!filtered || (!explicitlyFiltered && !fi.isInverted)) && fi.match.match(primitive)) { 
     202                    filtered = true; 
    151203                    if (!fi.isInverted) { 
    152                         explicitlyHidden = true; 
     204                        explicitlyFiltered = true; 
    153205                    } 
    154206                } 
     
    159211            // Technically not hidden by any filter, but we hide it anyway, if 
    160212            // it is untagged and all parent ways are hidden. 
    161             if (!selected) 
    162                 return !primitive.isTagged() && allParentWaysFiltered(primitive, hidden); 
     213            if (!filtered) { 
     214                if (!primitive.isTagged() && allParentWaysFiltered(primitive, hidden)) 
     215                    return FilterType.PASSIV; 
     216                else 
     217                    return FilterType.NOT_FILTERED; 
     218            } 
    163219            // At this point, selected == true, so the node is hidden. 
    164220            // However, if there is a parent way, that is not hidden, we ignore 
    165221            // this and show the node anyway, unless there is no non-inverted 
    166222            // filter that applies to the node directly. 
    167             if (!explicitlyHidden) 
    168                 return !oneParentWayNotFiltered(primitive, hidden); 
    169             return true; 
    170         } else 
    171             return selected; 
    172  
    173     } 
    174  
    175     public boolean isHidden(OsmPrimitive primitive) { 
     223            if (!explicitlyFiltered) { 
     224                if (!oneParentWayNotFiltered(primitive, hidden)) 
     225                    return FilterType.PASSIV; 
     226                else 
     227                    return FilterType.NOT_FILTERED; 
     228            } 
     229            return FilterType.PASSIV; 
     230        } else { 
     231            if (filtered) 
     232                return explicitlyFiltered ? FilterType.EXPLICIT : FilterType.PASSIV; 
     233            else 
     234                return FilterType.NOT_FILTERED; 
     235        } 
     236 
     237    } 
     238 
     239    /** 
     240     * Check if primitive is hidden. 
     241     * The filter flags for all parent objects must be set correctly, when 
     242     * calling this method. 
     243     * @param primitive the primitive 
     244     * @return FilterType.NOT_FILTERED when primitive is not hidden; 
     245     * FilterType.EXPLICIT when primitive is hidden and there is a non-inverted 
     246     * filter that applies; 
     247     * FilterType.PASSIV when primitive is hidden and all filters that apply 
     248     * are inverted 
     249     */ 
     250    public FilterType isHidden(OsmPrimitive primitive) { 
    176251        return test(hiddenFilters, primitive, true); 
    177252    } 
    178253 
    179     public boolean isDisabled(OsmPrimitive primitive) { 
     254    /** 
     255     * Check if primitive is disabled. 
     256     * The filter flags for all parent objects must be set correctly, when 
     257     * calling this method. 
     258     * @param primitive the primitive 
     259     * @return FilterType.NOT_FILTERED when primitive is not disabled; 
     260     * FilterType.EXPLICIT when primitive is disabled and there is a non-inverted 
     261     * filter that applies; 
     262     * FilterType.PASSIV when primitive is disabled and all filters that apply 
     263     * are inverted 
     264     */ 
     265    public FilterType isDisabled(OsmPrimitive primitive) { 
    180266        return test(disabledFilters, primitive, false); 
    181267    } 
  • trunk/src/org/openstreetmap/josm/data/osm/FilterWorker.java

    r5423 r5437  
    33 
    44import java.util.Collection; 
     5import java.util.Collections; 
     6 
     7import org.openstreetmap.josm.data.osm.FilterMatcher.FilterType; 
     8import org.openstreetmap.josm.tools.Utils; 
    59 
    610/** 
     
    1519     * be updated 
    1620     * @param filterMatcher the FilterMatcher 
    17      * @return true, if the filter state of any primitive has changed in the process 
     21     * @return true, if the filter state (normal / disabled / hidden) 
     22     * of any primitive has changed in the process 
    1823     */ 
    1924    public static boolean executeFilters(Collection<OsmPrimitive> all, FilterMatcher filterMatcher) { 
     25        boolean changed = false; 
     26        // first relations, then ways and nodes last; this is required to resolve dependencies 
     27        changed = doExecuteFilters(Utils.filter(all, OsmPrimitive.relationPredicate), filterMatcher); 
     28        changed |= doExecuteFilters(Utils.filter(all, OsmPrimitive.wayPredicate), filterMatcher); 
     29        changed |= doExecuteFilters(Utils.filter(all, OsmPrimitive.nodePredicate), filterMatcher); 
     30        return changed; 
     31    } 
     32 
     33    private static boolean doExecuteFilters(Collection<OsmPrimitive> all, FilterMatcher filterMatcher) { 
    2034 
    2135        boolean changed = false; 
    2236 
    23         // First relation and ways 
    2437        for (OsmPrimitive primitive: all) { 
    25             if (!(primitive instanceof Node)) { 
    26                 if (filterMatcher.isHidden(primitive)) { 
    27                     changed = changed | primitive.setDisabledState(true); 
    28                 } else if (filterMatcher.isDisabled(primitive)) { 
    29                     changed = changed | primitive.setDisabledState(false); 
     38            FilterType hiddenType = filterMatcher.isHidden(primitive); 
     39            if (hiddenType != FilterType.NOT_FILTERED) { 
     40                changed |= primitive.setDisabledState(true); 
     41                primitive.setHiddenType(hiddenType == FilterType.EXPLICIT); 
     42            } else { 
     43                FilterType disabledType = filterMatcher.isDisabled(primitive); 
     44                if (disabledType != FilterType.NOT_FILTERED) { 
     45                    changed |= primitive.setDisabledState(false); 
     46                    primitive.setDisabledType(hiddenType == FilterType.EXPLICIT); 
    3047                } else { 
    31                     changed = changed | primitive.unsetDisabledState(); 
     48                    changed |= primitive.unsetDisabledState(); 
    3249                } 
    3350            } 
    3451        } 
    35  
    36         // Then nodes (because they state may depend on parent ways) 
    37         for (OsmPrimitive primitive: all) { 
    38             if (primitive instanceof Node) { 
    39                 if (filterMatcher.isHidden(primitive)) { 
    40                     changed = changed | primitive.setDisabledState(true); 
    41                 } else if (filterMatcher.isDisabled(primitive)) { 
    42                     changed = changed | primitive.setDisabledState(false); 
    43                 } else { 
    44                     changed = changed | primitive.unsetDisabledState(); 
    45                 } 
    46             } 
    47         } 
    48  
    4952        return changed; 
    5053    } 
    5154 
    5255    public static boolean executeFilters(OsmPrimitive primitive, FilterMatcher filterMatcher) { 
    53         boolean changed = false; 
    54         if (filterMatcher.isHidden(primitive)) { 
    55             changed = changed | primitive.setDisabledState(true); 
    56         } else if (filterMatcher.isDisabled(primitive)) { 
    57             changed = changed | primitive.setDisabledState(false); 
    58         } else { 
    59             changed = changed | primitive.unsetDisabledState(); 
    60         } 
    61         return changed; 
     56        return doExecuteFilters(Collections.singleton(primitive), filterMatcher); 
    6257    } 
    6358 
  • trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r5423 r5437  
    5353    /** 
    5454     * This flag is only relevant if an object is disabled by the 
    55      * filter mechanism (i.e. FLAG_DISABLED is set). 
     55     * filter mechanism (i.e.&nbsp;FLAG_DISABLED is set). 
    5656     * Then it indicates, whether it is completely hidden or 
    5757     * just shown in gray color. 
     
    6161     */ 
    6262    protected static final int FLAG_HIDE_IF_DISABLED = 1 << 5; 
     63 
     64    /** 
     65     * Flag used internally by the filter mechanism. 
     66     */ 
     67    protected static final int FLAG_DISABLED_TYPE = 1 << 6; 
     68 
     69    /** 
     70     * Flag used internally by the filter mechanism. 
     71     */ 
     72    protected static final int FLAG_HIDDEN_TYPE = 1 << 7; 
    6373 
    6474    /** 
     
    6777     * (e.g. one way street.) 
    6878     */ 
    69     protected static final int FLAG_HAS_DIRECTIONS = 1 << 6; 
     79    protected static final int FLAG_HAS_DIRECTIONS = 1 << 8; 
    7080 
    7181    /** 
     
    7383     * Some trivial tags like source=* are ignored here. 
    7484     */ 
    75     protected static final int FLAG_TAGGED = 1 << 7; 
     85    protected static final int FLAG_TAGGED = 1 << 9; 
    7686 
    7787    /** 
     
    8090     * (E.g. oneway=-1.) 
    8191     */ 
    82     protected static final int FLAG_DIRECTION_REVERSED = 1 << 8; 
     92    protected static final int FLAG_DIRECTION_REVERSED = 1 << 10; 
    8393 
    8494    /** 
     
    8797     * that the primitive is currently highlighted. 
    8898     */ 
    89     protected static final int FLAG_HIGHLIGHTED = 1 << 9; 
     99    protected static final int FLAG_HIGHLIGHTED = 1 << 11; 
    90100 
    91101    /** 
     
    431441     * 
    432442     * To enable the primitive again, use unsetDisabledState. 
    433      * @param hide if the primitive should be completely hidden from view or 
     443     * @param hidden if the primitive should be completely hidden from view or 
    434444     *             just shown in gray color. 
    435445     * @return true, any flag has changed; false if you try to set the disabled 
    436446     * state to the value that is already preset 
    437447     */ 
    438     public boolean setDisabledState(boolean hide) { 
     448    public boolean setDisabledState(boolean hidden) { 
    439449        boolean locked = writeLock(); 
    440450        try { 
    441451            int oldFlags = flags; 
    442452            updateFlagsNoLock(FLAG_DISABLED, true); 
    443             updateFlagsNoLock(FLAG_HIDE_IF_DISABLED, hide); 
     453            updateFlagsNoLock(FLAG_HIDE_IF_DISABLED, hidden); 
    444454            return oldFlags != flags; 
    445455        } finally { 
     
    465475 
    466476    /** 
     477     * Set binary property used internally by the filter mechanism. 
     478     */ 
     479    public void setDisabledType(boolean isExplicit) { 
     480        updateFlags(FLAG_DISABLED_TYPE, isExplicit); 
     481    } 
     482 
     483    /** 
     484     * Set binary property used internally by the filter mechanism. 
     485     */ 
     486    public void setHiddenType(boolean isExplicit) { 
     487        updateFlags(FLAG_HIDDEN_TYPE, isExplicit); 
     488    } 
     489 
     490    /** 
    467491     * Replies true, if this primitive is disabled. (E.g. a filter 
    468492     * applies) 
     
    478502    public boolean isDisabledAndHidden() { 
    479503        return (((flags & FLAG_DISABLED) != 0) && ((flags & FLAG_HIDE_IF_DISABLED) != 0)); 
     504    } 
     505 
     506    /** 
     507     * Get binary property used internally by the filter mechanism. 
     508     */ 
     509    public boolean getHiddenType() { 
     510        return (flags & FLAG_HIDDEN_TYPE) != 0; 
     511    } 
     512 
     513    /** 
     514     * Get binary property used internally by the filter mechanism. 
     515     */ 
     516    public boolean getDisabledType() { 
     517        return (flags & FLAG_DISABLED_TYPE) != 0; 
    480518    } 
    481519 
Note: See TracChangeset for help on using the changeset viewer.