Skip to content

Commit

Permalink
See #24014: Add multiline and normalize attributes to preset xsd
Browse files Browse the repository at this point in the history
`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
  • Loading branch information
taylor.smock committed Nov 25, 2024
1 parent 2f216c3 commit 49e09d9
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 8 deletions.
12 changes: 6 additions & 6 deletions resources/data/defaultpresets.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7532,7 +7532,7 @@
<list_entry value="bench" short_description="A bench placed in memory of someone or something; usually has a plaque, and sometimes a statue sitting on (part of) it." />
</combo>
<optional>
<text key="inscription" text="Inscription" />
<text key="inscription" text="Inscription" multiline="true" />
<text key="artist_name" text="Artist Name" />
<combo key="material" text="Material" values="concrete,granite,metal,plastic,steel,stone,wood" />
<text key="start_date" text="Start date" />
Expand All @@ -7546,7 +7546,7 @@
<text key="name" text="Name" />
<reference ref="religious_catholic_christian" />
<text key="start_date" text="Start date" />
<text key="inscription" text="Inscription" />
<text key="inscription" text="Inscription" multiline="true" />
</item> <!-- Wayside Cross -->
<item name="Wayside Shrine" icon="presets/religion/wayside_shrine.svg" type="node,closedway" preset_name_label="true">
<link wiki="Tag:historic=wayside_shrine" />
Expand All @@ -7557,15 +7557,15 @@
<check key="amenity" text="Place of worship" value_on="place_of_worship" disable_off="true" />
<combo key="building" text="Building" values="wayside_shrine,yes" values_context="building" />
<text key="start_date" text="Start date" />
<text key="inscription" text="Inscription" />
<text key="inscription" text="Inscription" multiline="true" />
</item> <!-- Wayside Shrine -->
<item name="Boundary Stone" icon="presets/landmark/boundary_stone.svg" type="node,closedway" preset_name_label="true">
<link wiki="Tag:historic=boundary_stone" />
<space />
<key key="historic" value="boundary_stone" />
<optional>
<text key="name" text="Name" />
<text key="inscription" text="Inscription" />
<text key="inscription" text="Inscription" multiline="true" />
</optional>
<preset_link preset_name="Boundary Marker" text="Similar but different tags:" />
</item> <!-- Boundary Stone -->
Expand All @@ -7575,7 +7575,7 @@
<key key="historic" value="milestone" />
<optional>
<text key="name" text="Name" />
<text key="inscription" text="Inscription" />
<text key="inscription" text="Inscription" multiline="true" />
</optional>
</item> <!-- Milestone -->
</group> <!-- Historic Places -->
Expand Down Expand Up @@ -8964,7 +8964,7 @@
<key key="boundary" value="marker" />
<optional>
<reference ref="name_ref" />
<text key="inscription" text="Inscription" />
<text key="inscription" text="Inscription" multiline="true" />
<combo key="material" text="Material" values="concrete,metal,plastic,steel,stone,wood" />
</optional>
<preset_link preset_name="Boundary Stone" text="Similar but different tags:" />
Expand Down
14 changes: 14 additions & 0 deletions resources/data/tagging-preset.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,20 @@
</documentation>
</annotation>
</attribute>
<attribute name="multiline" type="boolean">
<annotation>
<documentation>
The text is expected to be multiline, and newlines must not be normalized (default is false)
</documentation>
</annotation>
</attribute>
<attribute name="normalize" type="boolean">
<annotation>
<documentation>
This performs normalization of the value by stripping extraneous spaces and consolidating whitespace (default is true for JOSM)
</documentation>
</annotation>
</attribute>
</attributeGroup>

<attributeGroup name="attributes.values">
Expand Down
10 changes: 9 additions & 1 deletion src/org/openstreetmap/josm/gui/tagging/presets/items/Text.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -240,7 +242,13 @@ public void addCommands(List<Tag> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
13 changes: 12 additions & 1 deletion src/org/openstreetmap/josm/tools/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -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(" ");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -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.

Check failure on line 56 in test/unit/org/openstreetmap/josm/gui/tagging/presets/items/TextTest.java

View workflow job for this annotation

GitHub Actions / Analyze

com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck

Line is longer than 145 characters (found 147).
final String expected = "This is a \nsample \ninscription";
final String toTest = MessageFormat.format(inscription, expected).replace("sample ", "sample ");
final Collection<TaggingPreset> presets = TaggingPresets.getMatchingPresets(Collections.singleton(TaggingPresetType.NODE), Map.of("historic", "boundary_stone", "inscription", "bar"), false);

Check failure on line 59 in test/unit/org/openstreetmap/josm/gui/tagging/presets/items/TextTest.java

View workflow job for this annotation

GitHub Actions / Analyze

com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck

Line is longer than 145 characters (found 198).
assertEquals(1, presets.size());
final TaggingPreset preset = presets.iterator().next();
final Text text = assertInstanceOf(Text.class, preset.data.get(5));
final List<Tag> 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");

Check failure on line 70 in test/unit/org/openstreetmap/josm/gui/tagging/presets/items/TextTest.java

View workflow job for this annotation

GitHub Actions / Analyze

com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck

Line is longer than 145 characters (found 152).
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.");
}
}

0 comments on commit 49e09d9

Please sign in to comment.