Ticket #9463: 0001-see-9463-Refactoring.patch
| File 0001-see-9463-Refactoring.patch, 14.6 KB (added by , 10 years ago) |
|---|
-
src/org/openstreetmap/josm/actions/search/SearchCompiler.java
From 776bcbbbda1132ae95d6a061dfc807972653baae Mon Sep 17 00:00:00 2001 From: Simon Legner <Simon.Legner@gmail.com> Date: Sun, 18 Oct 2015 20:17:06 +0200 Subject: [PATCH 1/2] see #9463 - Refactoring * Refactor `SearchCompiler` to work with `Tagged` instances * Extract `CompileSearchTextDecorator` from `RelationListDialog` --- .../josm/actions/search/SearchCompiler.java | 83 +++++++++++++++++----- .../josm/gui/dialogs/RelationListDialog.java | 37 ++-------- .../gui/widgets/CompileSearchTextDecorator.java | 74 +++++++++++++++++++ 3 files changed, 146 insertions(+), 48 deletions(-) create mode 100644 src/org/openstreetmap/josm/gui/widgets/CompileSearchTextDecorator.java diff --git a/src/org/openstreetmap/josm/actions/search/SearchCompiler.java b/src/org/openstreetmap/josm/actions/search/SearchCompiler.java index fec4084..1a16c84 100644
a b 27 27 import org.openstreetmap.josm.data.osm.OsmUtils; 28 28 import org.openstreetmap.josm.data.osm.Relation; 29 29 import org.openstreetmap.josm.data.osm.RelationMember; 30 import org.openstreetmap.josm.data.osm.Tagged; 30 31 import org.openstreetmap.josm.data.osm.Way; 31 32 import org.openstreetmap.josm.gui.mappaint.Environment; 32 33 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector; … … else if ("child".equals(keyword)) 232 233 } 233 234 234 235 /** 235 * Base class for all search operators. 236 * Base class for all search criteria. If the criterion only depends on an object's tags, 237 * inherit from {@link org.openstreetmap.josm.actions.search.SearchCompiler.TaggedMatch}. 236 238 */ 237 239 public abstract static class Match implements Predicate<OsmPrimitive> { 238 240 241 /** 242 * Tests whether the primitive matches this criterion. 243 * @param osm the primitive to test 244 * @return true if the primitive matches this criterion 245 */ 239 246 public abstract boolean match(OsmPrimitive osm); 240 247 241 248 /** 249 * Tests whether the tagged object matches this criterion. 250 * @param tagged the tagged object to test 251 * @return true if the tagged object matches this criterion 252 */ 253 public boolean match(Tagged tagged) { 254 return false; 255 } 256 257 /** 242 258 * Tests whether one of the primitives matches. 243 259 */ 244 260 protected boolean existsMatch(Collection<? extends OsmPrimitive> primitives) { … … public final boolean evaluate(OsmPrimitive object) { 266 282 } 267 283 } 268 284 285 public abstract static class TaggedMatch extends Match { 286 287 @Override 288 public abstract boolean match(Tagged tags); 289 290 @Override 291 public final boolean match(OsmPrimitive osm) { 292 return match((Tagged) osm); 293 } 294 } 295 269 296 /** 270 297 * A unary search operator which may take data parameters. 271 298 */ … … public Match getRhs() { 313 340 /** 314 341 * Matches every OsmPrimitive. 315 342 */ 316 public static class Always extends Match {343 public static class Always extends TaggedMatch { 317 344 /** The unique instance/ */ 318 345 public static final Always INSTANCE = new Always(); 319 346 @Override 320 public boolean match( OsmPrimitiveosm) {347 public boolean match(Tagged osm) { 321 348 return true; 322 349 } 323 350 } … … public boolean match(OsmPrimitive osm) { 325 352 /** 326 353 * Never matches any OsmPrimitive. 327 354 */ 328 public static class Never extends Match {355 public static class Never extends TaggedMatch { 329 356 @Override 330 public boolean match( OsmPrimitiveosm) {357 public boolean match(Tagged osm) { 331 358 return false; 332 359 } 333 360 } … … public boolean match(OsmPrimitive osm) { 346 373 } 347 374 348 375 @Override 376 public boolean match(Tagged osm) { 377 return !match.match(osm); 378 } 379 380 @Override 349 381 public String toString() { 350 382 return "!" + match; 351 383 } … … public Match getMatch() { 358 390 /** 359 391 * Matches if the value of the corresponding key is ''yes'', ''true'', ''1'' or ''on''. 360 392 */ 361 private static class BooleanMatch extends Match {393 private static class BooleanMatch extends TaggedMatch { 362 394 private final String key; 363 395 private final boolean defaultValue; 364 396 … … public Match getMatch() { 368 400 } 369 401 370 402 @Override 371 public boolean match( OsmPrimitiveosm) {403 public boolean match(Tagged osm) { 372 404 Boolean ret = OsmUtils.getOsmBoolean(osm.get(key)); 373 405 if (ret == null) 374 406 return defaultValue; … … public boolean match(OsmPrimitive osm) { 396 428 } 397 429 398 430 @Override 431 public boolean match(Tagged osm) { 432 return lhs.match(osm) && rhs.match(osm); 433 } 434 435 @Override 399 436 public String toString() { 400 437 return lhs + " && " + rhs; 401 438 } … … public boolean match(OsmPrimitive osm) { 415 452 } 416 453 417 454 @Override 455 public boolean match(Tagged osm) { 456 return lhs.match(osm) || rhs.match(osm); 457 } 458 459 @Override 418 460 public String toString() { 419 461 return lhs + " || " + rhs; 420 462 } … … public boolean match(OsmPrimitive osm) { 434 476 } 435 477 436 478 @Override 479 public boolean match(Tagged osm) { 480 return lhs.match(osm) ^ rhs.match(osm); 481 } 482 483 @Override 437 484 public String toString() { 438 485 return lhs + " ^ " + rhs; 439 486 } … … protected String getString() { 511 558 /** 512 559 * Matches objects with the given key-value pair. 513 560 */ 514 private static class KeyValue extends Match {561 private static class KeyValue extends TaggedMatch { 515 562 private final String key; 516 563 private final Pattern keyPattern; 517 564 private final String value; … … protected String getString() { 554 601 } 555 602 556 603 @Override 557 public boolean match( OsmPrimitiveosm) {604 public boolean match(Tagged osm) { 558 605 559 606 if (keyPattern != null) { 560 607 if (!osm.hasKeys()) … … public boolean match(OsmPrimitive osm) { 584 631 } else { 585 632 String mv = null; 586 633 587 if ("timestamp".equals(key) ) {588 mv = DateUtils.fromTimestamp( osm.getRawTimestamp());634 if ("timestamp".equals(key) && osm instanceof OsmPrimitive) { 635 mv = DateUtils.fromTimestamp(((OsmPrimitive) osm).getRawTimestamp()); 589 636 } else { 590 637 mv = osm.get(key); 591 638 if (!caseSensitive && mv == null) { … … public String toString() { 618 665 } 619 666 } 620 667 621 public static class ValueComparison extends Match {668 public static class ValueComparison extends TaggedMatch { 622 669 private final String key; 623 670 private final String referenceValue; 624 671 private final Double referenceNumber; … … public ValueComparison(String key, String referenceValue, int compareMode) { 641 688 } 642 689 643 690 @Override 644 public boolean match( OsmPrimitiveosm) {691 public boolean match(Tagged osm) { 645 692 final String currentValue = osm.get(key); 646 693 final int compareResult; 647 694 if (currentValue == null) { … … public String toString() { 669 716 /** 670 717 * Matches objects with the exact given key-value pair. 671 718 */ 672 public static class ExactKeyValue extends Match {719 public static class ExactKeyValue extends TaggedMatch { 673 720 674 721 private enum Mode { 675 722 ANY, ANY_KEY, ANY_VALUE, EXACT, NONE, MISSING_KEY, … … public ExactKeyValue(boolean regexp, String key, String value) throws ParseError 742 789 } 743 790 744 791 @Override 745 public boolean match( OsmPrimitiveosm) {792 public boolean match(Tagged osm) { 746 793 747 794 if (!osm.hasKeys()) 748 795 return mode == Mode.NONE; … … public String toString() { 799 846 /** 800 847 * Match a string in any tags (key or value), with optional regex and case insensitivity. 801 848 */ 802 private static class Any extends Match {849 private static class Any extends TaggedMatch { 803 850 private final String search; 804 851 private final Pattern searchRegex; 805 852 private final boolean caseSensitive; … … public String toString() { 826 873 } 827 874 828 875 @Override 829 public boolean match( OsmPrimitiveosm) {830 if (!osm.hasKeys() && osm.getUser() == null)876 public boolean match(Tagged osm) { 877 if (!osm.hasKeys()) 831 878 return search.isEmpty(); 832 879 833 880 for (String key: osm.keySet()) { -
src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java b/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java index a299979..7de01ca 100644
a b 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 6 import java.awt.BorderLayout; 7 import java.awt.Color;8 7 import java.awt.Component; 9 8 import java.awt.event.ActionEvent; 10 9 import java.awt.event.KeyEvent; 11 10 import java.awt.event.MouseEvent; 11 import java.beans.PropertyChangeEvent; 12 import java.beans.PropertyChangeListener; 12 13 import java.util.ArrayList; 13 14 import java.util.Arrays; 14 15 import java.util.Collection; … … 28 29 import javax.swing.JScrollPane; 29 30 import javax.swing.KeyStroke; 30 31 import javax.swing.ListSelectionModel; 31 import javax.swing.UIManager;32 import javax.swing.event.DocumentEvent;33 import javax.swing.event.DocumentListener;34 32 import javax.swing.event.ListSelectionEvent; 35 33 import javax.swing.event.ListSelectionListener; 36 34 … … 69 67 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 70 68 import org.openstreetmap.josm.gui.util.GuiHelper; 71 69 import org.openstreetmap.josm.gui.util.HighlightHelper; 70 import org.openstreetmap.josm.gui.widgets.CompileSearchTextDecorator; 72 71 import org.openstreetmap.josm.gui.widgets.DisableShortcutsOnFocusGainedTextField; 73 72 import org.openstreetmap.josm.gui.widgets.JosmTextField; 74 73 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher; … … public void selectRelations(Collection<Relation> relations) { 282 281 private JosmTextField setupFilter() { 283 282 final JosmTextField f = new DisableShortcutsOnFocusGainedTextField(); 284 283 f.setToolTipText(tr("Relation list filter")); 285 f.getDocument().addDocumentListener(new DocumentListener() { 286 287 private void setFilter() { 288 try { 289 f.setBackground(UIManager.getColor("TextField.background")); 290 f.setToolTipText(tr("Relation list filter")); 291 model.setFilter(SearchCompiler.compile(filter.getText())); 292 } catch (SearchCompiler.ParseError ex) { 293 f.setBackground(new Color(255, 224, 224)); 294 f.setToolTipText(ex.getMessage()); 295 model.setFilter(new SearchCompiler.Always()); 296 } 297 } 298 299 @Override 300 public void insertUpdate(DocumentEvent e) { 301 setFilter(); 302 } 303 304 @Override 305 public void removeUpdate(DocumentEvent e) { 306 setFilter(); 307 } 308 284 final CompileSearchTextDecorator decorator = CompileSearchTextDecorator.decorate(f); 285 f.addPropertyChangeListener("filter", new PropertyChangeListener() { 309 286 @Override 310 public void changedUpdate(DocumentEvent e) {311 setFilter();287 public void propertyChange(PropertyChangeEvent evt) { 288 model.setFilter(decorator.getMatch()); 312 289 } 313 290 }); 314 291 return f; -
new file src/org/openstreetmap/josm/gui/widgets/CompileSearchTextDecorator.java
diff --git a/src/org/openstreetmap/josm/gui/widgets/CompileSearchTextDecorator.java b/src/org/openstreetmap/josm/gui/widgets/CompileSearchTextDecorator.java new file mode 100644 index 0000000..bf0c70a
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.widgets; 3 4 import java.awt.Color; 5 6 import javax.swing.UIManager; 7 import javax.swing.event.DocumentEvent; 8 import javax.swing.event.DocumentListener; 9 import javax.swing.text.JTextComponent; 10 11 import org.openstreetmap.josm.actions.search.SearchCompiler; 12 13 /** 14 * Decorates a text component with an execution to the search compiler. Afterwards, a {@code "filter"} property change 15 * will be fired and the compiled search can be accessed with {@link #getMatch()}. 16 */ 17 public class CompileSearchTextDecorator implements DocumentListener { 18 19 private final JTextComponent textComponent; 20 private final String originalToolTipText; 21 private SearchCompiler.Match filter = null; 22 23 private CompileSearchTextDecorator(JTextComponent textComponent) { 24 this.textComponent = textComponent; 25 this.originalToolTipText = textComponent.getToolTipText(); 26 textComponent.getDocument().addDocumentListener(this); 27 } 28 29 /** 30 * Decorates a text component with an execution to the search compiler. Afterwards, a {@code "filter"} property change 31 * will be fired and the compiled search can be accessed with {@link #getMatch()}. 32 * @param f the text component to decorate 33 * @return an instance of the decorator in order to access the compiled search via {@link #getMatch()} 34 */ 35 public static CompileSearchTextDecorator decorate(JTextComponent f) { 36 return new CompileSearchTextDecorator(f); 37 } 38 39 private void setFilter() { 40 try { 41 textComponent.setBackground(UIManager.getColor("TextField.background")); 42 textComponent.setToolTipText(originalToolTipText); 43 filter = SearchCompiler.compile(textComponent.getText()); 44 } catch (SearchCompiler.ParseError ex) { 45 textComponent.setBackground(new Color(255, 224, 224)); 46 textComponent.setToolTipText(ex.getMessage()); 47 filter = new SearchCompiler.Always(); 48 } 49 textComponent.firePropertyChange("filter", 0, 1); 50 } 51 52 /** 53 * Returns the compiled search 54 * @return the compiled search 55 */ 56 public SearchCompiler.Match getMatch() { 57 return filter; 58 } 59 60 @Override 61 public void insertUpdate(DocumentEvent e) { 62 setFilter(); 63 } 64 65 @Override 66 public void removeUpdate(DocumentEvent e) { 67 setFilter(); 68 } 69 70 @Override 71 public void changedUpdate(DocumentEvent e) { 72 setFilter(); 73 } 74 }
