Ticket #11153: 11153.4.patch
| File 11153.4.patch, 36.4 KB (added by , 3 years ago) |
|---|
-
src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerFixCommand.java
Subject: [PATCH] #11153: improve readability of validator warnings --- IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerFixCommand.java b/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerFixCommand.java
a b 54 54 } else { 55 55 return null; 56 56 } 57 return MapCSSTagCheckerRule.insertArguments(matchingSelector, s, p );57 return MapCSSTagCheckerRule.insertArguments(matchingSelector, s, p, false); 58 58 } 59 59 60 60 /** … … 113 113 @Override 114 114 public Command createCommand(OsmPrimitive p, Selector matchingSelector) { 115 115 return new ChangePropertyKeyCommand(p, 116 MapCSSTagCheckerRule.insertArguments(matchingSelector, oldKey, p ),117 MapCSSTagCheckerRule.insertArguments(matchingSelector, newKey, p ));116 MapCSSTagCheckerRule.insertArguments(matchingSelector, oldKey, p, false), 117 MapCSSTagCheckerRule.insertArguments(matchingSelector, newKey, p, false)); 118 118 } 119 119 120 120 @Override -
src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerRule.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerRule.java b/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerRule.java
a b 262 262 * @param matchingSelector matching selector 263 263 * @param s any string 264 264 * @param p OSM primitive 265 * @param linkify {@code true} to insert links to wiki pages 265 266 * @return string with arguments inserted 266 267 */ 267 static String insertArguments(Selector matchingSelector, String s, OsmPrimitive p ) {268 static String insertArguments(Selector matchingSelector, String s, OsmPrimitive p, boolean linkify) { 268 269 if (s != null && matchingSelector instanceof Selector.ChildOrParentSelector) { 269 return insertArguments(((Selector.ChildOrParentSelector) matchingSelector).right, s, p );270 return insertArguments(((Selector.ChildOrParentSelector) matchingSelector).right, s, p, linkify); 270 271 } else if (s == null || !(matchingSelector instanceof Selector.GeneralSelector)) { 271 272 return s; 272 273 } 273 final Matcher m = Pattern.compile("\\{(\\d+)\\.(key|value|tag)\\}").matcher(s); 274 final Matcher m = Pattern.compile("\\{(\\S+?)\\.(key|value|tag)}", Pattern.UNICODE_CHARACTER_CLASS).matcher(s); 275 final Matcher number = Pattern.compile("^\\d+$").matcher(s); 274 276 final StringBuffer sb = new StringBuffer(); 275 277 while (m.find()) { 276 final String argument = determineArgument((Selector.GeneralSelector) matchingSelector, 277 Integer.parseInt(m.group(1)), m.group(2), p); 278 final String argument; 279 final String tag; 280 if (number.reset(m.group(1)).matches()) { 281 argument = determineArgument((Selector.GeneralSelector) matchingSelector, 282 Integer.parseInt(m.group(1)), m.group(2), p); 283 tag = determineArgument((Selector.GeneralSelector) matchingSelector, 284 Integer.parseInt(m.group(1)), "tag", p); 285 } else { 286 argument = m.group(1); 287 tag = argument; 288 } 278 289 try { 279 290 // Perform replacement with null-safe + regex-safe handling 280 m.appendReplacement(sb, String.valueOf(argument).replace("^(", "").replace(")$", "")); 291 final String replacement = String.valueOf(argument).replace("^(", "").replace(")$", ""); 292 final String replacementTag = String.valueOf(tag).replace("^(", "").replace(")$", ""); 293 final String[] splitTag = replacementTag.split("=", 2); 294 if (linkify) { 295 final String url = Test.getWikiLink(splitTag[0], !"key".equals(m.group(2)) && splitTag.length == 2 ? splitTag[1] : null); 296 m.appendReplacement(sb, "<a href=\"" + url + "\">" 297 + replacement 298 + "</a>"); 299 } else { 300 m.appendReplacement(sb, replacement); 301 } 281 302 } catch (IndexOutOfBoundsException | IllegalArgumentException e) { 282 303 Logging.log(Logging.LEVEL_ERROR, tr("Unable to replace argument {0} in {1}: {2}", argument, sb, e.getMessage()), e); 283 304 } … … 307 328 cmds.add(new DeleteCommand(p)); 308 329 } 309 330 return cmds.isEmpty() ? null 310 : new SequenceCommand(tr("Fix of {0}", getDescriptionForMatchingSelector(p, matchingSelector )), cmds);331 : new SequenceCommand(tr("Fix of {0}", getDescriptionForMatchingSelector(p, matchingSelector, false)), cmds); 311 332 } catch (IllegalArgumentException e) { 312 333 Logging.error(e); 313 334 return null; … … 356 377 * 357 378 * @param matchingSelector matching selector 358 379 * @param p OSM primitive 380 * @param linkify {@code true} to get a description with links to tag/key wiki pages 359 381 * @return a description (possibly with alternative suggestions) 360 382 */ 361 String getDescriptionForMatchingSelector(OsmPrimitive p, Selector matchingSelector ) {362 return insertArguments(matchingSelector, getDescription(p), p );383 String getDescriptionForMatchingSelector(OsmPrimitive p, Selector matchingSelector, boolean linkify) { 384 return insertArguments(matchingSelector, getDescription(p), p, linkify); 363 385 } 364 386 365 387 Severity getSeverity() { … … 384 406 List<TestError> res = new ArrayList<>(); 385 407 if (matchingSelector != null && !errors.isEmpty()) { 386 408 final Command fix = fixPrimitive(p); 387 final String description = getDescriptionForMatchingSelector(p, matchingSelector );409 final String description = getDescriptionForMatchingSelector(p, matchingSelector, true); 388 410 final String description1 = group == null ? description : group; 389 411 final String description2 = group == null ? null : description; 390 412 final String selector = matchingSelector.toString(); -
src/org/openstreetmap/josm/data/validation/Test.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/validation/Test.java b/src/org/openstreetmap/josm/data/validation/Test.java
a b 11 11 import java.util.function.Predicate; 12 12 import java.util.stream.Collectors; 13 13 14 import javax.annotation.Nonnull; 15 import javax.annotation.Nullable; 14 16 import javax.swing.JCheckBox; 15 17 import javax.swing.JPanel; 16 18 … … 26 28 import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper; 27 29 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 28 30 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 31 import org.openstreetmap.josm.spi.preferences.Config; 29 32 import org.openstreetmap.josm.tools.GBC; 30 33 import org.openstreetmap.josm.tools.Logging; 31 34 import org.openstreetmap.josm.tools.Stopwatch; … … 351 354 * @param p The primitive to be tested 352 355 * @return True if building key is set and different from no,entrance 353 356 */ 354 protected static finalboolean isBuilding(OsmPrimitive p) {357 protected static boolean isBuilding(OsmPrimitive p) { 355 358 return p.hasTagDifferent("building", "no", "entrance"); 356 359 } 357 360 … … 360 363 * @param p The primitive to be tested 361 364 * @return True if landuse key is equal to residential 362 365 */ 363 protected static finalboolean isResidentialArea(OsmPrimitive p) {366 protected static boolean isResidentialArea(OsmPrimitive p) { 364 367 return p.hasTag("landuse", "residential"); 365 368 } 366 369 370 /** 371 * Get the wiki link for a specified key and value 372 * @param key The key 373 * @param value The value 374 * @return The wiki link 375 * @since xxx 376 */ 377 @Nonnull 378 public static String getWikiLink(@Nonnull String key, @Nullable String value) { 379 final String wiki = Config.getUrls().getOSMWiki() + "/wiki/"; 380 if (value == null) { 381 return wiki + "Key:" + key; 382 } 383 return wiki + "Tag:" + key + "=" + value; 384 } 385 367 386 /** 368 387 * Free resources. 369 388 */ -
src/org/openstreetmap/josm/data/validation/TestError.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/validation/TestError.java b/src/org/openstreetmap/josm/data/validation/TestError.java
a b 12 12 import java.util.Locale; 13 13 import java.util.TreeSet; 14 14 import java.util.function.Supplier; 15 import java.util.regex.Pattern; 15 16 import java.util.stream.Collectors; 16 17 import java.util.stream.Stream; 17 18 … … 33 34 * @since 3669 34 35 */ 35 36 public class TestError implements Comparable<TestError> { 37 /** The pattern for html tags */ 38 private static final Pattern HTML_LINK_PATTERN = Pattern.compile("<a href=\".*?\">|</a>"); 36 39 /** is this error on the ignore list */ 37 40 private boolean ignored; 38 41 /** Severity */ … … 350 353 public String getIgnoreSubGroup() { 351 354 if (code == 3000) { 352 355 // see #19053 353 return "3000_" + (description == null ? message : description);356 return "3000_" + removeHtmlTags(getDescription() == null ? getMessage() : getDescription()); 354 357 } 355 358 String ignorestring = getIgnoreGroup(); 356 359 if (descriptionEn != null) { 357 ignorestring += '_' + descriptionEn;360 ignorestring += '_' + removeHtmlTags(descriptionEn); 358 361 } 359 362 return ignorestring; 360 363 } … … 367 370 public String getIgnoreGroup() { 368 371 if (code == 3000) { 369 372 // see #19053 370 return "3000_" + getMessage();373 return "3000_" + removeHtmlTags(getMessage()); 371 374 } 372 375 return Integer.toString(code); 373 376 } … … 573 576 return "TestError [tester=" + tester + ", code=" + code + ", message=" + message + ']'; 574 577 } 575 578 579 /** 580 * Remove html tags 581 * @param string The string to remove tags from (specifically the anchor tag) 582 * @return The stripped string 583 */ 584 private static String removeHtmlTags(String string) { 585 return HTML_LINK_PATTERN.matcher(string).replaceAll(""); 586 } 576 587 } -
src/org/openstreetmap/josm/gui/dialogs/validator/ValidatorTreeRenderer.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/gui/dialogs/validator/ValidatorTreeRenderer.java b/src/org/openstreetmap/josm/gui/dialogs/validator/ValidatorTreeRenderer.java
a b 3 3 4 4 import java.awt.Component; 5 5 6 import javax.swing.JLabel; 6 7 import javax.swing.JTree; 7 8 import javax.swing.tree.DefaultMutableTreeNode; 8 import javax.swing.tree.DefaultTreeCellRenderer;9 9 10 10 import org.openstreetmap.josm.data.validation.Severity; 11 11 import org.openstreetmap.josm.data.validation.TestError; 12 12 import org.openstreetmap.josm.data.validation.util.MultipleNameVisitor; 13 import org.openstreetmap.josm.gui.widgets.HtmlTreeCellRenderer; 13 14 import org.openstreetmap.josm.tools.ImageProvider; 14 15 15 16 /** 16 17 * Tree renderer for displaying errors 17 18 * @author frsantos 18 19 */ 19 public class ValidatorTreeRenderer extends DefaultTreeCellRenderer { 20 public class ValidatorTreeRenderer extends HtmlTreeCellRenderer { 21 22 private static final long serialVersionUID = 4750085115702320153L; 20 23 21 24 @Override 22 25 public Component getTreeCellRendererComponent(JTree tree, Object value, 23 26 boolean selected, boolean expanded, boolean leaf, int row, 24 27 boolean hasFocus) { 25 super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);28 final Component component = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); 26 29 27 DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;28 Object nodeInfo = node.getUserObject();30 final DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; 31 final Object nodeInfo = node.getUserObject(); 29 32 30 if (nodeInfo instanceof Severity) { 31 Severity s = (Severity) nodeInfo; 32 setIcon(ImageProvider.get("data", s.getIcon())); 33 } else if (nodeInfo instanceof TestError) { 34 TestError error = (TestError) nodeInfo; 35 MultipleNameVisitor v = error.getNameVisitor(); 36 setText(v.getText()); 37 setIcon(v.getIcon()); 33 if (component instanceof JLabel) { 34 final JLabel label = (JLabel) component; 35 if (nodeInfo instanceof Severity) { 36 final Severity s = (Severity) nodeInfo; 37 label.setIcon(ImageProvider.get("data", s.getIcon())); 38 } else if (nodeInfo instanceof TestError) { 39 final TestError error = (TestError) nodeInfo; 40 MultipleNameVisitor v = error.getNameVisitor(); 41 label.setText(v.getText()); 42 label.setIcon(v.getIcon()); 43 } 38 44 } 39 return this;45 return component; 40 46 } 41 47 } -
new file src/org/openstreetmap/josm/gui/widgets/HtmlTreeCellRenderer.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/gui/widgets/HtmlTreeCellRenderer.java b/src/org/openstreetmap/josm/gui/widgets/HtmlTreeCellRenderer.java new file mode 100644
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.widgets; 3 4 import java.awt.Color; 5 import java.awt.Component; 6 import java.awt.Cursor; 7 import java.awt.Point; 8 import java.awt.Rectangle; 9 import java.awt.event.MouseEvent; 10 import java.text.MessageFormat; 11 import java.util.Arrays; 12 13 import javax.annotation.Nullable; 14 import javax.swing.JLabel; 15 import javax.swing.JTree; 16 import javax.swing.event.HyperlinkEvent; 17 import javax.swing.event.MouseInputListener; 18 import javax.swing.text.html.HTMLDocument; 19 import javax.swing.text.html.StyleSheet; 20 import javax.swing.tree.DefaultMutableTreeNode; 21 import javax.swing.tree.DefaultTreeCellRenderer; 22 import javax.swing.tree.TreePath; 23 24 import org.openstreetmap.josm.tools.ColorHelper; 25 import org.openstreetmap.josm.tools.OpenBrowser; 26 27 /** 28 * A {@link javax.swing.tree.TreeCellRenderer} for cells that may contain hyperlinks. 29 * @since xxx 30 */ 31 public class HtmlTreeCellRenderer extends DefaultTreeCellRenderer { 32 /** 33 * This only exists since the JTree cannot pass events to subcomponents. 34 */ 35 private static class JTreeMouseInputListener implements MouseInputListener { 36 @Override 37 public void mouseClicked(MouseEvent mouseEvent) { 38 dispatchEvent(mouseEvent); 39 } 40 41 @Override 42 public void mouseMoved(MouseEvent mouseEvent) { 43 dispatchEvent(mouseEvent); 44 } 45 46 @Override 47 public void mousePressed(MouseEvent mouseEvent) { 48 // Do nothing -- this can cause issues with the popup menu 49 } 50 51 @Override 52 public void mouseReleased(MouseEvent mouseEvent) { 53 // Do nothing -- this can cause issues with the popup menu 54 } 55 56 @Override 57 public void mouseEntered(MouseEvent mouseEvent) { 58 dispatchEvent(mouseEvent); 59 } 60 61 @Override 62 public void mouseExited(MouseEvent mouseEvent) { 63 dispatchEvent(mouseEvent); 64 } 65 66 @Override 67 public void mouseDragged(MouseEvent mouseEvent) { 68 dispatchEvent(mouseEvent); 69 } 70 71 /** 72 * Dispatch mouse events for HTML-like cells 73 * @param mouseEvent The event to dispatch 74 */ 75 private static void dispatchEvent(MouseEvent mouseEvent) { 76 if (mouseEvent.getComponent() instanceof JTree) { 77 final Point p = mouseEvent.getPoint(); 78 final JTree tree = (JTree) mouseEvent.getComponent(); 79 final Component component = getComponentAt(tree, p); // p is translated here 80 if (component != null) { 81 component.dispatchEvent(new MouseEvent(component, // Use the component we found to fire the event 82 mouseEvent.getID(), mouseEvent.getWhen(), mouseEvent.getModifiers(), 83 p.x, p.y, mouseEvent.getClickCount(), mouseEvent.isPopupTrigger(), 84 mouseEvent.getButton())); 85 component.setBounds(0, 0, 0, 0); 86 } 87 } 88 } 89 90 /** 91 * Get a rendered component for HTML 92 * @param tree The tree to get the component from 93 * @param p The point to get the component at (will be modified) 94 * @return The component 95 */ 96 @Nullable 97 private static Component getComponentAt(JTree tree, Point p) { 98 final TreePath path = tree.getPathForLocation(p.x, p.y); 99 if (path != null && tree.getCellRenderer() instanceof HtmlTreeCellRenderer) { 100 final HtmlTreeCellRenderer renderer = (HtmlTreeCellRenderer) tree.getCellRenderer(); 101 final JosmEditorPane panel = renderer.panel; 102 renderer.panel.setText(null); // Reset text in panel to avoid having links in sub-elements. 103 final int row = tree.getRowForPath(path); 104 final Object last = path.getLastPathComponent(); 105 // We need to get the right text into the panel, so call the renderer 106 final Component component = renderer.getTreeCellRendererComponent(tree, last, 107 tree.isRowSelected(row), tree.isExpanded(row), 108 tree.getModel().isLeaf(last), row, true); 109 final Rectangle bounds = tree.getPathBounds(path); 110 if (bounds != null) { 111 // If we don't translate the point, we are attempting to get the link in the wrong frame of reference 112 // The reference x/y are 0. This is set in BasicTextUI#getVisibleEditorRect, so we must translate the point here. 113 final int width = (component instanceof JLabel) 114 ? ((JLabel) component).getIcon().getIconWidth() + ((JLabel) component).getIconTextGap() 115 : 0; 116 // This translation puts the origin point at the upper-left of the JLabel, but moves it to the right of the icon to the text 117 // Yes, it is - width, not + width. If you change this, make certain that clicking links still works! 118 p.translate(-bounds.x - width, -bounds.y); 119 // Just make certain that we are consistent for other objects. 120 bounds.x = 0; 121 bounds.y = 0; 122 // Set the correct width 123 bounds.width -= width; 124 // Set the bounds from the JTree component (needed for proper layout) 125 panel.setBounds(bounds); 126 return panel; 127 } 128 } 129 return null; 130 } 131 } 132 133 private static final long serialVersionUID = -4842755204541968238L; 134 /** 135 * A reusable panel to avoid new objects where possible. 136 * It isn't worth it to make a new object for each row, since it doesn't receive mouse events (tested on Java 8). 137 */ 138 private final JosmEditorPane panel = new JosmEditorPane(); 139 /** JTree does not send mouse events to subcomponents */ 140 private final JTreeMouseInputListener mouseTreeListener = new JTreeMouseInputListener(); 141 /** The tree used to set cursors when entering/leaving a hyperlink */ 142 private JTree tree; 143 144 /** 145 * Create a new renderer 146 */ 147 public HtmlTreeCellRenderer() { 148 panel.addHyperlinkListener(e -> { 149 if (e.getURL() != null) { 150 if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) { 151 OpenBrowser.displayUrl(e.getURL().toString()); 152 } else if (this.tree != null && HyperlinkEvent.EventType.ENTERED.equals(e.getEventType())) { 153 this.tree.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 154 } else if (this.tree != null && HyperlinkEvent.EventType.EXITED.equals(e.getEventType())) { 155 this.tree.setCursor(Cursor.getDefaultCursor()); 156 } 157 } 158 }); 159 JosmEditorPane.makeJLabelLike(panel, false); 160 final Color defaultLink = ColorHelper.html2color(JosmEditorPane.getLinkColor()); 161 final Color lighterLink = defaultLink.brighter().brighter(); 162 final Color darkerLink = defaultLink.darker().darker(); 163 final String divRule = "{0} '{'background-color:{1}; color:{2};'}'"; 164 final String aRule = "{0} a '{'text-decoration: underline; color:{1}'}'"; 165 StyleSheet ss = ((HTMLDocument) panel.getDocument()).getStyleSheet(); 166 ss.addRule(MessageFormat.format(divRule, ".selected", ColorHelper.color2html(getBackgroundSelectionColor()), 167 ColorHelper.color2html(getTextSelectionColor()))); 168 ss.addRule(MessageFormat.format(aRule, ".selected", 169 ColorHelper.color2html(getAppropriateColor(getBackgroundSelectionColor(), defaultLink, lighterLink, darkerLink)))); 170 ss.addRule(MessageFormat.format(divRule, ".not-selected", ColorHelper.color2html(getBackgroundNonSelectionColor()), 171 ColorHelper.color2html(getTextNonSelectionColor()))); 172 ss.addRule(MessageFormat.format(aRule, ".not-selected", 173 ColorHelper.color2html(getAppropriateColor(getBackgroundNonSelectionColor(), defaultLink, lighterLink, darkerLink)))); 174 } 175 176 @Override 177 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, 178 boolean leaf, int row, boolean hasFocus) { 179 final Component component = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); 180 this.tree = tree; 181 if (value instanceof DefaultMutableTreeNode) { 182 if (Arrays.stream(tree.getMouseListeners()).noneMatch(this.mouseTreeListener::equals)) { 183 tree.addMouseListener(this.mouseTreeListener); 184 tree.addMouseMotionListener(this.mouseTreeListener); 185 } 186 final DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; 187 final Object object = node.getUserObject(); 188 if (object instanceof String) { 189 final String text = (String) object; 190 final String modified = "<html><div class=\"" + (sel ? "selected" : "not-selected") + "\">" 191 + text + "</div></html>"; 192 this.panel.setText(modified); 193 this.setText(this.panel.getText()); // This gets the custom CSS into the JLabel 194 } 195 } 196 return component; 197 } 198 199 /** 200 * Convert the rgb value for use in a relative luminance calculation 201 * @param rgb The value to convert 202 * @return The appropriate value to use in the calculation 203 */ 204 private static double convertRGB(int rgb) { 205 final double normalized = rgb / 255d; 206 if (normalized <= 0.03928) { 207 return normalized / 12.92; 208 } 209 return Math.pow(((normalized + 0.055)/1.055), 2.4); 210 } 211 212 /** 213 * Calculate the contrast ratio between two luminance values 214 * @param luminanceOne The first luminance value 215 * @param luminanceTwo The second luminance value 216 * @return The contrast ratio. Higher is usually better. 217 */ 218 private static double contrastRatio(double luminanceOne, double luminanceTwo) { 219 final double min = Math.min(luminanceOne, luminanceTwo); 220 final double max = Math.max(luminanceOne, luminanceTwo); 221 return (max + 0.05) / (min + 0.05); 222 } 223 224 /** 225 * Calculate the luminance of a color 226 * @param red The red part 227 * @param green The green part 228 * @param blue The blue part 229 * @return The relative luminance (0-1, 0 black, 1 white) 230 */ 231 private static double luminance(int red, int green, int blue) { 232 return 0.2126 * convertRGB(red) 233 + 0.7152 * convertRGB(green) 234 + 0.0722 * convertRGB(blue); 235 } 236 237 /** 238 * Get the appropriate color given a background 239 * @param background The background color 240 * @param options The options to choose from 241 * @return The appropriate color 242 */ 243 private static Color getAppropriateColor(Color background, Color... options) { 244 if (options.length < 2) { 245 throw new IllegalArgumentException("There must be at least two color options"); 246 } 247 // sRGB calculation 248 final double backgroundLuminance = luminance(background.getRed(), background.getGreen(), background.getBlue()); 249 double lastContrastRatio = 0; // W3 recommends a contrast ratio of at least 4.5:1. We should be shooting for 7:1. 250 Color lastColor = null; 251 for (Color option : options) { 252 final double contrastRatio = contrastRatio(backgroundLuminance, luminance(option.getRed(), option.getGreen(), option.getBlue())); 253 if (contrastRatio > lastContrastRatio) { 254 lastContrastRatio = contrastRatio; 255 lastColor = option; 256 } 257 } 258 return lastColor; 259 } 260 } -
test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java b/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java
a b 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.validation.tests; 3 3 4 import static org.junit.jupiter.api.Assertions.assertAll; 4 5 import static org.junit.jupiter.api.Assertions.assertEquals; 5 6 import static org.junit.jupiter.api.Assertions.assertFalse; 6 7 import static org.junit.jupiter.api.Assertions.assertNotNull; … … 14 15 import java.util.LinkedHashSet; 15 16 import java.util.List; 16 17 import java.util.Set; 18 import java.util.stream.Stream; 17 19 18 20 import org.junit.jupiter.api.BeforeEach; 19 21 import org.junit.jupiter.api.Test; 20 22 import org.junit.jupiter.api.extension.RegisterExtension; 23 import org.junit.jupiter.params.ParameterizedTest; 24 import org.junit.jupiter.params.provider.Arguments; 25 import org.junit.jupiter.params.provider.MethodSource; 21 26 import org.openstreetmap.josm.TestUtils; 22 27 import org.openstreetmap.josm.command.ChangePropertyCommand; 23 28 import org.openstreetmap.josm.command.ChangePropertyKeyCommand; … … 105 110 final Collection<TestError> errors = check.getErrorsForPrimitive(n1, check.whichSelectorMatchesPrimitive(n1), new Environment(), null); 106 111 assertEquals(1, errors.size()); 107 112 TestError err = errors.iterator().next(); 108 assertEquals("deprecated", err.getMessage()); 109 assertEquals("natural=marsh is deprecated", err.getDescription()); 110 assertEquals(Severity.WARNING, err.getSeverity()); 111 assertEquals("Sequence: Fix of natural=marsh is deprecated", check.fixPrimitive(n1).getDescriptionText()); 112 assertEquals("{natural=}", ((ChangePropertyCommand) check.fixPrimitive(n1).getChildren().iterator().next()).getTags().toString()); 113 assertFalse(check.test(n2)); 114 assertEquals("The key is natural and the value is marsh", 115 MapCSSTagCheckerRule.insertArguments(check.rule.selectors.get(0), "The key is {0.key} and the value is {0.value}", null)); 113 assertAll(() -> assertEquals("deprecated", err.getMessage()), 114 () -> assertEquals("<a href=\"https://wiki.openstreetmap.org/wiki/Key:natural\">natural</a>=marsh is deprecated", 115 err.getDescription()), 116 () -> assertEquals(Severity.WARNING, err.getSeverity()), 117 () -> assertEquals("Sequence: Fix of natural=marsh is deprecated", check.fixPrimitive(n1).getDescriptionText()), 118 () -> assertEquals("{natural=}", 119 ((ChangePropertyCommand) check.fixPrimitive(n1).getChildren().iterator().next()).getTags().toString()), 120 () -> assertFalse(check.test(n2)), 121 () -> assertEquals("The key is natural and the value is marsh", 122 MapCSSTagCheckerRule.insertArguments(check.rule.selectors.get(0), 123 "The key is {0.key} and the value is {0.value}", null, false))); 116 124 } 117 125 118 126 /** … … 144 152 "throwWarning: tr(\"has {0} but not {1}\", \"{0.key}\", \"{1.key}\");}"); 145 153 final OsmPrimitive p = OsmUtils.createPrimitive("way alt_name=Foo"); 146 154 final Collection<TestError> errors = test.getErrorsForPrimitive(p, false); 147 assertEquals(1, errors.size()); 148 assertEquals("has alt_name but not name", errors.iterator().next().getMessage()); 149 assertEquals("3000_has alt_name but not name", errors.iterator().next().getIgnoreSubGroup()); 155 assertAll(() -> assertEquals(1, errors.size()), 156 () -> assertEquals("has <a href=\"https://wiki.openstreetmap.org/wiki/Key:alt_name\">alt_name</a> but not " + 157 "<a href=\"https://wiki.openstreetmap.org/wiki/Key:name\">name</a>", errors.iterator().next().getMessage()), 158 () -> assertEquals("3000_has alt_name but not name", errors.iterator().next().getIgnoreSubGroup())); 150 159 } 151 160 152 161 /** … … 159 168 " throwWarning: tr(\"{0} used with {1}\", \"{0.value}\", \"{1.tag}\");}"); 160 169 final OsmPrimitive p = OsmUtils.createPrimitive("way highway=footway foot=no"); 161 170 final Collection<TestError> errors = test.getErrorsForPrimitive(p, false); 162 assertEquals(1, errors.size()); 163 assertEquals("footway used with foot=no", errors.iterator().next().getMessage()); 164 assertEquals("3000_footway used with foot=no", errors.iterator().next().getIgnoreSubGroup()); 171 assertAll(() -> assertEquals(1, errors.size()), 172 () -> assertEquals("<a href=\"https://wiki.openstreetmap.org/wiki/Tag:highway=footway\">footway</a> used with " + 173 "<a href=\"https://wiki.openstreetmap.org/wiki/Tag:foot=no\">foot=no</a>", errors.iterator().next().getMessage()), 174 () -> assertEquals("3000_footway used with foot=no", errors.iterator().next().getIgnoreSubGroup())); 165 175 } 166 176 167 177 /** … … 207 217 assertTrue(c.getErrorsForPrimitive(node, false).isEmpty()); 208 218 } 209 219 220 static Stream<Arguments> testAssertions() { 221 MapCSSTagChecker c = new MapCSSTagChecker(); 222 return ValidatorPrefHelper.INSTANCE.getDefault().stream() 223 .map(entry -> Arguments.of(entry, c)); 224 } 225 210 226 /** 211 227 * Unit test for all {@link TagTest} assertions. 212 228 * @throws Exception if an error occurs 213 229 */ 214 @ Test215 void testAssertions() throws Exception {216 MapCSSTagChecker c = new MapCSSTagChecker();230 @ParameterizedTest 231 @MethodSource 232 void testAssertions(ExtendedSourceEntry entry, MapCSSTagChecker c) throws Exception { 217 233 Set<String> assertionErrors = new LinkedHashSet<>(); 218 234 219 235 // initialize 220 for (ExtendedSourceEntry entry : ValidatorPrefHelper.INSTANCE.getDefault()) { 221 c.addMapCSS(entry.url, assertionErrors::add); 222 } 236 c.addMapCSS(entry.url, assertionErrors::add); 223 237 224 238 for (String msg : assertionErrors) { 225 239 Logging.error(msg); -
test/unit/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetValidationTest.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/test/unit/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetValidationTest.java b/test/unit/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetValidationTest.java
a b 4 4 import static org.junit.jupiter.api.Assertions.assertEquals; 5 5 import static org.junit.jupiter.api.Assertions.assertTrue; 6 6 7 import java.util. Arrays;7 import java.util.Collections; 8 8 import java.util.Locale; 9 9 10 10 import javax.swing.JLabel; … … 31 31 */ 32 32 @RegisterExtension 33 33 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") 34 public JOSMTestRules rule = new JOSMTestRules().projection();34 static JOSMTestRules rule = new JOSMTestRules().projection(); 35 35 36 36 @BeforeEach 37 37 void setUp() { … … 54 54 assertTrue(label.isVisible()); 55 55 assertEquals("<html><ul>" + 56 56 "<li>Opening hours syntax (Hours without minutes)</li>" + 57 "<li>unusual value of width: meters is default; only positive values; point is decimal separator; if units, put space then unit</li>" +58 "<li>unusual value of incline, use x% or x° or up or down instead</li>" +59 "<li>suspicious tag combination ( widthon suspicious object)</li>" +60 "<li>suspicious tag combination ( inclineon suspicious object)</li></ul>", label.getToolTipText());57 "<li>unusual value of <a href=\"https://wiki.openstreetmap.org/wiki/Key:width\">width</a>: meters is default; only positive values; point is decimal separator; if units, put space then unit</li>" + 58 "<li>unusual value of <a href=\"https://wiki.openstreetmap.org/wiki/Key:incline\">incline</a>, use x% or x° or up or down instead</li>" + 59 "<li>suspicious tag combination (<a href=\"https://wiki.openstreetmap.org/wiki/Key:width\">width</a> on suspicious object)</li>" + 60 "<li>suspicious tag combination (<a href=\"https://wiki.openstreetmap.org/wiki/Key:incline\">incline</a> on suspicious object)</li></ul>", label.getToolTipText()); 61 61 // CHECKSTYLE.ON: LineLength 62 62 } 63 63 … … 68 68 void testApplyChangedTags() { 69 69 OsmPrimitive primitive = OsmUtils.createPrimitive("way incline=10m width=1mm opening_hours=\"Mo-Fr 8-10\""); 70 70 new DataSet(primitive); 71 OsmPrimitive clone = TaggingPresetValidation.applyChangedTags(primitive, Arrays.asList(new Tag("incline", "20m")));71 OsmPrimitive clone = TaggingPresetValidation.applyChangedTags(primitive, Collections.singletonList(new Tag("incline", "20m"))); 72 72 assertEquals("20m", clone.get("incline")); 73 73 assertEquals("1mm", clone.get("width")); 74 74 }
