mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-01 01:32:54 +08:00
GP-5327 - Fixed sizing issues with the data type and category editors
This commit is contained in:
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 17 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 22 KiB |
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -15,8 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.cmd.data;
|
package ghidra.app.cmd.data;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
@@ -73,9 +72,6 @@ public class CreateStructureCmd extends AbstractCreateStructureCmd {
|
|||||||
structureDataLength = structure.getLength();
|
structureDataLength = structure.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @see AbstractCreateStructureCmd#createStructure(Address, Program)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
Structure createStructure(Address address, Program program) {
|
Structure createStructure(Address address, Program program) {
|
||||||
|
|
||||||
@@ -87,9 +83,6 @@ public class CreateStructureCmd extends AbstractCreateStructureCmd {
|
|||||||
return structure;
|
return structure;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @see AbstractCreateStructureCmd#initializeStructureData(Program, Structure)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
DataType initializeStructureData(Program program, Structure localStructure) {
|
DataType initializeStructureData(Program program, Structure localStructure) {
|
||||||
|
|
||||||
@@ -101,11 +94,11 @@ public class CreateStructureCmd extends AbstractCreateStructureCmd {
|
|||||||
}
|
}
|
||||||
catch (AddressOverflowException e1) {
|
catch (AddressOverflowException e1) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Can't create structure because length exceeds address " + "space" +
|
"Can't create structure because length exceeds address space" +
|
||||||
structureDataLength);
|
structureDataLength);
|
||||||
}
|
}
|
||||||
ReferenceManager refMgr = program.getReferenceManager();
|
ReferenceManager refMgr = program.getReferenceManager();
|
||||||
Reference[] refs = findExistingRefs(refMgr, program.getAddressFactory(),
|
List<Reference> refs = findExistingRefs(refMgr, program.getAddressFactory(),
|
||||||
getStructureAddress(), endAddress);
|
getStructureAddress(), endAddress);
|
||||||
listing.clearCodeUnits(getStructureAddress(), endAddress, false);
|
listing.clearCodeUnits(getStructureAddress(), endAddress, false);
|
||||||
|
|
||||||
@@ -123,20 +116,20 @@ public class CreateStructureCmd extends AbstractCreateStructureCmd {
|
|||||||
return data.getDataType();
|
return data.getDataType();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Reference[] findExistingRefs(ReferenceManager refMgr, AddressFactory af, Address start,
|
private List<Reference> findExistingRefs(ReferenceManager refMgr, AddressFactory af,
|
||||||
|
Address start,
|
||||||
Address end) {
|
Address end) {
|
||||||
ArrayList<Reference> list = new ArrayList<Reference>();
|
List<Reference> list = new ArrayList<Reference>();
|
||||||
AddressIterator it = refMgr.getReferenceSourceIterator(new AddressSet(start, end), true);
|
AddressIterator it = refMgr.getReferenceSourceIterator(new AddressSet(start, end), true);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Address addr = it.next();
|
Address addr = it.next();
|
||||||
Reference[] refs = refMgr.getReferencesFrom(addr);
|
Reference[] refs = refMgr.getReferencesFrom(addr);
|
||||||
Collections.addAll(list, refs);
|
Collections.addAll(list, refs);
|
||||||
}
|
}
|
||||||
Reference[] refList = new Reference[list.size()];
|
return list;
|
||||||
return list.toArray(refList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addRefs(Program p, ReferenceManager refMgr, Reference[] refs) {
|
private void addRefs(Program p, ReferenceManager refMgr, List<Reference> refs) {
|
||||||
for (Reference ref : refs) {
|
for (Reference ref : refs) {
|
||||||
refMgr.addReference(ref);
|
refMgr.addReference(ref);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-19
@@ -1158,8 +1158,6 @@ public abstract class CompositeEditorPanel<T extends Composite, M extends Compos
|
|||||||
private int maxLength;
|
private int maxLength;
|
||||||
private boolean bitfieldAllowed;
|
private boolean bitfieldAllowed;
|
||||||
|
|
||||||
private JPanel editorPanel;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getTableCellEditorComponent(JTable table1, Object value,
|
public Component getTableCellEditorComponent(JTable table1, Object value,
|
||||||
boolean isSelected, int row, int column) {
|
boolean isSelected, int row, int column) {
|
||||||
@@ -1178,7 +1176,7 @@ public abstract class CompositeEditorPanel<T extends Composite, M extends Compos
|
|||||||
|
|
||||||
editor.setCellEditorValue(dt);
|
editor.setCellEditorValue(dt);
|
||||||
|
|
||||||
return editorPanel;
|
return editor.getEditorComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
@@ -1193,7 +1191,7 @@ public abstract class CompositeEditorPanel<T extends Composite, M extends Compos
|
|||||||
editor.setConsumeEnterKeyPress(false); // we want the table to handle Enter key presses
|
editor.setConsumeEnterKeyPress(false); // we want the table to handle Enter key presses
|
||||||
|
|
||||||
textField = editor.getDropDownTextField();
|
textField = editor.getDropDownTextField();
|
||||||
textField.setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
|
|
||||||
editor.addCellEditorListener(new CellEditorListener() {
|
editor.addCellEditorListener(new CellEditorListener() {
|
||||||
@Override
|
@Override
|
||||||
public void editingCanceled(ChangeEvent e) {
|
public void editingCanceled(ChangeEvent e) {
|
||||||
@@ -1206,17 +1204,8 @@ public abstract class CompositeEditorPanel<T extends Composite, M extends Compos
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// force a small button for the table's cell editor
|
JButton browseButton = editor.getBrowseButton();
|
||||||
JButton dataTypeChooserButton = new JButton("...") {
|
browseButton.addActionListener(e -> Swing.runLater(() -> stopEdit(tool)));
|
||||||
@Override
|
|
||||||
public Dimension getPreferredSize() {
|
|
||||||
Dimension preferredSize = super.getPreferredSize();
|
|
||||||
preferredSize.width = 15;
|
|
||||||
return preferredSize;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
dataTypeChooserButton.addActionListener(e -> Swing.runLater(() -> stopEdit(tool)));
|
|
||||||
|
|
||||||
textField.addFocusListener(new FocusAdapter() {
|
textField.addFocusListener(new FocusAdapter() {
|
||||||
@Override
|
@Override
|
||||||
@@ -1226,10 +1215,6 @@ public abstract class CompositeEditorPanel<T extends Composite, M extends Compos
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
editorPanel = new JPanel();
|
|
||||||
editorPanel.setLayout(new BorderLayout());
|
|
||||||
editorPanel.add(textField, BorderLayout.CENTER);
|
|
||||||
editorPanel.add(dataTypeChooserButton, BorderLayout.EAST);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopEdit(PluginTool tool) {
|
private void stopEdit(PluginTool tool) {
|
||||||
|
|||||||
+2
-2
@@ -99,7 +99,7 @@ class CreateStructureAction extends ListingContextAction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateStructureDialog dialog = new CreateStructureDialog(plugin.getTool());
|
CreateStructureDialog dialog = new CreateStructureDialog(plugin.getTool(), program);
|
||||||
Structure userChoice = dialog.showCreateStructureDialog(program, tempStructure);
|
Structure userChoice = dialog.showCreateStructureDialog(program, tempStructure);
|
||||||
|
|
||||||
if (userChoice != null) {
|
if (userChoice != null) {
|
||||||
@@ -148,7 +148,7 @@ class CreateStructureAction extends ListingContextAction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateStructureDialog dialog = new CreateStructureDialog(plugin.getTool());
|
CreateStructureDialog dialog = new CreateStructureDialog(plugin.getTool(), program);
|
||||||
Structure userChoice =
|
Structure userChoice =
|
||||||
dialog.showCreateStructureDialog(program, tempStructure);
|
dialog.showCreateStructureDialog(program, tempStructure);
|
||||||
|
|
||||||
|
|||||||
+111
-124
@@ -54,7 +54,7 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
private static final String EXISITING_STRUCTURE_STATUS_PREFIX = "Using existing structure: ";
|
private static final String EXISITING_STRUCTURE_STATUS_PREFIX = "Using existing structure: ";
|
||||||
|
|
||||||
private static final String STRUCTURE_COLUMN_NAME = "Structure";
|
private static final String STRUCTURE_COLUMN_NAME = "Structure";
|
||||||
private static final String PATH_COLUMN_NAME = "Path";
|
private static final String CATEGORY_COLUMN_NAME = "Category";
|
||||||
|
|
||||||
private JTextField nameTextField;
|
private JTextField nameTextField;
|
||||||
private CategoryPathSelectionEditor categoryPathEditor;
|
private CategoryPathSelectionEditor categoryPathEditor;
|
||||||
@@ -74,11 +74,13 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
* Creates a new dialog with the given parent.
|
* Creates a new dialog with the given parent.
|
||||||
*
|
*
|
||||||
* @param tool The current tool that this dialog needs to access services.
|
* @param tool The current tool that this dialog needs to access services.
|
||||||
|
* @param program the current program
|
||||||
*/
|
*/
|
||||||
public CreateStructureDialog(PluginTool tool) {
|
public CreateStructureDialog(PluginTool tool, Program program) {
|
||||||
super("Create Structure", true, true, true, false);
|
super("Create Structure", true, true, true, false);
|
||||||
|
|
||||||
pluginTool = tool;
|
this.pluginTool = tool;
|
||||||
|
this.currentProgram = program;
|
||||||
setHelpLocation(new HelpLocation("DataPlugin", "Create_Structure_Dialog"));
|
setHelpLocation(new HelpLocation("DataPlugin", "Create_Structure_Dialog"));
|
||||||
|
|
||||||
addWorkPanel(buildMainPanel());
|
addWorkPanel(buildMainPanel());
|
||||||
@@ -159,20 +161,15 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
|
|
||||||
JLabel nameLabel = new JLabel("Name: ");
|
JLabel nameLabel = new JLabel("Name: ");
|
||||||
|
|
||||||
nameTextField = new JTextField() {
|
nameTextField = new JTextField();
|
||||||
// make sure our height doesn't stretch
|
nameTextField.setName("StructureName");
|
||||||
@Override
|
nameTextField.getAccessibleContext().setAccessibleName("Name");
|
||||||
public Dimension getMaximumSize() {
|
|
||||||
Dimension d = super.getMaximumSize();
|
|
||||||
d.height = getPreferredSize().height;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Allow user to click on the text field to re-activate "create new" panel without forcing
|
// Allow user to click on the text field to re-activate "create new" panel without forcing
|
||||||
// a click on the radio button
|
// a click on the radio button
|
||||||
nameTextField.addMouseListener(new MouseAdapter() {
|
nameTextField.addFocusListener(new FocusAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void mouseClicked(MouseEvent event) {
|
public void focusGained(FocusEvent e) {
|
||||||
createNewStructButton.setSelected(true);
|
createNewStructButton.setSelected(true);
|
||||||
updateEnablement();
|
updateEnablement();
|
||||||
}
|
}
|
||||||
@@ -224,45 +221,13 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
|
|
||||||
private void buildCategoryPathEditor() {
|
private void buildCategoryPathEditor() {
|
||||||
categoryPathEditor = new CategoryPathSelectionEditor(pluginTool);
|
categoryPathEditor = new CategoryPathSelectionEditor(pluginTool);
|
||||||
categoryPathEditor.getEditorComponent()
|
JComponent editorComponent = categoryPathEditor.getEditorComponent();
|
||||||
.getAccessibleContext()
|
editorComponent.getAccessibleContext().setAccessibleName("Category");
|
||||||
.setAccessibleName("Category");
|
|
||||||
// make sure the "Category: " text field size matches the "Name: " text field size
|
|
||||||
categoryPathEditor.getEditorComponent().setMaximumSize(nameTextField.getMaximumSize());
|
|
||||||
categoryPathEditor.addDocumentListener(new DocumentListener() {
|
|
||||||
@Override
|
|
||||||
public void changedUpdate(DocumentEvent event) {
|
|
||||||
updateStatus(event.getDocument());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
categoryPathEditor.setCellEditorValue(CategoryPath.ROOT);
|
||||||
public void insertUpdate(DocumentEvent event) {
|
|
||||||
updateStatus(event.getDocument());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// Allow user to click on the text field to re-activate "create new" panel without forcing
|
||||||
public void removeUpdate(DocumentEvent event) {
|
// a click on the radio button
|
||||||
updateStatus(event.getDocument());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateStatus(Document document) {
|
|
||||||
try {
|
|
||||||
String text = document.getText(0, document.getLength());
|
|
||||||
if (StringUtils.isBlank(text)) {
|
|
||||||
updateStatusText(true, null);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
updateStatusText(true, "Using category: " + text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (BadLocationException ble) {
|
|
||||||
// nothing we can do here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Allow the user to re-activate the "new struct" panel without forcing toggle click. Use
|
|
||||||
// FocusListener because @CategoryPathSelectionEditor.java already contains a mouse listener
|
|
||||||
// and would override this one.
|
|
||||||
categoryPathEditor.addFocusListener(new FocusAdapter() {
|
categoryPathEditor.addFocusListener(new FocusAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void focusGained(FocusEvent e) {
|
public void focusGained(FocusEvent e) {
|
||||||
@@ -285,6 +250,16 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
updateEnablement();
|
updateEnablement();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ListSelectionModel selectionModel = table.getSelectionModel();
|
||||||
|
selectionModel.addListSelectionListener(e -> {
|
||||||
|
if (e.getValueIsAdjusting()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useExistingStructButton.isSelected()) {
|
||||||
|
setOkEnabled(table.getSelectedRowCount() > 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
filterPanel = new GhidraTableFilterPanel<>(table, structureTableModel) {
|
filterPanel = new GhidraTableFilterPanel<>(table, structureTableModel) {
|
||||||
// make sure our height doesn't stretch
|
// make sure our height doesn't stretch
|
||||||
@@ -527,6 +502,18 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JTextField getNameField() {
|
||||||
|
return nameTextField;
|
||||||
|
}
|
||||||
|
|
||||||
|
JTable getTable() {
|
||||||
|
return matchingStructuresTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
CategoryPathSelectionEditor getCategoryEditor() {
|
||||||
|
return categoryPathEditor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a dialog that allows the user to create a new structure.
|
* Shows a dialog that allows the user to create a new structure.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -577,34 +564,58 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
@Override
|
@Override
|
||||||
protected void okCallback() {
|
protected void okCallback() {
|
||||||
|
|
||||||
if (nameTextField.isEnabled()) {
|
if (useExistingStructButton.isSelected()) {
|
||||||
// just use the name set by the user
|
|
||||||
String nameText = nameTextField.getText();
|
|
||||||
|
|
||||||
if (!setCategoryPath()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
currentStructure.setName(nameText);
|
|
||||||
}
|
|
||||||
catch (InvalidNameException ine) {
|
|
||||||
setStatusText(ine.getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (DuplicateNameException dne) {
|
|
||||||
setStatusText(dne.getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// get the selected object in the table
|
// get the selected object in the table
|
||||||
currentStructure = getSelectedStructure();
|
currentStructure = getSelectedStructure();
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// just use the name set by the user
|
||||||
|
String nameText = nameTextField.getText();
|
||||||
|
try {
|
||||||
|
currentStructure.setName(nameText);
|
||||||
|
}
|
||||||
|
catch (InvalidNameException ine) {
|
||||||
|
setStatusText(ine.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException dne) {
|
||||||
|
setStatusText(dne.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setCategoryPath()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateName()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean validateName() {
|
||||||
|
// Use the current name and category path to see if there is already an existing name. This
|
||||||
|
// allows us to avoid a conflict.
|
||||||
|
ProgramBasedDataTypeManager dtm = currentProgram.getDataTypeManager();
|
||||||
|
CategoryPath path = currentStructure.getCategoryPath();
|
||||||
|
Category category = dtm.getCategory(path);
|
||||||
|
if (category == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String nameText = currentStructure.getName();
|
||||||
|
DataType existingDt = category.getDataType(nameText);
|
||||||
|
if (existingDt != null) {
|
||||||
|
setStatusText("Name already exists: " + nameText, MessageType.ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private Structure getSelectedStructure() {
|
private Structure getSelectedStructure() {
|
||||||
int row = matchingStructuresTable.getSelectedRow();
|
int row = matchingStructuresTable.getSelectedRow();
|
||||||
if (row < 0) {
|
if (row < 0) {
|
||||||
@@ -616,66 +627,43 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean setCategoryPath() {
|
private boolean setCategoryPath() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
doSetCategoryPath();
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException e) {
|
||||||
|
setStatusText(e.getMessage(), MessageType.ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doSetCategoryPath() throws DuplicateNameException {
|
||||||
CategoryPath path = categoryPathEditor.getCellEditorValue();
|
CategoryPath path = categoryPathEditor.getCellEditorValue();
|
||||||
// First see if a category from the list was chosen and make sure the user didn't modify it.
|
// First see if a category from the list was chosen and make sure the user didn't modify it.
|
||||||
// If they did, path needs to be parsed separately.
|
// If they did, path needs to be parsed separately.
|
||||||
if (path != null && path.getPath().equals(categoryPathEditor.getCellEditorValueAsText())) {
|
String editorValue = categoryPathEditor.getCellEditorValueAsText();
|
||||||
try {
|
if (path != null && path.getPath().equals(editorValue)) {
|
||||||
currentStructure.setCategoryPath(path);
|
currentStructure.setCategoryPath(path);
|
||||||
}
|
return;
|
||||||
catch (DuplicateNameException dne) {
|
|
||||||
setStatusText(dne.getMessage(), MessageType.ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String categoryText = categoryPathEditor.getCellEditorValueAsText();
|
|
||||||
// Selecting/entering a category is optional; root is default
|
// Selecting/entering a category is optional; root is default
|
||||||
if (!categoryText.isBlank()) {
|
if (!editorValue.isBlank()) {
|
||||||
try {
|
CategoryPath parsedPath = parseEnteredCategoryPath(editorValue);
|
||||||
CategoryPath parsedPath = parseEnteredCategoryPath(categoryText);
|
currentStructure.setCategoryPath(parsedPath);
|
||||||
currentStructure.setCategoryPath(parsedPath);
|
return;
|
||||||
}
|
|
||||||
catch (DuplicateNameException dne) {
|
|
||||||
setStatusText(dne.getMessage(), MessageType.ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
try {
|
currentStructure.setCategoryPath(CategoryPath.ROOT);
|
||||||
currentStructure.setCategoryPath(CategoryPath.ROOT);
|
|
||||||
}
|
|
||||||
catch (DuplicateNameException dne) {
|
|
||||||
setStatusText(dne.getMessage(), MessageType.ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CategoryPath parseEnteredCategoryPath(String categoryText) {
|
private CategoryPath parseEnteredCategoryPath(String categoryText) {
|
||||||
// entering a leading slash is optional, path is still generated accordingly
|
// entering a leading slash is optional, path is still generated accordingly
|
||||||
if (categoryText.startsWith(CategoryPath.DELIMITER_STRING)) {
|
if (categoryText.startsWith(CategoryPath.DELIMITER_STRING)) {
|
||||||
return generateCategoryPath(categoryText.substring(1));
|
return new CategoryPath(categoryText);
|
||||||
}
|
}
|
||||||
return generateCategoryPath(categoryText);
|
return new CategoryPath(CategoryPath.DELIMITER_STRING + categoryText);
|
||||||
}
|
|
||||||
|
|
||||||
private CategoryPath generateCategoryPath(String categoryText) {
|
|
||||||
if (!categoryText.contains(CategoryPath.DELIMITER_STRING)) {
|
|
||||||
return new CategoryPath(CategoryPath.ROOT, categoryText);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Additional slashes need parsed as branch(es) and final leaf
|
|
||||||
List<String> parts = split(categoryText);
|
|
||||||
return new CategoryPath(CategoryPath.ROOT, parts);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> split(String categoryText) {
|
|
||||||
List<String> parts = new ArrayList<String>(
|
|
||||||
Arrays.asList(categoryText.split(CategoryPath.DELIMITER_STRING)));
|
|
||||||
return parts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// a table model that is used to allow for the easy updating of the table with new List data
|
// a table model that is used to allow for the easy updating of the table with new List data
|
||||||
@@ -707,7 +695,7 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
case 0:
|
case 0:
|
||||||
return STRUCTURE_COLUMN_NAME;
|
return STRUCTURE_COLUMN_NAME;
|
||||||
case 1:
|
case 1:
|
||||||
return PATH_COLUMN_NAME;
|
return CATEGORY_COLUMN_NAME;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -735,8 +723,7 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
case 1: {
|
case 1: {
|
||||||
Structure structure = t.getStructure();
|
Structure structure = t.getStructure();
|
||||||
CategoryPath path = structure.getCategoryPath();
|
CategoryPath path = structure.getCategoryPath();
|
||||||
String name = structure.getName();
|
return path.toString();
|
||||||
return path.toString() + '/' + name;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -779,7 +766,7 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we need this renderer in order to create nice tool tip text values
|
// we need this renderer in order to create nice tool tip text values
|
||||||
class StructureCellRenderer extends GTableCellRenderer {
|
private class StructureCellRenderer extends GTableCellRenderer {
|
||||||
@Override
|
@Override
|
||||||
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
||||||
|
|
||||||
@@ -799,7 +786,7 @@ public class CreateStructureDialog extends ReusableDialogComponentProvider {
|
|||||||
renderer.setToolTipText(ToolTipUtils.getToolTipText(structure));
|
renderer.setToolTipText(ToolTipUtils.getToolTipText(structure));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (PATH_COLUMN_NAME.equals(columnName)) {
|
else if (CATEGORY_COLUMN_NAME.equals(columnName)) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
renderer.setToolTipText(value.toString());
|
renderer.setToolTipText(value.toString());
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -598,6 +598,7 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
|||||||
public CategoryPath getCategoryPath(TreePath selectedPath) {
|
public CategoryPath getCategoryPath(TreePath selectedPath) {
|
||||||
DataTypeChooserDialog dialog = new DataTypeChooserDialog(this);
|
DataTypeChooserDialog dialog = new DataTypeChooserDialog(this);
|
||||||
dialog.setCategorySelectionMode(true);
|
dialog.setCategorySelectionMode(true);
|
||||||
|
dialog.setShowProgramArchiveOnly(true);
|
||||||
|
|
||||||
if (selectedPath != null) {
|
if (selectedPath != null) {
|
||||||
dialog.setSelectedPath(selectedPath);
|
dialog.setSelectedPath(selectedPath);
|
||||||
|
|||||||
+46
-13
@@ -169,10 +169,37 @@ public class DataTypeIndexer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class CaseInsensitiveCategoryComparator implements Comparator<CategoryPath> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(CategoryPath cp1, CategoryPath cp2) {
|
||||||
|
|
||||||
|
String name1 = cp1.getName();
|
||||||
|
String name2 = cp2.getName();
|
||||||
|
|
||||||
|
int result = name1.compareToIgnoreCase(name2);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = name1.compareTo(name2);
|
||||||
|
if (result != 0) {
|
||||||
|
// let equivalent names be sorted by case ('-' for lower-case first)
|
||||||
|
return -result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the names are the same, then sort by full path
|
||||||
|
String p1 = cp1.getPath();
|
||||||
|
String p2 = cp2.getPath();
|
||||||
|
return p1.compareToIgnoreCase(p2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class IndexerTask extends Task {
|
private class IndexerTask extends Task {
|
||||||
|
|
||||||
private List<DataType> dataTypes = new ArrayList<>();
|
private List<DataType> dataTypes = new ArrayList<>();
|
||||||
private List<CategoryPath> categories;
|
private List<CategoryPath> categories = new ArrayList<>();
|
||||||
|
private Set<CategoryPath> categorySet = new HashSet<>();
|
||||||
|
|
||||||
IndexerTask() {
|
IndexerTask() {
|
||||||
super("Data Type Indexer Task", false, true, true);
|
super("Data Type Indexer Task", false, true, true);
|
||||||
@@ -184,26 +211,32 @@ public class DataTypeIndexer {
|
|||||||
monitor.initialize(dataTypeManagers.size());
|
monitor.initialize(dataTypeManagers.size());
|
||||||
monitor.setMessage("Preparing to index data types...");
|
monitor.setMessage("Preparing to index data types...");
|
||||||
|
|
||||||
for (DataTypeManager dataTypeManager : dataTypeManagers) {
|
for (DataTypeManager dtm : dataTypeManagers) {
|
||||||
monitor.setMessage("Searching " + dataTypeManager.getName());
|
monitor.setMessage("Searching " + dtm.getName());
|
||||||
dataTypeManager.getAllDataTypes(dataTypes);
|
dtm.getAllDataTypes(dataTypes);
|
||||||
|
|
||||||
|
Category root = dtm.getRootCategory();
|
||||||
|
populateCategories(root);
|
||||||
|
|
||||||
monitor.incrementProgress(1);
|
monitor.incrementProgress(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.sort(dataTypes, new CaseInsensitiveDataTypeComparator());
|
Collections.sort(dataTypes, new CaseInsensitiveDataTypeComparator());
|
||||||
populateCategoryList(dataTypes);
|
|
||||||
|
categories.addAll(categorySet);
|
||||||
|
Collections.sort(categories, new CaseInsensitiveCategoryComparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateCategoryList(List<DataType> dataTypes) {
|
private void populateCategories(Category parent) {
|
||||||
|
|
||||||
Set<CategoryPath> set = new HashSet<>();
|
categorySet.add(parent.getCategoryPath());
|
||||||
for (DataType dt : dataTypes) {
|
Category[] children = parent.getCategories();
|
||||||
CategoryPath path = dt.getCategoryPath();
|
for (Category category : children) {
|
||||||
set.add(path);
|
CategoryPath path = category.getCategoryPath();
|
||||||
|
categorySet.add(path);
|
||||||
|
|
||||||
|
populateCategories(category);
|
||||||
}
|
}
|
||||||
|
|
||||||
categories = new ArrayList<>(set);
|
|
||||||
Collections.sort(categories);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DataType> getList() {
|
List<DataType> getList() {
|
||||||
|
|||||||
+8
@@ -674,6 +674,13 @@ public class DataTypeManagerHandler {
|
|||||||
return builtInDataTypesManager;
|
return builtInDataTypesManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DataTypeManager getProgramDataTypeManager() {
|
||||||
|
if (programArchive != null) {
|
||||||
|
return programArchive.getDataTypeManager();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public DataTypeIndexer getDataTypeIndexer() {
|
public DataTypeIndexer getDataTypeIndexer() {
|
||||||
return dataTypeIndexer;
|
return dataTypeIndexer;
|
||||||
}
|
}
|
||||||
@@ -1810,4 +1817,5 @@ public class DataTypeManagerHandler {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-15
@@ -34,8 +34,15 @@ public class ArchiveRootNode extends DataTypeTreeNode {
|
|||||||
|
|
||||||
private DtFilterState dtFilterState = new DtFilterState();
|
private DtFilterState dtFilterState = new DtFilterState();
|
||||||
|
|
||||||
ArchiveRootNode(DataTypeManagerHandler archiveManager) {
|
private boolean programDtmOnly;
|
||||||
|
|
||||||
|
public ArchiveRootNode(DataTypeManagerHandler archiveManager) {
|
||||||
|
this(archiveManager, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchiveRootNode(DataTypeManagerHandler archiveManager, boolean programDtmOnly) {
|
||||||
this.archiveManager = archiveManager;
|
this.archiveManager = archiveManager;
|
||||||
|
this.programDtmOnly = programDtmOnly;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,21 +100,29 @@ public class ArchiveRootNode extends DataTypeTreeNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// a factory method to isolate non-OO inheritance checks
|
// a factory method to isolate non-OO inheritance checks
|
||||||
private static final GTreeNode createArchiveNode(Archive archive, DtFilterState dtFilterState) {
|
private final GTreeNode createArchiveNode(Archive archive, DtFilterState filterState) {
|
||||||
|
|
||||||
|
if (programDtmOnly) {
|
||||||
|
if (archive instanceof ProgramArchive) {
|
||||||
|
return new ProgramArchiveNode((ProgramArchive) archive, filterState);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (archive instanceof FileArchive) {
|
if (archive instanceof FileArchive) {
|
||||||
return new FileArchiveNode((FileArchive) archive, dtFilterState);
|
return new FileArchiveNode((FileArchive) archive, filterState);
|
||||||
}
|
}
|
||||||
else if (archive instanceof ProjectArchive) {
|
else if (archive instanceof ProjectArchive) {
|
||||||
return new ProjectArchiveNode((ProjectArchive) archive, dtFilterState);
|
return new ProjectArchiveNode((ProjectArchive) archive, filterState);
|
||||||
}
|
}
|
||||||
else if (archive instanceof InvalidFileArchive) {
|
else if (archive instanceof InvalidFileArchive) {
|
||||||
return new InvalidArchiveNode((InvalidFileArchive) archive);
|
return new InvalidArchiveNode((InvalidFileArchive) archive);
|
||||||
}
|
}
|
||||||
else if (archive instanceof ProgramArchive) {
|
else if (archive instanceof ProgramArchive) {
|
||||||
return new ProgramArchiveNode((ProgramArchive) archive, dtFilterState);
|
return new ProgramArchiveNode((ProgramArchive) archive, filterState);
|
||||||
}
|
}
|
||||||
else if (archive instanceof BuiltInArchive) {
|
else if (archive instanceof BuiltInArchive) {
|
||||||
return new BuiltInArchiveNode((BuiltInArchive) archive, dtFilterState);
|
return new BuiltInArchiveNode((BuiltInArchive) archive, filterState);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -178,7 +193,10 @@ public class ArchiveRootNode extends DataTypeTreeNode {
|
|||||||
public List<GTreeNode> generateChildren() {
|
public List<GTreeNode> generateChildren() {
|
||||||
List<GTreeNode> list = new ArrayList<>();
|
List<GTreeNode> list = new ArrayList<>();
|
||||||
for (Archive element : archiveManager.getAllArchives()) {
|
for (Archive element : archiveManager.getAllArchives()) {
|
||||||
list.add(createArchiveNode(element, dtFilterState));
|
GTreeNode node = createArchiveNode(element, dtFilterState);
|
||||||
|
if (node != null) {
|
||||||
|
list.add(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(list);
|
Collections.sort(list);
|
||||||
return list;
|
return list;
|
||||||
@@ -221,15 +239,21 @@ public class ArchiveRootNode extends DataTypeTreeNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void archiveOpened(Archive archive) {
|
public void archiveOpened(Archive archive) {
|
||||||
if (isLoaded()) {
|
if (!isLoaded()) {
|
||||||
GTreeNode node = createArchiveNode(archive, dtFilterState);
|
return;
|
||||||
List<GTreeNode> allChildrenList = getChildren();
|
|
||||||
int index = Collections.binarySearch(allChildrenList, node);
|
|
||||||
if (index < 0) {
|
|
||||||
index = -index - 1;
|
|
||||||
}
|
|
||||||
addNode(index, node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GTreeNode node = createArchiveNode(archive, dtFilterState);
|
||||||
|
if (node == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GTreeNode> allChildrenList = getChildren();
|
||||||
|
int index = Collections.binarySearch(allChildrenList, node);
|
||||||
|
if (index < 0) {
|
||||||
|
index = -index - 1;
|
||||||
|
}
|
||||||
|
addNode(index, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+34
-3
@@ -31,12 +31,14 @@ import docking.DialogComponentProvider;
|
|||||||
import docking.Tool;
|
import docking.Tool;
|
||||||
import docking.widgets.filter.FilterOptions;
|
import docking.widgets.filter.FilterOptions;
|
||||||
import docking.widgets.filter.TextFilterStrategy;
|
import docking.widgets.filter.TextFilterStrategy;
|
||||||
import docking.widgets.label.GLabel;
|
import docking.widgets.label.GDLabel;
|
||||||
import docking.widgets.tree.*;
|
import docking.widgets.tree.*;
|
||||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||||
|
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||||
import ghidra.app.util.datatype.DataTypeSelectionDialog;
|
import ghidra.app.util.datatype.DataTypeSelectionDialog;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
@@ -46,17 +48,20 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
* {@link DataTypeSelectionDialog} utility widget.
|
* {@link DataTypeSelectionDialog} utility widget.
|
||||||
*/
|
*/
|
||||||
public class DataTypeChooserDialog extends DialogComponentProvider {
|
public class DataTypeChooserDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
|
private DataTypeManagerPlugin plugin;
|
||||||
private DataTypeArchiveGTree tree;
|
private DataTypeArchiveGTree tree;
|
||||||
private DataType selectedDataType;
|
private DataType selectedDataType;
|
||||||
private CategoryPath selectedCategoryPath;
|
private CategoryPath selectedCategoryPath;
|
||||||
|
|
||||||
private GLabel messageLabel;
|
private GDLabel messageLabel;
|
||||||
private boolean isFilterEditable;
|
private boolean isFilterEditable;
|
||||||
|
|
||||||
private boolean categorySelectionMode;
|
private boolean categorySelectionMode;
|
||||||
|
|
||||||
public DataTypeChooserDialog(DataTypeManagerPlugin plugin) {
|
public DataTypeChooserDialog(DataTypeManagerPlugin plugin) {
|
||||||
super("Data Type Chooser", true, true, true, false);
|
super("Data Type Chooser", true, true, true, false);
|
||||||
|
this.plugin = plugin;
|
||||||
|
|
||||||
tree = new DataTypeArchiveGTree(plugin);
|
tree = new DataTypeArchiveGTree(plugin);
|
||||||
|
|
||||||
@@ -98,6 +103,8 @@ public class DataTypeChooserDialog extends DialogComponentProvider {
|
|||||||
addOKButton();
|
addOKButton();
|
||||||
addCancelButton();
|
addCancelButton();
|
||||||
setOkEnabled(false);
|
setOkEnabled(false);
|
||||||
|
|
||||||
|
setHelpLocation(new HelpLocation("DataTypeEditors", "browse"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,6 +113,29 @@ public class DataTypeChooserDialog extends DialogComponentProvider {
|
|||||||
*/
|
*/
|
||||||
public void setCategorySelectionMode(boolean categorySelectionMode) {
|
public void setCategorySelectionMode(boolean categorySelectionMode) {
|
||||||
this.categorySelectionMode = categorySelectionMode;
|
this.categorySelectionMode = categorySelectionMode;
|
||||||
|
if (categorySelectionMode) {
|
||||||
|
setTitle("Category Chooser");
|
||||||
|
messageLabel.setText("Choose a category:");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setTitle("Data Type Chooser");
|
||||||
|
messageLabel.setText("Choose a data type:");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowProgramArchiveOnly(boolean programOnly) {
|
||||||
|
DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
|
||||||
|
if (programOnly) {
|
||||||
|
DataTypeManager programDtm = handler.getProgramDataTypeManager();
|
||||||
|
if (programDtm != null) {
|
||||||
|
ArchiveRootNode root = new ArchiveRootNode(handler, true);
|
||||||
|
tree.setRootNode(root);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveRootNode root = new ArchiveRootNode(handler);
|
||||||
|
tree.setRootNode(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidNodeSelected() {
|
private boolean isValidNodeSelected() {
|
||||||
@@ -152,7 +182,7 @@ public class DataTypeChooserDialog extends DialogComponentProvider {
|
|||||||
|
|
||||||
private JComponent createWorkPanel() {
|
private JComponent createWorkPanel() {
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
messageLabel = new GLabel("Choose the data type you wish to use.");
|
messageLabel = new GDLabel("Choose the data type you wish to use.");
|
||||||
messageLabel.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 2));
|
messageLabel.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 2));
|
||||||
messageLabel.getAccessibleContext().setAccessibleName("Message");
|
messageLabel.getAccessibleContext().setAccessibleName("Message");
|
||||||
panel.add(messageLabel, BorderLayout.NORTH);
|
panel.add(messageLabel, BorderLayout.NORTH);
|
||||||
@@ -335,4 +365,5 @@ public class DataTypeChooserDialog extends DialogComponentProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-23
@@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.function.editor;
|
package ghidra.app.plugin.core.function.editor;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.Component;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.util.EventObject;
|
import java.util.EventObject;
|
||||||
|
|
||||||
@@ -32,16 +32,15 @@ import ghidra.app.util.datatype.DataTypeSelectionEditor;
|
|||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.data.DataTypeManager;
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
import ghidra.util.MessageType;
|
import ghidra.util.MessageType;
|
||||||
|
import ghidra.util.Swing;
|
||||||
import ghidra.util.data.DataTypeParser;
|
import ghidra.util.data.DataTypeParser;
|
||||||
|
|
||||||
class ParameterDataTypeCellEditor extends AbstractCellEditor
|
class ParameterDataTypeCellEditor extends AbstractCellEditor
|
||||||
implements TableCellEditor, FocusableEditor {
|
implements TableCellEditor, FocusableEditor {
|
||||||
private DataTypeSelectionEditor editor;
|
private DataTypeSelectionEditor editor;
|
||||||
private DropDownSelectionTextField<DataType> textField;
|
private DropDownSelectionTextField<DataType> textField;
|
||||||
private JButton dataTypeChooserButton;
|
|
||||||
private DataType dt;
|
private DataType dt;
|
||||||
|
|
||||||
private JPanel editorPanel;
|
|
||||||
private DataTypeManagerService service;
|
private DataTypeManagerService service;
|
||||||
private DialogComponentProvider dialog;
|
private DialogComponentProvider dialog;
|
||||||
private DataTypeManager dtm;
|
private DataTypeManager dtm;
|
||||||
@@ -62,7 +61,7 @@ class ParameterDataTypeCellEditor extends AbstractCellEditor
|
|||||||
|
|
||||||
editor.setCellEditorValue(dt);
|
editor.setCellEditorValue(dt);
|
||||||
|
|
||||||
return editorPanel;
|
return editor.getEditorComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
@@ -83,17 +82,8 @@ class ParameterDataTypeCellEditor extends AbstractCellEditor
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// force a small button for the table's cell editor
|
JButton browseButton = editor.getBrowseButton();
|
||||||
dataTypeChooserButton = new JButton("...") {
|
browseButton.addActionListener(e -> Swing.runLater(() -> {
|
||||||
@Override
|
|
||||||
public Dimension getPreferredSize() {
|
|
||||||
Dimension preferredSize = super.getPreferredSize();
|
|
||||||
preferredSize.width = 15;
|
|
||||||
return preferredSize;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
dataTypeChooserButton.addActionListener(e -> SwingUtilities.invokeLater(() -> {
|
|
||||||
DataType dataType = service.getDataType((String) null);
|
DataType dataType = service.getDataType((String) null);
|
||||||
if (dataType != null) {
|
if (dataType != null) {
|
||||||
editor.setCellEditorValue(dataType);
|
editor.setCellEditorValue(dataType);
|
||||||
@@ -104,18 +94,13 @@ class ParameterDataTypeCellEditor extends AbstractCellEditor
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
FocusAdapter focusListener = new FocusAdapter() {
|
textField.addFocusListener(new FocusAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void focusGained(FocusEvent e) {
|
public void focusGained(FocusEvent e) {
|
||||||
textField.selectAll();
|
textField.selectAll();
|
||||||
textField.removeFocusListener(this);
|
textField.removeFocusListener(this);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
textField.addFocusListener(focusListener);
|
|
||||||
|
|
||||||
editorPanel = new JPanel(new BorderLayout());
|
|
||||||
editorPanel.add(textField, BorderLayout.CENTER);
|
|
||||||
editorPanel.add(dataTypeChooserButton, BorderLayout.EAST);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -136,7 +121,7 @@ class ParameterDataTypeCellEditor extends AbstractCellEditor
|
|||||||
* be returned if getTableCellEditorComponent method has not yet been invoked.
|
* be returned if getTableCellEditorComponent method has not yet been invoked.
|
||||||
*/
|
*/
|
||||||
public JButton getChooserButton() {
|
public JButton getChooserButton() {
|
||||||
return dataTypeChooserButton;
|
return editor.getBrowseButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+73
-72
@@ -15,11 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.util.datatype;
|
package ghidra.app.util.datatype;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import javax.swing.border.Border;
|
||||||
import javax.swing.event.*;
|
import javax.swing.event.*;
|
||||||
import javax.swing.tree.TreePath;
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
@@ -30,7 +33,6 @@ import docking.widgets.list.GListCellRenderer;
|
|||||||
import ghidra.app.services.DataTypeManagerService;
|
import ghidra.app.services.DataTypeManagerService;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.program.model.data.CategoryPath;
|
import ghidra.program.model.data.CategoryPath;
|
||||||
import ghidra.util.exception.AssertException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An editor that is used to show the {@link DropDownSelectionTextField} for the entering of
|
* An editor that is used to show the {@link DropDownSelectionTextField} for the entering of
|
||||||
@@ -92,6 +94,8 @@ public class CategoryPathSelectionEditor extends AbstractCellEditor {
|
|||||||
private void init() {
|
private void init() {
|
||||||
selectionField = createDropDownSelectionTextField(
|
selectionField = createDropDownSelectionTextField(
|
||||||
new CategoryPathDropDownSelectionDataModel(dataTypeManagerService));
|
new CategoryPathDropDownSelectionDataModel(dataTypeManagerService));
|
||||||
|
selectionField.setName("CategoryPath");
|
||||||
|
selectionField.getAccessibleContext().setAccessibleName("Category");
|
||||||
selectionField.addCellEditorListener(new CellEditorListener() {
|
selectionField.addCellEditorListener(new CellEditorListener() {
|
||||||
@Override
|
@Override
|
||||||
public void editingCanceled(ChangeEvent e) {
|
public void editingCanceled(ChangeEvent e) {
|
||||||
@@ -113,16 +117,12 @@ public class CategoryPathSelectionEditor extends AbstractCellEditor {
|
|||||||
selectionField.requestFocus();
|
selectionField.requestFocus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
selectionField.setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
|
|
||||||
browseButton = new BrowseButton();
|
|
||||||
browseButton.setToolTipText("Browse Existing Category Paths");
|
|
||||||
browseButton.addActionListener(e -> showBrowser());
|
|
||||||
|
|
||||||
|
JPanel browsePanel = buildBrowsePanel();
|
||||||
editorPanel = new JPanel();
|
editorPanel = new JPanel();
|
||||||
editorPanel.setLayout(new BoxLayout(editorPanel, BoxLayout.X_AXIS));
|
editorPanel.setLayout(new BoxLayout(editorPanel, BoxLayout.X_AXIS));
|
||||||
editorPanel.add(selectionField);
|
editorPanel.add(selectionField);
|
||||||
editorPanel.add(Box.createHorizontalStrut(5));
|
editorPanel.add(browsePanel);
|
||||||
editorPanel.add(browseButton);
|
|
||||||
|
|
||||||
keyListener = new KeyAdapter() {
|
keyListener = new KeyAdapter() {
|
||||||
|
|
||||||
@@ -144,6 +144,60 @@ public class CategoryPathSelectionEditor extends AbstractCellEditor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JPanel buildBrowsePanel() {
|
||||||
|
|
||||||
|
// We override the various sizes to make sure the button does not get too big or too small,
|
||||||
|
// which changes depending upon the theme being used.
|
||||||
|
JPanel browsePanel = new JPanel() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
int width = getBestWidth();
|
||||||
|
Dimension preferredSize = super.getPreferredSize();
|
||||||
|
preferredSize.width = Math.min(width, preferredSize.width);
|
||||||
|
return preferredSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getMinimumSize() {
|
||||||
|
int width = getBestWidth();
|
||||||
|
Dimension preferredSize = super.getPreferredSize();
|
||||||
|
preferredSize.width = Math.min(width, preferredSize.width);
|
||||||
|
return preferredSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getMaximumSize() {
|
||||||
|
int width = getBestWidth();
|
||||||
|
Dimension preferredSize = super.getPreferredSize();
|
||||||
|
preferredSize.width = Math.min(width, preferredSize.width);
|
||||||
|
return preferredSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getBestWidth() {
|
||||||
|
Font f = getFont();
|
||||||
|
FontMetrics fm = getFontMetrics(f);
|
||||||
|
int width = fm.stringWidth(" . . . ");
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
browsePanel.setLayout(new BorderLayout());
|
||||||
|
browsePanel.setOpaque(false);
|
||||||
|
|
||||||
|
// Space the button so that it pops out visually. This was chosen by trial-and-error and
|
||||||
|
// looks reasonable on all themes.
|
||||||
|
Border empty = BorderFactory.createEmptyBorder(2, 2, 1, 1);
|
||||||
|
browsePanel.setBorder(empty);
|
||||||
|
|
||||||
|
browseButton = new BrowseButton();
|
||||||
|
browseButton.setToolTipText("Browse Existing Category Paths");
|
||||||
|
browseButton.addActionListener(e -> showBrowser());
|
||||||
|
browsePanel.add(browseButton);
|
||||||
|
|
||||||
|
return browsePanel;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the value in the cell.
|
* Retrieve the value in the cell.
|
||||||
* @return categoryPath of the selected value from the drop-down
|
* @return categoryPath of the selected value from the drop-down
|
||||||
@@ -179,8 +233,8 @@ public class CategoryPathSelectionEditor extends AbstractCellEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the dropdown text field that holds the category path collection.
|
* Retrieve the drop-down text field that holds the category path collection.
|
||||||
* @return CategoryPath dropdown selection text field object
|
* @return CategoryPath drop-down selection text field object
|
||||||
*/
|
*/
|
||||||
public DropDownSelectionTextField<CategoryPath> getDropDownTextField() {
|
public DropDownSelectionTextField<CategoryPath> getDropDownTextField() {
|
||||||
return selectionField;
|
return selectionField;
|
||||||
@@ -333,13 +387,6 @@ public class CategoryPathSelectionEditor extends AbstractCellEditor {
|
|||||||
|
|
||||||
private List<CategoryPath> data;
|
private List<CategoryPath> data;
|
||||||
|
|
||||||
private Comparator<Object> searchComparator = new CategoryPathComparator();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance.
|
|
||||||
*
|
|
||||||
* @param dataTypeService {@link DataTypeManagerService}
|
|
||||||
*/
|
|
||||||
public CategoryPathDropDownSelectionDataModel(DataTypeManagerService dataTypeService) {
|
public CategoryPathDropDownSelectionDataModel(DataTypeManagerService dataTypeService) {
|
||||||
data = dataTypeService.getSortedCategoryPathList();
|
data = dataTypeService.getSortedCategoryPathList();
|
||||||
}
|
}
|
||||||
@@ -349,66 +396,32 @@ public class CategoryPathSelectionEditor extends AbstractCellEditor {
|
|||||||
return new CategoryPathDropDownRenderer();
|
return new CategoryPathDropDownRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Description of the CategoryPath is the display text of the path as a string.
|
|
||||||
|
|
||||||
* @param categoryPath CategoryPath
|
|
||||||
* @return String representation of the Category Path
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription(CategoryPath categoryPath) {
|
public String getDescription(CategoryPath categoryPath) {
|
||||||
return getDisplayText(categoryPath);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the CategoryPath string representation.
|
|
||||||
*
|
|
||||||
* @param categoryPath CategoryPath
|
|
||||||
* @return String representation of the Category Path
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getDisplayText(CategoryPath categoryPath) {
|
public String getDisplayText(CategoryPath categoryPath) {
|
||||||
return categoryPath.getPath();
|
return categoryPath.getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Support for the filtering mechanism on the collection of Category Paths in the Data Manager.
|
|
||||||
*
|
|
||||||
* @param searchText String entered text
|
|
||||||
* @return filtered list of Category Paths
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public List<CategoryPath> getMatchingData(String searchText) {
|
public List<CategoryPath> getMatchingData(String searchText) {
|
||||||
if (searchText == null || searchText.length() == 0) {
|
if (searchText == null || searchText.length() == 0) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
char END_CHAR = '\uffff';
|
List<CategoryPath> results = new ArrayList<>();
|
||||||
String searchTextStart = searchText;
|
for (CategoryPath path : data) {
|
||||||
String searchTextEnd = searchText + END_CHAR;
|
String pathString = path.getPath();
|
||||||
|
if (pathString.contains(searchText)) {
|
||||||
int startIndex = Collections.binarySearch(data, searchTextStart, searchComparator);
|
results.add(path);
|
||||||
int endIndex = Collections.binarySearch(data, searchTextEnd, searchComparator);
|
}
|
||||||
|
|
||||||
// the binary search returns a negative, incremented position if there is no match in the
|
|
||||||
// list for the given search
|
|
||||||
if (startIndex < 0) {
|
|
||||||
startIndex = -startIndex - 1;
|
|
||||||
}
|
}
|
||||||
|
return results;
|
||||||
if (endIndex < 0) {
|
|
||||||
endIndex = -endIndex - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data.subList(startIndex, endIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Identify index of first matching CategoryPath from entered text string.
|
|
||||||
* @param dataCollection list of Category Paths
|
|
||||||
* @param text search string
|
|
||||||
* @return int index of first match
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int getIndexOfFirstMatchingEntry(List<CategoryPath> dataCollection, String text) {
|
public int getIndexOfFirstMatchingEntry(List<CategoryPath> dataCollection, String text) {
|
||||||
int lastPreferredMatchIndex = -1;
|
int lastPreferredMatchIndex = -1;
|
||||||
@@ -434,18 +447,6 @@ public class CategoryPathSelectionEditor extends AbstractCellEditor {
|
|||||||
return -1; // we only get here when the list is empty
|
return -1; // we only get here when the list is empty
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CategoryPathComparator implements Comparator<Object> {
|
|
||||||
@Override
|
|
||||||
public int compare(Object o1, Object o2) {
|
|
||||||
if (o1 instanceof CategoryPath && o2 instanceof String) {
|
|
||||||
CategoryPath path = (CategoryPath) o1;
|
|
||||||
return path.getName().compareToIgnoreCase(((String) o2));
|
|
||||||
}
|
|
||||||
throw new AssertException(
|
|
||||||
"CategoryPathCompartor used to compare files against a String key!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class CategoryPathDropDownRenderer extends GListCellRenderer<CategoryPath> {
|
private class CategoryPathDropDownRenderer extends GListCellRenderer<CategoryPath> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+60
-5
@@ -15,9 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.util.datatype;
|
package ghidra.app.util.datatype;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import javax.swing.border.Border;
|
||||||
import javax.swing.event.*;
|
import javax.swing.event.*;
|
||||||
import javax.swing.tree.TreePath;
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
@@ -141,15 +143,13 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
|
|||||||
|
|
||||||
selectionField.setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
|
selectionField.setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
|
||||||
|
|
||||||
browseButton = new BrowseButton();
|
JPanel browsePanel = buildBrowsePanel();
|
||||||
browseButton.setToolTipText("Browse the Data Manager");
|
|
||||||
browseButton.addActionListener(e -> showDataTypeBrowser());
|
|
||||||
|
|
||||||
editorPanel = new JPanel();
|
editorPanel = new JPanel();
|
||||||
|
editorPanel.setOpaque(false);
|
||||||
editorPanel.setLayout(new BoxLayout(editorPanel, BoxLayout.X_AXIS));
|
editorPanel.setLayout(new BoxLayout(editorPanel, BoxLayout.X_AXIS));
|
||||||
editorPanel.add(selectionField);
|
editorPanel.add(selectionField);
|
||||||
editorPanel.add(Box.createHorizontalStrut(5));
|
editorPanel.add(browsePanel);
|
||||||
editorPanel.add(browseButton);
|
|
||||||
|
|
||||||
keyListener = new KeyAdapter() {
|
keyListener = new KeyAdapter() {
|
||||||
|
|
||||||
@@ -171,6 +171,61 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JPanel buildBrowsePanel() {
|
||||||
|
|
||||||
|
// We override the various sizes to make sure the button does not get too big or too small,
|
||||||
|
// which changes depending upon the theme being used.
|
||||||
|
JPanel browsePanel = new JPanel() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
int width = getBestWidth();
|
||||||
|
Dimension preferredSize = super.getPreferredSize();
|
||||||
|
preferredSize.width = Math.min(width, preferredSize.width);
|
||||||
|
return preferredSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getMinimumSize() {
|
||||||
|
int width = getBestWidth();
|
||||||
|
Dimension preferredSize = super.getPreferredSize();
|
||||||
|
preferredSize.width = Math.min(width, preferredSize.width);
|
||||||
|
return preferredSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getMaximumSize() {
|
||||||
|
int width = getBestWidth();
|
||||||
|
Dimension preferredSize = super.getPreferredSize();
|
||||||
|
preferredSize.width = Math.min(width, preferredSize.width);
|
||||||
|
return preferredSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getBestWidth() {
|
||||||
|
Font f = getFont();
|
||||||
|
FontMetrics fm = getFontMetrics(f);
|
||||||
|
int width = fm.stringWidth(" . . . ");
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
browsePanel.setLayout(new BorderLayout());
|
||||||
|
browsePanel.setOpaque(false);
|
||||||
|
|
||||||
|
// Space the button so that it pops out visually. This was chosen by trial-and-error and
|
||||||
|
// looks reasonable on all themes.
|
||||||
|
Border empty = BorderFactory.createEmptyBorder(2, 2, 1, 1);
|
||||||
|
browsePanel.setBorder(empty);
|
||||||
|
|
||||||
|
browseButton = new BrowseButton();
|
||||||
|
browseButton.setToolTipText("Browse the Data Manager");
|
||||||
|
browseButton.addActionListener(e -> showDataTypeBrowser());
|
||||||
|
|
||||||
|
browsePanel.add(browseButton);
|
||||||
|
|
||||||
|
return browsePanel;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getCellEditorValue() {
|
public Object getCellEditorValue() {
|
||||||
return selectionField.getSelectedValue();
|
return selectionField.getSelectedValue();
|
||||||
|
|||||||
@@ -1001,7 +1001,10 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn
|
|||||||
public void selectRow(final JTable table, final int rowIndex) {
|
public void selectRow(final JTable table, final int rowIndex) {
|
||||||
waitForTable(table);
|
waitForTable(table);
|
||||||
|
|
||||||
runSwing(() -> table.setRowSelectionInterval(rowIndex, rowIndex));
|
runSwing(() -> {
|
||||||
|
table.setRowSelectionInterval(rowIndex, rowIndex);
|
||||||
|
table.requestFocus();
|
||||||
|
});
|
||||||
waitForTable(table);
|
waitForTable(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -974,7 +974,7 @@ public class DropDownTextField<T> extends JTextField implements GComponent {
|
|||||||
fireUserChoiceMade(selectedItem);
|
fireUserChoiceMade(selectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PreviewListener implements ListSelectionListener {
|
private class PreviewListener implements ListSelectionListener {
|
||||||
@Override
|
@Override
|
||||||
public void valueChanged(ListSelectionEvent e) {
|
public void valueChanged(ListSelectionEvent e) {
|
||||||
if (e.getValueIsAdjusting()) {
|
if (e.getValueIsAdjusting()) {
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -55,5 +55,7 @@ public class BrowseButton extends JButton {
|
|||||||
setIcon(ICON);
|
setIcon(ICON);
|
||||||
setName(NAME);
|
setName(NAME);
|
||||||
setToolTipText(TOOLTIP_TEXT);
|
setToolTipText(TOOLTIP_TEXT);
|
||||||
|
|
||||||
|
getAccessibleContext().setAccessibleName("Browse");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-1
@@ -19,6 +19,9 @@ import java.util.Set;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.swing.JRadioButton;
|
import javax.swing.JRadioButton;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.table.TableColumn;
|
||||||
|
import javax.swing.table.TableColumnModel;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -66,7 +69,21 @@ public class DataPluginScreenShots extends GhidraScreenShotGenerator {
|
|||||||
GhidraTable table = (GhidraTable) getInstanceField("matchingStructuresTable", dialog);
|
GhidraTable table = (GhidraTable) getInstanceField("matchingStructuresTable", dialog);
|
||||||
selectRow(table, 2);
|
selectRow(table, 2);
|
||||||
|
|
||||||
captureDialog(500, 400);
|
shrinkCategoryColumn(table);
|
||||||
|
|
||||||
|
captureDialog(600, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shrinkCategoryColumn(JTable table) {
|
||||||
|
|
||||||
|
runSwing(() -> {
|
||||||
|
TableColumnModel columnModel = table.getColumnModel();
|
||||||
|
int columnIndex = columnModel.getColumnIndex("Category");
|
||||||
|
TableColumn column = columnModel.getColumn(columnIndex);
|
||||||
|
int size = 150;
|
||||||
|
column.setPreferredWidth(size);
|
||||||
|
column.setMaxWidth(size);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user