From 2f278bd4ca2d914ebc4241f98183d78be6f94513 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 22 Feb 2022 18:21:11 -0500 Subject: [PATCH 1/2] GP-1754 - Updated Symbol Edit Dialog to not allow namespaces editing with a blank name --- .../java/ghidra/app/util/AddEditDialog.java | 6 +++++ .../plugin/core/label/AddEditDialoglTest.java | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddEditDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddEditDialog.java index 632f88416a..b075eb3037 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddEditDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddEditDialog.java @@ -153,6 +153,11 @@ public class AddEditDialog extends DialogComponentProvider { } String symbolName = symbolPath.getName(); + if (StringUtils.isBlank(symbolName)) { + // this is the case of having a namespace without a name, such as "Namespace::" + setStatusText("Name cannot be blank while changing namespace"); + return; + } // see if the user specified a namespace path and if so, then get the // new namespace name from that path @@ -178,6 +183,7 @@ public class AddEditDialog extends DialogComponentProvider { return; } + cmd = new CompoundCmd(symbol == null ? "Add Label" : "Edit Label"); if (primaryCheckBox.isEnabled() && primaryCheckBox.isSelected()) { cmd.add(new SetLabelPrimaryCmd(addr, symbolName, parent)); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/AddEditDialoglTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/AddEditDialoglTest.java index d3ede93d7c..7311dbd800 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/AddEditDialoglTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/label/AddEditDialoglTest.java @@ -754,6 +754,32 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(nsName, parentNs.getName()); } + @Test + public void testSetNamespace_NamespaceWithoutFunctionName() throws Exception { + + // + // Test that we can cannot create a new namespace and clear a symbol name using this form: + // "Namespace::" + // + // A blank name is a signal to reset to a default name, but we do not currently support + // changing a namespace and resetting the name in the same operation. + // + + String functionName = "FUN_010065f0"; + Symbol functionSymbol = getSymbol(functionName); + Namespace originalNamespace = functionSymbol.getParentNamespace(); + editLabel(functionSymbol); + String nsName = "NewNamespace"; + setText(nsName + Namespace.DELIMITER); + pressOk(); + assertTrue("Rename unsuccesful", dialog.isShowing()); + assertStatusText("Name cannot be blank while changing namespace"); + + Symbol newFunction = functionSymbol; + Namespace parentNs = newFunction.getParentNamespace(); + assertSame(originalNamespace, parentNs); + } + //================================================================================================== // Private Methods //================================================================================================== From 79ae7d0b992bcf01c0e11c96458f9b0255374852 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Thu, 24 Feb 2022 12:15:18 -0500 Subject: [PATCH 2/2] GP-1764 - Fixed table CSV export of boolean values --- .../widgets/table/GBooleanCellRenderer.java | 4 + .../docking/widgets/table/GTableToCSV.java | 32 ++++- .../docking/widgets/table/GTableCSVTest.java | 111 +++++++++++++----- 3 files changed, 115 insertions(+), 32 deletions(-) diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GBooleanCellRenderer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GBooleanCellRenderer.java index 9722093a52..386d5e81f9 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GBooleanCellRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GBooleanCellRenderer.java @@ -42,6 +42,10 @@ public class GBooleanCellRenderer extends GTableCellRenderer { return this; } + public boolean isSelected() { + return cb.isSelected(); + } + @Override public void invalidate() { superValidate(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableToCSV.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableToCSV.java index 4876a27d5a..31d862d09c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableToCSV.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableToCSV.java @@ -77,7 +77,7 @@ public final class GTableToCSV { private static List getVisibleColumnsInOrder(JTable table, TaskMonitor monitor) { TableColumnModel columnModel = table.getColumnModel(); - List columns = new ArrayList(); + List columns = new ArrayList<>(); for (int columnIndex = 0; columnIndex < table.getColumnCount(); ++columnIndex) { if (monitor.isCancelled()) { break; @@ -92,7 +92,7 @@ public final class GTableToCSV { List columnIndices) { TableColumnModel columnModel = table.getColumnModel(); - List columns = new ArrayList(); + List columns = new ArrayList<>(); for (Integer index : columnIndices) { TableColumn column = columnModel.getColumn(index); columns.add(column); @@ -163,7 +163,7 @@ public final class GTableToCSV { } /** - * Attempts to get the text value for the cell so that the data will match what the user sees. + * Attempts to get the text value for the cell so that the data will match what the user sees. */ private static String getTableCellValue(JTable table, TableModel model, int row, int column) { TableCellRenderer renderer = table.getCellRenderer(row, column); @@ -174,6 +174,10 @@ public final class GTableToCSV { Component component = renderer.getTableCellRendererComponent(table, value, false, false, row, column); + if (isCheckBox(component)) { + return getCheckBoxValue(component); + } + if (component instanceof JLabel) { JLabel label = (JLabel) component; return getTextForLabel(label); @@ -187,7 +191,27 @@ public final class GTableToCSV { return value == null ? "" : value.toString(); } + private static boolean isCheckBox(Component component) { + return component instanceof JCheckBox || component instanceof GBooleanCellRenderer; + } + + private static String getCheckBoxValue(Component component) { + + if (component instanceof JCheckBox) { + JCheckBox cb = (JCheckBox) component; + return Boolean.toString(cb.isSelected()); + } + + if (component instanceof GBooleanCellRenderer) { + GBooleanCellRenderer renderer = (GBooleanCellRenderer) component; + return Boolean.toString(renderer.isSelected()); + } + + return ""; + } + private static String getTextForLabel(JLabel label) { + String text = label.getText(); if (text != null) { return text; @@ -334,7 +358,7 @@ public final class GTableToCSV { private final GTable table; private File file; - private List columns = new ArrayList(); + private List columns = new ArrayList<>(); ConvertTask(File file, GTable table) { super(GTableToCSV.TITLE, true, true, true); diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/GTableCSVTest.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/GTableCSVTest.java index 6b89463670..c68a36a51f 100644 --- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/GTableCSVTest.java +++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/table/GTableCSVTest.java @@ -28,20 +28,17 @@ import ghidra.util.task.TaskMonitor; public class GTableCSVTest { @Test - public void testCSV_QuotesGetEscaped() { + public void testCsv_QuotesGetEscaped() { - AnyObjectTableModel model = - new AnyObjectTableModel<>("MyModel", CSVRowObject.class, + AnyObjectTableModel model = + new AnyObjectTableModel<>("MyModel", CsvRowObject.class, "getName", "getDescription", "getNumber"); - //@formatter:off - List data = Arrays.asList( - new CSVRowObject("Bob", "Bobby", 11), - new CSVRowObject("Joan", "Joan has \"quoted\" text", 0), - new CSVRowObject("Sam", "\"Sam has a single quote text", 23), - new CSVRowObject("Time", "Tim is last", 33) - ); - //@formatter:on + List data = Arrays.asList( + new CsvRowObject("Bob", "Bobby", 11), + new CsvRowObject("Joan", "Joan has \"quoted\" text", 0), + new CsvRowObject("Sam", "\"Sam has a single quote text", 23), + new CsvRowObject("Time", "Tim is last", 33)); model.setModelData(data); GTable table = new GTable(model); @@ -50,24 +47,21 @@ public class GTableCSVTest { PrintWriterSpy writer = new PrintWriterSpy(); GTableToCSV.writeCSV(writer, table, columns, TaskMonitor.DUMMY); - assertRowValues(data, writer); + assertCsvRowValues(data, writer); } @Test - public void testCSV_CommasGetEscaped() { + public void testCsv_CommasGetEscaped() { - AnyObjectTableModel model = - new AnyObjectTableModel<>("MyModel", CSVRowObject.class, + AnyObjectTableModel model = + new AnyObjectTableModel<>("MyModel", CsvRowObject.class, "getName", "getDescription", "getNumber"); - //@formatter:off - List data = Arrays.asList( - new CSVRowObject("Bob", "Bobby", 11), - new CSVRowObject("Joan", "Joan has a comma, in her text", 0), - new CSVRowObject("Sam", ",Sam has a leading comma", 23), - new CSVRowObject("Time", "Tim is last", 33) - ); - //@formatter:on + List data = Arrays.asList( + new CsvRowObject("Bob", "Bobby", 11), + new CsvRowObject("Joan", "Joan has a comma, in her text", 0), + new CsvRowObject("Sam", ",Sam has a leading comma", 23), + new CsvRowObject("Time", "Tim is last", 33)); model.setModelData(data); GTable table = new GTable(model); @@ -76,16 +70,39 @@ public class GTableCSVTest { PrintWriterSpy writer = new PrintWriterSpy(); GTableToCSV.writeCSV(writer, table, columns, TaskMonitor.DUMMY); - assertRowValues(data, writer); + assertCsvRowValues(data, writer); } - private void assertRowValues(List data, PrintWriterSpy writer) { + @Test + public void testCsv_BooleaValues() { + + AnyObjectTableModel model = + new AnyObjectTableModel<>("MyModel", BooleanCsvRowObject.class, + "getName", "isSelected"); + + List data = Arrays.asList( + new BooleanCsvRowObject("Bob", true), + new BooleanCsvRowObject("Joan", false), + new BooleanCsvRowObject("Sam", false), + new BooleanCsvRowObject("Time", true)); + model.setModelData(data); + + GTable table = new GTable(model); + List columns = new ArrayList<>(); + + PrintWriterSpy writer = new PrintWriterSpy(); + GTableToCSV.writeCSV(writer, table, columns, TaskMonitor.DUMMY); + + assertBooleanCsvRowValues(data, writer); + } + + private void assertCsvRowValues(List data, PrintWriterSpy writer) { String results = writer.toString(); String[] lines = results.split("\n"); for (int i = 1; i < lines.length; i++) { int index = i - 1; // the first line is the header - CSVRowObject row = data.get(index); + CsvRowObject row = data.get(index); String line = lines[i]; String[] columns = line.split("(? data, PrintWriterSpy writer) { + + String results = writer.toString(); + String[] lines = results.split("\n"); + for (int i = 1; i < lines.length; i++) { + int index = i - 1; // the first line is the header + BooleanCsvRowObject row = data.get(index); + String line = lines[i]; + String[] columns = line.split("(?