Skip to content

Commit dabaa34

Browse files
committed
Merge remote-tracking branch 'origin/GT-3207-dragonmacher-table-header-npe' into Ghidra_9.1
2 parents 40c5493 + 53ba79e commit dabaa34

File tree

3 files changed

+138
-4
lines changed

3 files changed

+138
-4
lines changed

Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/functionwindow/FunctionWindowPluginTest.java

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@
1515
*/
1616
package ghidra.app.plugin.core.functionwindow;
1717

18-
import static org.junit.Assert.assertEquals;
18+
import static org.junit.Assert.*;
19+
20+
import javax.swing.*;
21+
import javax.swing.event.ChangeEvent;
22+
import javax.swing.table.*;
1923

2024
import org.junit.*;
2125

2226
import docking.ComponentProvider;
27+
import docking.widgets.combobox.GComboBox;
28+
import docking.widgets.dialogs.SettingsDialog;
2329
import docking.widgets.table.GTable;
2430
import docking.widgets.table.threaded.ThreadedTableModel;
2531
import ghidra.app.plugin.core.clear.ClearCmd;
@@ -99,6 +105,84 @@ public void testProgramClose() throws Exception {
99105
loadProgram("notepad");
100106
}
101107

108+
@Test
109+
public void testChangeSettings() throws Exception {
110+
//
111+
// This test is for a regression bug. There were multiple exceptions happening when
112+
// executing the code paths below.
113+
//
114+
115+
int row = 0;
116+
int column = getColumnIndex("Function Size");
117+
String startValue = getRenderedTableCellValue(functionTable, row, column);
118+
119+
JPopupMenu menu = functionTable.getTableColumnPopupMenu(column);
120+
JMenuItem item = (JMenuItem) menu.getComponent(1);
121+
assertEquals("Column Settings...", item.getText());
122+
123+
pressButton(item, false);
124+
125+
SettingsDialog dialog = waitForDialogComponent(SettingsDialog.class);
126+
int editRow = getFormatRow(dialog);
127+
//triggerEdit(dialog, editRow, 1);
128+
editCell(dialog.getTable(), editRow, 1);
129+
setComboValue(dialog, "hex");
130+
endEdit(dialog);
131+
pressButtonByText(dialog, "Dismiss");
132+
133+
String endValue = getRenderedTableCellValue(functionTable, row, column);
134+
assertNotEquals("Changing the format did not change the view", startValue, endValue);
135+
}
136+
137+
private int getFormatRow(SettingsDialog dialog) {
138+
GTable table = dialog.getTable();
139+
int column = getColumnIndex(table, "Name");
140+
int n = table.getRowCount();
141+
for (int i = 0; i < n; i++) {
142+
int row = i;
143+
Object name = runSwing(() -> table.getValueAt(row, column));
144+
if ("Format".equals(name)) {
145+
return i;
146+
}
147+
}
148+
149+
fail("Unable to find the 'Format' row in the Settings Dialog");
150+
return -1;
151+
}
152+
153+
private int getColumnIndex(String text) {
154+
return getColumnIndex(functionTable, text);
155+
}
156+
157+
private int getColumnIndex(JTable table, String text) {
158+
TableColumnModel columnModel = table.getColumnModel();
159+
int n = columnModel.getColumnCount();
160+
for (int i = 0; i < n; i++) {
161+
TableColumn column = columnModel.getColumn(i);
162+
if (text.equals(column.getIdentifier().toString())) {
163+
return i;
164+
}
165+
}
166+
fail("Could not find column '" + text + "'");
167+
return -1;
168+
}
169+
170+
private void setComboValue(SettingsDialog d, String string) {
171+
GTable table = d.getTable();
172+
TableCellEditor activeEditor = runSwing(() -> table.getCellEditor());
173+
assertNotNull("Table should be editing, but is not", activeEditor);
174+
175+
assertTrue(activeEditor.getClass().getSimpleName().contains("SettingsEditor"));
176+
@SuppressWarnings("unchecked")
177+
GComboBox<String> combo = (GComboBox<String>) getInstanceField("comboBox", activeEditor);
178+
setComboBoxSelection(combo, string);
179+
}
180+
181+
private void endEdit(SettingsDialog d) {
182+
GTable table = d.getTable();
183+
runSwing(() -> table.editingStopped(new ChangeEvent(table)));
184+
}
185+
102186
private void waitForNotBusy(GTable table) {
103187
waitForTableModel((ThreadedTableModel<?, ?>) table.getModel());
104188
}

Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/SettingsDialog.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,14 @@ public void show(Component parent, String title, SettingsDefinition[] newSetting
6363
this.settingsDefs = newSettingsDefs;
6464
this.settings = newSettings;
6565
setTitle(title);
66-
settingsTableModel.fireTableDataChanged();
66+
67+
settingsTableModel.setSettingsDefinitions(settingsDefs);
6768
DockingWindowManager.showDialog(parent, this);
6869
}
6970

