Changeset 5437 in josm for trunk


Ignore:
Timestamp:
2012-08-12T23:43:00+02:00 (12 years 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.