mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-10-22 21:21:02 +00:00
Merge remote-tracking branch 'origin/GP-4179-dragonmacher-data-window-filter-fixes--SQUASHED'
This commit is contained in:
commit
046a0e4e12
Binary file not shown.
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 24 KiB |
|
@ -44,7 +44,7 @@ class DataTableModel extends AddressBasedTableModel<DataRowObject> {
|
|||
private DataWindowPlugin plugin;
|
||||
private AddressMapImpl addressMap;
|
||||
private Listing listing;
|
||||
private AddressSet addresses;
|
||||
private AddressSet restrictedAddresses;
|
||||
|
||||
DataTableModel(DataWindowPlugin plugin) {
|
||||
super("Data", plugin.getTool(), null, null);
|
||||
|
@ -66,7 +66,7 @@ class DataTableModel extends AddressBasedTableModel<DataRowObject> {
|
|||
|
||||
void reload(Program newProgram) {
|
||||
this.setProgram(newProgram);
|
||||
addresses = plugin.getLimitedAddresses();
|
||||
restrictedAddresses = plugin.getLimitedAddresses();
|
||||
if (newProgram != null) {
|
||||
addressMap = new AddressMapImpl();
|
||||
listing = newProgram.getListing();
|
||||
|
@ -88,12 +88,14 @@ class DataTableModel extends AddressBasedTableModel<DataRowObject> {
|
|||
@Override
|
||||
protected void doLoad(Accumulator<DataRowObject> accumulator, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
LongIterator it = LongIterator.EMPTY;
|
||||
if (listing != null) {
|
||||
it = new DataKeyIterator();
|
||||
|
||||
if (listing == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
monitor.initialize(getKeyCount());
|
||||
int progress = 0;
|
||||
LongIterator it = new DataKeyIterator();
|
||||
while (it.hasNext()) {
|
||||
monitor.setProgress(progress++);
|
||||
monitor.checkCancelled();
|
||||
|
@ -104,51 +106,18 @@ class DataTableModel extends AddressBasedTableModel<DataRowObject> {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean filterAccepts(long key) {
|
||||
private boolean filterAccepts(long key) {
|
||||
if (listing == null || addressMap == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Data curData = listing.getDataAt(addressMap.decodeAddress(key));
|
||||
String displayName = curData.getDataType().getDisplayName();
|
||||
if (addresses != null) {
|
||||
return plugin.typeEnabled(displayName) && addresses.contains(curData.getMinAddress());
|
||||
}
|
||||
return plugin.typeEnabled(displayName);
|
||||
}
|
||||
|
||||
private class DataKeyIterator implements LongIterator {
|
||||
private DataIterator itr;
|
||||
|
||||
DataKeyIterator() {
|
||||
itr = listing.getDefinedData(getProgram().getMemory(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (itr == null || getProgram() == null)
|
||||
return false;
|
||||
return itr.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long next() {
|
||||
Data data = itr.next();
|
||||
if (addressMap != null) {
|
||||
return addressMap.getKey(data.getMinAddress());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long previous() {
|
||||
return -1;
|
||||
Data data = listing.getDataAt(addressMap.decodeAddress(key));
|
||||
String displayName = data.getDataType().getDisplayName();
|
||||
if (restrictedAddresses != null) {
|
||||
Address minAddress = data.getMinAddress();
|
||||
return plugin.isTypeEnabled(displayName) && restrictedAddresses.contains(minAddress);
|
||||
}
|
||||
return plugin.isTypeEnabled(displayName);
|
||||
}
|
||||
|
||||
void dataAdded(Address addr) {
|
||||
|
@ -191,6 +160,41 @@ class DataTableModel extends AddressBasedTableModel<DataRowObject> {
|
|||
// Inner Classes
|
||||
//==================================================================================================
|
||||
|
||||
private class DataKeyIterator implements LongIterator {
|
||||
private DataIterator it;
|
||||
|
||||
DataKeyIterator() {
|
||||
it = listing.getDefinedData(getProgram().getMemory(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (it == null || getProgram() == null) {
|
||||
return false;
|
||||
}
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long next() {
|
||||
Data data = it.next();
|
||||
if (addressMap != null) {
|
||||
return addressMap.getKey(data.getMinAddress());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long previous() {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private class DataValueTableColumn
|
||||
extends AbstractProgramBasedDynamicTableColumn<DataRowObject, String> {
|
||||
|
||||
|
@ -200,7 +204,7 @@ class DataTableModel extends AddressBasedTableModel<DataRowObject> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getValue(DataRowObject rowObject, Settings settings, Program program,
|
||||
public String getValue(DataRowObject rowObject, Settings settings, Program p,
|
||||
ServiceProvider provider) throws IllegalArgumentException {
|
||||
Data data = getDataForRowObject(rowObject);
|
||||
if (data == null) {
|
||||
|
@ -222,7 +226,7 @@ class DataTableModel extends AddressBasedTableModel<DataRowObject> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getValue(DataRowObject rowObject, Settings settings, Program program,
|
||||
public String getValue(DataRowObject rowObject, Settings settings, Program p,
|
||||
ServiceProvider provider) throws IllegalArgumentException {
|
||||
Data data = getDataForRowObject(rowObject);
|
||||
if (data == null) {
|
||||
|
@ -243,7 +247,7 @@ class DataTableModel extends AddressBasedTableModel<DataRowObject> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue(DataRowObject rowObject, Settings settings, Program program,
|
||||
public Integer getValue(DataRowObject rowObject, Settings settings, Program p,
|
||||
ServiceProvider provider) throws IllegalArgumentException {
|
||||
Data data = getDataForRowObject(rowObject);
|
||||
if (data == null) {
|
||||
|
|
|
@ -0,0 +1,307 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.datawindow;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.DockingUtils;
|
||||
import docking.widgets.button.GRadioButton;
|
||||
import docking.widgets.checkbox.GHtmlCheckBox;
|
||||
import docking.widgets.combobox.GhidraComboBox;
|
||||
import docking.widgets.filter.FilterListener;
|
||||
import docking.widgets.filter.FilterTextField;
|
||||
import docking.widgets.label.GLabel;
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import ghidra.app.plugin.core.datawindow.DataWindowPlugin.Coverage;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.task.SwingUpdateManager;
|
||||
|
||||
class DataWindowFilterDialog extends DialogComponentProvider {
|
||||
|
||||
private JPanel mainPanel;
|
||||
private List<JCheckBox> checkboxes = new ArrayList<>();
|
||||
private JPanel checkboxPanel;
|
||||
private JRadioButton enabledButton;
|
||||
private JRadioButton disabledButton;
|
||||
private GhidraComboBox<Coverage> coverageCombo;
|
||||
private JButton selectAllButton;
|
||||
private JButton selectNoneButton;
|
||||
private FilterTextField filterField;
|
||||
private List<String> filteredList = new ArrayList<>();
|
||||
|
||||
private SortedMap<String, Boolean> typeEnabledMap;
|
||||
private boolean isFilterEnabled = true;
|
||||
|
||||
private SwingUpdateManager updateManager =
|
||||
new SwingUpdateManager(250, 1000, () -> filterCheckboxes());
|
||||
|
||||
private KeyListener listener = new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER && e.getModifiersEx() == 0) {
|
||||
e.consume();
|
||||
okCallback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private ItemListener itemListener = e -> {
|
||||
JCheckBox checkBox = (JCheckBox) e.getItem();
|
||||
typeEnabledMap.put(checkBox.getName(), checkBox.isSelected());
|
||||
};
|
||||
|
||||
private FilterListener filterListener = new FilterActionFilterListener();
|
||||
private DataWindowPlugin plugin;
|
||||
|
||||
DataWindowFilterDialog(DataWindowPlugin plugin) {
|
||||
super("Set Data Type Filter");
|
||||
this.plugin = plugin;
|
||||
|
||||
typeEnabledMap = new TreeMap<>(plugin.getTypeMap());
|
||||
|
||||
addWorkPanel(create());
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
|
||||
setSelectionEnabled(plugin.getSelection() != null);
|
||||
|
||||
setHelpLocation(new HelpLocation(plugin.getName(), "Filter_Data_Types"));
|
||||
setPreferredSize(360, 730);
|
||||
}
|
||||
|
||||
private JComponent create() {
|
||||
|
||||
mainPanel = new JPanel();
|
||||
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
|
||||
|
||||
JPanel enablePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||
ButtonGroup group = new ButtonGroup();
|
||||
enabledButton = new GRadioButton("Enabled", true);
|
||||
enabledButton.addKeyListener(listener);
|
||||
enablePanel.add(enabledButton);
|
||||
group.add(enabledButton);
|
||||
disabledButton = new GRadioButton("Disabled", false);
|
||||
disabledButton.addKeyListener(listener);
|
||||
enablePanel.add(disabledButton);
|
||||
group.add(disabledButton);
|
||||
enablePanel.setBorder(BorderFactory.createTitledBorder("Filter State"));
|
||||
mainPanel.add(enablePanel);
|
||||
|
||||
enabledButton.addChangeListener(e -> {
|
||||
boolean enabled = enabledButton.isSelected();
|
||||
isFilterEnabled = enabled;
|
||||
for (JCheckBox cb : checkboxes) {
|
||||
cb.setEnabled(enabled);
|
||||
}
|
||||
|
||||
selectAllButton.setEnabled(enabled);
|
||||
selectNoneButton.setEnabled(enabled);
|
||||
coverageCombo.setEnabled(enabled);
|
||||
filterField.setEnabled(enabled);
|
||||
});
|
||||
|
||||
JPanel limitPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||
coverageCombo = new GhidraComboBox<>();
|
||||
coverageCombo.addKeyListener(listener);
|
||||
coverageCombo.setModel(new DefaultComboBoxModel<>(Coverage.values()));
|
||||
limitPanel.add(coverageCombo);
|
||||
limitPanel.setBorder(BorderFactory.createTitledBorder("Limit Data To"));
|
||||
mainPanel.add(limitPanel);
|
||||
|
||||
JPanel typesPanel = new JPanel(new BorderLayout());
|
||||
|
||||
JPanel typeButtonPanel = new JPanel(new GridLayout(1, 2, 5, 0));
|
||||
selectAllButton = new JButton("Check All");
|
||||
selectAllButton.setMnemonic('A');
|
||||
selectAllButton.addActionListener(evt -> {
|
||||
for (JCheckBox element : checkboxes) {
|
||||
element.setSelected(true);
|
||||
}
|
||||
});
|
||||
typeButtonPanel.add(selectAllButton);
|
||||
selectNoneButton = new JButton("Check None");
|
||||
selectNoneButton.setMnemonic('N');
|
||||
selectNoneButton.addActionListener(evt -> {
|
||||
for (JCheckBox element : checkboxes) {
|
||||
element.setSelected(false);
|
||||
}
|
||||
});
|
||||
typeButtonPanel.add(selectNoneButton);
|
||||
|
||||
checkboxPanel = new JPanel();
|
||||
checkboxPanel.setBackground(Colors.BACKGROUND);
|
||||
checkboxPanel.setLayout(new BoxLayout(checkboxPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
buildCheckBoxList();
|
||||
|
||||
JScrollPane scroller = new JScrollPane(checkboxPanel);
|
||||
typesPanel.add(scroller, BorderLayout.CENTER);
|
||||
typesPanel.setBorder(BorderFactory.createTitledBorder("Enabled Data Types"));
|
||||
typesPanel.add(typeButtonPanel, BorderLayout.SOUTH);
|
||||
mainPanel.add(typesPanel);
|
||||
|
||||
filterField = new FilterTextField(checkboxPanel);
|
||||
filterField.addFilterListener(filterListener);
|
||||
|
||||
JPanel filterPanel = new JPanel();
|
||||
filterPanel.setLayout(new BoxLayout(filterPanel, BoxLayout.LINE_AXIS));
|
||||
filterPanel.add(new GLabel("Filter:"));
|
||||
filterPanel.add(Box.createHorizontalStrut(10));
|
||||
filterPanel.add(filterField);
|
||||
filterPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
|
||||
|
||||
mainPanel.add(filterPanel);
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
private void buildCheckBoxList() {
|
||||
checkboxPanel.removeAll();
|
||||
checkboxes.clear();
|
||||
if (!filteredList.isEmpty()) {
|
||||
String filteredText = getFilterText();
|
||||
for (String type : filteredList) {
|
||||
Boolean enabled = typeEnabledMap.get(type);
|
||||
StringBuilder html = new StringBuilder(type);
|
||||
int firstIndex = StringUtils.indexOfIgnoreCase(type, filteredText, 0);
|
||||
int lastIndex = firstIndex + filteredText.length();
|
||||
html.insert(lastIndex, "</b>"); // do before first index (for no math on index)
|
||||
html.insert(firstIndex, "<b>");
|
||||
html.insert(0, "<html>");
|
||||
createCheckBox(html.toString(), type, enabled);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (StringUtils.isBlank(getFilterText())) { // no filter text to highlight
|
||||
for (String type : typeEnabledMap.keySet()) {
|
||||
Boolean enabled = typeEnabledMap.get(type);
|
||||
createCheckBox(type, type, enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
private String getFilterText() {
|
||||
if (filterField != null) {
|
||||
return filterField.getText().trim();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void repaint() {
|
||||
checkboxPanel.invalidate();
|
||||
mainPanel.validate();
|
||||
mainPanel.repaint();
|
||||
}
|
||||
|
||||
private void createCheckBox(String html, String typeName, Boolean enabled) {
|
||||
JCheckBox newCb = new GHtmlCheckBox(html, enabled.booleanValue());
|
||||
newCb.setName(typeName);
|
||||
newCb.addKeyListener(listener);
|
||||
newCb.addItemListener(itemListener);
|
||||
DockingUtils.setTransparent(newCb);
|
||||
checkboxes.add(newCb);
|
||||
checkboxPanel.add(newCb);
|
||||
}
|
||||
|
||||
private void filterCheckboxes() {
|
||||
List<String> checkboxNameList = new ArrayList<>();
|
||||
String filterText = getFilterText();
|
||||
if (!StringUtils.isBlank(filterText)) {
|
||||
Set<Entry<String, Boolean>> entrySet = typeEnabledMap.entrySet();
|
||||
for (Entry<String, Boolean> entry : entrySet) {
|
||||
String checkboxName = entry.getKey();
|
||||
if (StringUtils.containsIgnoreCase(checkboxName, filterText)) {
|
||||
checkboxNameList.add(checkboxName);
|
||||
}
|
||||
}
|
||||
}
|
||||
filteredList = checkboxNameList;
|
||||
buildCheckBoxList();
|
||||
}
|
||||
|
||||
boolean isFilterEnabled() {
|
||||
return isFilterEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void okCallback() {
|
||||
|
||||
if (!isFilterEnabled) {
|
||||
plugin.setFilterEnabled(false);
|
||||
}
|
||||
else {
|
||||
Coverage coverage = (Coverage) coverageCombo.getSelectedItem();
|
||||
plugin.setFilter(typeEnabledMap, coverage);
|
||||
}
|
||||
|
||||
typeEnabledMap.clear();
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelCallback() {
|
||||
typeEnabledMap.clear();
|
||||
close();
|
||||
}
|
||||
|
||||
void setSelectionEnabled(boolean enableSelection) {
|
||||
if (enableSelection) {
|
||||
coverageCombo.setModel(new DefaultComboBoxModel<>(Coverage.values()));
|
||||
}
|
||||
else {
|
||||
coverageCombo.setModel(
|
||||
new DefaultComboBoxModel<>(new Coverage[] { Coverage.PROGRAM, Coverage.VIEW }));
|
||||
}
|
||||
}
|
||||
|
||||
void setTypeEnabled(String type, boolean b) {
|
||||
|
||||
for (JCheckBox cb : checkboxes) {
|
||||
String name = cb.getName();
|
||||
if (name.equals(type)) {
|
||||
cb.setSelected(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setFilterEnabled(boolean b) {
|
||||
if (b) {
|
||||
enabledButton.setSelected(true);
|
||||
}
|
||||
else {
|
||||
disabledButton.setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
private class FilterActionFilterListener implements FilterListener {
|
||||
|
||||
@Override
|
||||
public void filterChanged(String text) {
|
||||
filterCheckboxes();
|
||||
updateManager.updateLater();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,8 +18,7 @@ package ghidra.app.plugin.core.datawindow;
|
|||
import static ghidra.framework.model.DomainObjectEvent.*;
|
||||
import static ghidra.program.util.ProgramEvent.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.*;
|
||||
|
||||
import docking.action.DockingAction;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
|
@ -31,7 +30,6 @@ import ghidra.app.services.GoToService;
|
|||
import ghidra.app.services.ProgramTreeService;
|
||||
import ghidra.framework.model.DomainObjectListener;
|
||||
import ghidra.framework.model.DomainObjectListenerBuilder;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.program.model.address.AddressRangeIterator;
|
||||
|
@ -70,11 +68,16 @@ public class DataWindowPlugin extends ProgramPlugin {
|
|||
private boolean resetTypesNeeded;
|
||||
private DomainObjectListener domainObjectListener = createDomainObjectListener();
|
||||
|
||||
private SortedMap<String, Boolean> typeEnablementByDisplayName =
|
||||
new TreeMap<>(new DataTypeNameComparator());
|
||||
|
||||
private boolean isFilterEnabled = false;
|
||||
private Coverage coverage = Coverage.PROGRAM;
|
||||
|
||||
public DataWindowPlugin(PluginTool tool) {
|
||||
super(tool);
|
||||
|
||||
resetUpdateMgr = new SwingUpdateManager(100, 60000, () -> doReset());
|
||||
|
||||
reloadUpdateMgr = new SwingUpdateManager(100, 60000, () -> doReload());
|
||||
}
|
||||
|
||||
|
@ -97,7 +100,7 @@ public class DataWindowPlugin extends ProgramPlugin {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
DomainObjectListener createDomainObjectListener() {
|
||||
private DomainObjectListener createDomainObjectListener() {
|
||||
// @formatter:off
|
||||
return new DomainObjectListenerBuilder(this)
|
||||
.any(RESTORED)
|
||||
|
@ -119,18 +122,37 @@ public class DataWindowPlugin extends ProgramPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
void reload() {
|
||||
void dataWindowShown() {
|
||||
if (resetTypesNeeded) {
|
||||
resetTypes();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setFilterEnabled(boolean enabled) {
|
||||
isFilterEnabled = enabled;
|
||||
reload();
|
||||
}
|
||||
|
||||
void setFilter(SortedMap<String, Boolean> typeEnabledMap, Coverage coverage) {
|
||||
this.isFilterEnabled = true;
|
||||
this.typeEnablementByDisplayName = new TreeMap<>(typeEnabledMap);
|
||||
this.coverage = coverage;
|
||||
reload();
|
||||
}
|
||||
|
||||
private void reload() {
|
||||
reloadUpdateMgr.update();
|
||||
}
|
||||
|
||||
void doReload() {
|
||||
private void doReload() {
|
||||
provider.reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processEvent(PluginEvent event) {
|
||||
if (event instanceof ViewChangedPluginEvent) {
|
||||
if (filterAction.getViewMode() && provider.isVisible()) {
|
||||
if (isFilterEnabled && provider.isVisible()) {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +165,7 @@ public class DataWindowPlugin extends ProgramPlugin {
|
|||
protected void programActivated(Program program) {
|
||||
program.addListener(domainObjectListener);
|
||||
provider.programOpened(program);
|
||||
filterAction.programOpened(program);
|
||||
filterAction.setEnabled(true);
|
||||
resetTypes();
|
||||
}
|
||||
|
||||
|
@ -151,7 +173,7 @@ public class DataWindowPlugin extends ProgramPlugin {
|
|||
protected void programDeactivated(Program program) {
|
||||
program.removeListener(domainObjectListener);
|
||||
provider.programClosed();
|
||||
filterAction.programClosed();
|
||||
filterAction.setEnabled(false);
|
||||
}
|
||||
|
||||
Program getProgram() {
|
||||
|
@ -162,14 +184,11 @@ public class DataWindowPlugin extends ProgramPlugin {
|
|||
return currentSelection;
|
||||
}
|
||||
|
||||
// Junit access
|
||||
// test access
|
||||
DataWindowProvider getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the action objects for this plugin.
|
||||
*/
|
||||
private void createActions() {
|
||||
|
||||
selectAction = new MakeProgramSelectionAction(this, provider.getTable());
|
||||
|
@ -201,55 +220,85 @@ public class DataWindowPlugin extends ProgramPlugin {
|
|||
|
||||
private void doReset() {
|
||||
resetTypesNeeded = false;
|
||||
ArrayList<String> selectedList = filterAction.getSelectedTypes();
|
||||
|
||||
filterAction.clearTypes();
|
||||
if (currentProgram != null) {
|
||||
DataTypeManager typeManager = currentProgram.getDataTypeManager();
|
||||
Iterator<DataType> itr = typeManager.getAllDataTypes();
|
||||
while (itr.hasNext()) {
|
||||
DataType type = itr.next();
|
||||
filterAction.addType(type.getDisplayName());
|
||||
}
|
||||
filterAction.selectTypes(selectedList);
|
||||
provider.reload();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean typeEnabled(String type) {
|
||||
return filterAction.typeEnabled(type);
|
||||
}
|
||||
|
||||
public AddressSet getLimitedAddresses() {
|
||||
if (filterAction.getSelectionMode()) {
|
||||
AddressSet ret = new AddressSet();
|
||||
AddressRangeIterator itr = currentSelection.getAddressRanges();
|
||||
while (itr.hasNext()) {
|
||||
ret.add(itr.next());
|
||||
}
|
||||
|
||||
return ret;
|
||||
typeEnablementByDisplayName.clear();
|
||||
if (currentProgram == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filterAction.getViewMode()) {
|
||||
DataTypeManager dtm = currentProgram.getDataTypeManager();
|
||||
Iterator<DataType> it = dtm.getAllDataTypes();
|
||||
while (it.hasNext()) {
|
||||
DataType type = it.next();
|
||||
typeEnablementByDisplayName.put(type.getDisplayName(), true);
|
||||
}
|
||||
|
||||
provider.reload();
|
||||
}
|
||||
|
||||
boolean isTypeEnabled(String type) {
|
||||
if (!isFilterEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Boolean enabled = typeEnablementByDisplayName.get(type);
|
||||
return enabled != null && enabled;
|
||||
}
|
||||
|
||||
SortedMap<String, Boolean> getTypeMap() {
|
||||
return typeEnablementByDisplayName;
|
||||
}
|
||||
|
||||
AddressSet getLimitedAddresses() {
|
||||
if (coverage == Coverage.SELECTION) {
|
||||
AddressSet addrs = new AddressSet();
|
||||
AddressRangeIterator it = currentSelection.getAddressRanges();
|
||||
while (it.hasNext()) {
|
||||
addrs.add(it.next());
|
||||
}
|
||||
|
||||
return addrs;
|
||||
}
|
||||
|
||||
if (coverage == Coverage.VIEW) {
|
||||
ProgramTreeService service = tool.getService(ProgramTreeService.class);
|
||||
if (service != null) {
|
||||
return service.getView();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
return null; // PROGRAM
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readConfigState(SaveState saveState) {
|
||||
filterAction.setSelected(true);
|
||||
private static class DataTypeNameComparator implements Comparator<String> {
|
||||
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
if (o1 != null) {
|
||||
if (!o1.equalsIgnoreCase(o2)) {
|
||||
return o1.compareToIgnoreCase(o2);
|
||||
}
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void dataWindowShown() {
|
||||
if (resetTypesNeeded) {
|
||||
resetTypes();
|
||||
public enum Coverage {
|
||||
//@formatter:off
|
||||
PROGRAM("Entire Program"),
|
||||
SELECTION("Current Selection"),
|
||||
VIEW("Current View");
|
||||
//@formatter:on
|
||||
|
||||
private String displayName;
|
||||
|
||||
Coverage(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return displayName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.awt.Dimension;
|
|||
import java.awt.event.MouseEvent;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
|
||||
import docking.ActionContext;
|
||||
import generic.theme.GIcon;
|
||||
|
@ -30,9 +30,6 @@ import ghidra.program.model.listing.Program;
|
|||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.table.*;
|
||||
|
||||
/**
|
||||
* Provider for the equates table.
|
||||
*/
|
||||
class DataWindowProvider extends ComponentProviderAdapter {
|
||||
|
||||
public static final Icon ICON = new GIcon("icon.plugin.datawindow.provider");
|
||||
|
@ -76,9 +73,6 @@ class DataWindowProvider extends ComponentProviderAdapter {
|
|||
return mainPanel;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see ghidra.framework.docking.HelpTopic#getHelpLocation()
|
||||
*/
|
||||
@Override
|
||||
public HelpLocation getHelpLocation() {
|
||||
return new HelpLocation(plugin.getName(), plugin.getName());
|
||||
|
@ -131,8 +125,6 @@ class DataWindowProvider extends ComponentProviderAdapter {
|
|||
|
||||
dataTable.installNavigation(tool);
|
||||
|
||||
JTableHeader dataHeader = dataTable.getTableHeader();
|
||||
dataHeader.setUpdateTableInRealTime(true);
|
||||
setDataTableRenderer();
|
||||
|
||||
filterPanel = new GhidraTableFilterPanel<>(dataTable, dataModel);
|
||||
|
@ -153,11 +145,10 @@ class DataWindowProvider extends ComponentProviderAdapter {
|
|||
}
|
||||
|
||||
private void setDataTableRenderer() {
|
||||
dataTable.getColumnModel()
|
||||
.getColumn(DataTableModel.LOCATION_COL)
|
||||
TableColumnModel columnModel = dataTable.getColumnModel();
|
||||
columnModel.getColumn(DataTableModel.LOCATION_COL)
|
||||
.setPreferredWidth(DataTableModel.ADDRESS_COL_WIDTH);
|
||||
dataTable.getColumnModel()
|
||||
.getColumn(DataTableModel.SIZE_COL)
|
||||
columnModel.getColumn(DataTableModel.SIZE_COL)
|
||||
.setPreferredWidth(DataTableModel.SIZE_COL_WIDTH);
|
||||
}
|
||||
|
||||
|
@ -173,7 +164,7 @@ class DataWindowProvider extends ComponentProviderAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
public GhidraTable getTable() {
|
||||
GhidraTable getTable() {
|
||||
return dataTable;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,429 +15,30 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.datawindow;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.*;
|
||||
import docking.ActionContext;
|
||||
import docking.action.ToggleDockingAction;
|
||||
import docking.action.ToolBarData;
|
||||
import docking.widgets.button.GRadioButton;
|
||||
import docking.widgets.checkbox.GHtmlCheckBox;
|
||||
import docking.widgets.combobox.GhidraComboBox;
|
||||
import docking.widgets.filter.FilterListener;
|
||||
import docking.widgets.filter.FilterTextField;
|
||||
import docking.widgets.label.GLabel;
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.task.SwingUpdateManager;
|
||||
import resources.Icons;
|
||||
|
||||
class FilterAction extends ToggleDockingAction {
|
||||
|
||||
private static final String ENTIRE_PROGRAM = "Entire Program";
|
||||
private static final String CURRENT_VIEW = "Current View";
|
||||
private static final String SELECTION = "Current Selection";
|
||||
|
||||
private DataWindowPlugin plugin;
|
||||
|
||||
private boolean filterEnabled = false;
|
||||
private boolean viewMode = false;
|
||||
private boolean selectionMode = false;
|
||||
|
||||
private static class SortMapComparatorASC implements Comparator<String> {
|
||||
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
if (o1 != null) {
|
||||
if (!o1.equalsIgnoreCase(o2)) {
|
||||
return o1.compareToIgnoreCase(o2);
|
||||
}
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private SortMapComparatorASC SortMapComparatorASCObj = new SortMapComparatorASC();
|
||||
private SortedMap<String, Boolean> typeEnabledMap = new TreeMap<>(SortMapComparatorASCObj);
|
||||
|
||||
FilterAction(DataWindowPlugin plugin) {
|
||||
super("Filter Data Types", plugin.getName());
|
||||
this.plugin = plugin;
|
||||
setDescription("Filters table so only specified types are displayed");
|
||||
setEnabled(true);
|
||||
setToolBarData(new ToolBarData(Icons.CONFIGURE_FILTER_ICON));
|
||||
setSelected(false);
|
||||
|
||||
setEnabled(false); // action is disabled until a program is open
|
||||
setSelected(false); // not selected; filter is off until the user turns on
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
FilterDialog dialog = new FilterDialog();
|
||||
dialog.setSelectionEnabled(plugin.getSelection() != null);
|
||||
dialog.updateButtonEnabledState();
|
||||
DataWindowFilterDialog dialog = new DataWindowFilterDialog(plugin);
|
||||
plugin.getTool().showDialog(dialog);
|
||||
}
|
||||
|
||||
synchronized void clearTypes() {
|
||||
typeEnabledMap.clear();
|
||||
}
|
||||
|
||||
synchronized void addType(String type) {
|
||||
Boolean bool = !filterEnabled;
|
||||
typeEnabledMap.put(type, bool);
|
||||
}
|
||||
|
||||
synchronized boolean typeEnabled(String type) {
|
||||
if (!filterEnabled) {
|
||||
return true;
|
||||
}
|
||||
Boolean bool = typeEnabledMap.get(type);
|
||||
return (bool != null && bool.booleanValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array list of strings that are the names of the
|
||||
* data types that are selected.
|
||||
*/
|
||||
synchronized ArrayList<String> getSelectedTypes() {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
Iterator<String> iter = typeEnabledMap.keySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
String type = iter.next();
|
||||
Boolean lEnabled = typeEnabledMap.get(type);
|
||||
if (lEnabled != null && typeEnabledMap.get(type).booleanValue()) {
|
||||
list.add(type);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
synchronized void selectTypes(ArrayList<String> list) {
|
||||
for (String element : list) {
|
||||
typeEnabledMap.put(element, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
boolean getViewMode() {
|
||||
return viewMode;
|
||||
}
|
||||
|
||||
boolean getSelectionMode() {
|
||||
return selectionMode;
|
||||
}
|
||||
|
||||
void setTypeEnabled(String type, boolean enabled) {
|
||||
typeEnabledMap.put(type, enabled);
|
||||
}
|
||||
|
||||
void setFilterEnabled(boolean filterEnabled) {
|
||||
this.filterEnabled = filterEnabled;
|
||||
}
|
||||
|
||||
void programClosed() {
|
||||
typeEnabledMap = new TreeMap<>();
|
||||
filterEnabled = false;
|
||||
viewMode = false;
|
||||
selectionMode = false;
|
||||
setEnabled(false);
|
||||
clearTypes();
|
||||
}
|
||||
|
||||
void programOpened(Program program) {
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
private class FilterDialog extends DialogComponentProvider {
|
||||
|
||||
private JPanel mainPanel;
|
||||
private List<JCheckBox> checkboxes = new ArrayList<>();
|
||||
private JPanel checkboxPanel;
|
||||
private JRadioButton enableButton;
|
||||
private JRadioButton disableButton;
|
||||
private GhidraComboBox<String> limitComboBox;
|
||||
private JButton selectAllButton;
|
||||
private JButton selectNoneButton;
|
||||
private FilterTextField filterField;
|
||||
private List<String> filteredList = new ArrayList<>();
|
||||
|
||||
private SwingUpdateManager updateManager =
|
||||
new SwingUpdateManager(250, 1000, () -> updateCheckBoxListFilter());
|
||||
|
||||
private KeyListener listener = new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER && e.getModifiers() == 0) {
|
||||
e.consume();
|
||||
okCallback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private ItemListener itemListener = e -> {
|
||||
JCheckBox typeCheckBox = (JCheckBox) e.getItem();
|
||||
setTypeEnabled(typeCheckBox.getName(), typeCheckBox.isSelected());
|
||||
};
|
||||
|
||||
private FilterListener filterListener = new FilterActionFilterListener();
|
||||
|
||||
FilterDialog() {
|
||||
super("Set Data Type Filter");
|
||||
|
||||
addWorkPanel(create());
|
||||
addOKButton();
|
||||
// addCancelButton();
|
||||
setHelpLocation(new HelpLocation(plugin.getName(), "Filter_Data_Types"));
|
||||
setPreferredSize(360, 730);
|
||||
}
|
||||
|
||||
void selectTypes(ArrayList<String> list) {
|
||||
for (String type : list) {
|
||||
selectCheckBox(type);
|
||||
}
|
||||
}
|
||||
|
||||
private void selectCheckBox(String typeName) {
|
||||
for (JCheckBox cb : checkboxes) {
|
||||
if (cb.getText().equals(typeName)) {
|
||||
cb.setSelected(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JComponent create() {
|
||||
|
||||
mainPanel = new JPanel();
|
||||
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
JPanel enablePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||
ButtonGroup group = new ButtonGroup();
|
||||
enableButton = new GRadioButton("Enabled", true);
|
||||
enableButton.addKeyListener(listener);
|
||||
enablePanel.add(enableButton);
|
||||
group.add(enableButton);
|
||||
disableButton = new GRadioButton("Disabled", false);
|
||||
disableButton.addKeyListener(listener);
|
||||
enablePanel.add(disableButton);
|
||||
group.add(disableButton);
|
||||
enablePanel.setBorder(BorderFactory.createTitledBorder("Filter Enable"));
|
||||
mainPanel.add(enablePanel);
|
||||
|
||||
enableButton.addChangeListener(e -> {
|
||||
boolean lenabled = enableButton.isSelected();
|
||||
Iterator<JCheckBox> itr = checkboxes.iterator();
|
||||
while (itr.hasNext()) {
|
||||
JCheckBox curCheckbox = itr.next();
|
||||
curCheckbox.setEnabled(lenabled);
|
||||
}
|
||||
|
||||
selectAllButton.setEnabled(isEnabled());
|
||||
selectNoneButton.setEnabled(isEnabled());
|
||||
limitComboBox.setEnabled(isEnabled());
|
||||
filterField.setEnabled(lenabled);
|
||||
});
|
||||
|
||||
JPanel limitPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||
limitComboBox = new GhidraComboBox<>();
|
||||
limitComboBox.addKeyListener(listener);
|
||||
limitComboBox.setModel(new DefaultComboBoxModel<>(
|
||||
new String[] { ENTIRE_PROGRAM, CURRENT_VIEW, SELECTION }));
|
||||
limitPanel.add(limitComboBox);
|
||||
limitPanel.setBorder(BorderFactory.createTitledBorder("Limit Data To"));
|
||||
mainPanel.add(limitPanel);
|
||||
|
||||
JPanel typesPanel = new JPanel(new BorderLayout());
|
||||
|
||||
JPanel typeButtonPanel = new JPanel(new GridLayout(1, 2, 5, 0));
|
||||
selectAllButton = new JButton("Select All");
|
||||
selectAllButton.setMnemonic('A');
|
||||
selectAllButton.addActionListener(evt -> {
|
||||
Iterator<JCheckBox> itr = checkboxes.iterator();
|
||||
while (itr.hasNext()) {
|
||||
itr.next().setSelected(true);
|
||||
}
|
||||
});
|
||||
typeButtonPanel.add(selectAllButton);
|
||||
selectNoneButton = new JButton("Select None");
|
||||
selectNoneButton.setMnemonic('N');
|
||||
selectNoneButton.addActionListener(evt -> {
|
||||
Iterator<JCheckBox> itr = checkboxes.iterator();
|
||||
while (itr.hasNext()) {
|
||||
itr.next().setSelected(false);
|
||||
}
|
||||
});
|
||||
typeButtonPanel.add(selectNoneButton);
|
||||
|
||||
checkboxPanel = new JPanel();
|
||||
checkboxPanel.setBackground(Colors.BACKGROUND);
|
||||
checkboxPanel.setLayout(new BoxLayout(checkboxPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
buildCheckBoxList();
|
||||
|
||||
JScrollPane scroller = new JScrollPane(checkboxPanel);
|
||||
scroller.setPreferredSize(new Dimension(checkboxPanel.getPreferredSize().width, 150));
|
||||
typesPanel.add(scroller, BorderLayout.CENTER);
|
||||
typesPanel.setBorder(BorderFactory.createTitledBorder("Enabled Data Types"));
|
||||
typesPanel.add(typeButtonPanel, BorderLayout.SOUTH);
|
||||
mainPanel.add(typesPanel);
|
||||
|
||||
JPanel filterBorderPanel = new JPanel(new GridLayout(1, 2, 5, 0));
|
||||
filterBorderPanel.setBorder(
|
||||
BorderFactory.createTitledBorder("Filter Enabled Data Types List Above"));
|
||||
|
||||
JPanel filterPanel = new JPanel(new BorderLayout());
|
||||
filterField = new FilterTextField(checkboxPanel);
|
||||
filterPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
|
||||
filterPanel.add(new GLabel("Filter:"), BorderLayout.WEST);
|
||||
|
||||
filterPanel.add(filterField, BorderLayout.CENTER);
|
||||
filterField.addFilterListener(filterListener);
|
||||
|
||||
filterBorderPanel.add(filterPanel, BorderLayout.CENTER);
|
||||
mainPanel.add(filterBorderPanel);
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
private void updateButtonEnabledState() {
|
||||
if (filteredTextExists()) {
|
||||
selectNoneButton.setEnabled(false);
|
||||
selectAllButton.setEnabled(false);
|
||||
}
|
||||
else {
|
||||
selectNoneButton.setEnabled(true);
|
||||
selectAllButton.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildCheckBoxList() {
|
||||
checkboxPanel.removeAll();
|
||||
checkboxes.clear();
|
||||
if (!filteredList.isEmpty()) {
|
||||
Iterator<String> itr = filteredList.iterator();
|
||||
String filteredText = getFilteredText();
|
||||
while (itr.hasNext()) {
|
||||
String curType = itr.next();
|
||||
Boolean lEnabled = typeEnabledMap.get(curType);
|
||||
StringBuffer buildMetaCurTypeBuff = new StringBuffer(curType);
|
||||
int firstIndex = StringUtils.indexOfIgnoreCase(curType, filteredText, 0);
|
||||
int lastIndex = firstIndex + filteredText.length();
|
||||
buildMetaCurTypeBuff.insert(lastIndex, "</b>");//THIS MUST ALWAYS COME BEFORE FIRST INDEX (FOR NO MATH on INDEX)
|
||||
buildMetaCurTypeBuff.insert(firstIndex, "<b>");
|
||||
buildMetaCurTypeBuff.insert(0, "<html>");
|
||||
createCheckBox(buildMetaCurTypeBuff.toString(), curType, lEnabled);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!filteredTextExists()) {//Typed Incorrectly, so show nothing...
|
||||
Iterator<String> itr = typeEnabledMap.keySet().iterator();
|
||||
while (itr.hasNext()) {
|
||||
String curType = itr.next();
|
||||
Boolean lEnabled = typeEnabledMap.get(curType);
|
||||
createCheckBox(curType, curType, lEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
private String getFilteredText() {
|
||||
if (filterField != null) {
|
||||
return filterField.getText().trim();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean filteredTextExists() {
|
||||
return (((getFilteredText() != null) && (getFilteredText().length() > 0)) ? true
|
||||
: false);
|
||||
}
|
||||
|
||||
private void repaint() {
|
||||
checkboxPanel.invalidate();
|
||||
mainPanel.validate();
|
||||
mainPanel.repaint();
|
||||
}
|
||||
|
||||
private void createCheckBox(String curTypeHtml, String curType, Boolean lEnabled) {
|
||||
JCheckBox newCheckbox = new GHtmlCheckBox(curTypeHtml, lEnabled.booleanValue());
|
||||
newCheckbox.setName(curType);
|
||||
newCheckbox.addKeyListener(listener);
|
||||
newCheckbox.addItemListener(itemListener);
|
||||
DockingUtils.setTransparent(newCheckbox);
|
||||
checkboxes.add(newCheckbox);
|
||||
checkboxPanel.add(newCheckbox);
|
||||
}
|
||||
|
||||
private void updateCheckBoxListFilter() {
|
||||
ArrayList<String> checkboxNameList = new ArrayList<>();
|
||||
if (filteredTextExists()) {
|
||||
String filteredText = getFilteredText();
|
||||
Set<Entry<String, Boolean>> entrySet = typeEnabledMap.entrySet();
|
||||
Iterator<Entry<String, Boolean>> iteratorIndex = entrySet.iterator();
|
||||
while (iteratorIndex.hasNext()) {
|
||||
Entry<String, Boolean> entry = iteratorIndex.next();
|
||||
String checkboxName = entry.getKey();
|
||||
if (StringUtils.containsIgnoreCase(checkboxName, filteredText)) {
|
||||
checkboxNameList.add(checkboxName);
|
||||
}
|
||||
}
|
||||
}
|
||||
filteredList = checkboxNameList;
|
||||
buildCheckBoxList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void okCallback() {
|
||||
filterEnabled = enableButton.isSelected();
|
||||
|
||||
viewMode = limitComboBox.getSelectedItem() == CURRENT_VIEW;
|
||||
selectionMode = limitComboBox.getSelectedItem() == SELECTION;
|
||||
|
||||
close();
|
||||
setSelected(filterEnabled);
|
||||
plugin.reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelCallback() {
|
||||
okCallback();
|
||||
}
|
||||
|
||||
private void clearTypes() {
|
||||
checkboxes.clear();
|
||||
checkboxPanel.removeAll();
|
||||
mainPanel.validate();
|
||||
}
|
||||
|
||||
public void setSelectionEnabled(boolean enableSelection) {
|
||||
int modelSize = limitComboBox.getModel().getSize();
|
||||
if (enableSelection) {
|
||||
if (modelSize != 3) {
|
||||
limitComboBox.setModel(new DefaultComboBoxModel<>(
|
||||
new String[] { ENTIRE_PROGRAM, CURRENT_VIEW, SELECTION }));
|
||||
}
|
||||
}
|
||||
else if (modelSize != 2) {
|
||||
limitComboBox.setModel(
|
||||
new DefaultComboBoxModel<>(new String[] { ENTIRE_PROGRAM, CURRENT_VIEW }));
|
||||
}
|
||||
}
|
||||
|
||||
private class FilterActionFilterListener implements FilterListener {
|
||||
|
||||
@Override
|
||||
public void filterChanged(String text) {
|
||||
updateButtonEnabledState();
|
||||
updateManager.updateLater();
|
||||
}
|
||||
}
|
||||
setSelected(dialog.isFilterEnabled());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,6 @@ public class DataWindowPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
}
|
||||
|
||||
private void loadProgram(String programName) throws Exception {
|
||||
|
||||
ClassicSampleX86ProgramBuilder builder = new ClassicSampleX86ProgramBuilder();
|
||||
program = builder.getProgram();
|
||||
}
|
||||
|
@ -89,13 +88,14 @@ public class DataWindowPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testNavigation() throws Exception {
|
||||
int numRows = dataTable.getRowCount();
|
||||
for (int i = 0; i < numRows; i++) {
|
||||
int rows = 10; // no need to test them all; a sample will do
|
||||
for (int i = 0; i < rows; i++) {
|
||||
clickTableCell(dataTable, i, DataTableModel.LOCATION_COL, 2);
|
||||
waitForSwing();
|
||||
Address addr = browser.getCurrentAddress();
|
||||
Object tableAddr =
|
||||
addr.getAddress(dataTable.getValueAt(i, DataTableModel.LOCATION_COL).toString());
|
||||
int row = i;
|
||||
Object value = runSwing(() -> dataTable.getValueAt(row, DataTableModel.LOCATION_COL));
|
||||
Object tableAddr = addr.getAddress(value.toString());
|
||||
assertEquals(addr, tableAddr);
|
||||
}
|
||||
}
|
||||
|
@ -105,45 +105,36 @@ public class DataWindowPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
int numData = dataTable.getRowCount();
|
||||
|
||||
int id = program.startTransaction(testName.getMethodName());
|
||||
try {
|
||||
tx(program, () -> {
|
||||
program.getListing().clearAll(false, TaskMonitor.DUMMY);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(id, true);
|
||||
}
|
||||
waitForNotBusy(dataTable);
|
||||
});
|
||||
|
||||
waitForNotBusy(dataTable);
|
||||
assertEquals(0, dataTable.getRowCount());
|
||||
|
||||
undo(program);
|
||||
waitForNotBusy(dataTable);
|
||||
|
||||
assertEquals(numData, dataTable.getRowCount());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilter() throws Exception {
|
||||
int totalRows = dataTable.getRowCount();
|
||||
String type = dataTable.getValueAt(0, DataTableModel.TYPE_COL).toString();
|
||||
filterAction.setTypeEnabled(type, false);
|
||||
filterAction.setFilterEnabled(true);
|
||||
plugin.reload();
|
||||
waitForNotBusy(dataTable);
|
||||
|
||||
filterType(type);
|
||||
|
||||
int filteredRows = dataTable.getRowCount();
|
||||
for (int i = 0; i < filteredRows; i++) {
|
||||
assertEquals(dataTable.getValueAt(i, DataTableModel.TYPE_COL).toString().equals(type),
|
||||
false);
|
||||
}
|
||||
|
||||
assertEquals(totalRows > filteredRows, true);
|
||||
|
||||
filterAction.setFilterEnabled(false);
|
||||
plugin.reload();
|
||||
waitForNotBusy(dataTable);
|
||||
for (int i = 0; i < filteredRows; i++) {
|
||||
int row = i;
|
||||
Object value = runSwing(() -> dataTable.getValueAt(row, DataTableModel.TYPE_COL));
|
||||
assertNotEquals(value.toString(), type);
|
||||
}
|
||||
|
||||
disableFilter();
|
||||
assertEquals(dataTable.getRowCount(), totalRows);
|
||||
}
|
||||
|
||||
|
@ -156,4 +147,31 @@ public class DataWindowPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(dataTable.getRowCount(), 0);
|
||||
loadProgram("notepad");
|
||||
}
|
||||
|
||||
private void disableFilter() {
|
||||
performAction(filterAction, false);
|
||||
DataWindowFilterDialog filterDialog = waitForDialogComponent(DataWindowFilterDialog.class);
|
||||
|
||||
runSwing(() -> {
|
||||
filterDialog.setFilterEnabled(false);
|
||||
});
|
||||
|
||||
pressButtonByText(filterDialog, "OK");
|
||||
waitForNotBusy(dataTable);
|
||||
}
|
||||
|
||||
private void filterType(String type) {
|
||||
|
||||
performAction(filterAction, false);
|
||||
DataWindowFilterDialog filterDialog = waitForDialogComponent(DataWindowFilterDialog.class);
|
||||
|
||||
runSwing(() -> {
|
||||
filterDialog.setTypeEnabled(type, false);
|
||||
filterDialog.setFilterEnabled(true);
|
||||
});
|
||||
|
||||
pressButtonByText(filterDialog, "OK");
|
||||
waitForNotBusy(dataTable);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,10 +27,10 @@ public class DataWindowPluginScreenShots extends GhidraScreenShotGenerator {
|
|||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataWindow() {
|
||||
@Test
|
||||
public void testDataWindow() {
|
||||
|
||||
performAction("Defined Data", "DockingWindows", true);
|
||||
performAction("Data Window", "DataWindowPlugin", true);
|
||||
|
||||
ComponentProvider provider = getProvider("Data Window");
|
||||
|
||||
|
@ -42,9 +42,9 @@ public class DataWindowPluginScreenShots extends GhidraScreenShotGenerator {
|
|||
captureIsolatedProviderWindow(provider.getClass(), 500, 300);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataWindowFilter() {
|
||||
performAction("Defined Data", "DockingWindows", true);
|
||||
@Test
|
||||
public void testDataWindowFilter() {
|
||||
performAction("Data Window", "DataWindowPlugin", true);
|
||||
|
||||
performAction("Filter Data Types", "DataWindowPlugin", false);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user