Skip to content

Commit

Permalink
Merge pull request #12716 from riverwanderer/Search-HelpFix-Now-with-…
Browse files Browse the repository at this point in the history
…Regex

Support regular expressions in Editor search
  • Loading branch information
uckelman authored Sep 20, 2023
2 parents 12a79d4 + 0165658 commit 1c30631
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 8 deletions.
52 changes: 44 additions & 8 deletions vassal-app/src/main/java/VASSAL/configure/ConfigureTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -1813,6 +1813,7 @@ public Class<? extends Buildable> getChild() {
private static class SearchParameters {
public static final String SEARCH_STRING = "searchString"; //$NON-NLS-1$//
public static final String MATCH_CASE = "matchCase"; //$NON-NLS-1$//
public static final String MATCH_REGEX = "matchRegex"; //$NON-NLS-1$//
public static final String MATCH_NAMES = "matchNames"; //$NON-NLS-1$//
public static final String MATCH_TYPES = "matchTypes"; //$NON-NLS-1$//
public static final String MATCH_ADVANCED = "matchAdvanced"; //$NON-NLS-1$//
Expand All @@ -1829,6 +1830,9 @@ private static class SearchParameters {
/** True if case-sensitive */
private boolean matchCase;

/** True if matching on a Regular Expression */
private boolean matchRegex;

/** True if match configurable names */
private boolean matchNames;

Expand Down Expand Up @@ -1868,6 +1872,7 @@ public SearchParameters() {

prefs.addOption(null, new StringConfigurer(SearchParameters.SEARCH_STRING, null, ""));
prefs.addOption(null, new BooleanConfigurer(SearchParameters.MATCH_CASE, null, false));
prefs.addOption(null, new BooleanConfigurer(SearchParameters.MATCH_REGEX, null, false));
prefs.addOption(null, new BooleanConfigurer(SearchParameters.MATCH_NAMES, null, true));
prefs.addOption(null, new BooleanConfigurer(SearchParameters.MATCH_TYPES, null, true));
prefs.addOption(null, new BooleanConfigurer(SearchParameters.MATCH_ADVANCED, null, false));
Expand All @@ -1880,6 +1885,7 @@ public SearchParameters() {

searchString = (String) prefs.getValue(SearchParameters.SEARCH_STRING);
matchCase = (Boolean)prefs.getValue(SearchParameters.MATCH_CASE);
matchRegex = (Boolean)prefs.getValue(SearchParameters.MATCH_REGEX);
matchNames = (Boolean)prefs.getValue(SearchParameters.MATCH_NAMES);
matchTypes = (Boolean)prefs.getValue(SearchParameters.MATCH_TYPES);
matchAdvanced = (Boolean)prefs.getValue(SearchParameters.MATCH_ADVANCED);
Expand All @@ -1894,9 +1900,10 @@ public SearchParameters() {
/**
* Constructs a new search parameters object
*/
public SearchParameters(String searchString, boolean matchCase, boolean matchNames, boolean matchTypes, boolean matchAdvanced, boolean matchTraits, boolean matchExpressions, boolean matchProperties, boolean matchKeys, boolean matchMenus, boolean matchMessages) {
public SearchParameters(String searchString, boolean matchCase, boolean matchRegex, boolean matchNames, boolean matchTypes, boolean matchAdvanced, boolean matchTraits, boolean matchExpressions, boolean matchProperties, boolean matchKeys, boolean matchMenus, boolean matchMessages) {
this.searchString = searchString;
this.matchCase = matchCase;
this.matchRegex = matchRegex;
this.matchNames = matchNames;
this.matchTypes = matchTypes;
this.matchAdvanced = matchAdvanced;
Expand All @@ -1921,6 +1928,10 @@ public boolean isMatchCase() {
return matchCase;
}

public boolean isMatchRegex() {
return matchRegex;
}

public void setMatchCase(boolean matchCase) {
this.matchCase = matchCase;
writePrefs();
Expand Down Expand Up @@ -2012,6 +2023,7 @@ public void setMatchMessages(boolean matchMessages) {
public void setFrom(final SearchParameters searchParameters) {
searchString = searchParameters.getSearchString();
matchCase = searchParameters.isMatchCase();
matchRegex = searchParameters.isMatchRegex();
matchNames = searchParameters.isMatchNames();
matchTypes = searchParameters.isMatchTypes();
matchAdvanced = searchParameters.isMatchAdvanced();
Expand All @@ -2028,6 +2040,7 @@ public void writePrefs() {
if (prefs != null) {
prefs.setValue(SEARCH_STRING, searchString);
prefs.setValue(MATCH_CASE, matchCase);
prefs.setValue(MATCH_REGEX, matchRegex);
prefs.setValue(MATCH_NAMES, matchNames);
prefs.setValue(MATCH_TYPES, matchTypes);
prefs.setValue(MATCH_ADVANCED, matchAdvanced);
Expand All @@ -2050,6 +2063,7 @@ public boolean equals(Object o) {
}
final SearchParameters that = (SearchParameters) o;
return isMatchCase() == that.isMatchCase() &&
isMatchRegex() == that.isMatchRegex() &&
isMatchNames() == that.isMatchNames() &&
isMatchTypes() == that.isMatchTypes() &&
isMatchTraits() == that.isMatchTraits() &&
Expand All @@ -2064,7 +2078,7 @@ public boolean equals(Object o) {

@Override
public int hashCode() {
return Objects.hash(getSearchString(), isMatchCase(), isMatchNames(), isMatchTypes(), isMatchAdvanced(),
return Objects.hash(getSearchString(), isMatchCase(), isMatchRegex(), isMatchNames(), isMatchTypes(), isMatchAdvanced(),
isMatchTraits(), isMatchExpressions(), isMatchProperties(), isMatchKeys(),
isMatchMenus(), isMatchMessages());
}
Expand Down Expand Up @@ -2110,6 +2124,7 @@ public void actionPerformed(ActionEvent e) {
search.selectAll();

final JCheckBox sensitive = new JCheckBox(Resources.getString("Editor.search_case"), searchParameters.isMatchCase());
final JCheckBox regex = new JCheckBox(Resources.getString("Editor.search_regex"), searchParameters.isMatchRegex());
final JCheckBox advanced = new JCheckBox(Resources.getString("Editor.search_advanced"), searchParameters.isMatchAdvanced());

final JCheckBox names = new JCheckBox(Resources.getString("Editor.search_names"), searchParameters.isMatchNames());
Expand Down Expand Up @@ -2146,7 +2161,7 @@ public void actionPerformed(ActionEvent e) {
final JButton find = new JButton(Resources.getString("Editor.search_next"));
find.addActionListener(e12 -> {
final SearchParameters parametersSetInDialog =
new SearchParameters(search.getText(), sensitive.isSelected(), names.isSelected(), types.isSelected(), true, traits.isSelected(), expressions.isSelected(), properties.isSelected(), keys.isSelected(), menus.isSelected(), messages.isSelected());
new SearchParameters(search.getText(), sensitive.isSelected(), regex.isSelected(), names.isSelected(), types.isSelected(), true, traits.isSelected(), expressions.isSelected(), properties.isSelected(), keys.isSelected(), menus.isSelected(), messages.isSelected());

final boolean anyChanges = !searchParameters.equals(parametersSetInDialog);

Expand All @@ -2161,7 +2176,7 @@ public void actionPerformed(ActionEvent e) {
ConfigureTree.chat(Resources.getString("Editor.search_all_off"));
}

if (!searchParameters.getSearchString().isEmpty()) {
if (!searchParameters.getSearchString().isEmpty() && (!searchParameters.isMatchRegex() || isValidRegex(searchParameters.getSearchString()))) {
if (anyChanges) {
// Unless we're just continuing to the next match in an existing search, compute & display hit count
final int matches = getNumMatches(searchParameters.getSearchString());
Expand Down Expand Up @@ -2201,6 +2216,7 @@ public void actionPerformed(ActionEvent e) {

// options row
panel.add(sensitive);
panel.add(regex);
panel.add(advanced);

// Advanced 1
Expand Down Expand Up @@ -2638,18 +2654,38 @@ else if (c instanceof PrototypeDefinition) {
}
}

private boolean isValidRegex(String searchString) { // avoid exceptions by checking the Regex before use
try {
return "".matches(searchString) || true;
}
catch (java.util.regex.PatternSyntaxException e) {
chat("Search string is not a valid Regular Expression: " + e.getMessage()); //NON-NLS
return false;
}
}

/**
* Checks a single string against our search parameters
* @param target - string to check
* @param searchString - our search string
* @return true if this is a match based on our "matchCase" checkbox
* @return true if this is a match based on our "matchCase" & "matchRegex"checkboxes.
*/
private boolean checkString(String target, String searchString) {
if (searchParameters.isMatchCase()) {
return target.contains(searchString);
if (searchParameters.isMatchRegex()) {
if (searchParameters.isMatchCase()) {
return target.matches(searchString);
}
else {
return target.toLowerCase().matches(searchString.toLowerCase());
}
}
else {
return target.toLowerCase().contains(searchString.toLowerCase());
if (searchParameters.isMatchCase()) {
return target.contains(searchString);
}
else {
return target.toLowerCase().contains(searchString.toLowerCase());
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ Editor.search=Search...
Editor.search_string=String to find
Editor.search_next=Find next
Editor.search_case=Exact case
Editor.search_regex=Regular Expression
Editor.search_advanced=Advanced search
Editor.search_names=Match names
Editor.search_types=Match [Class names]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ a|
===== Exact Case
Force an Exact case search (i.e. abc is different to ABC).

===== Regular Expression
The specified search string is a https://en.wikipedia.org/wiki/Regular_expression[Regular Expression]. In the simplest example, a search for ABC will find matches that equate wholly to "ABC", and lower or mixed case variants (unless _Exact Case_ is checked as well).

===== Advanced Search
Show the advanced search options. All search options are on in a simple search. The advanced options allow you to turn off options to narrow your search.

Expand Down

0 comments on commit 1c30631

Please sign in to comment.