GP-3755 - Added filter to the Memory Map provider

This commit is contained in:
dragonmacher 2023-08-22 18:34:10 -04:00
parent b261137b40
commit 6afed33ce0
7 changed files with 276 additions and 281 deletions

View file

@ -15,30 +15,33 @@
*/
package ghidra.app.plugin.core.memory;
import java.awt.Cursor;
import java.util.*;
import java.util.stream.Collectors;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellEditor;
import org.apache.commons.lang3.exception.ExceptionUtils;
import docking.widgets.OptionDialog;
import docking.widgets.dialogs.NumberInputDialog;
import docking.widgets.table.AbstractSortedTableModel;
/**
* Table Model for a Table where each entry represents a MemoryBlock
* from a Program's Memory.
*/
import ghidra.framework.model.DomainFile;
import ghidra.framework.store.LockException;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.util.Msg;
import ghidra.util.Swing;
import ghidra.util.table.ProgramTableModel;
class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
/**
* Table Model for a Table where each entry represents a MemoryBlock from a Program's Memory.
*/
class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> implements ProgramTableModel {
final static byte NAME = 0;
final static byte START = 1;
@ -70,9 +73,11 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
final static String SOURCE_COL = "Source";
final static String COMMENT_COL = "Comment";
private Program program;
private final static Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
private final static Cursor DEFAULT_CURSOR = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
private ArrayList<MemoryBlock> memList;
private Program program;
private List<MemoryBlock> memList;
private MemoryMapProvider provider;
private final static String COLUMN_NAMES[] =
@ -81,9 +86,12 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
MemoryMapModel(MemoryMapProvider provider, Program program) {
super(START);
this.program = program;
this.provider = provider;
setProgram(program);
}
void setProgram(Program program) {
this.program = program;
populateMap();
}
@ -91,6 +99,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
memList = new ArrayList<>();
if (program == null) {
fireTableDataChanged();
return;
}
@ -141,12 +150,6 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
return COLUMN_NAMES[column];
}
/**
* Convenience method for locating columns by name.
* Implementation is naive so this should be overridden if
* this method is to be called often. This method is not
* in the TableModel interface and is not used by the JTable.
*/
@Override
public int findColumn(String columnName) {
for (int i = 0; i < COLUMN_NAMES.length; i++) {
@ -157,9 +160,6 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
return 0;
}
/**
* Returns Object.class by default
*/
@Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE ||
@ -169,9 +169,6 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
return String.class;
}
/**
* Return whether this column is editable.
*/
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
@ -195,15 +192,6 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
}
}
/**
* Returns the number of records managed by the data source object. A
* <B>JTable</B> uses this method to determine how many rows it
* should create and display. This method should be quick, as it
* is call by <B>JTable</B> quite frequently.
*
* @return the number or rows in the model
* @see #getColumnCount
*/
@Override
public int getRowCount() {
return memList.size();
@ -226,157 +214,134 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
if (rowIndex < 0 || rowIndex >= memList.size()) {
return null;
}
MemoryBlock block = memList.get(rowIndex);
try {
// make sure block is still valid
block.getStart();
}
catch (ConcurrentModificationException e) {
update();
}
return memList.get(rowIndex);
}
/**
* This empty implementation is provided so users don't have to implement
* this method if their data model is not editable.
*/
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
provider.setCursor(MemoryMapPlugin.WAIT_CURSOR);
public void setValueAt(Object aValue, int row, int column) {
provider.setCursor(WAIT_CURSOR);
try {
MemoryBlock block = getBlockAt(rowIndex);
MemoryBlock block = getBlockAt(row);
if (block == null) {
// this can happen when the tool is closing while an edit is open
return;
}
switch (columnIndex) {
case NAME:
String name = ((String) aValue).trim();
if (!verifyRenameAllowed(block, name)) {
return;
}
if (name.length() == 0) {
Msg.showError(this, provider.getComponent(), "Enter Block Label",
"Please enter a label name.");
break;
}
if (name.equals(block.getName())) {
break;
}
if (!Memory.isValidMemoryBlockName(name)) {
Msg.showError(this, provider.getComponent(), "Invalid Name",
"Invalid Memory Block Name: " + name);
break;
}
if (!name.equals(block.getName())) {
program.withTransaction("Rename Memory Block", () -> {
try {
block.setName(name);
}
catch (LockException e) {
provider.setStatusText(e.getMessage());
}
});
}
break;
case READ: {
program.withTransaction("Set Read State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setRead(value);
provider.setStatusText("");
});
break;
}
case WRITE: {
program.withTransaction("Set Write State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setWrite(value);
provider.setStatusText("");
});
break;
}
case EXECUTE: {
int id = program.startTransaction("Set Execute State");
try {
boolean value = ((Boolean) aValue).booleanValue();
block.setExecute(value);
provider.setStatusText("");
program.endTransaction(id, true);
}
catch (RuntimeException e) {
program.endTransaction(id, false);
throw e;
}
break;
}
case VOLATILE: {
int id = program.startTransaction("Set Volatile State");
try {
boolean value = ((Boolean) aValue).booleanValue();
block.setVolatile(value);
provider.setStatusText("");
program.endTransaction(id, true);
}
catch (RuntimeException e) {
program.endTransaction(id, false);
throw e;
}
break;
}
case INIT:
MemoryBlockType blockType = block.getType();
if (blockType == MemoryBlockType.BIT_MAPPED ||
blockType == MemoryBlockType.BYTE_MAPPED) {
showMessage("Cannot change intialized memory state of a mapped Block");
return;
}
provider.setStatusText("");
boolean booleanValue = ((Boolean) aValue).booleanValue();
if (booleanValue) {
initializeBlock(block);
}
else {
revertBlockToUninitialized(block);
}
return;
case SOURCE:
break;
case COMMENT:
String cmt = block.getComment();
if (cmt == null || !cmt.equals(aValue)) {
String value = (String) aValue;
if (value.length() == 0) {
value = null;
}
int id = program.startTransaction("Set Comment State");
try {
block.setComment(value);
program.endTransaction(id, true);
}
catch (RuntimeException e) {
program.endTransaction(id, false);
throw e;
}
}
break;
default:
break;
}
fireTableRowsUpdated(rowIndex, rowIndex);
doSetValueAt(aValue, row, column, block);
}
finally {
provider.setCursor(MemoryMapPlugin.NORM_CURSOR);
provider.setCursor(DEFAULT_CURSOR);
}
}
private void doSetValueAt(Object aValue, int row, int column, MemoryBlock block) {
switch (column) {
case NAME:
setName(block, (String) aValue);
break;
case READ: {
program.withTransaction("Set Read State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setRead(value);
provider.setStatusText("");
});
break;
}
case WRITE: {
program.withTransaction("Set Write State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setWrite(value);
provider.setStatusText("");
});
break;
}
case EXECUTE: {
program.withTransaction("Set Execute State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setExecute(value);
provider.setStatusText("");
});
break;
}
case VOLATILE: {
program.withTransaction("Set Volatile State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setVolatile(value);
provider.setStatusText("");
});
break;
}
case INIT:
MemoryBlockType blockType = block.getType();
if (blockType == MemoryBlockType.BIT_MAPPED ||
blockType == MemoryBlockType.BYTE_MAPPED) {
showMessage("Cannot change intialized memory state of a mapped Block");
break;
}
provider.setStatusText("");
boolean booleanValue = ((Boolean) aValue).booleanValue();
if (booleanValue) {
initializeBlock(block);
}
else {
revertBlockToUninitialized(block);
}
break;
case SOURCE:
break;
case COMMENT:
setComment(block, (String) aValue);
break;
default:
break;
}
fireTableRowsUpdated(row, column);
}
private void setComment(MemoryBlock block, String aValue) {
String cmt = block.getComment();
if (cmt == null || !cmt.equals(aValue)) {
if (aValue.length() == 0) {
aValue = null;
}
String newValue = aValue;
program.withTransaction("Set Comment", () -> {
block.setComment(newValue);
});
}
}
private void setName(MemoryBlock block, String name) {
name = name.trim();
if (!verifyRenameAllowed(block, name)) {
return;
}
if (name.length() == 0) {
Msg.showError(this, provider.getComponent(), "Enter Block Label",
"Please enter a label name.");
return;
}
if (name.equals(block.getName())) {
return;
}
if (!Memory.isValidMemoryBlockName(name)) {
Msg.showError(this, provider.getComponent(), "Invalid Name",
"Invalid Memory Block Name: " + name);
return;
}
try {
String newName = name;
program.withTransaction("Rename Memory Block", () -> {
block.setName(newName);
});
}
catch (LockException e) {
this.provider.setStatusText(e.getMessage());
}
}
@ -438,15 +403,14 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
}
catch (Throwable t) {
program.endTransaction(id, false);
String msg = t.getMessage();
msg = msg == null ? t.toString() : msg;
String msg = ExceptionUtils.getMessage(t);
Msg.showError(this, provider.getComponent(), "Block Initialization Failed", msg, t);
}
}
private void showMessage(final String msg) {
private void showMessage(String msg) {
// mouse listeners wipe out the message so show it later...
SwingUtilities.invokeLater(() -> provider.setStatusText(msg));
Swing.runLater(() -> provider.setStatusText(msg));
}
@Override
@ -530,6 +494,44 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
return new MemoryMapComparator(columnIndex);
}
@Override
public ProgramLocation getProgramLocation(int row, int column) {
MemoryBlock block = getRowObject(row);
Address address = block.getStart();
if (column == END) {
address = block.getEnd();
}
return new ProgramLocation(program, address);
}
@Override
public ProgramSelection getProgramSelection(int[] rows) {
if (rows.length == 0) {
return null;
}
AddressSet addressSet = new AddressSet();
for (int row : rows) {
MemoryBlock block = getRowObject(row);
Address start = block.getStart();
Address end = block.getEnd();
if (start.isMemoryAddress() && end.isMemoryAddress()) {
addressSet.addRange(start, end);
}
}
return new ProgramSelection(addressSet);
}
@Override
public Program getProgram() {
return program;
}
private class MemoryMapComparator implements Comparator<MemoryBlock> {
private final int sortColumn;
@ -607,4 +609,5 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
}
}
}
}

