mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GT-3044 - Table Actions - test and review fixes
This commit is contained in:
parent
28f6500039
commit
e9c0921cfe
36 changed files with 920 additions and 748 deletions
|
@ -30,58 +30,62 @@ import ghidra.util.exception.NoValueException;
|
|||
import ghidra.util.table.GhidraTable;
|
||||
|
||||
public class SizeAlignmentPanel extends JPanel {
|
||||
|
||||
|
||||
GhidraTable table;
|
||||
DataOrganizationImpl dataOrganization;
|
||||
|
||||
public SizeAlignmentPanel() {
|
||||
super(new BorderLayout());
|
||||
TableModel tableModel = new SizeAlignmentTableModel();
|
||||
table = new GhidraTable(tableModel, true);
|
||||
JScrollPane sp = new JScrollPane(table);
|
||||
table.setPreferredScrollableViewportSize(new Dimension(200, 80));
|
||||
table = new GhidraTable(tableModel);
|
||||
table.setAutoEditEnabled(true);
|
||||
JScrollPane sp = new JScrollPane(table);
|
||||
table.setPreferredScrollableViewportSize(new Dimension(200, 80));
|
||||
add(sp, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
public void setOrganization(DataOrganizationImpl dataOrganization) {
|
||||
this.dataOrganization = dataOrganization;
|
||||
((SizeAlignmentTableModel)table.getModel()).fireTableDataChanged();
|
||||
((SizeAlignmentTableModel) table.getModel()).fireTableDataChanged();
|
||||
}
|
||||
|
||||
|
||||
class SizeAlignmentTableModel extends AbstractTableModel {
|
||||
|
||||
private final String[] columnNames = new String[] {"Size", "Alignment"};
|
||||
|
||||
private final String[] columnNames = new String[] { "Size", "Alignment" };
|
||||
private final int SIZE_COLUMN = 0;
|
||||
private final int ALIGNMENT_COLUMN = 1;
|
||||
|
||||
|
||||
SizeAlignmentTableModel() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableModelListener(TableModelListener l) {
|
||||
public void addTableModelListener(TableModelListener l) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return columnNames.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int columnIndex) {
|
||||
public String getColumnName(int columnIndex) {
|
||||
return columnNames[columnIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return dataOrganization.getSizeAlignmentCount() + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
int[] sizes = dataOrganization.getSizes();
|
||||
if (rowIndex < sizes.length) {
|
||||
|
@ -92,7 +96,8 @@ public class SizeAlignmentPanel extends JPanel {
|
|||
else if (columnIndex == ALIGNMENT_COLUMN) {
|
||||
try {
|
||||
return dataOrganization.getSizeAlignment(size);
|
||||
} catch (NoValueException e) {
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +106,7 @@ public class SizeAlignmentPanel extends JPanel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
if (rowIndex == dataOrganization.getSizeAlignmentCount()) {
|
||||
return columnIndex == SIZE_COLUMN;
|
||||
}
|
||||
|
@ -109,30 +114,31 @@ public class SizeAlignmentPanel extends JPanel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void removeTableModelListener(TableModelListener l) {
|
||||
public void removeTableModelListener(TableModelListener l) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(Object value, int rowIndex, int columnIndex) {
|
||||
public void setValueAt(Object value, int rowIndex, int columnIndex) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
int[] sizes = dataOrganization.getSizes();
|
||||
if (rowIndex < sizes.length) {
|
||||
int alignment = ((Integer)value).intValue();
|
||||
int alignment = ((Integer) value).intValue();
|
||||
int size = sizes[rowIndex];
|
||||
dataOrganization.setSizeAlignment(size, alignment);
|
||||
}
|
||||
if (rowIndex == sizes.length) {
|
||||
int size = ((Integer)value).intValue();
|
||||
int size = ((Integer) value).intValue();
|
||||
// Check that we don't already have this size.
|
||||
try {
|
||||
dataOrganization.getSizeAlignment(size);
|
||||
setStatusMessage("An alignment is already defined for a size of "+size+".");
|
||||
setStatusMessage("An alignment is already defined for a size of " + size + ".");
|
||||
return;
|
||||
} catch (NoValueException e) {
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
// Actually don't want to find a value so we can set one below.
|
||||
}
|
||||
int alignment = size; // Set the alignment to match the size initially.
|
||||
|
|
|
@ -113,25 +113,22 @@ class EnumEditorPanel extends JPanel {
|
|||
|
||||
// invoke later because the key press on the table causes the selection
|
||||
// to change
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (table.isEditing()) {
|
||||
return; // don't change the selection if a new edit is in progress
|
||||
}
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
try {
|
||||
if (table.isEditing()) {
|
||||
return; // don't change the selection if a new edit is in progress
|
||||
}
|
||||
|
||||
int row = tableModel.getRow(name);
|
||||
if (row >= 0 && row < tableModel.getRowCount()) {
|
||||
table.setRowSelectionInterval(row, row);
|
||||
Rectangle rect = table.getCellRect(row, 0, false);
|
||||
table.scrollRectToVisible(rect);
|
||||
}
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
// ignore
|
||||
int row = tableModel.getRow(name);
|
||||
if (row >= 0 && row < tableModel.getRowCount()) {
|
||||
table.setRowSelectionInterval(row, row);
|
||||
Rectangle rect = table.getCellRect(row, 0, false);
|
||||
table.scrollRectToVisible(rect);
|
||||
}
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -232,8 +229,8 @@ class EnumEditorPanel extends JPanel {
|
|||
void deleteSelectedEntries() {
|
||||
EnumDataType enuum = getEnum();
|
||||
int[] rows = getSelectedRows();
|
||||
for (int i = 0; i < rows.length; i++) {
|
||||
String name = tableModel.getNameAt(rows[i]);
|
||||
for (int row : rows) {
|
||||
String name = tableModel.getNameAt(row);
|
||||
enuum.remove(name);
|
||||
}
|
||||
tableModel.setEnum(enuum, true);
|
||||
|
@ -262,15 +259,12 @@ class EnumEditorPanel extends JPanel {
|
|||
"All possible Enum values have already been used");
|
||||
return;
|
||||
}
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
table.setRowSelectionInterval(newRow, newRow);
|
||||
table.editCellAt(newRow, EnumTableModel.NAME_COL);
|
||||
Rectangle r = table.getCellRect(newRow, 0, true);
|
||||
table.scrollRectToVisible(r);
|
||||
provider.stateChanged(null);
|
||||
}
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
table.setRowSelectionInterval(newRow, newRow);
|
||||
table.editCellAt(newRow, EnumTableModel.NAME_COL);
|
||||
Rectangle r = table.getCellRect(newRow, 0, true);
|
||||
table.scrollRectToVisible(r);
|
||||
provider.stateChanged(null);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -418,18 +412,15 @@ class EnumEditorPanel extends JPanel {
|
|||
|
||||
sizeComboBox = new GhidraComboBox(new Integer[] { 1, 2, 4, 8 });
|
||||
sizeComboBox.setName("Size");
|
||||
sizeComboBox.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
Integer length = (Integer) sizeComboBox.getSelectedItem();
|
||||
if (!validateNewLength(length)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setStatusMessage("");
|
||||
tableModel.setLength(length);
|
||||
provider.stateChanged(null);
|
||||
sizeComboBox.addItemListener(e -> {
|
||||
Integer length = (Integer) sizeComboBox.getSelectedItem();
|
||||
if (!validateNewLength(length)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setStatusMessage("");
|
||||
tableModel.setLength(length);
|
||||
provider.stateChanged(null);
|
||||
});
|
||||
|
||||
JLabel label = new GLabel("Category:", SwingConstants.RIGHT);
|
||||
|
@ -465,13 +456,10 @@ class EnumEditorPanel extends JPanel {
|
|||
}
|
||||
|
||||
private void vetoSizeChange(final int newLength, final int currentLength, final long badValue) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setStatusMessage("Enum size of " + newLength + " cannot contain the value " + "0x" +
|
||||
Long.toHexString(badValue));
|
||||
sizeComboBox.setSelectedItem(new Integer(currentLength));
|
||||
}
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
setStatusMessage("Enum size of " + newLength + " cannot contain the value " + "0x" +
|
||||
Long.toHexString(badValue));
|
||||
sizeComboBox.setSelectedItem(new Integer(currentLength));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -495,12 +483,9 @@ class EnumEditorPanel extends JPanel {
|
|||
}
|
||||
|
||||
private void focus(final JTextField field) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
field.requestFocusInWindow();
|
||||
field.selectAll();
|
||||
}
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
field.requestFocusInWindow();
|
||||
field.selectAll();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -510,7 +495,8 @@ class EnumEditorPanel extends JPanel {
|
|||
|
||||
private class EnumTable extends GhidraTable {
|
||||
EnumTable(TableModel model) {
|
||||
super(model, true);
|
||||
super(model);
|
||||
setAutoEditEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -534,12 +520,7 @@ class EnumEditorPanel extends JPanel {
|
|||
public EnumCellEditor(JTextField textField) {
|
||||
super(textField);
|
||||
textField.addKeyListener(editingKeyListener);
|
||||
textField.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
table.editingStopped(null);
|
||||
}
|
||||
});
|
||||
textField.addActionListener(e -> table.editingStopped(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -148,9 +148,8 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
|||
};
|
||||
findTableAction.setHelpLocation(
|
||||
new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
|
||||
findTableAction.setMenuBarData(
|
||||
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Address Tables..." }, null,
|
||||
"search for"));
|
||||
findTableAction.setMenuBarData(new MenuData(
|
||||
new String[] { ToolConstants.MENU_SEARCH, "For Address Tables" }, null, "search for"));
|
||||
findTableAction.setDescription(getPluginDescription().getDescription());
|
||||
|
||||
tool.addAction(findTableAction);
|
||||
|
|
|
@ -251,7 +251,7 @@ public class InstructionSearchPlugin extends ProgramPlugin {
|
|||
};
|
||||
searchAction.setHelpLocation(new HelpLocation("Search", "Instruction_Pattern_Search"));
|
||||
searchAction.setMenuBarData(
|
||||
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Instruction Patterns..." },
|
||||
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Instruction Patterns" },
|
||||
null, "search for"));
|
||||
searchAction.setDescription("Construct searches using selected instructions");
|
||||
tool.addAction(searchAction);
|
||||
|
|
|
@ -21,6 +21,7 @@ import javax.swing.JToolBar;
|
|||
import javax.swing.table.TableCellRenderer;
|
||||
|
||||
import docking.widgets.table.GTable;
|
||||
import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin;
|
||||
import ghidra.app.plugin.core.instructionsearch.model.*;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
|
||||
|
@ -85,6 +86,10 @@ public abstract class AbstractInstructionTable extends GhidraTable {
|
|||
this.setRowHeight(this.getRowHeight() + CELL_HEIGHT_PADDING);
|
||||
}
|
||||
|
||||
InstructionSearchPlugin getPlugin() {
|
||||
return dialog.getPlugin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data object at the given cell location. We need to check
|
||||
* first to make sure the row/col values map to a valid cell.
|
||||
|
|
|
@ -504,13 +504,12 @@ public class InstructionSearchDialog extends DialogComponentProvider implements
|
|||
SystemUtilities.runSwingLater(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param addr
|
||||
*/
|
||||
private void goToLocation(Address addr) {
|
||||
GoToService gs = plugin.getTool().getService(GoToService.class);
|
||||
gs.goTo(addr);
|
||||
}
|
||||
|
||||
public InstructionSearchPlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,14 +25,17 @@ import java.util.*;
|
|||
import javax.swing.*;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
|
||||
import docking.*;
|
||||
import docking.action.*;
|
||||
import docking.ActionContext;
|
||||
import docking.EmptyBorderToggleButton;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.dnd.GClipboard;
|
||||
import docking.widgets.EmptyBorderButton;
|
||||
import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin;
|
||||
import ghidra.app.plugin.core.instructionsearch.model.*;
|
||||
import ghidra.app.plugin.core.instructionsearch.ui.SelectionModeWidget.InputMode;
|
||||
import ghidra.app.plugin.core.instructionsearch.util.InstructionSearchUtils;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.*;
|
||||
|
@ -78,6 +81,7 @@ public class PreviewTable extends AbstractInstructionTable {
|
|||
*
|
||||
* @param numColumns the number of columns in the table
|
||||
* @param plugin the parent plugin
|
||||
* @param dialog the search dialog
|
||||
*/
|
||||
public PreviewTable(int numColumns, InstructionSearchPlugin plugin,
|
||||
InstructionSearchDialog dialog) {
|
||||
|
@ -131,30 +135,6 @@ public class PreviewTable extends AbstractInstructionTable {
|
|||
refreshView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds custom context-sensitive menus to the table. This does NOT modify
|
||||
* any existing menus; it simply adds to them.
|
||||
*/
|
||||
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO Change the custom menu items to be real Docking Actions
|
||||
// TODO
|
||||
// TODO
|
||||
|
||||
// @Override
|
||||
// public List<DockingActionIf> getPopupActions(DockingTool tool, ActionContext context) {
|
||||
//
|
||||
// // Invoke the base class method to add default menu options.
|
||||
// List<DockingActionIf> list = super.getPopupActions(tool, context);
|
||||
//
|
||||
// // And now add our own.
|
||||
// addCustomMenuItems(list);
|
||||
//
|
||||
// return list;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Replaces the contents of the preview table at the given row with the
|
||||
* given string.
|
||||
|
@ -381,14 +361,6 @@ public class PreviewTable extends AbstractInstructionTable {
|
|||
return binaryBtn;
|
||||
}
|
||||
|
||||
private void addCustomMenuItems(List<DockingActionIf> list) {
|
||||
DockingWindowManager dwm = DockingWindowManager.getInstance(this);
|
||||
dwm.setMenuGroup(new String[] { "Copy Special" }, actionMenuGroup, "1");
|
||||
list.add(copyNoSpacesAction);
|
||||
list.add(copyInstructionAction);
|
||||
list.add(copyInstructionWithCommentsAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers the search strings for each instruction and returns them as a
|
||||
* single string.
|
||||
|
@ -470,6 +442,10 @@ public class PreviewTable extends AbstractInstructionTable {
|
|||
private void createContextMenuActions() {
|
||||
String owner = getClass().getSimpleName();
|
||||
|
||||
InstructionSearchPlugin plugin = getPlugin();
|
||||
PluginTool tool = plugin.getTool();
|
||||
tool.setMenuGroup(new String[] { "Copy Special" }, actionMenuGroup, "1");
|
||||
|
||||
createCopyNoSpacesAction(owner);
|
||||
copyNoSpacesAction.setPopupMenuData(
|
||||
new MenuData(new String[] { "Copy Special", "Selected instructions (no spaces)" },
|
||||
|
@ -487,6 +463,10 @@ public class PreviewTable extends AbstractInstructionTable {
|
|||
new MenuData(new String[] { "Copy Special", "Selected Instructions (with comments)" },
|
||||
ResourceManager.loadImage("images/page_white_copy.png"), actionMenuGroup,
|
||||
MenuData.NO_MNEMONIC, Integer.toString(1)));
|
||||
|
||||
dialog.addAction(copyNoSpacesAction);
|
||||
dialog.addAction(copyInstructionAction);
|
||||
dialog.addAction(copyInstructionWithCommentsAction);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -518,7 +498,14 @@ public class PreviewTable extends AbstractInstructionTable {
|
|||
Clipboard clip = GClipboard.getSystemClipboard();
|
||||
clip.setContents(sel, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return context.getSourceComponent() == PreviewTable.this;
|
||||
}
|
||||
};
|
||||
|
||||
copyInstructionWithCommentsAction.setHelpLocation(dialog.getHelpLocatdion());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -539,7 +526,14 @@ public class PreviewTable extends AbstractInstructionTable {
|
|||
Clipboard clip = GClipboard.getSystemClipboard();
|
||||
clip.setContents(sel, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return context.getSourceComponent() == PreviewTable.this;
|
||||
}
|
||||
};
|
||||
|
||||
copyInstructionAction.setHelpLocation(dialog.getHelpLocatdion());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -560,7 +554,14 @@ public class PreviewTable extends AbstractInstructionTable {
|
|||
Clipboard clip = GClipboard.getSystemClipboard();
|
||||
clip.setContents(sel, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return context.getSourceComponent() == PreviewTable.this;
|
||||
}
|
||||
};
|
||||
|
||||
copyNoSpacesAction.setHelpLocation(dialog.getHelpLocatdion());
|
||||
}
|
||||
|
||||
private class BinaryAction extends AbstractAction {
|
||||
|
|
|
@ -652,7 +652,8 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
|
||||
private class MemoryMapTable extends GhidraTable {
|
||||
MemoryMapTable(TableModel model) {
|
||||
super(model, true);
|
||||
super(model);
|
||||
setAutoEditEnabled(true);
|
||||
setActionsEnabled(true);
|
||||
setVisibleRowCount(10);
|
||||
}
|
||||
|
|
|
@ -51,66 +51,10 @@ public class GhidraTable extends GTable {
|
|||
|
||||
public GhidraTable() {
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
public GhidraTable(TableModel model) {
|
||||
super(model);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new GhidraTable using the specified table model.
|
||||
* If <code>allowAutoEdit</code> is true, then automatic editing is enabled.
|
||||
* Auto-editing implies that typing in an editable cell will automatically
|
||||
* force the cell into edit mode.
|
||||
* If <code>allowAutoEdit</code> is false, then <code>F2</code> must be hit before editing may commence.
|
||||
* @param dm the table model
|
||||
* @param allowAutoEdit true if auto-editing is allowed
|
||||
*/
|
||||
public GhidraTable(TableModel dm, boolean allowAutoEdit) {
|
||||
super(dm, allowAutoEdit);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>GhidraTable</code> to display the values in the two dimensional array,
|
||||
* <code>rowData</code>, with column names, <code>columnNames</code>.
|
||||
* <code>rowData</code> is an array of rows, so the value of the cell at row 1,
|
||||
* column 5 can be obtained with the following code:
|
||||
* <p>
|
||||
* <pre> rowData[1][5]; </pre>
|
||||
* <p>
|
||||
* All rows must be of the same length as <code>columnNames</code>.
|
||||
* <p>
|
||||
* @param rowData the data for the new table
|
||||
* @param columnNames names of each column
|
||||
*/
|
||||
public GhidraTable(Object[][] rowData, Object[] columnNames) {
|
||||
super(rowData, columnNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>GhidraTable</code> to display the values in the two dimensional array,
|
||||
* <code>rowData</code>, with column names, <code>columnNames</code>.
|
||||
* <code>rowData</code> is an array of rows, so the value of the cell at row 1,
|
||||
* column 5 can be obtained with the following code:
|
||||
* <p>
|
||||
* <pre> rowData[1][5]; </pre>
|
||||
* <p>
|
||||
* All rows must be of the same length as <code>columnNames</code>.
|
||||
* <p>
|
||||
* If <code>allowAutoEdit</code> is true, then automatic editing is enabled.
|
||||
* Auto-editing implies that typing in an editable cell will automatically
|
||||
* force the cell into edit mode.
|
||||
* If <code>allowAutoEdit</code> is false, then <code>F2</code> must be hit before editing may commence.
|
||||
*
|
||||
* @param rowData the data for the new table
|
||||
* @param columnNames names of each column
|
||||
* @param allowAutoEdit true if auto-editing is allowed
|
||||
*/
|
||||
public GhidraTable(Object[][] rowData, Object[] columnNames, boolean allowAutoEdit) {
|
||||
super(rowData, columnNames, allowAutoEdit);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.util.table.actions;
|
||||
|
||||
import java.awt.Component;
|
||||
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import docking.ActionContext;
|
||||
|
@ -36,10 +38,9 @@ import resources.Icons;
|
|||
*/
|
||||
public class MakeProgramSelectionAction extends DockingAction {
|
||||
|
||||
private GhidraTable table;
|
||||
|
||||
// we will have one of these fields be non-null after construction
|
||||
private Plugin plugin;
|
||||
private GhidraTable table;
|
||||
|
||||
/**
|
||||
* Special constructor for clients that do not have a plugin. Clients using this
|
||||
|
@ -92,8 +93,8 @@ public class MakeProgramSelectionAction extends DockingAction {
|
|||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
|
||||
Object contextObject = context.getContextObject();
|
||||
if (contextObject != table) {
|
||||
Component component = context.getSourceComponent();
|
||||
if (component != table) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,8 +33,7 @@ import ghidra.framework.options.ToolOptions;
|
|||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.test.TestEnv;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.SpyErrorLogger;
|
||||
import ghidra.util.*;
|
||||
import resources.Icons;
|
||||
import resources.ResourceManager;
|
||||
|
||||
|
@ -335,8 +334,11 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
|||
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
||||
setKeyBindingViaF4Dialog_FromCloseButton(controlEsc);
|
||||
|
||||
// Note: there may be a test focus issue here. If this test fails sporadically due to
|
||||
// how the action context is generated (it depends on focus). It is only useful to fail
|
||||
// here in development mode.
|
||||
pressKey(controlEsc);
|
||||
assertProviderIsHidden();
|
||||
assertProviderIsHidden_InNonBatchMode();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -461,9 +463,18 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
|||
// runSwing(() -> tool.isActive(provider)));
|
||||
}
|
||||
|
||||
private void assertProviderIsHidden() {
|
||||
assertFalse("The test provider is showing, but should be hidden",
|
||||
runSwing(() -> tool.isVisible(provider)));
|
||||
private void assertProviderIsHidden_InNonBatchMode() {
|
||||
|
||||
boolean isVisible = runSwing(() -> tool.isVisible(provider));
|
||||
if (!SystemUtilities.isInTestingBatchMode()) {
|
||||
assertFalse("The test provider is showing, but should be hidden", isVisible);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVisible) {
|
||||
Msg.error(this,
|
||||
"Provider should not be visible after pressing the 'close provider' key bindings");
|
||||
}
|
||||
}
|
||||
|
||||
private void assertNoToolbarAction() {
|
||||
|
|
|
@ -27,6 +27,7 @@ import javax.swing.table.TableModel;
|
|||
|
||||
import org.junit.*;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingActionIf;
|
||||
import ghidra.app.cmd.memory.*;
|
||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||
|
@ -100,11 +101,12 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
for (DockingActionIf action : actions) {
|
||||
String name = action.getName();
|
||||
if (name.equals("Add Block") || name.equals("Set Image Base") ||
|
||||
name.equals("Memory Map") || name.equals("Close Window")) {
|
||||
assertTrue(action.isEnabledForContext(provider.getActionContext(null)));
|
||||
name.equals("Memory Map") || name.equals("Close Window") ||
|
||||
name.contains("Table")) {
|
||||
assertActionEnabled(action, getActionContext(), true);
|
||||
}
|
||||
else {
|
||||
assertFalse(action.isEnabledForContext(provider.getActionContext(null)));
|
||||
assertActionEnabled(action, getActionContext(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,10 +123,26 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
if (name.equals("Memory Map") || name.equals("Close Window")) {
|
||||
continue;
|
||||
}
|
||||
assertFalse(action.isEnabledForContext(provider.getActionContext(null)));
|
||||
assertActionEnabled(action, getActionContext(), false);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertActionEnabled(DockingActionIf action, ActionContext context,
|
||||
boolean shouldBeEnabled) {
|
||||
|
||||
String text = shouldBeEnabled ? "should be enabled" : "should be disabled";
|
||||
assertEquals("Action " + text + ", but is not: '" + action.getFullName() + "'",
|
||||
shouldBeEnabled, action.isEnabledForContext(context));
|
||||
}
|
||||
|
||||
private ActionContext getActionContext() {
|
||||
ActionContext context = provider.getActionContext(null);
|
||||
if (context == null) {
|
||||
return new ActionContext();
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockNameChanged() throws Exception {
|
||||
MemoryBlock block = memory.getBlock(program.getMinAddress());
|
||||
|
|
|
@ -331,26 +331,6 @@ public class NextPrevAddressPluginTest extends AbstractGhidraHeadedIntegrationTe
|
|||
clickMouse(component, MouseEvent.BUTTON1, x, y, 1, 0);
|
||||
}
|
||||
|
||||
private JPopupMenu getPopupMenu(Container parent) {
|
||||
Component[] components = parent.getComponents();
|
||||
for (Component component : components) {
|
||||
if (component instanceof JPopupMenu) {
|
||||
return (JPopupMenu) component;
|
||||
}
|
||||
}
|
||||
|
||||
for (Component component : components) {
|
||||
if (component instanceof Container) {
|
||||
JPopupMenu popupMenu = getPopupMenu((Container) component);
|
||||
if (popupMenu != null) {
|
||||
return popupMenu;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
// let caution fly
|
||||
private JButton findButtonForAction(DockingWindowManager windowManager, DockingAction action) {
|
||||
|
|
|
@ -31,7 +31,7 @@ import javax.swing.table.*;
|
|||
import org.jdom.Element;
|
||||
import org.junit.*;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.*;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.action.ToggleDockingAction;
|
||||
import docking.widgets.filter.*;
|
||||
|
@ -117,7 +117,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testNavigation() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
int row = findRow("ghidra", "Global");
|
||||
|
||||
TableModel model = symbolTable.getModel();
|
||||
|
@ -128,7 +128,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testSortingLabelColumn() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
Rectangle rect = symbolTableHeader.getHeaderRect(SymbolTableModel.LABEL_COL);
|
||||
|
||||
|
@ -170,7 +170,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
// Note: this is somewhat of a tripwire test--it is designed to catch a major breakage
|
||||
// to the DynamicTableColumn discovery mechanism.
|
||||
//
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
List<String> columnNames = new ArrayList<>();
|
||||
int columnCount = symbolModel.getColumnCount();
|
||||
|
@ -203,7 +203,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testSortingAddressColumn() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
Rectangle rect = symbolTableHeader.getHeaderRect(SymbolTableModel.LOCATION_COL);
|
||||
|
||||
|
@ -239,7 +239,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testSortingReferenceColumn() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
sortOnColumn(SymbolTableModel.REFS_COL);
|
||||
|
||||
|
@ -267,7 +267,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testFilter() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
performAction(setFilterAction, new ActionContext(), false);
|
||||
waitForSwing();
|
||||
|
@ -331,15 +331,6 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(2, symbolTable.getRowCount());
|
||||
}
|
||||
|
||||
private FilterDialog showFilterDialog() {
|
||||
|
||||
performAction(setFilterAction, false);
|
||||
|
||||
FilterDialog dialog = waitForDialogComponent(FilterDialog.class);
|
||||
assertNotNull(dialog);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterPersistence() throws Exception {
|
||||
|
||||
|
@ -362,39 +353,9 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(savedXml, restoredXml);
|
||||
}
|
||||
|
||||
private void changeSomeFilterSettings(NewSymbolFilter filter) {
|
||||
//
|
||||
// Change different filter types and values. (This requires some guilty knowledge).
|
||||
//
|
||||
// Symbol type name and default state:
|
||||
//
|
||||
// Symbol Types:
|
||||
// Label filters: instruction (active), data (active), function (active)
|
||||
// Non-label filters: namespaces, classes, params, etc (all inactive)
|
||||
//
|
||||
// Advanced filters: externals, globals, entry points, locals, etc (all inactive)
|
||||
//
|
||||
// Symbol Source Types: user defined (active), imported (active),
|
||||
// default label (inactive), default function, analysis (active)
|
||||
//
|
||||
|
||||
boolean active = true;
|
||||
boolean inactive = false;
|
||||
filter.setFilter("User Defined", inactive);
|
||||
filter.setFilter("Default (Labels)", active);
|
||||
|
||||
filter.setFilter("Function Labels", inactive);
|
||||
|
||||
filter.setFilter("Local Variables", active);
|
||||
|
||||
filter.setFilter("Register Variables", active);
|
||||
filter.setFilter("Subroutines", active);
|
||||
filter.setFilter("Non-Primary Labels", active);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditing() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
waitForNotBusy(symbolTable);
|
||||
|
||||
|
@ -421,7 +382,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testQuickLookup() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
int id = prog.startTransaction(testName.getMethodName());
|
||||
try {
|
||||
|
@ -440,7 +401,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
waitForNotBusy(symbolTable);
|
||||
|
||||
runSwing(() -> symbolTable.setRowSelectionInterval(0, 0));
|
||||
selectRow(0);
|
||||
|
||||
triggerAutoLookup("a");
|
||||
waitForNotBusy(symbolTable);
|
||||
|
@ -462,7 +423,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(findRow("abc1", "Global"), symbolTable.getSelectedRow());
|
||||
Thread.sleep(GTable.KEY_TIMEOUT);
|
||||
|
||||
runSwing(() -> symbolTable.setRowSelectionInterval(0, 0));
|
||||
selectRow(0);
|
||||
waitForSwing();
|
||||
triggerAutoLookup("abc12");
|
||||
waitForNotBusy(symbolTable);
|
||||
|
@ -471,7 +432,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testDeleting() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
int rowCount = symbolTable.getRowCount();
|
||||
assertTrue(!deleteAction.isEnabled());
|
||||
|
@ -501,8 +462,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(rowCount, symbolTable.getRowCount());
|
||||
|
||||
final int anotherLocal_RowIndex = findRow("AnotherLocal", "Global");
|
||||
runSwing(() -> symbolTable.setRowSelectionInterval(anotherLocal_RowIndex,
|
||||
anotherLocal_RowIndex));
|
||||
selectRow(anotherLocal_RowIndex);
|
||||
|
||||
int selectedRow = symbolTable.getSelectedRow();
|
||||
assertEquals("Row was not selected!", anotherLocal_RowIndex, selectedRow);
|
||||
|
@ -538,29 +498,37 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
setupSymbolTableFilterToShowParameters();
|
||||
|
||||
final int row = getRowForSymbol(param1Symbol);
|
||||
|
||||
// select that row
|
||||
runSwing(() -> symbolTable.setRowSelectionInterval(row, row));
|
||||
int row = getRowForSymbol(param1Symbol);
|
||||
selectRow(row);
|
||||
|
||||
// execute the delete action
|
||||
performAction(deleteAction, true);
|
||||
Assert.assertNotEquals(param1Symbol, getUniqueSymbol(prog, "param_1", function));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuiltInTableActionsAvailable() throws Exception {
|
||||
openProgram("sample");
|
||||
|
||||
int row = 0;
|
||||
selectRow(row);
|
||||
|
||||
JPopupMenu popup = triggerPopup(row);
|
||||
List<JMenuItem> popupItems = getPopupMenuItems(popup);
|
||||
assertMenuContains(popupItems, "Copy");
|
||||
assertMenuContains(popupItems, "Export");
|
||||
assertMenuContains(popupItems, "Select All");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeSelection() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
assertTrue(!makeSelectionAction.isEnabled());
|
||||
|
||||
final int row = findRow("ghidra", "Global");
|
||||
int rowCount = 3;
|
||||
runSwing(() -> {
|
||||
symbolTable.setRowSelectionInterval(row, row + 2);
|
||||
Rectangle rect = symbolTable.getCellRect(row + 2, 0, true);
|
||||
symbolTable.scrollRectToVisible(rect);
|
||||
});
|
||||
selectRow(row, row + 2);
|
||||
|
||||
assertTrue(makeSelectionAction.isEnabled());
|
||||
|
||||
|
@ -590,14 +558,11 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testSetAndClearPinnedAction() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
int row = findRow("ADVAPI32.dll_IsTextUnicode", "Global");
|
||||
selectRow(row, row + 2);
|
||||
|
||||
final int row = findRow("ADVAPI32.dll_IsTextUnicode", "Global");
|
||||
runSwing(() -> {
|
||||
symbolTable.setRowSelectionInterval(row, row + 2);
|
||||
Rectangle rect = symbolTable.getCellRect(row + 2, 0, true);
|
||||
symbolTable.scrollRectToVisible(rect);
|
||||
});
|
||||
ActionContext actionContext = provider.getActionContext(null);
|
||||
int[] selectedRows = symbolTable.getSelectedRows();
|
||||
assertEquals(3, selectedRows.length);
|
||||
|
@ -626,14 +591,11 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testSetPinnedActionNotEnabledForExternalSymbols() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
int row = findRow("CharLowerW", "USER32.dll");
|
||||
selectRow(row, row + 1);
|
||||
|
||||
final int row = findRow("CharLowerW", "USER32.dll");
|
||||
runSwing(() -> {
|
||||
symbolTable.setRowSelectionInterval(row, row + 1);
|
||||
Rectangle rect = symbolTable.getCellRect(row + 1, 0, true);
|
||||
symbolTable.scrollRectToVisible(rect);
|
||||
});
|
||||
ActionContext actionContext = provider.getActionContext(null);
|
||||
int[] selectedRows = symbolTable.getSelectedRows();
|
||||
|
||||
|
@ -648,7 +610,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testUpdateOnSymbolsAdded() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
Address sample = prog.getMinAddress();
|
||||
SymbolTable st = prog.getSymbolTable();
|
||||
Symbol sym = null;
|
||||
|
@ -673,7 +635,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testSymbolsAddedWithFilterOn() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
final JTextField textField = getFilterTextField();
|
||||
final JCheckBox checkBox = findComponent(filterPanel, JCheckBox.class);
|
||||
|
@ -709,7 +671,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testDefaultFunctionToNamedFunctionWithFilterOn() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
performAction(setFilterAction, new ActionContext(), false);
|
||||
waitForSwing();
|
||||
|
@ -742,7 +704,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testUpdateOnSymbolsRemoved() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
SymbolTable st = prog.getSymbolTable();
|
||||
Symbol sym = getUniqueSymbol(prog, "entry");
|
||||
|
@ -765,7 +727,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testUpdateOnReferencesAdded() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
Address sample = prog.getMinAddress();
|
||||
|
||||
Symbol s = getUniqueSymbol(prog, "entry");
|
||||
|
@ -796,7 +758,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testUpdateOnReferencesRemoved() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
Address sample = prog.getMinAddress();
|
||||
|
||||
Symbol s = getUniqueSymbol(prog, "doStuff");
|
||||
|
@ -836,7 +798,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testUpdateOnProgramRestore() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
int id = prog.startTransaction(testName.getMethodName());
|
||||
try {
|
||||
|
@ -959,7 +921,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testReferences() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
showReferencesTable();
|
||||
|
||||
|
@ -1020,7 +982,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testFilterTextField() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
JTextField textField = getFilterTextField();
|
||||
|
||||
|
@ -1167,7 +1129,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testFilterTextFieldFindsAllMatches() throws Exception {
|
||||
openProgram("notepad");
|
||||
openProgram("sample");
|
||||
|
||||
JTextField textField = getFilterTextField();
|
||||
|
||||
|
@ -1214,6 +1176,86 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
// Helper methods
|
||||
//==================================================================================================
|
||||
|
||||
private void assertMenuContains(List<JMenuItem> popupItems, String string) {
|
||||
for (JMenuItem item : popupItems) {
|
||||
String text = item.getText();
|
||||
if (text.equals(string)) {
|
||||
return; // found it
|
||||
}
|
||||
}
|
||||
fail("'" + string + "' not in the popup menu!");
|
||||
}
|
||||
|
||||
private List<JMenuItem> getPopupMenuItems(JPopupMenu popup) {
|
||||
List<JMenuItem> list = new ArrayList<>();
|
||||
Component[] children = popup.getComponents();
|
||||
for (Component child : children) {
|
||||
if (child instanceof JMenuItem) {
|
||||
list.add((JMenuItem) child);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private JPopupMenu triggerPopup(int row) {
|
||||
DockingWindowManager dwm = DockingWindowManager.getInstance(symbolTable);
|
||||
ActionContext context = provider.getActionContext(null);
|
||||
JPopupMenu popup =
|
||||
runSwing(() -> DockingWindowManagerTestHelper.getPopupMenu(dwm, context));
|
||||
return popup;
|
||||
}
|
||||
|
||||
private void selectRow(int row) {
|
||||
selectRow(row, row);
|
||||
}
|
||||
|
||||
private void selectRow(int start, int end) {
|
||||
runSwing(() -> {
|
||||
symbolTable.setRowSelectionInterval(start, end);
|
||||
Rectangle rect = symbolTable.getCellRect(end, 0, true);
|
||||
symbolTable.scrollRectToVisible(rect);
|
||||
});
|
||||
}
|
||||
|
||||
private FilterDialog showFilterDialog() {
|
||||
|
||||
performAction(setFilterAction, false);
|
||||
|
||||
FilterDialog dialog = waitForDialogComponent(FilterDialog.class);
|
||||
assertNotNull(dialog);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private void changeSomeFilterSettings(NewSymbolFilter filter) {
|
||||
//
|
||||
// Change different filter types and values. (This requires some guilty knowledge).
|
||||
//
|
||||
// Symbol type name and default state:
|
||||
//
|
||||
// Symbol Types:
|
||||
// Label filters: instruction (active), data (active), function (active)
|
||||
// Non-label filters: namespaces, classes, params, etc (all inactive)
|
||||
//
|
||||
// Advanced filters: externals, globals, entry points, locals, etc (all inactive)
|
||||
//
|
||||
// Symbol Source Types: user defined (active), imported (active),
|
||||
// default label (inactive), default function, analysis (active)
|
||||
//
|
||||
|
||||
boolean active = true;
|
||||
boolean inactive = false;
|
||||
filter.setFilter("User Defined", inactive);
|
||||
filter.setFilter("Default (Labels)", active);
|
||||
|
||||
filter.setFilter("Function Labels", inactive);
|
||||
|
||||
filter.setFilter("Local Variables", active);
|
||||
|
||||
filter.setFilter("Register Variables", active);
|
||||
filter.setFilter("Subroutines", active);
|
||||
filter.setFilter("Non-Primary Labels", active);
|
||||
}
|
||||
|
||||
private void triggerAutoLookup(String text) {
|
||||
|
||||
KeyListener listener = (KeyListener) getInstanceField("autoLookupListener", symbolTable);
|
||||
|
|
|
@ -29,6 +29,7 @@ import javax.swing.tree.TreePath;
|
|||
|
||||
import org.junit.*;
|
||||
|
||||
import docking.ComponentProvider;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.actions.KeyBindingUtils;
|
||||
import docking.options.editor.OptionsDialog;
|
||||
|
@ -86,6 +87,13 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
// Msg.debug(this, "Writing debug data to: " + file);
|
||||
// debug = new FileWriter(file);
|
||||
|
||||
// debug to the local console
|
||||
// debug = new PrintWriter(System.out);
|
||||
|
||||
setUpTool();
|
||||
}
|
||||
|
||||
private void setUpTool() throws Exception {
|
||||
debug("setUp()");
|
||||
|
||||
env = new TestEnv();
|
||||
|
@ -104,9 +112,21 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
tool.addPlugin(FunctionPlugin.class.getName());
|
||||
tool.addPlugin(EquateTablePlugin.class.getName());
|
||||
|
||||
// Unusual Code: Some actions don't get created until the table is shown (like GTable
|
||||
// actions). Show a provider that has a table so that the actions will get correctly
|
||||
// loaded into the key bindings panel
|
||||
showTableProvider();
|
||||
|
||||
debug("two");
|
||||
}
|
||||
|
||||
private void showTableProvider() {
|
||||
EquateTablePlugin eqp = env.getPlugin(EquateTablePlugin.class);
|
||||
ComponentProvider provider = (ComponentProvider) getInstanceField("provider", eqp);
|
||||
env.showTool();
|
||||
tool.showComponentProvider(provider, true);
|
||||
}
|
||||
|
||||
private void debug(String message) {
|
||||
if (debug == null) {
|
||||
return;
|
||||
|
@ -208,7 +228,7 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
ToolOptions originalOptions = importOptions(saveFile);
|
||||
|
||||
assertOptionsMatch(
|
||||
"The Options objects do not contain different data after " + "changes have been made.",
|
||||
"The Options objects do not contain different data after changes have been made.",
|
||||
toolKeyBindingOptions, originalOptions);
|
||||
|
||||
debug("c");
|
||||
|
@ -220,7 +240,7 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
// verify the changes are different than the original values
|
||||
assertOptionsDontMatch(
|
||||
"The Options objects do not contain different data after " + "changes have been made.",
|
||||
"The Options objects do not contain different data after changes have been made.",
|
||||
toolKeyBindingOptions, originalOptions);
|
||||
|
||||
debug("e");
|
||||
|
@ -319,6 +339,7 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
private void setKeyBindingsUpDialog() throws Exception {
|
||||
env.showTool();
|
||||
showTableProvider();
|
||||
setKeyBindingsUpDialog(tool);
|
||||
}
|
||||
|
||||
|
@ -531,13 +552,13 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
// compares the provided options with the mapping of property names to
|
||||
// keystrokes (the map is obtained from the key bindings panel after an
|
||||
// import is done).
|
||||
private boolean compareOptionsWithKeyStrokeMap(Options options,
|
||||
private boolean compareOptionsWithKeyStrokeMap(Options oldOptions,
|
||||
Map<String, KeyStroke> panelKeyStrokeMap) {
|
||||
List<String> propertyNames = options.getOptionNames();
|
||||
List<String> propertyNames = oldOptions.getOptionNames();
|
||||
for (String element : propertyNames) {
|
||||
boolean match = panelKeyStrokeMap.containsKey(element);
|
||||
|
||||
KeyStroke optionsKs = options.getKeyStroke(element, null);
|
||||
boolean match = panelKeyStrokeMap.containsKey(element);
|
||||
KeyStroke optionsKs = oldOptions.getKeyStroke(element, null);
|
||||
KeyStroke panelKs = panelKeyStrokeMap.get(element);
|
||||
|
||||
// if the value is null, then it would not have been placed into the options map
|
||||
|
|
|
@ -109,12 +109,22 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
public void testManagedKeyBindings() {
|
||||
Set<DockingActionIf> list = tool.getAllActions();
|
||||
for (DockingActionIf action : list) {
|
||||
if (action.getKeyBindingType().isManaged()) {
|
||||
assertTrue(actionInTable(action));
|
||||
if (!ignoreAction(action)) {
|
||||
boolean inTable = actionInKeyBindingsTable(action);
|
||||
assertTrue("Action should be in the key bindingds table: " + action.getFullName(),
|
||||
inTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ignoreAction(DockingActionIf action) {
|
||||
if (!action.getKeyBindingType().isManaged()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return action.getFullName().contains("Table Data");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditKeyBinding() throws Exception {
|
||||
// find action that has a keystroke assigned
|
||||
|
@ -316,14 +326,14 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
}
|
||||
|
||||
private boolean supportsKeyBindings(DockingActionIf action) {
|
||||
return action.getKeyBindingType().isManaged();
|
||||
return ignoreAction(action);
|
||||
}
|
||||
|
||||
private DockingActionIf getKeyBindingPluginAction() {
|
||||
Set<DockingActionIf> list = tool.getAllActions();
|
||||
for (DockingActionIf action : list) {
|
||||
KeyStroke ks = action.getKeyBinding();
|
||||
if (action.getKeyBindingType().isManaged() && ks != null &&
|
||||
if (ignoreAction(action) && ks != null &&
|
||||
ks != KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0)) {
|
||||
return action;
|
||||
}
|
||||
|
@ -331,7 +341,7 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
return null;
|
||||
}
|
||||
|
||||
private boolean actionInTable(DockingActionIf action) {
|
||||
private boolean actionInKeyBindingsTable(DockingActionIf action) {
|
||||
String actionName = action.getName();
|
||||
KeyStroke ks = action.getKeyBinding();
|
||||
|
||||
|
@ -373,15 +383,14 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
private void setUpDialog() throws Exception {
|
||||
runSwing(() -> {
|
||||
panel = new KeyBindingsPanel(tool, tool.getOptions(DockingToolConstants.KEY_BINDINGS));
|
||||
panel.setOptionsPropertyChangeListener(evt -> {
|
||||
// stub
|
||||
});
|
||||
|
||||
dialog = new JDialog(tool.getToolFrame(), "Test KeyBindings", false);
|
||||
dialog.getContentPane().add(panel);
|
||||
dialog.pack();
|
||||
dialog.setVisible(true);
|
||||
// set the dialog so that the panel can enable the apply button
|
||||
panel.setOptionsPropertyChangeListener(evt -> {
|
||||
// stub
|
||||
});
|
||||
});
|
||||
table = findComponent(panel, JTable.class);
|
||||
keyField = findComponent(panel, JTextField.class);
|
||||
|
@ -390,21 +399,26 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
model = table.getModel();
|
||||
}
|
||||
|
||||
// find 2 actions that do not have key bindings so that we can add and change the values
|
||||
private void grabActionsWithoutKeybinding() {
|
||||
Set<DockingActionIf> list = tool.getAllActions();
|
||||
for (DockingActionIf action : list) {
|
||||
if (!action.getKeyBindingType().isManaged()) {
|
||||
if (ignoreAction(action)) {
|
||||
continue;
|
||||
}
|
||||
if (action.getKeyBinding() != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// good action
|
||||
if (action1 == null) {
|
||||
action1 = action;
|
||||
}
|
||||
else {
|
||||
|
||||
if (action.getName().equals(action1.getName())) {
|
||||
continue; // same name, different owners; these are 'shared' actions--ignore
|
||||
}
|
||||
|
||||
action2 = action;
|
||||
return; // grabbed all actions--we are done
|
||||
}
|
||||
|
|
|
@ -67,9 +67,4 @@ public class DummyToolActions implements DockingToolActions {
|
|||
public void removeActions(ComponentProvider provider) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAction(DockingActionIf action) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue