- Timestamp:
- 2020-02-10T23:58:31+01:00 (5 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/gui/autofilter
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterManager.java
r15818 r15838 8 8 import java.util.Arrays; 9 9 import java.util.Collection; 10 import java.util.Comparator; 11 import java.util.Iterator; 10 import java.util.Collections; 12 11 import java.util.List; 13 12 import java.util.Map; 14 13 import java.util.NavigableSet; 15 14 import java.util.Objects; 16 import java.util.Set;17 15 import java.util.TreeMap; 18 16 import java.util.TreeSet; … … 21 19 import java.util.regex.Pattern; 22 20 import java.util.stream.IntStream; 23 import java.util.stream.Stream;24 21 25 22 import org.openstreetmap.josm.actions.mapmode.MapMode; … … 94 91 * The buttons currently displayed in map view. 95 92 */ 96 private final Map< String, AutoFilterButton> buttons = new TreeMap<>();93 private final Map<Integer, AutoFilterButton> buttons = new TreeMap<>(); 97 94 98 95 /** … … 146 143 && enabledRule.getMinZoomLevel() <= Selector.GeneralSelector.scale2level(map.mapView.getDist100Pixel())) { 147 144 // Retrieve the values from current rule visible on screen 148 NavigableSet< String> values = getNumericValues(enabledRule.getKey(), enabledRule.getValueComparator());145 NavigableSet<Integer> values = getNumericValues(enabledRule.getKey()); 149 146 // Make sure current auto filter button remains visible even if no data is found, to allow user to disable it 150 147 if (currentAutoFilter != null) { … … 158 155 } 159 156 160 staticclass CompiledFilter extends Filter implements MatchSupplier {157 class CompiledFilter extends Filter implements MatchSupplier { 161 158 final String key; 162 final Stringvalue;163 164 CompiledFilter(String key, Stringvalue) {159 final int value; 160 161 CompiledFilter(String key, int value) { 165 162 this.key = key; 166 163 this.value = value; … … 175 172 @Override 176 173 public boolean match(OsmPrimitive osm) { 177 return getTagValuesForPrimitive(key, osm).anyMatch(v alue::equals);174 return getTagValuesForPrimitive(key, osm).anyMatch(v -> v == value); 178 175 } 179 176 }; … … 181 178 } 182 179 183 private synchronized void addNewButtons(NavigableSet< String> values) {180 private synchronized void addNewButtons(NavigableSet<Integer> values) { 184 181 if (values.isEmpty()) { 185 182 return; … … 188 185 int maxWidth = 16; 189 186 final AutoFilterButton keyButton = AutoFilterButton.forOsmKey(enabledRule.getKey()); 190 addButton(keyButton, Integer. toString(Integer.MIN_VALUE), i++);191 for (final Stringvalue : values.descendingSet()) {187 addButton(keyButton, Integer.MIN_VALUE, i++); 188 for (final Integer value : values.descendingSet()) { 192 189 CompiledFilter filter = new CompiledFilter(enabledRule.getKey(), value); 193 190 String label = enabledRule.getValueFormatter().apply(value); … … 206 203 } 207 204 208 private void addButton(AutoFilterButton button, Stringvalue, int i) {205 private void addButton(AutoFilterButton button, int value, int i) { 209 206 MapView mapView = MainApplication.getMap().mapView; 210 207 buttons.put(value, button); … … 213 210 214 211 private void removeAllButtons() { 215 for (Iterator<String> it = buttons.keySet().iterator(); it.hasNext();) { 216 MainApplication.getMap().mapView.remove(buttons.get(it.next())); 217 it.remove(); 218 } 219 } 220 221 private static NavigableSet<String> getNumericValues(String key, Comparator<String> comparator) { 222 NavigableSet<String> values = new TreeSet<>(comparator); 223 for (String s : getTagValues(key)) { 224 try { 225 Integer.parseInt(s); 226 values.add(s); 227 } catch (NumberFormatException e) { 228 Logging.trace(e); 229 } 230 } 212 buttons.values().forEach(MainApplication.getMap().mapView::remove); 213 buttons.clear(); 214 } 215 216 private NavigableSet<Integer> getNumericValues(String key) { 217 DataSet ds = MainApplication.getLayerManager().getActiveDataSet(); 218 if (ds == null) { 219 return Collections.emptyNavigableSet(); 220 } 221 BBox bbox = MainApplication.getMap().mapView.getState().getViewArea().getLatLonBoundsBox().toBBox(); 222 NavigableSet<Integer> values = new TreeSet<>(); 223 Consumer<OsmPrimitive> consumer = o -> getTagValuesForPrimitive(key, o).forEach(values::add); 224 ds.searchNodes(bbox).forEach(consumer); 225 ds.searchWays(bbox).forEach(consumer); 226 ds.searchRelations(bbox).forEach(consumer); 231 227 return values; 232 228 } 233 229 234 private static Set<String> getTagValues(String key) { 235 DataSet ds = MainApplication.getLayerManager().getActiveDataSet(); 236 Set<String> values = new TreeSet<>(); 237 if (ds != null) { 238 BBox bbox = MainApplication.getMap().mapView.getState().getViewArea().getLatLonBoundsBox().toBBox(); 239 Consumer<OsmPrimitive> consumer = o -> getTagValuesForPrimitive(key, o).forEach(values::add); 240 ds.searchNodes(bbox).forEach(consumer); 241 ds.searchWays(bbox).forEach(consumer); 242 ds.searchRelations(bbox).forEach(consumer); 243 } 244 return values; 245 } 246 247 static Stream<String> getTagValuesForPrimitive(String key, OsmPrimitive osm) { 230 protected IntStream getTagValuesForPrimitive(String key, OsmPrimitive osm) { 231 if (enabledRule == null) { 232 return IntStream.empty(); 233 } 248 234 String value = osm.get(key); 249 235 if (value != null) { 250 236 Pattern p = Pattern.compile("(-?[0-9]+)-(-?[0-9]+)"); 251 return OsmUtils.splitMultipleValues(value).flatMap (v -> {237 return OsmUtils.splitMultipleValues(value).flatMapToInt(v -> { 252 238 Matcher m = p.matcher(v); 253 239 if (m.matches()) { 254 240 int a = Integer.parseInt(m.group(1)); 255 241 int b = Integer.parseInt(m.group(2)); 256 return IntStream.rangeClosed(Math.min(a, b), Math.max(a, b)) 257 .mapToObj(Integer::toString); 242 return IntStream.rangeClosed(Math.min(a, b), Math.max(a, b)); 258 243 } else { 259 return Stream.of(v); 244 try { 245 return IntStream.of(enabledRule.getValueExtractor().applyAsInt(v)); 246 } catch (NumberFormatException e) { 247 Logging.trace(e); 248 return IntStream.empty(); 249 } 260 250 } 261 251 }); 262 } else if (PROP_AUTO_FILTER_DEFAULTS.get() && "layer".equals(key)) { 263 // assume sensible defaults, see #17496 264 if (osm.hasTag("bridge") || osm.hasTag("power", "line") || osm.hasTag("location", "overhead")) { 265 return Stream.of("1"); 266 } else if (osm.isKeyTrue("tunnel") || osm.hasTag("tunnel", "culvert") || osm.hasTag("location", "underground")) { 267 return Stream.of("-1"); 268 } else if (osm.hasTag("tunnel", "building_passage") || osm.hasKey("highway", "railway", "waterway")) { 269 return Stream.of("0"); 270 } 271 } 272 return Stream.empty(); 252 } 253 return enabledRule.getDefaultValueSupplier().apply(osm); 273 254 } 274 255 -
trunk/src/org/openstreetmap/josm/gui/autofilter/AutoFilterRule.java
r15293 r15838 2 2 package org.openstreetmap.josm.gui.autofilter; 3 3 4 import java.util. Comparator;4 import java.util.Arrays; 5 5 import java.util.Objects; 6 import java.util.Optional; 6 7 import java.util.function.Function; 7 import java.util.function.UnaryOperator; 8 import java.util.function.IntFunction; 9 import java.util.function.ToIntFunction; 10 import java.util.stream.IntStream; 11 12 import org.openstreetmap.josm.data.osm.OsmPrimitive; 8 13 9 14 /** … … 20 25 private final int minZoomLevel; 21 26 22 private UnaryOperator<String> valueFormatter = s -> s;27 private Function<OsmPrimitive, IntStream> defaultValueSupplier = p -> IntStream.empty(); 23 28 24 private Comparator<String> valueComparator = Comparator.comparingInt(s -> Integer.parseInt(valueFormatter.apply(s))); 29 private ToIntFunction<String> valueExtractor = Integer::parseInt; 30 31 private IntFunction<String> valueFormatter = Integer::toString; 25 32 26 33 /** … … 54 61 * @return the OSM value formatter that defines the associated button label (identity by default) 55 62 */ 56 public Function<String,String> getValueFormatter() {63 public IntFunction<String> getValueFormatter() { 57 64 return valueFormatter; 58 65 } … … 64 71 * @throws NullPointerException if {@code valueFormatter} is null 65 72 */ 66 public AutoFilterRule setValueFormatter( UnaryOperator<String> valueFormatter) {73 public AutoFilterRule setValueFormatter(IntFunction<String> valueFormatter) { 67 74 this.valueFormatter = Objects.requireNonNull(valueFormatter); 68 75 return this; … … 70 77 71 78 /** 72 * Returns the OSM value comparator used to order the buttons.73 * @return the OSM value comparator79 * Returns a function which yields default values for the given OSM primitive 80 * @return a function which yields default values for the given OSM primitive 74 81 */ 75 public Comparator<String> getValueComparator() {76 return valueComparator;82 public Function<OsmPrimitive, IntStream> getDefaultValueSupplier() { 83 return defaultValueSupplier; 77 84 } 78 85 79 86 /** 80 * Sets the OSM value comparator used to order the buttons. 81 * @param valueComparator the OSM value comparator 87 * Sets the function which yields default values for the given OSM primitive. 88 * This function is invoked if the primitive does not have this {@linkplain #getKey() key}. 89 * @param defaultValueSupplier the function which yields default values for the given OSM primitive 82 90 * @return {@code this} 83 * @throws NullPointerException if {@code valueComparator} is null91 * @throws NullPointerException if {@code defaultValueSupplier} is null 84 92 */ 85 public AutoFilterRule setValueComparator(Comparator<String> valueComparator) { 86 this.valueComparator = valueComparator; 93 public AutoFilterRule setDefaultValueSupplier(Function<OsmPrimitive, IntStream> defaultValueSupplier) { 94 this.defaultValueSupplier = Objects.requireNonNull(defaultValueSupplier); 95 return this; 96 } 97 98 /** 99 * Returns a function which extracts a numeric value from an OSM value 100 * @return a function which extracts a numeric value from an OSM value 101 */ 102 public ToIntFunction<String> getValueExtractor() { 103 return valueExtractor; 104 } 105 106 /** 107 * Sets the function which extracts a numeric value from an OSM value 108 * @param valueExtractor the function which extracts a numeric value from an OSM value 109 * @return {@code this} 110 * @throws NullPointerException if {@code valueExtractor} is null 111 */ 112 public AutoFilterRule setValueExtractor(ToIntFunction<String> valueExtractor) { 113 this.valueExtractor = Objects.requireNonNull(valueExtractor); 87 114 return this; 88 115 } … … 93 120 */ 94 121 public static AutoFilterRule[] defaultRules() { 95 return new AutoFilterRule[] 122 return new AutoFilterRule[]{ 96 123 new AutoFilterRule("level", 17), 97 new AutoFilterRule("layer", 16), 124 new AutoFilterRule("layer", 16) 125 .setDefaultValueSupplier(AutoFilterRule::defaultLayer), 98 126 new AutoFilterRule("maxspeed", 16) 99 .setValueFormatter(s -> s.replace(" mph", "")),127 .setValueExtractor(s -> Integer.parseInt(s.replace(" mph", ""))), 100 128 new AutoFilterRule("voltage", 5) 101 .setValueFormatter(s -> s.replaceAll("000$", "k") + 'V') 102 .setValueComparator(Comparator.comparingInt(Integer::parseInt)) 129 .setValueFormatter(s -> s % 1000 == 0 ? (s / 1000) + "kV" : s + "V"), 130 new AutoFilterRule("building:levels", 17), 131 new AutoFilterRule("gauge", 5), 132 new AutoFilterRule("frequency", 5), 133 new AutoFilterRule("incline", 13) 134 .setValueExtractor(s -> Integer.parseInt(s.replaceAll("%$", ""))) 135 .setValueFormatter(v -> v + "\u2009%"), 136 new AutoFilterRule("lanes", 13), 137 new AutoFilterRule("admin_level", 11) 103 138 }; 139 } 140 141 /** 142 * Returns the default auto filter rule for the given key 143 * @param key the OSM key 144 * @return default auto filter rule for the given key 145 */ 146 static Optional<AutoFilterRule> getDefaultRule(String key) { 147 return Arrays.stream(AutoFilterRule.defaultRules()) 148 .filter(r -> key.equals(r.getKey())) 149 .findFirst(); 150 } 151 152 private static IntStream defaultLayer(OsmPrimitive osm) { 153 // assume sensible defaults, see #17496 154 if (osm.hasTag("bridge") || osm.hasTag("power", "line") || osm.hasTag("location", "overhead")) { 155 return IntStream.of(1); 156 } else if (osm.isKeyTrue("tunnel") || osm.hasTag("tunnel", "culvert") || osm.hasTag("location", "underground")) { 157 return IntStream.of(-1); 158 } else if (osm.hasTag("tunnel", "building_passage") || osm.hasKey("highway", "railway", "waterway")) { 159 return IntStream.of(0); 160 } else { 161 return IntStream.empty(); 162 } 104 163 } 105 164
Note:
See TracChangeset
for help on using the changeset viewer.