View file

@ -15,8 +15,6 @@
*/
package ghidra.app.plugin.core.memory;
import java.awt.Cursor;
import ghidra.app.CorePluginPackage;
import ghidra.app.events.ProgramLocationPluginEvent;
import ghidra.app.plugin.PluginCategoryNames;
@ -51,9 +49,6 @@ import ghidra.program.util.ProgramLocation;
//@formatter:on
public class MemoryMapPlugin extends ProgramPlugin implements DomainObjectListener {
final static Cursor WAIT_CURSOR = new Cursor(Cursor.WAIT_CURSOR);
final static Cursor NORM_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR);
private MemoryMapProvider provider;
private GoToService goToService;
private MemoryMapManager memManager;

View file

@ -26,7 +26,6 @@ import javax.swing.table.TableModel;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.ToolBarData;
import docking.widgets.label.GLabel;
import docking.widgets.table.*;
import docking.widgets.textfield.GValidatedTextField.MaxLengthField;
import generic.theme.GIcon;
@ -41,18 +40,19 @@ import ghidra.program.model.mem.MemoryBlockType;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import ghidra.util.table.GhidraTable;
import ghidra.util.table.GhidraTableFilterPanel;
import ghidra.util.table.actions.MakeProgramSelectionAction;
/**
* Provider for the memory map Component.
*
*/
class MemoryMapProvider extends ComponentProviderAdapter {
private final static int MAX_SIZE = 256;
private JPanel mainPanel;
private GTable memTable;
private JScrollPane memPane;
private MemoryMapModel mapModel;
private MemoryMapModel tableModel;
private GhidraTable table;
private GTableFilterPanel<MemoryBlock> filterPanel;
private DockingAction addAction;
private DockingAction moveAction;
@ -84,6 +84,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
@Override
public void componentShown() {
updateMap();
contextChanged();
}
@Override
@ -96,7 +97,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
if (program == null) {
return null;
}
return new ProgramActionContext(this, program);
return new ProgramActionContext(this, program, table);
}
void setStatusText(String msg) {
@ -105,7 +106,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
void dispose() {
removeFromTool();
memTable.dispose();
filterPanel.dispose();
plugin = null;
program = null;
tool = null;
@ -113,7 +114,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
void setProgram(Program program) {
this.program = program;
updateMap(program);
updateProgram(program);
arrangeTable();
}
@ -121,69 +122,67 @@ class MemoryMapProvider extends ComponentProviderAdapter {
return memManager;
}
/**
* Creates the Main Panel for the Memory Map Dialog
*/
private JPanel buildMainPanel() {
JPanel memPanel = new JPanel(new BorderLayout());
mapModel = new MemoryMapModel(this, null);
memTable = new MemoryMapTable(mapModel);
tableModel = new MemoryMapModel(this, null);
table = new MemoryMapTable(tableModel);
filterPanel = new GhidraTableFilterPanel<>(table, tableModel);
memTable.setAutoCreateColumnsFromModel(false);
table.setAutoCreateColumnsFromModel(false);
GTableCellRenderer monoRenderer = new GTableCellRenderer();
monoRenderer.setFont(monoRenderer.getFixedWidthFont());
TableColumn column = memTable.getColumn(MemoryMapModel.START_COL);
TableColumn column = table.getColumn(MemoryMapModel.START_COL);
column.setCellRenderer(monoRenderer);
column = memTable.getColumn(MemoryMapModel.END_COL);
column = table.getColumn(MemoryMapModel.END_COL);
column.setCellRenderer(monoRenderer);
column = memTable.getColumn(MemoryMapModel.LENGTH_COL);
column = table.getColumn(MemoryMapModel.LENGTH_COL);
column.setCellRenderer(monoRenderer);
column = memTable.getColumn(MemoryMapModel.READ_COL);
column = table.getColumn(MemoryMapModel.READ_COL);
column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.WRITE_COL);
column = table.getColumn(MemoryMapModel.WRITE_COL);
column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.EXECUTE_COL);
column = table.getColumn(MemoryMapModel.EXECUTE_COL);
column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.VOLATILE_COL);
column = table.getColumn(MemoryMapModel.VOLATILE_COL);
column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.OVERLAY_COL);
column = table.getColumn(MemoryMapModel.OVERLAY_COL);
column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.INIT_COL);
column = table.getColumn(MemoryMapModel.INIT_COL);
column.setCellRenderer(new GBooleanCellRenderer());
memTable.setDefaultEditor(String.class,
table.setDefaultEditor(String.class,
new GTableTextCellEditor(new MaxLengthField(MAX_SIZE)));
memPane = new JScrollPane(memTable);
memTable.setPreferredScrollableViewportSize(new Dimension(700, 105));
table.setPreferredScrollableViewportSize(new Dimension(700, 105));
memTable.addMouseListener(new MouseHandler());
table.addMouseListener(new MouseHandler());
memTable.addKeyListener(new KeyHandler());
table.addKeyListener(new KeyHandler());
memTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
ListSelectionModel lsm = memTable.getSelectionModel();
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
ListSelectionModel lsm = table.getSelectionModel();
lsm.addListSelectionListener(e -> {
// Ignore extra messages.
if (e.getValueIsAdjusting()) {
return;
}
ListSelectionModel model = (ListSelectionModel) e.getSource();
enableOptions(model);
contextChanged();
});
memPanel.add(new GLabel("Memory Blocks", SwingConstants.CENTER), BorderLayout.NORTH);
memPanel.add(memPane, BorderLayout.CENTER);
memPanel.add(new JScrollPane(table), BorderLayout.CENTER);
memPanel.add(filterPanel, BorderLayout.SOUTH);
return memPanel;
}
private void addLocalActions() {
Icon addImage = new GIcon("icon.plugin.memorymap.add");
addAction = new MemoryMapAction("Add Block", addImage) {
@ -294,6 +293,11 @@ class MemoryMapProvider extends ComponentProviderAdapter {
setBaseAction.setDescription("Set Image Base");
tool.addLocalAction(this, setBaseAction);
MakeProgramSelectionAction action =
new MakeProgramSelectionAction(plugin, table);
action.getToolBarData().setToolBarGroup("B"); // the other actions are in group 'A'
tool.addLocalAction(this, action);
}
private void setBase() {
@ -332,12 +336,6 @@ class MemoryMapProvider extends ComponentProviderAdapter {
}
}
/**
* Enable/disable the expand up/down actions according to the selected
* block.
*
* @param numSelected number of blocks selected
*/
private void enableExpandActions(int numSelected) {
if (numSelected != 1) {
expandUpAction.setEnabled(false);
@ -368,7 +366,11 @@ class MemoryMapProvider extends ComponentProviderAdapter {
}
JTable getTable() {
return memTable;
return table;
}
MemoryMapModel getModel() {
return tableModel;
}
/**
@ -376,7 +378,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
*/
void updateMap() {
if (isVisible()) {
mapModel.update();
tableModel.update();
arrangeTable();
updateTitle();
}
@ -385,7 +387,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
void updateData() {
if (isVisible()) {
updateTitle();
memTable.repaint();
table.repaint();
}
}
@ -398,9 +400,9 @@ class MemoryMapProvider extends ComponentProviderAdapter {
/**
* Update the memory map with the new program's memory
*/
private void updateMap(Program updateProgram) {
private void updateProgram(Program updatedProgram) {
enableOptions(null);
if (updateProgram == null) {
if (updatedProgram == null) {
addAction.setEnabled(false);
setBaseAction.setEnabled(false);
}
@ -408,8 +410,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
setBaseAction.setEnabled(true);
}
mapModel = new MemoryMapModel(this, updateProgram);
memTable.setModel(mapModel);
tableModel.setProgram(updatedProgram);
updateTitle();
}
@ -420,48 +421,48 @@ class MemoryMapProvider extends ComponentProviderAdapter {
// memTable.setRowHeight(20);
TableColumn column;
column = memTable.getColumn(MemoryMapModel.READ_COL);
column = table.getColumn(MemoryMapModel.READ_COL);
if (column != null) {
column.setMaxWidth(25);
column.setMinWidth(25);
column.setResizable(false);
}
column = memTable.getColumn(MemoryMapModel.WRITE_COL);
column = table.getColumn(MemoryMapModel.WRITE_COL);
if (column != null) {
column.setMaxWidth(25);
column.setMinWidth(25);
column.setResizable(false);
}
column = memTable.getColumn(MemoryMapModel.EXECUTE_COL);
column = table.getColumn(MemoryMapModel.EXECUTE_COL);
if (column != null) {
column.setMaxWidth(25);
column.setMinWidth(25);
column.setResizable(false);
}
column = memTable.getColumn(MemoryMapModel.VOLATILE_COL);
column = table.getColumn(MemoryMapModel.VOLATILE_COL);
if (column != null) {
column.setMaxWidth(65);
column.setMinWidth(65);
column.setResizable(false);
}
column = memTable.getColumn(MemoryMapModel.OVERLAY_COL);
column = table.getColumn(MemoryMapModel.OVERLAY_COL);
if (column != null) {
column.setMaxWidth(65);
column.setMinWidth(65);
column.setResizable(false);
}
column = memTable.getColumn(MemoryMapModel.BLOCK_TYPE_COL);
column = table.getColumn(MemoryMapModel.BLOCK_TYPE_COL);
if (column != null) {
column.setMinWidth(60);
// column.setResizable(true);
}
column = memTable.getColumn(MemoryMapModel.INIT_COL);
column = table.getColumn(MemoryMapModel.INIT_COL);
if (column != null) {
column.setMaxWidth(80);
column.setMinWidth(80);
@ -484,7 +485,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
if (!e.isPopupTrigger()) {
if ((e.getModifiersEx() &
(InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)) == 0) {
selectAddress();
navigateToAddress();
}
}
}
@ -499,30 +500,30 @@ class MemoryMapProvider extends ComponentProviderAdapter {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
selectAddress();
navigateToAddress();
e.consume();
}
}
}
private void selectAddress() {
int row = memTable.getSelectedRow();
int viewColumn = memTable.getSelectedColumn();
int col = memTable.convertColumnIndexToModel(viewColumn);
MemoryBlock block = mapModel.getBlockAt(row);
if (block != null && (col == 1 || col == 2)) {
Address addr = (col == 1 ? block.getStart() : block.getEnd());
private void navigateToAddress() {
int viewRow = table.getSelectedRow();
int viewColumn = table.getSelectedColumn();
int modelColumn = table.convertColumnIndexToModel(viewColumn);
MemoryBlock block = tableModel.getBlockAt(viewRow);
if (block != null && (modelColumn == 1 || modelColumn == 2)) {
Address addr = (modelColumn == 1 ? block.getStart() : block.getEnd());
plugin.blockSelected(block, addr);
memTable.setRowSelectionInterval(row, row);
table.setRowSelectionInterval(viewRow, viewRow);
}
}
private MemoryBlock getSelectedBlock() {
int row = memTable.getSelectedRow();
int row = table.getSelectedRow();
if (row < 0) {
return null;
}
return mapModel.getBlockAt(row);
return tableModel.getBlockAt(row);
}
/**
@ -534,12 +535,12 @@ class MemoryMapProvider extends ComponentProviderAdapter {
return;
}
ArrayList<MemoryBlock> delBlocks = new ArrayList<>();
int delRows[] = memTable.getSelectedRows();
int delRows[] = table.getSelectedRows();
for (int element : delRows) {
MemoryBlock block = mapModel.getBlockAt(element);
MemoryBlock block = tableModel.getBlockAt(element);
delBlocks.add(block);
}
memTable.clearSelection();
table.clearSelection();
deleteBlock(delBlocks);
}
@ -642,12 +643,12 @@ class MemoryMapProvider extends ComponentProviderAdapter {
*/
private void mergeBlocks() {
ArrayList<MemoryBlock> blocks = new ArrayList<>();
int rows[] = memTable.getSelectedRows();
int rows[] = table.getSelectedRows();
for (int element : rows) {
MemoryBlock block = mapModel.getBlockAt(element);
MemoryBlock block = tableModel.getBlockAt(element);
blocks.add(block);
}
memTable.clearSelection();
table.clearSelection();
memManager.mergeBlocks(blocks);
}
@ -670,9 +671,9 @@ class MemoryMapProvider extends ComponentProviderAdapter {
return plugin.getTool();
}
// ==================================================================================================
//==================================================================================================
// Inner Classes
// ==================================================================================================
//==================================================================================================
private class MemoryMapTable extends GhidraTable {
MemoryMapTable(TableModel model) {
@ -691,7 +692,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
private abstract class MemoryMapAction extends DockingAction {
MemoryMapAction(String name, Icon icon) {
super(name, plugin.getName());
this.setToolBarData(new ToolBarData(icon, null));
this.setToolBarData(new ToolBarData(icon, "A"));
}
public boolean checkExclusiveAccess() {

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,31 +20,28 @@ import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
/**
* An interface for translating table rows and columns
* into program locations and selections.
* An interface for translating table rows and columns into program locations and selections.
*/
public interface ProgramTableModel {
/**
* Returns a program location corresponding the given row and column.
* Motivation:
* Given a table that has a column that contains addresses.
* If the user clicks on this column, then it would be nice
* to have the CodeBrowser navigate to this address.
* @param row the row
* @param column the column
* @return a program location corresponding the given row and column
*/
public ProgramLocation getProgramLocation(int row, int column);
/**
* Returns a program location corresponding the given row and column.
* <p>
* Motivation: Given a table that has a column that contains addresses. If the user clicks on
* this column, then it would be nice to have the CodeBrowser navigate to this address.
* @param row the row
* @param modelColumn the column in the model's index
* @return a program location corresponding the given row and column
*/
public ProgramLocation getProgramLocation(int row, int modelColumn);
/**
* Returns a program selection corresponding to the
* specified row index array. This array will contain
* the currently selected rows.
* Returns a program selection corresponding to the specified row index array. This array will
* contain the currently selected rows.
* @param rows the currently selected rows.
* @return a program selection
*/
public ProgramSelection getProgramSelection(int[] rows);
/**
* Returns the program associated with this ProgramTableModel.
* @return the program associated with this ProgramTableModel.

View file

@ -673,8 +673,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
waitForSwing();
provider = plugin.getMemoryMapProvider();
table = provider.getTable();
model = (MemoryMapModel) table.getModel();
model = provider.getModel();
}
private Address getAddr(long offset) {

View file

@ -109,7 +109,8 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
private static final Icon ICON_HOME = new GIcon("icon.filechooser.places.home");
private static final Icon ICON_RECENT = new GIcon("icon.filechooser.places.recent");
// base and overlay?
private final static Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
private final static Cursor DEFAULT_CURSOR = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
/** Instruction to display only files. */
public static final int FILES_ONLY = 0;
@ -464,13 +465,13 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
@Override
public void mouseEntered(MouseEvent e) {
waitPanel.setCursor(new Cursor(Cursor.WAIT_CURSOR));
waitPanel.setCursor(WAIT_CURSOR);
e.consume();
}
@Override
public void mouseExited(MouseEvent e) {
waitPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
waitPanel.setCursor(DEFAULT_CURSOR);
}
});
waitPanel.addMouseMotionListener(new MouseMotionAdapter() {

View file

@ -32,8 +32,8 @@ import ghidra.util.task.TaskMonitor;
public class DataTypeArchiveTransformerPanel extends JPanel {
private final static Cursor WAIT_CURSOR = new Cursor(Cursor.WAIT_CURSOR);
private final static Cursor NORM_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR);
private final static Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
private final static Cursor DEFAULT_CURSOR = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
private JPanel filePanel;
private JTextField oldFileTextField;
@ -85,7 +85,7 @@ public class DataTypeArchiveTransformerPanel extends JPanel {
oldBrowseButton.addActionListener(e -> {
setCursor(WAIT_CURSOR);
File file = chooseFile("Choose old data type archive");
setCursor(NORM_CURSOR);
setCursor(DEFAULT_CURSOR);
if (file != null) {
oldFileTextField.setText(file.getAbsolutePath());
}
@ -119,7 +119,7 @@ public class DataTypeArchiveTransformerPanel extends JPanel {
newBrowseButton.addActionListener(e -> {
setCursor(WAIT_CURSOR);
File file = chooseFile("Choose new data type archive");
setCursor(NORM_CURSOR);
setCursor(DEFAULT_CURSOR);
if (file != null) {
newFileTextField.setText(file.getAbsolutePath());
}
@ -148,7 +148,7 @@ public class DataTypeArchiveTransformerPanel extends JPanel {
destinationBrowseButton.addActionListener(e -> {
setCursor(WAIT_CURSOR);
File file = chooseFile("Choose destination file");
setCursor(NORM_CURSOR);
setCursor(DEFAULT_CURSOR);
if (file != null) {
destinationFileTextField.setText(file.getAbsolutePath());
}