7071
public void dispose() {
7172
settingsTable.editingStopped(null);
73+
settingsTable.dispose();
7274

7375
close();
7476
settingsDefs = null;
@@ -79,7 +81,7 @@ private JPanel buildWorkPanel() {
7981
JPanel workPanel = new JPanel(new BorderLayout());
8082
workPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
8183

82-
settingsTableModel = new SettingsTableModel(settingsDefs);
84+
settingsTableModel = new SettingsTableModel();
8385
settingsTable = new GTable(settingsTableModel);
8486
settingsTable.setAutoscrolls(true);
8587
settingsTable.setRowSelectionAllowed(false);
@@ -106,6 +108,10 @@ protected void cancelCallback() {
106108
dispose();
107109
}
108110

111+
public GTable getTable() {
112+
return settingsTable;
113+
}
114+
109115
//==================================================================================================
110116
// Private Methods
111117
//==================================================================================================
@@ -161,10 +167,12 @@ private class SettingsTableModel extends AbstractSortedTableModel<SettingsRowObj
161167

162168
private List<SettingsRowObject> rows = new ArrayList<>();
163169

164-
SettingsTableModel(SettingsDefinition[] settingsDefs) {
170+
void setSettingsDefinitions(SettingsDefinition[] settingsDefs) {
165171
for (SettingsDefinition sd : settingsDefs) {
166172
rows.add(new SettingsRowObject(sd));
167173
}
174+
175+
settingsTableModel.fireTableDataChanged();
168176
}
169177

170178
@Override
@@ -203,6 +211,17 @@ public String getColumnName(int col) {
203211
return null;
204212
}
205213

214+
@Override
215+
public Class<?> getColumnClass(int col) {
216+
switch (col) {
217+
case 0:
218+
return String.class;
219+
case 1:
220+
return Settings.class;
221+
}
222+
return null;
223+
}
224+
206225
@Override
207226
public Object getColumnValueForRow(SettingsRowObject t, int columnIndex) {
208227
switch (columnIndex) {

Ghidra/Framework/Generic/src/main/java/generic/test/AbstractGenericTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import javax.swing.*;
3434
import javax.swing.table.TableCellEditor;
35+
import javax.swing.table.TableCellRenderer;
3536
import javax.swing.text.JTextComponent;
3637
import javax.swing.tree.*;
3738

@@ -1307,6 +1308,36 @@ public static TableCellEditor editCell(final JTable table, final int row, final
13071308
return editor;
13081309
}
13091310

1311+
/**
1312+
* Gets the rendered value for the specified table cell. The actual value at the cell may
1313+
* not be a String. This method will get the String display value, as created by the table.
1314+
*
1315+
* @param table the table to query
1316+
* @param row the row to query
1317+
* @param column the column to query
1318+
* @return the String value
1319+
* @throws IllegalArgumentException if there is no renderer or the rendered component is
1320+
* something from which this method can get a String (such as a JLabel)
1321+
*/
1322+
public static String getRenderedTableCellValue(JTable table, int row, int column) {
1323+
1324+
return runSwing(() -> {
1325+
1326+
TableCellRenderer renderer = table.getCellRenderer(row, column);
1327+
if (renderer == null) {
1328+
throw new IllegalArgumentException(
1329+
"No renderer registered for row/col: " + row + '/' + column);
1330+
}
1331+
Component component = table.prepareRenderer(renderer, row, column);
1332+
if (!(component instanceof JLabel)) {
1333+
throw new IllegalArgumentException(
1334+
"Do not know how to get text from a renderer " + "that is not a JLabel");
1335+
}
1336+
1337+
return ((JLabel) component).getText();
1338+
});
1339+
}
1340+
13101341
public static <T> void setComboBoxSelection(final JComboBox<T> comboField, final T selection) {
13111342
runSwing(() -> comboField.setSelectedItem(selection));
13121343
waitForSwing();

0 commit comments

Comments
 (0)