From 49e09d94ca381bf8217520c8d02c4c00f7a66e06 Mon Sep 17 00:00:00 2001 From: "taylor.smock" Date: Mon, 25 Nov 2024 22:08:52 +0000 Subject: [PATCH] See #24014: Add `multiline` and `normalize` attributes to preset xsd `normalize="false"` will prevent all whitespace normalization while `normalize="true"` + `multiline="true"` will strip start and end whitespace and inner whitespace that is not newlines. The primary reason for this change is osmwiki:Key:inscription which can have newlines in order to match the inscription. This does not modify UI elements to support multiline editing. git-svn-id: https://josm.openstreetmap.de/svn/trunk@19261 0c6e7542-c601-0410-84e7-c038aed88b3b --- resources/data/defaultpresets.xml | 12 +++--- resources/data/tagging-preset.xsd | 14 ++++++ .../josm/gui/tagging/presets/items/Text.java | 10 ++++- .../gui/tagging/presets/items/TextItem.java | 5 +++ src/org/openstreetmap/josm/tools/Utils.java | 13 +++++- .../gui/tagging/presets/items/TextTest.java | 43 +++++++++++++++++++ 6 files changed, 89 insertions(+), 8 deletions(-) diff --git a/resources/data/defaultpresets.xml b/resources/data/defaultpresets.xml index e07b906d105..0013d6f425c 100644 --- a/resources/data/defaultpresets.xml +++ b/resources/data/defaultpresets.xml @@ -7532,7 +7532,7 @@ - + @@ -7546,7 +7546,7 @@ - + @@ -7557,7 +7557,7 @@ - + @@ -7565,7 +7565,7 @@ - + @@ -7575,7 +7575,7 @@ - + @@ -8964,7 +8964,7 @@ - + diff --git a/resources/data/tagging-preset.xsd b/resources/data/tagging-preset.xsd index a8e5f043a56..84aa3ad6455 100644 --- a/resources/data/tagging-preset.xsd +++ b/resources/data/tagging-preset.xsd @@ -648,6 +648,20 @@ + + + + The text is expected to be multiline, and newlines must not be normalized (default is false) + + + + + + + This performs normalization of the value by stripping extraneous spaces and consolidating whitespace (default is true for JOSM) + + + diff --git a/src/org/openstreetmap/josm/gui/tagging/presets/items/Text.java b/src/org/openstreetmap/josm/gui/tagging/presets/items/Text.java index e1fe38ee426..7dd7254e4ea 100644 --- a/src/org/openstreetmap/josm/gui/tagging/presets/items/Text.java +++ b/src/org/openstreetmap/josm/gui/tagging/presets/items/Text.java @@ -13,6 +13,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.regex.Pattern; import javax.swing.AbstractButton; import javax.swing.BorderFactory; @@ -47,6 +48,7 @@ * Text field type. */ public class Text extends KeyedItem { + private static final Pattern MULTILINE_WHITESPACE_PATTERN = Pattern.compile("[\\s&&[^\n]]+"); private static int auto_increment_selected; // NOSONAR @@ -240,7 +242,13 @@ public void addCommands(List changedTags) { return; } - v = Utils.removeWhiteSpaces(v); + if (this.normalize) { + if (this.multiline) { + v = Utils.removeWhiteSpaces(MULTILINE_WHITESPACE_PATTERN, v); + } else { + v = Utils.removeWhiteSpaces(v); + } + } if (!"false".equals(use_last_as_default) || auto_increment != null) { LAST_VALUES.put(key, v); diff --git a/src/org/openstreetmap/josm/gui/tagging/presets/items/TextItem.java b/src/org/openstreetmap/josm/gui/tagging/presets/items/TextItem.java index d5511f36d67..c868969e8c9 100644 --- a/src/org/openstreetmap/josm/gui/tagging/presets/items/TextItem.java +++ b/src/org/openstreetmap/josm/gui/tagging/presets/items/TextItem.java @@ -23,6 +23,11 @@ public abstract class TextItem extends TaggingPresetItem { /** The context used for translating {@link #text} */ public String text_context; // NOSONAR + /** {@code true} if the value is a multiline value */ + public boolean multiline; // NOSONAR + /** {@code true} if the value should be normalized */ + public boolean normalize = true; // NOSONAR + /** The localized version of {@link #text} */ public String locale_text; // NOSONAR diff --git a/src/org/openstreetmap/josm/tools/Utils.java b/src/org/openstreetmap/josm/tools/Utils.java index 34565416769..c51ca89eba6 100644 --- a/src/org/openstreetmap/josm/tools/Utils.java +++ b/src/org/openstreetmap/josm/tools/Utils.java @@ -820,10 +820,21 @@ private static boolean isStrippedChar(char c, final String skipChars) { * @since 13597 */ public static String removeWhiteSpaces(String s) { + return removeWhiteSpaces(WHITE_SPACES_PATTERN, s); + } + + /** + * Removes leading, trailing, and multiple inner whitespaces from the given string, to be used as a key or value. + * @param s The string + * @param whitespaces The regex for whitespaces to remove outside the leading and trailing whitespaces (see {@link #strip(String)}) + * @return The string without leading, trailing or multiple inner whitespaces + * @since 19261 + */ + public static String removeWhiteSpaces(Pattern whitespaces, String s) { if (isEmpty(s)) { return s; } - return strip(s).replaceAll("\\s+", " "); + return whitespaces.matcher(strip(s)).replaceAll(" "); } /** diff --git a/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/TextTest.java b/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/TextTest.java index 84dc79195c3..71c5eece5b1 100644 --- a/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/TextTest.java +++ b/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/TextTest.java @@ -2,13 +2,29 @@ package org.openstreetmap.josm.gui.tagging.presets.items; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import javax.swing.JComponent; import javax.swing.JPanel; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.openstreetmap.josm.data.osm.Tag; +import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset; import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItemGuiSupport; import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItemTest; +import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetType; +import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets; +import org.openstreetmap.josm.gui.widgets.JosmTextField; import org.openstreetmap.josm.testutils.annotations.Main; /** @@ -32,4 +48,31 @@ public void testAddToPanel() { assertTrue(getInstance().addToPanel(p, TaggingPresetItemGuiSupport.create(false))); assertTrue(p.getComponentCount() > 0); } + + @org.openstreetmap.josm.testutils.annotations.TaggingPresets + @ParameterizedTest + @ValueSource(strings = {"\n\n\n\t\r {0}\n\n\n", "{0}"}) + void testNonRegression24023(String inscription) { + // There is a bit of "extra" whitespace in the string (` \n`). It is somewhat deliberate. We probably ought to remove the ` ` at some time. + final String expected = "This is a \nsample \ninscription"; + final String toTest = MessageFormat.format(inscription, expected).replace("sample ", "sample "); + final Collection presets = TaggingPresets.getMatchingPresets(Collections.singleton(TaggingPresetType.NODE), Map.of("historic", "boundary_stone", "inscription", "bar"), false); + assertEquals(1, presets.size()); + final TaggingPreset preset = presets.iterator().next(); + final Text text = assertInstanceOf(Text.class, preset.data.get(5)); + final List changeCommands = new ArrayList<>(1); + final JPanel panel = new JPanel(); + text.addToPanel(panel, TaggingPresetItemGuiSupport.create(false)); + JComponent value = assertInstanceOf(JComponent.class, panel.getComponent(1)); + while (value instanceof JPanel) { + value = (JComponent) value.getComponent(0); + } + final JosmTextField textField = assertInstanceOf(JosmTextField.class, value, "Until we support multiline editing, this should be a text field"); + textField.setText(toTest); + text.addCommands(changeCommands); + assertTrue(text.multiline); + assertTrue(text.normalize); + assertEquals(1, changeCommands.size()); + assertEquals(expected, changeCommands.get(0).getValue(), "If the only difference is a trailing space was removed, update the test."); + } }