Merge branch
'GP-5979_dragonmacher-search-memory-accessibility--SQUASHED' (Closes #8264)
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 18 KiB |
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.features.base.memsearch.gui;
|
package ghidra.features.base.memsearch.gui;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
import java.awt.FlowLayout;
|
import java.awt.FlowLayout;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -38,20 +37,30 @@ public class MemoryScanControlPanel extends JPanel {
|
||||||
private JButton scanButton;
|
private JButton scanButton;
|
||||||
|
|
||||||
MemoryScanControlPanel(MemorySearchProvider provider) {
|
MemoryScanControlPanel(MemorySearchProvider provider) {
|
||||||
super(new BorderLayout());
|
super();
|
||||||
|
|
||||||
|
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
|
||||||
|
|
||||||
setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
|
setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
|
||||||
add(buildButtonPanel(), BorderLayout.CENTER);
|
|
||||||
scanButton = new JButton("Scan Values");
|
scanButton = new JButton("Scan Values");
|
||||||
|
scanButton.setMnemonic('V');
|
||||||
|
scanButton.setEnabled(false);
|
||||||
scanButton.setToolTipText("Refreshes byte values of current results and eliminates " +
|
scanButton.setToolTipText("Refreshes byte values of current results and eliminates " +
|
||||||
"those that don't meet the selected change criteria");
|
"those that don't meet the selected change criteria");
|
||||||
|
|
||||||
|
add(scanButton);
|
||||||
|
add(Box.createHorizontalStrut(20));
|
||||||
|
add(buildButtonPanel());
|
||||||
|
|
||||||
HelpService helpService = Help.getHelpService();
|
HelpService helpService = Help.getHelpService();
|
||||||
helpService.registerHelp(this, new HelpLocation(HelpTopics.SEARCH, "Scan_Controls"));
|
helpService.registerHelp(this, new HelpLocation(HelpTopics.SEARCH, "Scan_Controls"));
|
||||||
add(scanButton, BorderLayout.WEST);
|
|
||||||
scanButton.addActionListener(e -> provider.scan(selectedScanner));
|
scanButton.addActionListener(e -> provider.scan(selectedScanner));
|
||||||
}
|
}
|
||||||
|
|
||||||
private JComponent buildButtonPanel() {
|
private JComponent buildButtonPanel() {
|
||||||
JPanel panel = new JPanel(new FlowLayout());
|
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEADING));
|
||||||
ButtonGroup buttonGroup = new ButtonGroup();
|
ButtonGroup buttonGroup = new ButtonGroup();
|
||||||
for (Scanner scanner : Scanner.values()) {
|
for (Scanner scanner : Scanner.values()) {
|
||||||
GRadioButton button = new GRadioButton(scanner.getName());
|
GRadioButton button = new GRadioButton(scanner.getName());
|
||||||
|
|
|
@ -24,14 +24,17 @@ import java.util.List;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
|
import javax.swing.border.CompoundBorder;
|
||||||
import javax.swing.text.*;
|
import javax.swing.text.*;
|
||||||
|
|
||||||
import docking.DockingUtils;
|
import docking.DockingUtils;
|
||||||
import docking.menu.ButtonState;
|
import docking.menu.ButtonState;
|
||||||
import docking.menu.MultiStateButton;
|
import docking.menu.MultiStateButton;
|
||||||
import docking.widgets.PopupWindow;
|
import docking.widgets.PopupWindow;
|
||||||
|
import docking.widgets.combobox.GComboBox;
|
||||||
import docking.widgets.combobox.GhidraComboBox;
|
import docking.widgets.combobox.GhidraComboBox;
|
||||||
import docking.widgets.label.GDLabel;
|
import docking.widgets.label.GDLabel;
|
||||||
|
import docking.widgets.label.GLabel;
|
||||||
import docking.widgets.list.GComboBoxCellRenderer;
|
import docking.widgets.list.GComboBoxCellRenderer;
|
||||||
import generic.theme.GThemeDefaults.Colors.Messages;
|
import generic.theme.GThemeDefaults.Colors.Messages;
|
||||||
import ghidra.features.base.memsearch.combiner.Combiner;
|
import ghidra.features.base.memsearch.combiner.Combiner;
|
||||||
|
@ -89,9 +92,11 @@ class MemorySearchControlPanel extends JPanel {
|
||||||
searchButton = new MultiStateButton<Combiner>(initialSearchButtonStates);
|
searchButton = new MultiStateButton<Combiner>(initialSearchButtonStates);
|
||||||
searchButton
|
searchButton
|
||||||
.setStateChangedListener(state -> model.setMatchCombiner(state.getClientData()));
|
.setStateChangedListener(state -> model.setMatchCombiner(state.getClientData()));
|
||||||
|
searchButton.setMnemonic('S');
|
||||||
searchButton.addActionListener(e -> search());
|
searchButton.addActionListener(e -> search());
|
||||||
panel.add(searchButton, BorderLayout.WEST);
|
panel.add(searchButton, BorderLayout.WEST);
|
||||||
selectionCheckbox = new JCheckBox("Selection Only");
|
selectionCheckbox = new JCheckBox("Selection Only");
|
||||||
|
selectionCheckbox.setMnemonic('O');
|
||||||
selectionCheckbox.setSelected(model.isSearchSelectionOnly());
|
selectionCheckbox.setSelected(model.isSearchSelectionOnly());
|
||||||
selectionCheckbox.setEnabled(model.hasSelection());
|
selectionCheckbox.setEnabled(model.hasSelection());
|
||||||
selectionCheckbox
|
selectionCheckbox
|
||||||
|
@ -132,9 +137,10 @@ class MemorySearchControlPanel extends JPanel {
|
||||||
if (!formatComboBox.getSelectedItem().equals(searchFormat)) {
|
if (!formatComboBox.getSelectedItem().equals(searchFormat)) {
|
||||||
formatComboBox.setSelectedItem(searchFormat);
|
formatComboBox.setSelectedItem(searchFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
selectionCheckbox.setSelected(model.isSearchSelectionOnly());
|
selectionCheckbox.setSelected(model.isSearchSelectionOnly());
|
||||||
selectionCheckbox.setEnabled(model.hasSelection());
|
selectionCheckbox.setEnabled(model.hasSelection());
|
||||||
searchInputField.setToolTipText(searchFormat.getToolTip());
|
searchInputField.setToolTipText("Search Text: " + searchFormat.getToolTip());
|
||||||
|
|
||||||
String text = searchInputField.getText();
|
String text = searchInputField.getText();
|
||||||
String convertedText = searchFormat.convertText(text, oldSettings, model.getSettings());
|
String convertedText = searchFormat.convertText(text, oldSettings, model.getSettings());
|
||||||
|
@ -144,23 +150,53 @@ class MemorySearchControlPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private JComponent buildLeftSearchInputPanel() {
|
private JComponent buildLeftSearchInputPanel() {
|
||||||
createSearchInputField();
|
|
||||||
|
JPanel searchInputPanel = createSearchInputPanel();
|
||||||
|
GLabel searchLabel = new GLabel("Search Text:");
|
||||||
|
searchLabel.setDisplayedMnemonic('T');
|
||||||
|
searchLabel.setLabelFor(searchInputField);
|
||||||
|
|
||||||
|
JLabel bytesLabel = new GLabel("Byte Sequence:", SwingConstants.RIGHT);
|
||||||
|
bytesLabel.setToolTipText("The byte sequence that will be searched (if applicable)");
|
||||||
|
JPanel bytesPanel = createBytesPanel();
|
||||||
|
|
||||||
|
JPanel panel = new JPanel(new PairLayout(2, 10));
|
||||||
|
|
||||||
|
// row 1
|
||||||
|
panel.add(searchLabel);
|
||||||
|
panel.add(searchInputPanel);
|
||||||
|
|
||||||
|
// row 2
|
||||||
|
panel.add(bytesLabel);
|
||||||
|
panel.add(bytesPanel);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JPanel createBytesPanel() {
|
||||||
|
|
||||||
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
hexSearchSequenceField = new GDLabel();
|
hexSearchSequenceField = new GDLabel();
|
||||||
hexSearchSequenceField.setName("HexSequenceField");
|
hexSearchSequenceField.setName("Hex Sequence Field");
|
||||||
Border outerBorder = BorderFactory.createLoweredBevelBorder();
|
Border outerBorder = BorderFactory.createLoweredBevelBorder();
|
||||||
Border innerBorder = BorderFactory.createEmptyBorder(0, 4, 0, 4);
|
Border innerBorder = BorderFactory.createEmptyBorder(0, 4, 0, 4);
|
||||||
Border border = BorderFactory.createCompoundBorder(outerBorder, innerBorder);
|
Border border = BorderFactory.createCompoundBorder(outerBorder, innerBorder);
|
||||||
hexSearchSequenceField.setBorder(border);
|
hexSearchSequenceField.setBorder(border);
|
||||||
|
|
||||||
JPanel panel = new JPanel(new PairLayout(2, 10));
|
panel.add(hexSearchSequenceField, BorderLayout.CENTER);
|
||||||
panel.add(buildSearchFormatCombo());
|
int spaceWidth = formatComboBox.getPreferredSize().width;
|
||||||
panel.add(searchInputField);
|
panel.add(Box.createHorizontalStrut(spaceWidth), BorderLayout.EAST);
|
||||||
JLabel byteSequenceLabel = new JLabel("Byte Sequence:", SwingConstants.RIGHT);
|
|
||||||
byteSequenceLabel.setToolTipText(
|
return panel;
|
||||||
"This field shows the byte sequence that will be search (if applicable)");
|
}
|
||||||
|
|
||||||
|
private JPanel createSearchInputPanel() {
|
||||||
|
|
||||||
|
createSearchInputField();
|
||||||
|
|
||||||
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
|
panel.add(searchInputField, BorderLayout.CENTER);
|
||||||
|
panel.add(buildSearchFormatCombo(), BorderLayout.EAST);
|
||||||
|
|
||||||
panel.add(byteSequenceLabel);
|
|
||||||
panel.add(hexSearchSequenceField);
|
|
||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +217,7 @@ class MemorySearchControlPanel extends JPanel {
|
||||||
updateCombo();
|
updateCombo();
|
||||||
searchInputField.setAutoCompleteEnabled(false); // this interferes with validation
|
searchInputField.setAutoCompleteEnabled(false); // this interferes with validation
|
||||||
searchInputField.setEditable(true);
|
searchInputField.setEditable(true);
|
||||||
searchInputField.setToolTipText(model.getSearchFormat().getToolTip());
|
searchInputField.setToolTipText("Search Text: " + model.getSearchFormat().getToolTip());
|
||||||
searchInputField.setDocument(new RestrictedInputDocument());
|
searchInputField.setDocument(new RestrictedInputDocument());
|
||||||
searchInputField.addActionListener(ev -> search());
|
searchInputField.addActionListener(ev -> search());
|
||||||
JTextField searchTextField = searchInputField.getTextField();
|
JTextField searchTextField = searchInputField.getTextField();
|
||||||
|
@ -220,11 +256,14 @@ class MemorySearchControlPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private JComponent buildSearchFormatCombo() {
|
private JComponent buildSearchFormatCombo() {
|
||||||
formatComboBox = new JComboBox<>(SearchFormat.ALL);
|
formatComboBox = new GComboBox<>(SearchFormat.ALL);
|
||||||
formatComboBox.setSelectedItem(model.getSearchFormat());
|
formatComboBox.setSelectedItem(model.getSearchFormat());
|
||||||
formatComboBox.addItemListener(this::formatComboChanged);
|
formatComboBox.addItemListener(this::formatComboChanged);
|
||||||
formatComboBox.setToolTipText("The selected format will determine how to " +
|
formatComboBox.setToolTipText("Search Format: how to interpret search text");
|
||||||
"interpret text typed into the input field");
|
Border inside = formatComboBox.getBorder();
|
||||||
|
CompoundBorder paddingBorder =
|
||||||
|
BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0), inside);
|
||||||
|
formatComboBox.setBorder(paddingBorder);
|
||||||
|
|
||||||
return formatComboBox;
|
return formatComboBox;
|
||||||
}
|
}
|
||||||
|
@ -252,7 +291,7 @@ class MemorySearchControlPanel extends JPanel {
|
||||||
currentMatcher = byteMatcher;
|
currentMatcher = byteMatcher;
|
||||||
String text = currentMatcher.getDescription();
|
String text = currentMatcher.getDescription();
|
||||||
hexSearchSequenceField.setText(text);
|
hexSearchSequenceField.setText(text);
|
||||||
hexSearchSequenceField.setToolTipText(currentMatcher.getToolTip());
|
hexSearchSequenceField.setToolTipText("Search as hex: " + currentMatcher.getToolTip());
|
||||||
updateSearchButton();
|
updateSearchButton();
|
||||||
provider.setByteMatcher(byteMatcher);
|
provider.setByteMatcher(byteMatcher);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import javax.swing.text.*;
|
||||||
|
|
||||||
import docking.widgets.checkbox.GCheckBox;
|
import docking.widgets.checkbox.GCheckBox;
|
||||||
import docking.widgets.combobox.GComboBox;
|
import docking.widgets.combobox.GComboBox;
|
||||||
|
import docking.widgets.label.GLabel;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.docking.util.LookAndFeelUtils;
|
import ghidra.docking.util.LookAndFeelUtils;
|
||||||
import ghidra.features.base.memsearch.bytesource.SearchRegion;
|
import ghidra.features.base.memsearch.bytesource.SearchRegion;
|
||||||
|
@ -57,7 +58,7 @@ class MemorySearchOptionsPanel extends JPanel {
|
||||||
super(new BorderLayout());
|
super(new BorderLayout());
|
||||||
this.model = model;
|
this.model = model;
|
||||||
|
|
||||||
// if the look and feel is Nimbus, the spaceing it too big, so we use less spacing
|
// if the look and feel is Nimbus, the spacing it too big, so we use less spacing
|
||||||
// between elements.
|
// between elements.
|
||||||
isNimbus = LookAndFeelUtils.isUsingNimbusUI();
|
isNimbus = LookAndFeelUtils.isUsingNimbusUI();
|
||||||
|
|
||||||
|
@ -93,9 +94,22 @@ class MemorySearchOptionsPanel extends JPanel {
|
||||||
JPanel panel = new JPanel(new VerticalLayout(3));
|
JPanel panel = new JPanel(new VerticalLayout(3));
|
||||||
panel.setBorder(createBorder("Search Region Filter"));
|
panel.setBorder(createBorder("Search Region Filter"));
|
||||||
|
|
||||||
|
boolean accelerator = true;
|
||||||
List<SearchRegion> choices = model.getMemoryRegionChoices();
|
List<SearchRegion> choices = model.getMemoryRegionChoices();
|
||||||
for (SearchRegion region : choices) {
|
for (SearchRegion region : choices) {
|
||||||
GCheckBox checkbox = new GCheckBox(region.getName());
|
GCheckBox checkbox = new GCheckBox(region.getName());
|
||||||
|
|
||||||
|
if (accelerator) {
|
||||||
|
// The text for the checkbox is dynamic. If the first letter is taken by a menu,
|
||||||
|
// then the accelerator may not work. At the time of writing, the first letter of
|
||||||
|
// the first option seems not to conflict with the other accelerators in the parent
|
||||||
|
// dialog.
|
||||||
|
String name = region.getName();
|
||||||
|
char c = name.charAt(0);
|
||||||
|
checkbox.setMnemonic(c);
|
||||||
|
accelerator = false;
|
||||||
|
}
|
||||||
|
|
||||||
checkbox.setToolTipText(region.getDescription());
|
checkbox.setToolTipText(region.getDescription());
|
||||||
checkbox.setSelected(model.isSelectedRegion(region));
|
checkbox.setSelected(model.isSelectedRegion(region));
|
||||||
checkbox.addItemListener(e -> model.selectRegion(region, checkbox.isSelected()));
|
checkbox.addItemListener(e -> model.selectRegion(region, checkbox.isSelected()));
|
||||||
|
@ -109,13 +123,15 @@ class MemorySearchOptionsPanel extends JPanel {
|
||||||
panel.setBorder(createBorder("Decimal Options"));
|
panel.setBorder(createBorder("Decimal Options"));
|
||||||
|
|
||||||
JPanel innerPanel = new JPanel(new PairLayout(5, 5));
|
JPanel innerPanel = new JPanel(new PairLayout(5, 5));
|
||||||
JLabel label = new JLabel("Size:");
|
GLabel label = new GLabel("Size:");
|
||||||
|
label.setDisplayedMnemonic('z');
|
||||||
label.setToolTipText("Size of decimal values in bytes");
|
label.setToolTipText("Size of decimal values in bytes");
|
||||||
innerPanel.add(label);
|
innerPanel.add(label);
|
||||||
|
|
||||||
Integer[] decimalSizes = new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 16 };
|
Integer[] decimalSizes = new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 16 };
|
||||||
int decimalByteSize = model.getDecimalByteSize();
|
int decimalByteSize = model.getDecimalByteSize();
|
||||||
decimalByteSizeCombo = new GComboBox<>(decimalSizes);
|
decimalByteSizeCombo = new GComboBox<>(decimalSizes);
|
||||||
|
label.setLabelFor(decimalByteSizeCombo);
|
||||||
decimalByteSizeCombo.setSelectedItem(decimalByteSize);
|
decimalByteSizeCombo.setSelectedItem(decimalByteSize);
|
||||||
decimalByteSizeCombo.addItemListener(this::byteSizeComboChanged);
|
decimalByteSizeCombo.addItemListener(this::byteSizeComboChanged);
|
||||||
decimalByteSizeCombo.setToolTipText("Size of decimal values in bytes");
|
decimalByteSizeCombo.setToolTipText("Size of decimal values in bytes");
|
||||||
|
@ -123,6 +139,7 @@ class MemorySearchOptionsPanel extends JPanel {
|
||||||
panel.add(innerPanel);
|
panel.add(innerPanel);
|
||||||
|
|
||||||
decimalUnsignedCheckbox = new GCheckBox("Unsigned");
|
decimalUnsignedCheckbox = new GCheckBox("Unsigned");
|
||||||
|
decimalUnsignedCheckbox.setMnemonic('U');
|
||||||
decimalUnsignedCheckbox.setToolTipText(
|
decimalUnsignedCheckbox.setToolTipText(
|
||||||
"Sets whether decimal values should be interpreted as unsigned values");
|
"Sets whether decimal values should be interpreted as unsigned values");
|
||||||
decimalUnsignedCheckbox.addActionListener(
|
decimalUnsignedCheckbox.addActionListener(
|
||||||
|
@ -145,8 +162,11 @@ class MemorySearchOptionsPanel extends JPanel {
|
||||||
JPanel panel = new JPanel(new VerticalLayout(5));
|
JPanel panel = new JPanel(new VerticalLayout(5));
|
||||||
panel.setBorder(createBorder("Code Type Filter"));
|
panel.setBorder(createBorder("Code Type Filter"));
|
||||||
GCheckBox instructionsCheckBox = new GCheckBox("Instructions");
|
GCheckBox instructionsCheckBox = new GCheckBox("Instructions");
|
||||||
|
instructionsCheckBox.setMnemonic('I');
|
||||||
GCheckBox definedDataCheckBox = new GCheckBox("Defined Data");
|
GCheckBox definedDataCheckBox = new GCheckBox("Defined Data");
|
||||||
|
definedDataCheckBox.setMnemonic('D');
|
||||||
GCheckBox undefinedDataCheckBox = new GCheckBox("Undefined Data");
|
GCheckBox undefinedDataCheckBox = new GCheckBox("Undefined Data");
|
||||||
|
undefinedDataCheckBox.setMnemonic('U');
|
||||||
instructionsCheckBox.setToolTipText(
|
instructionsCheckBox.setToolTipText(
|
||||||
"If selected, include matches found in instructions");
|
"If selected, include matches found in instructions");
|
||||||
definedDataCheckBox.setToolTipText(
|
definedDataCheckBox.setToolTipText(
|
||||||
|
@ -185,9 +205,15 @@ class MemorySearchOptionsPanel extends JPanel {
|
||||||
alignField.setToolTipText(
|
alignField.setToolTipText(
|
||||||
"Filters out matches whose address is not divisible by the alignment value");
|
"Filters out matches whose address is not divisible by the alignment value");
|
||||||
|
|
||||||
panel.add(new JLabel("Endianess:"));
|
GLabel endianessLabel = new GLabel("Endianess:");
|
||||||
|
endianessLabel.setLabelFor(endianessCombo);
|
||||||
|
endianessLabel.setDisplayedMnemonic('n');
|
||||||
|
GLabel alignmentLabel = new GLabel("Alignment:");
|
||||||
|
alignmentLabel.setDisplayedMnemonic('A');
|
||||||
|
alignmentLabel.setLabelFor(alignField);
|
||||||
|
panel.add(endianessLabel);
|
||||||
panel.add(endianessCombo);
|
panel.add(endianessCombo);
|
||||||
panel.add(new JLabel("Alignment:"));
|
panel.add(alignmentLabel);
|
||||||
panel.add(alignField);
|
panel.add(alignField);
|
||||||
|
|
||||||
return panel;
|
return panel;
|
||||||
|
@ -215,19 +241,23 @@ class MemorySearchOptionsPanel extends JPanel {
|
||||||
charsetCombo.setToolTipText("Character encoding for translating strings to bytes");
|
charsetCombo.setToolTipText("Character encoding for translating strings to bytes");
|
||||||
|
|
||||||
JPanel innerPanel = new JPanel(new PairLayout(5, 5));
|
JPanel innerPanel = new JPanel(new PairLayout(5, 5));
|
||||||
JLabel label = new JLabel("Encoding:");
|
GLabel label = new GLabel("Encoding:");
|
||||||
|
label.setDisplayedMnemonic('c');
|
||||||
|
label.setLabelFor(charsetCombo);
|
||||||
label.setToolTipText("Character encoding for translating strings to bytes");
|
label.setToolTipText("Character encoding for translating strings to bytes");
|
||||||
innerPanel.add(label);
|
innerPanel.add(label);
|
||||||
innerPanel.add(charsetCombo);
|
innerPanel.add(charsetCombo);
|
||||||
panel.add(innerPanel);
|
panel.add(innerPanel);
|
||||||
|
|
||||||
caseSensitiveCheckbox = new GCheckBox("Case Sensitive");
|
caseSensitiveCheckbox = new GCheckBox("Case Sensitive");
|
||||||
|
caseSensitiveCheckbox.setMnemonic('n');
|
||||||
caseSensitiveCheckbox.setSelected(model.isCaseSensitive());
|
caseSensitiveCheckbox.setSelected(model.isCaseSensitive());
|
||||||
caseSensitiveCheckbox.setToolTipText("Allows for case sensitive searching.");
|
caseSensitiveCheckbox.setToolTipText("Allows for case sensitive searching.");
|
||||||
caseSensitiveCheckbox.addActionListener(
|
caseSensitiveCheckbox.addActionListener(
|
||||||
e -> model.setCaseSensitive(caseSensitiveCheckbox.isSelected()));
|
e -> model.setCaseSensitive(caseSensitiveCheckbox.isSelected()));
|
||||||
|
|
||||||
escapeSequencesCheckbox = new GCheckBox("Escape Sequences");
|
escapeSequencesCheckbox = new GCheckBox("Escape Sequences");
|
||||||
|
escapeSequencesCheckbox.setMnemonic('c');
|
||||||
escapeSequencesCheckbox.setSelected(model.useEscapeSequences());
|
escapeSequencesCheckbox.setSelected(model.useEscapeSequences());
|
||||||
escapeSequencesCheckbox.setToolTipText(
|
escapeSequencesCheckbox.setToolTipText(
|
||||||
"Allows specifying control characters using escape sequences " +
|
"Allows specifying control characters using escape sequences " +
|
||||||
|
|
|
@ -698,10 +698,18 @@ public class MemorySearchProvider extends ComponentProviderAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ActionContext createContext(Component sourceComponent, Object contextObject) {
|
protected ActionContext createContext(Component focusedComponent, Object contextObject) {
|
||||||
ActionContext context = new NavigatableActionContext(this, navigatable);
|
ActionContext context = new NavigatableActionContext(this, navigatable);
|
||||||
context.setContextObject(contextObject);
|
context.setContextObject(contextObject);
|
||||||
context.setSourceComponent(sourceComponent);
|
|
||||||
|
// the 'sourceComponent' will be the focused item if the focus owner is in our provider,
|
||||||
|
// otherwise it will be the main component
|
||||||
|
context.setSourceObject(focusedComponent);
|
||||||
|
|
||||||
|
// we make the source component be the table so that the 'activate filter' action works
|
||||||
|
// from anywhere in this provider
|
||||||
|
GhidraTable table = resultsPanel.getTable();
|
||||||
|
context.setSourceComponent(table);
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|