diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Trees/GhidraTreeFilter.html b/Ghidra/Features/Base/src/main/help/help/topics/Trees/GhidraTreeFilter.html
index b7a8651a04..8a69d02136 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/Trees/GhidraTreeFilter.html
+++ b/Ghidra/Features/Base/src/main/help/help/topics/Trees/GhidraTreeFilter.html
@@ -293,7 +293,7 @@
-
protected Pattern generateFindsPattern() {
String regexString = UserSearchUtils.createPatternString(patternString, true);
return Pattern.compile("(" + regexString + ")",
- Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
+ Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.DOTALL);
}
@Override
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringContainsColumnConstraint.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringContainsColumnConstraint.java
index 801cdf8fe9..4e058d591f 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringContainsColumnConstraint.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringContainsColumnConstraint.java
@@ -46,7 +46,6 @@ public class StringContainsColumnConstraint extends StringColumnConstraint {
@Override
protected Pattern generateMatchesPattern(String patternString) {
return UserSearchUtils.createContainsPattern(patternString.trim(), true,
- Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
+ Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.DOTALL);
}
-
}
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringEndsWithColumnConstraint.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringEndsWithColumnConstraint.java
index a2216f96fe..b36c02f61f 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringEndsWithColumnConstraint.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringEndsWithColumnConstraint.java
@@ -45,6 +45,6 @@ public class StringEndsWithColumnConstraint extends StringColumnConstraint {
@Override
protected Pattern generateMatchesPattern(String patternString) {
return UserSearchUtils.createEndsWithPattern(patternString, true,
- Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
+ Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.DOTALL);
}
}
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringMatchesColumnConstraint.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringMatchesColumnConstraint.java
index aa4d04ea85..f91aa75172 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringMatchesColumnConstraint.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringMatchesColumnConstraint.java
@@ -18,6 +18,8 @@ package docking.widgets.table.constraint;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
+import ghidra.util.UserSearchUtils;
+
/**
* String column constraint for matching column values if they match a full regular expression pattern.
*/
@@ -26,7 +28,7 @@ public class StringMatchesColumnConstraint extends StringColumnConstraint {
* Constructor
*
* This class is for users to enter true regular expression which is why it creates
- * a pattern directly without using the UserSearchUtils
+ * a pattern directly without using the {@link UserSearchUtils}.
*
* @param spec the string to use to create a "matcher" pattern.
*/
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringNotMatchesColumnConstraint.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringNotMatchesColumnConstraint.java
index eafc74cedb..4cae6043e4 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringNotMatchesColumnConstraint.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringNotMatchesColumnConstraint.java
@@ -15,6 +15,8 @@
*/
package docking.widgets.table.constraint;
+import ghidra.util.UserSearchUtils;
+
/**
* String column constraint for matching column values if they do not match a full regular
* expression pattern.
@@ -25,7 +27,7 @@ public class StringNotMatchesColumnConstraint extends StringMatchesColumnConstra
* Constructor
*
*
This class is for users to enter true regular expression which is why it creates
- * a pattern directly without using the UserSearchUtils
+ * a pattern directly without using the {@link UserSearchUtils}
*
* @param spec the string to use to create a "matcher" pattern.
*/
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringStartsWithColumnConstraint.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringStartsWithColumnConstraint.java
index 0feb03a8ad..5d6aa1ff05 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringStartsWithColumnConstraint.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/StringStartsWithColumnConstraint.java
@@ -46,6 +46,6 @@ public class StringStartsWithColumnConstraint extends StringColumnConstraint {
@Override
protected Pattern generateMatchesPattern(String patternString) {
return UserSearchUtils.createStartsWithPattern(patternString, true,
- Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
+ Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.DOTALL);
}
}
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AutocompletingStringConstraintEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AutocompletingStringConstraintEditor.java
index 4617f4ecbc..16ecd266be 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AutocompletingStringConstraintEditor.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AutocompletingStringConstraintEditor.java
@@ -227,7 +227,6 @@ public class AutocompletingStringConstraintEditor extends DataLoadingConstraintE
matcher.appendReplacement(sb, replacement);
}
matcher.appendTail(sb);
-
return sb.toString();
}
diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/columnfilter/ColumnTableFilterTest.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/columnfilter/ColumnTableFilterTest.java
index a43419bc8c..bee2fdec36 100644
--- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/columnfilter/ColumnTableFilterTest.java
+++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/columnfilter/ColumnTableFilterTest.java
@@ -19,8 +19,8 @@ import static org.junit.Assert.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.time.LocalDate;
-import java.util.*;
+import java.util.Date;
+import java.util.List;
import javax.swing.table.TableColumn;
@@ -29,14 +29,9 @@ import org.junit.Test;
import docking.test.AbstractDockingTest;
import docking.widgets.table.*;
-import docking.widgets.table.constraint.ColumnConstraint;
-import docking.widgets.table.constraint.MappedColumnConstraint;
import docking.widgets.table.constraint.dialog.*;
-import docking.widgets.table.constraint.provider.*;
import ghidra.framework.options.SaveState;
-import ghidra.util.Msg;
import ghidra.util.classfinder.ClassSearcher;
-import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
@@ -85,6 +80,18 @@ public class ColumnTableFilterTest extends AbstractDockingTest {
return new TableModelWrapper<>(testTableModel);
}
+ private RowObjectFilterModel createTableModelWithNewlines() {
+ TestTableModel testTableModel = new TestTableModel();
+
+ testTableModel.addColumn("Name",
+ new String[] { "Hello World\n", "\nHello World", "Hello\nWorld", "Hello World" });
+
+ testTableModel.addColumn("Long ID",
+ new Long[] { 1000l, 2000l, 3000l });
+
+ return new TableModelWrapper<>(testTableModel);
+ }
+
private Date date(String dateString) {
try {
return DATE_FORMAT.parse(dateString);
@@ -107,6 +114,27 @@ public class ColumnTableFilterTest extends AbstractDockingTest {
assertEquals("Chuck", tableModel.getValueAt(0, col));
}
+ @Test
+ public void testStringStartsWithColumnFilter_WithNewline() {
+
+ runSwing(() -> gTable.dispose());
+
+ tableModel = createTableModelWithNewlines();
+ gTable = new GTable(tableModel);
+ filterModel = new ColumnFilterDialogModel<>(tableModel, gTable.getColumnModel(), null);
+
+ addFirstFilter("Name", "Starts With", "Hello");
+
+ applyFilter();
+
+ assertEquals(3, tableModel.getRowCount());
+
+ int col = getColumn("Name");
+ assertEquals("Hello World\n", tableModel.getValueAt(0, col));
+ assertEquals("Hello\nWorld", tableModel.getValueAt(1, col));
+ assertEquals("Hello World", tableModel.getValueAt(2, col));
+ }
+
@Test
public void testStringDoesNotStartsWithColumnFilter() {
addFirstFilter("Name", "Does Not Start With", "C");
@@ -136,6 +164,27 @@ public class ColumnTableFilterTest extends AbstractDockingTest {
assertEquals("Dave", tableModel.getValueAt(1, col));
}
+ @Test
+ public void testStringEndsWithColumnFilter_WithNewline() {
+
+ runSwing(() -> gTable.dispose());
+
+ tableModel = createTableModelWithNewlines();
+ gTable = new GTable(tableModel);
+ filterModel = new ColumnFilterDialogModel<>(tableModel, gTable.getColumnModel(), null);
+
+ addFirstFilter("Name", "Ends With", "World");
+
+ applyFilter();
+
+ assertEquals(3, tableModel.getRowCount());
+
+ int col = getColumn("Name");
+ assertEquals("\nHello World", tableModel.getValueAt(0, col));
+ assertEquals("Hello\nWorld", tableModel.getValueAt(1, col));
+ assertEquals("Hello World", tableModel.getValueAt(2, col));
+ }
+
@Test
public void testStringContainsColumnFilter() {
addFirstFilter("Name", "Contains", "l");
@@ -149,6 +198,44 @@ public class ColumnTableFilterTest extends AbstractDockingTest {
assertEquals("Ellen", tableModel.getValueAt(1, col));
}
+ @Test
+ public void testStringContainsColumnFilter_WithNewline() {
+
+ runSwing(() -> gTable.dispose());
+
+ tableModel = createTableModelWithNewlines();
+ gTable = new GTable(tableModel);
+ filterModel = new ColumnFilterDialogModel<>(tableModel, gTable.getColumnModel(), null);
+
+ addFirstFilter("Name", "Contains", "Hello");
+
+ applyFilter();
+
+ assertEquals(4, tableModel.getRowCount());
+
+ int col = getColumn("Name");
+ assertEquals("Hello World\n", tableModel.getValueAt(0, col));
+ assertEquals("\nHello World", tableModel.getValueAt(1, col));
+ assertEquals("Hello\nWorld", tableModel.getValueAt(2, col));
+ assertEquals("Hello World", tableModel.getValueAt(3, col));
+ }
+
+ @Test
+ public void testStringNotContainsColumnFilter_WithNewline() {
+
+ runSwing(() -> gTable.dispose());
+
+ tableModel = createTableModelWithNewlines();
+ gTable = new GTable(tableModel);
+ filterModel = new ColumnFilterDialogModel<>(tableModel, gTable.getColumnModel(), null);
+
+ addFirstFilter("Name", "Does Not Contain", "Hello");
+
+ applyFilter();
+
+ assertEquals(0, tableModel.getRowCount());
+ }
+
@Test
public void testStringMatchesColumnFilter() {
addFirstFilter("Name", "Matches Regex", ".*l.*e.*");
@@ -162,6 +249,49 @@ public class ColumnTableFilterTest extends AbstractDockingTest {
assertEquals("Ellen", tableModel.getValueAt(1, col));
}
+ @Test
+ public void testStringMatchesColumnFilter_WithNewline() {
+
+ runSwing(() -> gTable.dispose());
+
+ tableModel = createTableModelWithNewlines();
+ gTable = new GTable(tableModel);
+ filterModel = new ColumnFilterDialogModel<>(tableModel, gTable.getColumnModel(), null);
+
+ addFirstFilter("Name", "Matches Regex", ".*Hello\\sWorld.*");
+
+ applyFilter();
+
+ assertEquals(2, tableModel.getRowCount());
+
+ // only matches when newline not at the beginning or end, since DOTALL mode is not used
+ int col = getColumn("Name");
+ assertEquals("Hello\nWorld", tableModel.getValueAt(0, col));
+ assertEquals("Hello World", tableModel.getValueAt(1, col));
+ }
+
+ @Test
+ public void testStringMatchesColumnFilter_WithNewline_WithDotallMode() {
+
+ runSwing(() -> gTable.dispose());
+
+ tableModel = createTableModelWithNewlines();
+ gTable = new GTable(tableModel);
+ filterModel = new ColumnFilterDialogModel<>(tableModel, gTable.getColumnModel(), null);
+
+ addFirstFilter("Name", "Matches Regex", "(?s).*Hello\\sWorld.*");
+
+ applyFilter();
+
+ assertEquals(4, tableModel.getRowCount());
+
+ int col = getColumn("Name");
+ assertEquals("Hello World\n", tableModel.getValueAt(0, col));
+ assertEquals("\nHello World", tableModel.getValueAt(1, col));
+ assertEquals("Hello\nWorld", tableModel.getValueAt(2, col));
+ assertEquals("Hello World", tableModel.getValueAt(3, col));
+ }
+
@Test
public void testStringNotMatchesColumnFilter() {
addFirstFilter("Name", "Does Not Match Regex", ".*l.*e.*");
@@ -683,20 +813,6 @@ public class ColumnTableFilterTest extends AbstractDockingTest {
return null;
}
- @SuppressWarnings("unchecked")
- private List> loadConstraints() {
- List> list = new ArrayList<>();
- list.addAll(new NumberColumnConstraintProvider().getColumnConstraints());
- list.addAll(new StringColumnConstraintProvider().getColumnConstraints());
- Collection> columnConstraints =
- new DateColumnConstraintProvider().getColumnConstraints();
- for (ColumnConstraint> c : columnConstraints) {
- list.add(new MappedColumnConstraint<>(new DateColumnTypeMapper(),
- (ColumnConstraint) c));
- }
- return list;
- }
-
private void addConstraints(String columnName, String[] constraintNames,
String[] constraintValues, boolean first) {
diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/columnfilter/TestTableModel.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/columnfilter/TestTableModel.java
index 3cb62dacc6..147e42f9f2 100644
--- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/columnfilter/TestTableModel.java
+++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/columnfilter/TestTableModel.java
@@ -112,7 +112,7 @@ class TestTableModel implements RowObjectTableModel {
@Override
public List getModelData() {
List rowObjects = new ArrayList<>();
- for (int i = 0; i < getColumnCount(); i++) {
+ for (int i = 0; i < rowCount; i++) {
rowObjects.add(i);
}
return rowObjects;