mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-01 11:55:59 +08:00
GP-5327 - Create Structure Dialog - New text category box & existing
categories chooser
This commit is contained in:
committed by
dragonmacher
parent
795d92cb1a
commit
8234bfb14a
+10
@@ -93,6 +93,11 @@ public class DefaultDataTypeManagerService extends DefaultDataTypeArchiveService
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CategoryPath getCategoryPath(TreePath selectedPath) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DataType> getFavorites() {
|
public List<DataType> getFavorites() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
@@ -111,6 +116,11 @@ public class DefaultDataTypeManagerService extends DefaultDataTypeArchiveService
|
|||||||
return dataTypes;
|
return dataTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CategoryPath> getSortedCategoryPathList() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
|
public void removeDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|||||||
+6
-19
@@ -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.
|
||||||
@@ -40,7 +40,6 @@ class CreateStructureAction extends ListingContextAction {
|
|||||||
new String[] { "Data", "Create Structure..." };
|
new String[] { "Data", "Create Structure..." };
|
||||||
|
|
||||||
private DataPlugin plugin;
|
private DataPlugin plugin;
|
||||||
private CreateStructureDialog createStructureDialog;
|
|
||||||
|
|
||||||
public CreateStructureAction(DataPlugin plugin) {
|
public CreateStructureAction(DataPlugin plugin) {
|
||||||
super("Create Structure", plugin.getName());
|
super("Create Structure", plugin.getName());
|
||||||
@@ -49,25 +48,12 @@ class CreateStructureAction extends ListingContextAction {
|
|||||||
setKeyBindingData(new KeyBindingData(KeyEvent.VK_OPEN_BRACKET, InputEvent.SHIFT_DOWN_MASK));
|
setKeyBindingData(new KeyBindingData(KeyEvent.VK_OPEN_BRACKET, InputEvent.SHIFT_DOWN_MASK));
|
||||||
|
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
setEnabled(true);
|
|
||||||
createStructureDialog = new CreateStructureDialog(plugin.getTool());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
|
|
||||||
createStructureDialog.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method called when the action is invoked.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ListingActionContext programActionContext) {
|
public void actionPerformed(ListingActionContext programActionContext) {
|
||||||
Program program = programActionContext.getProgram();
|
Program program = programActionContext.getProgram();
|
||||||
ProgramSelection sel = programActionContext.getSelection();
|
ProgramSelection sel = programActionContext.getSelection();
|
||||||
|
|
||||||
if (sel != null && !sel.isEmpty()) {
|
if (sel != null && !sel.isEmpty()) {
|
||||||
InteriorSelection interiorSel = sel.getInteriorSelection();
|
InteriorSelection interiorSel = sel.getInteriorSelection();
|
||||||
if (interiorSel != null) {
|
if (interiorSel != null) {
|
||||||
@@ -113,8 +99,8 @@ class CreateStructureAction extends ListingContextAction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Structure userChoice =
|
CreateStructureDialog dialog = new CreateStructureDialog(plugin.getTool());
|
||||||
createStructureDialog.showCreateStructureDialog(program, tempStructure);
|
Structure userChoice = dialog.showCreateStructureDialog(program, tempStructure);
|
||||||
|
|
||||||
if (userChoice != null) {
|
if (userChoice != null) {
|
||||||
CreateStructureInStructureCmd cmd = new CreateStructureInStructureCmd(userChoice,
|
CreateStructureInStructureCmd cmd = new CreateStructureInStructureCmd(userChoice,
|
||||||
@@ -162,8 +148,9 @@ class CreateStructureAction extends ListingContextAction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CreateStructureDialog dialog = new CreateStructureDialog(plugin.getTool());
|
||||||
Structure userChoice =
|
Structure userChoice =
|
||||||
createStructureDialog.showCreateStructureDialog(program, tempStructure);
|
dialog.showCreateStructureDialog(program, tempStructure);
|
||||||
|
|
||||||
// exit if the user cancels the operation
|
// exit if the user cancels the operation
|
||||||
if (userChoice != null) {
|
if (userChoice != null) {
|
||||||
|
|||||||
+294
-116
File diff suppressed because it is too large
Load Diff
+17
@@ -594,6 +594,18 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
|||||||
return dialog.getSelectedDataType();
|
return dialog.getSelectedDataType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CategoryPath getCategoryPath(TreePath selectedPath) {
|
||||||
|
DataTypeChooserDialog dialog = new DataTypeChooserDialog(this);
|
||||||
|
dialog.setCategorySelectionMode(true);
|
||||||
|
|
||||||
|
if (selectedPath != null) {
|
||||||
|
dialog.setSelectedPath(selectedPath);
|
||||||
|
}
|
||||||
|
tool.showDialog(dialog);
|
||||||
|
return dialog.getSelectedCategoryPath();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataTypeManager[] getDataTypeManagers() {
|
public DataTypeManager[] getDataTypeManagers() {
|
||||||
return dataTypeManagerHandler.getDataTypeManagers();
|
return dataTypeManagerHandler.getDataTypeManagers();
|
||||||
@@ -664,6 +676,11 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
|||||||
return dataTypeManagerHandler.getDataTypeIndexer().getSortedDataTypeList();
|
return dataTypeManagerHandler.getDataTypeIndexer().getSortedDataTypeList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CategoryPath> getSortedCategoryPathList() {
|
||||||
|
return dataTypeManagerHandler.getDataTypeIndexer().getSortedCategoryPathList();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setDataTypeSelected(DataType dataType) {
|
public void setDataTypeSelected(DataType dataType) {
|
||||||
if (provider.isVisible()) {
|
if (provider.isVisible()) {
|
||||||
|
|||||||
+45
-10
@@ -23,10 +23,11 @@ import ghidra.program.model.data.*;
|
|||||||
import ghidra.util.task.*;
|
import ghidra.util.task.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that stores a sorted list of all the {@link DataType} objects in the current data type
|
* A class that stores a sorted list of all the {@link DataType} and a list of all the
|
||||||
* manager plugin. This class does its work lazily such that no work is done until
|
* {@link CategoryPath} objects in the current data type manager plugin. This class does its work
|
||||||
* {@link #getSortedDataTypeList()} is called. Even when that method is called no work will be
|
* lazily such that no work is done until {@link #getSortedDataTypeList()} is called. Even when that
|
||||||
* done if the state of the data types in the system hasn't changed.
|
* method is called no work will be done if the state of the data types in the system hasn't
|
||||||
|
* changed.
|
||||||
*/
|
*/
|
||||||
public class DataTypeIndexer {
|
public class DataTypeIndexer {
|
||||||
private List<DataTypeManager> dataTypeManagers = new ArrayList<>();
|
private List<DataTypeManager> dataTypeManagers = new ArrayList<>();
|
||||||
@@ -34,6 +35,7 @@ public class DataTypeIndexer {
|
|||||||
private DataTypeIndexUpdateListener listener = new DataTypeIndexUpdateListener();
|
private DataTypeIndexUpdateListener listener = new DataTypeIndexUpdateListener();
|
||||||
|
|
||||||
private volatile boolean isStale = true;
|
private volatile boolean isStale = true;
|
||||||
|
private List<CategoryPath> categoryPathList = Collections.emptyList();
|
||||||
|
|
||||||
// Note: synchronizing here prevents concurrent mod issues with the managers list
|
// Note: synchronizing here prevents concurrent mod issues with the managers list
|
||||||
public synchronized void addDataTypeManager(DataTypeManager dataTypeManager) {
|
public synchronized void addDataTypeManager(DataTypeManager dataTypeManager) {
|
||||||
@@ -79,6 +81,18 @@ public class DataTypeIndexer {
|
|||||||
return Collections.unmodifiableList(newList);
|
return Collections.unmodifiableList(newList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of the unique Category Paths ({@link CategoryPath}) as utilized by the
|
||||||
|
* data types open in the current tool.
|
||||||
|
*
|
||||||
|
* @return a list of the {@link CategoryPath} associated with the data types open in the
|
||||||
|
* current tool.
|
||||||
|
*/
|
||||||
|
public List<CategoryPath> getSortedCategoryPathList() {
|
||||||
|
updateDataTypeList(); // the category list is quietly updated in the background
|
||||||
|
return categoryPathList;
|
||||||
|
}
|
||||||
|
|
||||||
private List<DataType> updateDataTypeList() {
|
private List<DataType> updateDataTypeList() {
|
||||||
if (!isStale) {
|
if (!isStale) {
|
||||||
return dataTypeList;
|
return dataTypeList;
|
||||||
@@ -95,8 +109,9 @@ public class DataTypeIndexer {
|
|||||||
task.run(TaskMonitor.DUMMY);
|
task.run(TaskMonitor.DUMMY);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DataType> newList = task.getList();
|
List<DataType> newDataTypeList = task.getList();
|
||||||
return newList;
|
categoryPathList = task.getCategoryPathList();
|
||||||
|
return newDataTypeList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: purposefully not synchronized for speed
|
// Note: purposefully not synchronized for speed
|
||||||
@@ -107,6 +122,7 @@ public class DataTypeIndexer {
|
|||||||
// is possible that once marked stale, we may never have another request for this data
|
// is possible that once marked stale, we may never have another request for this data
|
||||||
// again.
|
// again.
|
||||||
dataTypeList = Collections.emptyList();
|
dataTypeList = Collections.emptyList();
|
||||||
|
categoryPathList = Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
@@ -155,7 +171,8 @@ public class DataTypeIndexer {
|
|||||||
|
|
||||||
private class IndexerTask extends Task {
|
private class IndexerTask extends Task {
|
||||||
|
|
||||||
private List<DataType> list = new ArrayList<>();
|
private List<DataType> dataTypes = new ArrayList<>();
|
||||||
|
private List<CategoryPath> categories;
|
||||||
|
|
||||||
IndexerTask() {
|
IndexerTask() {
|
||||||
super("Data Type Indexer Task", false, true, true);
|
super("Data Type Indexer Task", false, true, true);
|
||||||
@@ -169,15 +186,32 @@ public class DataTypeIndexer {
|
|||||||
|
|
||||||
for (DataTypeManager dataTypeManager : dataTypeManagers) {
|
for (DataTypeManager dataTypeManager : dataTypeManagers) {
|
||||||
monitor.setMessage("Searching " + dataTypeManager.getName());
|
monitor.setMessage("Searching " + dataTypeManager.getName());
|
||||||
dataTypeManager.getAllDataTypes(list);
|
dataTypeManager.getAllDataTypes(dataTypes);
|
||||||
monitor.incrementProgress(1);
|
monitor.incrementProgress(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.sort(list, new CaseInsensitiveDataTypeComparator());
|
Collections.sort(dataTypes, new CaseInsensitiveDataTypeComparator());
|
||||||
|
populateCategoryList(dataTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateCategoryList(List<DataType> dataTypes) {
|
||||||
|
|
||||||
|
Set<CategoryPath> set = new HashSet<>();
|
||||||
|
for (DataType dt : dataTypes) {
|
||||||
|
CategoryPath path = dt.getCategoryPath();
|
||||||
|
set.add(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
categories = new ArrayList<>(set);
|
||||||
|
Collections.sort(categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DataType> getList() {
|
List<DataType> getList() {
|
||||||
return list;
|
return dataTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CategoryPath> getCategoryPathList() {
|
||||||
|
return categories;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,4 +300,5 @@ public class DataTypeIndexer {
|
|||||||
markStale();
|
markStale();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+84
-12
@@ -34,10 +34,9 @@ import docking.widgets.filter.TextFilterStrategy;
|
|||||||
import docking.widgets.label.GLabel;
|
import docking.widgets.label.GLabel;
|
||||||
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.tree.DataTypeArchiveGTree;
|
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
|
||||||
import ghidra.app.util.datatype.DataTypeSelectionDialog;
|
import ghidra.app.util.datatype.DataTypeSelectionDialog;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
@@ -49,8 +48,12 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
public class DataTypeChooserDialog extends DialogComponentProvider {
|
public class DataTypeChooserDialog extends DialogComponentProvider {
|
||||||
private DataTypeArchiveGTree tree;
|
private DataTypeArchiveGTree tree;
|
||||||
private DataType selectedDataType;
|
private DataType selectedDataType;
|
||||||
|
private CategoryPath selectedCategoryPath;
|
||||||
|
|
||||||
private GLabel messageLabel;
|
private GLabel messageLabel;
|
||||||
boolean isFilterEditable;
|
private boolean isFilterEditable;
|
||||||
|
|
||||||
|
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);
|
||||||
@@ -60,7 +63,7 @@ public class DataTypeChooserDialog extends DialogComponentProvider {
|
|||||||
tree.setEditable(false);
|
tree.setEditable(false);
|
||||||
tree.updateFilterForChoosingDataType();
|
tree.updateFilterForChoosingDataType();
|
||||||
|
|
||||||
tree.addGTreeSelectionListener(e -> setOkEnabled(getSelectedNode() != null));
|
tree.addGTreeSelectionListener(e -> setOkEnabled(isValidNodeSelected()));
|
||||||
|
|
||||||
tree.addMouseListener(new MouseAdapter() {
|
tree.addMouseListener(new MouseAdapter() {
|
||||||
@Override
|
@Override
|
||||||
@@ -69,7 +72,18 @@ public class DataTypeChooserDialog extends DialogComponentProvider {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataTypeNode selectedNode = getSelectedNode();
|
if (categorySelectionMode) {
|
||||||
|
CategoryPath path = getCurrentCategoryPath();
|
||||||
|
if (path == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedCategoryPath = path;
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypeNode selectedNode = getSelectedDtNode();
|
||||||
if (selectedNode == null) {
|
if (selectedNode == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -86,18 +100,48 @@ public class DataTypeChooserDialog extends DialogComponentProvider {
|
|||||||
setOkEnabled(false);
|
setOkEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataTypeNode getSelectedNode() {
|
/**
|
||||||
|
* Signals that this chooser is intended to pick {@link CategoryPath}s instead of data types.
|
||||||
|
* @param categorySelectionMode true to pick category paths
|
||||||
|
*/
|
||||||
|
public void setCategorySelectionMode(boolean categorySelectionMode) {
|
||||||
|
this.categorySelectionMode = categorySelectionMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidNodeSelected() {
|
||||||
|
TreePath[] selectionPath = tree.getSelectionPaths();
|
||||||
|
if (selectionPath.length != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GTreeNode node = (GTreeNode) selectionPath[0].getLastPathComponent();
|
||||||
|
return node instanceof DataTypeTreeNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataTypeNode getSelectedDtNode() {
|
||||||
TreePath[] selectionPath = tree.getSelectionPaths();
|
TreePath[] selectionPath = tree.getSelectionPaths();
|
||||||
if (selectionPath.length != 1) {
|
if (selectionPath.length != 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
GTreeNode node = (GTreeNode) selectionPath[0].getLastPathComponent();
|
GTreeNode node = (GTreeNode) selectionPath[0].getLastPathComponent();
|
||||||
if (!(node instanceof DataTypeNode)) {
|
if (node instanceof DataTypeNode dtNode) {
|
||||||
|
return dtNode;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CategoryNode getSelectedCategoryNode() {
|
||||||
|
TreePath[] selectionPath = tree.getSelectionPaths();
|
||||||
|
if (selectionPath.length != 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (DataTypeNode) node;
|
GTreeNode node = (GTreeNode) selectionPath[0].getLastPathComponent();
|
||||||
|
if (node instanceof CategoryNode catNode) {
|
||||||
|
return catNode;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -119,12 +163,36 @@ public class DataTypeChooserDialog extends DialogComponentProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void okCallback() {
|
protected void okCallback() {
|
||||||
// can't be null since we control button enablement
|
|
||||||
DataTypeNode dataTypeNode = getSelectedNode();
|
if (categorySelectionMode) {
|
||||||
selectedDataType = dataTypeNode.getDataType();
|
selectedCategoryPath = getCurrentCategoryPath();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DataTypeNode dtNode = getSelectedDtNode();
|
||||||
|
selectedDataType = dtNode.getDataType();
|
||||||
|
}
|
||||||
|
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CategoryPath getCurrentCategoryPath() {
|
||||||
|
|
||||||
|
DataTypeNode dtNode = getSelectedDtNode();
|
||||||
|
|
||||||
|
// the user may have picked a data type node or a category node
|
||||||
|
if (dtNode != null) {
|
||||||
|
return dtNode.getDataType().getCategoryPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
CategoryNode categoryNode = getSelectedCategoryNode();
|
||||||
|
if (categoryNode != null) {
|
||||||
|
Category category = categoryNode.getCategory();
|
||||||
|
return category.getCategoryPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience method to show this dialog with the following configuration:
|
* A convenience method to show this dialog with the following configuration:
|
||||||
* <ul>
|
* <ul>
|
||||||
@@ -207,6 +275,10 @@ public class DataTypeChooserDialog extends DialogComponentProvider {
|
|||||||
tree.setFilterProvider(provider);
|
tree.setFilterProvider(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CategoryPath getSelectedCategoryPath() {
|
||||||
|
return selectedCategoryPath;
|
||||||
|
}
|
||||||
|
|
||||||
public DataType getSelectedDataType() {
|
public DataType getSelectedDataType() {
|
||||||
return selectedDataType;
|
return selectedDataType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,6 +137,15 @@ public interface DataTypeManagerService extends DataTypeQueryService, DataTypeAr
|
|||||||
*/
|
*/
|
||||||
public DataType getDataType(TreePath selectedPath);
|
public DataType getDataType(TreePath selectedPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the user a dialog that allows them to choose a category path from a tree of all
|
||||||
|
* available categories.
|
||||||
|
*
|
||||||
|
* @param selectedPath An optional tree path to select in the tree
|
||||||
|
* @return A category path chosen by the user
|
||||||
|
*/
|
||||||
|
public CategoryPath getCategoryPath(TreePath selectedPath);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Examines all enum dataTypes for items that match the given value. Returns a list of Strings
|
* Examines all enum dataTypes for items that match the given value. Returns a list of Strings
|
||||||
* that might make sense for the given value.
|
* that might make sense for the given value.
|
||||||
|
|||||||
@@ -40,6 +40,18 @@ public interface DataTypeQueryService {
|
|||||||
*/
|
*/
|
||||||
public List<DataType> getSortedDataTypeList();
|
public List<DataType> getSortedDataTypeList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user for a data type. The optional filter text will be used to filter the tree
|
||||||
|
* of available types.
|
||||||
|
* Gets the sorted list of all category paths known by this service via its owned
|
||||||
|
* DataTypeManagers. This method can be called frequently, as the underlying data is indexed
|
||||||
|
* and only updated as changes are made. The sorting of the list is done using the
|
||||||
|
* natural sort of the {@link CategoryPath} objects.
|
||||||
|
*
|
||||||
|
* @return the sorted list of known category paths.
|
||||||
|
*/
|
||||||
|
public List<CategoryPath> getSortedCategoryPathList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method simply calls {@link #promptForDataType(String)}
|
* This method simply calls {@link #promptForDataType(String)}
|
||||||
* @deprecated use {@link #promptForDataType(String)}
|
* @deprecated use {@link #promptForDataType(String)}
|
||||||
@@ -49,8 +61,10 @@ public interface DataTypeQueryService {
|
|||||||
public DataType getDataType(String filterText);
|
public DataType getDataType(String filterText);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prompts the user for a data type. The optional filter text will be used to filter the tree
|
* Obtain the preferred datatype which corresponds to the specified
|
||||||
* of available types.
|
* datatype specified by filterText. A tool-based service provider
|
||||||
|
* may prompt the user to select a datatype if more than one possibility
|
||||||
|
* exists.
|
||||||
*
|
*
|
||||||
* @param filterText If not null, this text filters the visible data types to only show those
|
* @param filterText If not null, this text filters the visible data types to only show those
|
||||||
* that start with the given text
|
* that start with the given text
|
||||||
|
|||||||
+466
@@ -0,0 +1,466 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.util.datatype;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.event.*;
|
||||||
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
|
import docking.widgets.DropDownSelectionTextField;
|
||||||
|
import docking.widgets.DropDownTextFieldDataModel;
|
||||||
|
import docking.widgets.button.BrowseButton;
|
||||||
|
import docking.widgets.list.GListCellRenderer;
|
||||||
|
import ghidra.app.services.DataTypeManagerService;
|
||||||
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
|
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
|
||||||
|
* category paths by name and offers the user of a completion window. This editor also provides a
|
||||||
|
* browse button that when pressed will show a data type tree so that the user may browse a tree
|
||||||
|
* of known category paths.
|
||||||
|
* <p>
|
||||||
|
* <u>Stand Alone Usage</u><br>
|
||||||
|
* In order to use this component directly you need to call {@link #getEditorComponent()}. This
|
||||||
|
* will give you a Component for editing.
|
||||||
|
* <p>
|
||||||
|
* In order to know when changes are made to the component you need to add a DocumentListener
|
||||||
|
* via the {@link #addDocumentListener(DocumentListener)} method. The added listener will be
|
||||||
|
* notified as the user enters text into the editor's text field.
|
||||||
|
*/
|
||||||
|
public class CategoryPathSelectionEditor extends AbstractCellEditor {
|
||||||
|
|
||||||
|
private JPanel editorPanel;
|
||||||
|
private DropDownSelectionTextField<CategoryPath> selectionField;
|
||||||
|
private JButton browseButton;
|
||||||
|
private DataTypeManagerService dataTypeManagerService;
|
||||||
|
|
||||||
|
private KeyAdapter keyListener;
|
||||||
|
private NavigationDirection navigationDirection;
|
||||||
|
|
||||||
|
// optional path to initially select in the data type chooser tree
|
||||||
|
private TreePath initiallySelectedTreePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
*
|
||||||
|
* @param serviceProvider {@link ServiceProvider}
|
||||||
|
*/
|
||||||
|
public CategoryPathSelectionEditor(ServiceProvider serviceProvider) {
|
||||||
|
|
||||||
|
this.dataTypeManagerService = serviceProvider.getService(DataTypeManagerService.class);
|
||||||
|
|
||||||
|
if (this.dataTypeManagerService == null) {
|
||||||
|
throw new NullPointerException("DataTypeManagerService cannot be null");
|
||||||
|
}
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this editor should consumer Enter key presses
|
||||||
|
* @see DropDownSelectionTextField#setConsumeEnterKeyPress(boolean)
|
||||||
|
*
|
||||||
|
* @param consume true to consume
|
||||||
|
*/
|
||||||
|
public void setConsumeEnterKeyPress(boolean consume) {
|
||||||
|
selectionField.setConsumeEnterKeyPress(consume);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DropDownSelectionTextField<CategoryPath> createDropDownSelectionTextField(
|
||||||
|
CategoryPathDropDownSelectionDataModel model) {
|
||||||
|
return new DropDownSelectionTextField<>(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
selectionField = createDropDownSelectionTextField(
|
||||||
|
new CategoryPathDropDownSelectionDataModel(dataTypeManagerService));
|
||||||
|
selectionField.addCellEditorListener(new CellEditorListener() {
|
||||||
|
@Override
|
||||||
|
public void editingCanceled(ChangeEvent e) {
|
||||||
|
fireEditingCanceled();
|
||||||
|
navigationDirection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void editingStopped(ChangeEvent e) {
|
||||||
|
fireEditingStopped();
|
||||||
|
navigationDirection = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
selectionField.addMouseListener(new MouseAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent event) {
|
||||||
|
selectionField.setEnabled(true);
|
||||||
|
selectionField.requestFocus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
selectionField.setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
|
||||||
|
browseButton = new BrowseButton();
|
||||||
|
browseButton.setToolTipText("Browse Existing Category Paths");
|
||||||
|
browseButton.addActionListener(e -> showBrowser());
|
||||||
|
|
||||||
|
editorPanel = new JPanel();
|
||||||
|
editorPanel.setLayout(new BoxLayout(editorPanel, BoxLayout.X_AXIS));
|
||||||
|
editorPanel.add(selectionField);
|
||||||
|
editorPanel.add(Box.createHorizontalStrut(5));
|
||||||
|
editorPanel.add(browseButton);
|
||||||
|
|
||||||
|
keyListener = new KeyAdapter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyPressed(KeyEvent e) {
|
||||||
|
int keyCode = e.getKeyCode();
|
||||||
|
if (keyCode == KeyEvent.VK_TAB) {
|
||||||
|
if (e.isShiftDown()) {
|
||||||
|
navigationDirection = NavigationDirection.BACKWARD;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
navigationDirection = NavigationDirection.FORWARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEditingStopped();
|
||||||
|
e.consume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the value in the cell.
|
||||||
|
* @return categoryPath of the selected value from the drop-down
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CategoryPath getCellEditorValue() {
|
||||||
|
return selectionField.getSelectedValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a path was selected from the drop-down list, it is already
|
||||||
|
* well-formed and cannot be null.
|
||||||
|
* @return the selected category path as CategoryPath
|
||||||
|
*/
|
||||||
|
public CategoryPath getCellEditorValueAsCategoryPath() {
|
||||||
|
return selectionField.getSelectedValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text value of the editor's text field.
|
||||||
|
* @return the text value of the editor's text field.
|
||||||
|
*/
|
||||||
|
public String getCellEditorValueAsText() {
|
||||||
|
return selectionField.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the component that allows the user to edit.
|
||||||
|
* @return the component that allows the user to edit.
|
||||||
|
*/
|
||||||
|
public JComponent getEditorComponent() {
|
||||||
|
return editorPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the dropdown text field that holds the category path collection.
|
||||||
|
* @return CategoryPath dropdown selection text field object
|
||||||
|
*/
|
||||||
|
public DropDownSelectionTextField<CategoryPath> getDropDownTextField() {
|
||||||
|
return selectionField;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The browse button which opens a menu with the Category Path collection from the data manager.
|
||||||
|
* @return browseButton
|
||||||
|
*/
|
||||||
|
public JButton getBrowseButton() {
|
||||||
|
return browseButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the initially selected node in the data type tree that the user can choose to
|
||||||
|
* show.
|
||||||
|
*
|
||||||
|
* @param path The path to set
|
||||||
|
*/
|
||||||
|
public void setDefaultSelectedTreePath(TreePath path) {
|
||||||
|
this.initiallySelectedTreePath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place focus on the selectionField.
|
||||||
|
*/
|
||||||
|
public void requestFocus() {
|
||||||
|
selectionField.requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlights the text of the cell editor.
|
||||||
|
*/
|
||||||
|
void selectCellEditorValue() {
|
||||||
|
selectionField.selectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the cell editor value as the entered String text.
|
||||||
|
* @param text String input
|
||||||
|
*/
|
||||||
|
public void setCellEditorValueAsText(String text) {
|
||||||
|
selectionField.setText(text);
|
||||||
|
navigationDirection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value to be edited on this cell editor.
|
||||||
|
*
|
||||||
|
* @param path The data type which is to be edited.
|
||||||
|
*/
|
||||||
|
public void setCellEditorValue(CategoryPath path) {
|
||||||
|
selectionField.setSelectedValue(path);
|
||||||
|
navigationDirection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a document listener to the text field editing component of this editor so that users
|
||||||
|
* can be notified when the text contents of the editor change.
|
||||||
|
* @param listener the listener to add.
|
||||||
|
*/
|
||||||
|
public void addDocumentListener(DocumentListener listener) {
|
||||||
|
selectionField.getDocument().addDocumentListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a previously added document listener.
|
||||||
|
* @param listener the listener to remove.
|
||||||
|
*/
|
||||||
|
public void removeDocumentListener(DocumentListener listener) {
|
||||||
|
selectionField.getDocument().removeDocumentListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the provided FocusListener to the selectionField.
|
||||||
|
* @param listener FocusListener
|
||||||
|
*/
|
||||||
|
public void addFocusListener(FocusListener listener) {
|
||||||
|
selectionField.addFocusListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the provided FocusListener from the selectionField.
|
||||||
|
* @param listener FocusListener
|
||||||
|
*/
|
||||||
|
public void removeFocusListener(FocusListener listener) {
|
||||||
|
selectionField.removeFocusListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle Tab key commits an edit. Sets the traversal key enabled field of the selectionField.
|
||||||
|
* @param doesCommit Boolean
|
||||||
|
*/
|
||||||
|
public void setTabCommitsEdit(boolean doesCommit) {
|
||||||
|
selectionField.setFocusTraversalKeysEnabled(!doesCommit);
|
||||||
|
|
||||||
|
removeKeyListener(keyListener); // always remove to prevent multiple additions
|
||||||
|
if (doesCommit) {
|
||||||
|
addKeyListener(keyListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the direction of the user triggered navigation; null if the user did not trigger
|
||||||
|
* navigation out of this component.
|
||||||
|
* @return the direction
|
||||||
|
*/
|
||||||
|
public NavigationDirection getNavigationDirection() {
|
||||||
|
return navigationDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addKeyListener(KeyListener listener) {
|
||||||
|
selectionField.addKeyListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeKeyListener(KeyListener listener) {
|
||||||
|
selectionField.removeKeyListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showBrowser() {
|
||||||
|
CategoryPath path = dataTypeManagerService.getCategoryPath(initiallySelectedTreePath);
|
||||||
|
if (path != null) {
|
||||||
|
setCellEditorValue(path);
|
||||||
|
selectionField.requestFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable the Category Path Text Field.
|
||||||
|
* @param createStructureByName Boolean
|
||||||
|
*/
|
||||||
|
public void setEnabled(boolean createStructureByName) {
|
||||||
|
selectionField.setEnabled(createStructureByName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the Category Path Text Field is enabled.
|
||||||
|
* @return isEnabled boolean
|
||||||
|
*/
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return selectionField.isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CategoryPathDropDownSelectionDataModel class handles the display and selection of a
|
||||||
|
* Category Path.
|
||||||
|
*/
|
||||||
|
private class CategoryPathDropDownSelectionDataModel
|
||||||
|
implements DropDownTextFieldDataModel<CategoryPath> {
|
||||||
|
|
||||||
|
private List<CategoryPath> data;
|
||||||
|
|
||||||
|
private Comparator<Object> searchComparator = new CategoryPathComparator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
*
|
||||||
|
* @param dataTypeService {@link DataTypeManagerService}
|
||||||
|
*/
|
||||||
|
public CategoryPathDropDownSelectionDataModel(DataTypeManagerService dataTypeService) {
|
||||||
|
data = dataTypeService.getSortedCategoryPathList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListCellRenderer<CategoryPath> getListRenderer() {
|
||||||
|
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
|
||||||
|
public String getDescription(CategoryPath categoryPath) {
|
||||||
|
return getDisplayText(categoryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the CategoryPath string representation.
|
||||||
|
*
|
||||||
|
* @param categoryPath CategoryPath
|
||||||
|
* @return String representation of the Category Path
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDisplayText(CategoryPath categoryPath) {
|
||||||
|
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
|
||||||
|
public List<CategoryPath> getMatchingData(String searchText) {
|
||||||
|
if (searchText == null || searchText.length() == 0) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
char END_CHAR = '\uffff';
|
||||||
|
String searchTextStart = searchText;
|
||||||
|
String searchTextEnd = searchText + END_CHAR;
|
||||||
|
|
||||||
|
int startIndex = Collections.binarySearch(data, searchTextStart, searchComparator);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
public int getIndexOfFirstMatchingEntry(List<CategoryPath> dataCollection, String text) {
|
||||||
|
int lastPreferredMatchIndex = -1;
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
CategoryPath dataType = data.get(i);
|
||||||
|
String dataTypeName = dataType.getName();
|
||||||
|
dataTypeName = dataTypeName.replaceAll(" ", "");
|
||||||
|
if (dataTypeName.equals(text)) {
|
||||||
|
// an exact match is the best possible match!
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataTypeName.equalsIgnoreCase(text)) {
|
||||||
|
// keep going, but remember this location, in case we don't find any more matches
|
||||||
|
lastPreferredMatchIndex = i;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// we've encountered a non-matching entry--nothing left to search
|
||||||
|
return lastPreferredMatchIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getItemText(CategoryPath path) {
|
||||||
|
return path.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getListCellRendererComponent(JList<? extends CategoryPath> list,
|
||||||
|
CategoryPath value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||||
|
|
||||||
|
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-8
@@ -22,7 +22,7 @@ import javax.swing.JPanel;
|
|||||||
import javax.swing.event.*;
|
import javax.swing.event.*;
|
||||||
|
|
||||||
import docking.DialogComponentProvider;
|
import docking.DialogComponentProvider;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
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.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
@@ -36,17 +36,17 @@ import ghidra.util.data.DataTypeParser.AllowedDataTypes;
|
|||||||
public class DataTypeSelectionDialog extends DialogComponentProvider {
|
public class DataTypeSelectionDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
private DataTypeSelectionEditor editor;
|
private DataTypeSelectionEditor editor;
|
||||||
private PluginTool pluginTool;
|
private ServiceProvider serviceProvider;
|
||||||
private DataType userChoice;
|
private DataType userChoice;
|
||||||
private int maxSize = -1;
|
private int maxSize = -1;
|
||||||
private DataTypeManager dtm;
|
private DataTypeManager dtm;
|
||||||
private final AllowedDataTypes allowedTypes;
|
private final AllowedDataTypes allowedTypes;
|
||||||
|
|
||||||
public DataTypeSelectionDialog(PluginTool pluginTool, DataTypeManager dtm, int maxSize,
|
public DataTypeSelectionDialog(ServiceProvider serviceProvider, DataTypeManager dtm,
|
||||||
DataTypeParser.AllowedDataTypes allowedTypes) {
|
int maxSize, DataTypeParser.AllowedDataTypes allowedTypes) {
|
||||||
super("Data Type Chooser Dialog", true, true, true, false);
|
super("Data Type Chooser Dialog", true, true, true, false);
|
||||||
|
|
||||||
this.pluginTool = pluginTool;
|
this.serviceProvider = serviceProvider;
|
||||||
this.dtm = dtm;
|
this.dtm = dtm;
|
||||||
this.maxSize = maxSize;
|
this.maxSize = maxSize;
|
||||||
this.allowedTypes = allowedTypes;
|
this.allowedTypes = allowedTypes;
|
||||||
@@ -65,7 +65,7 @@ public class DataTypeSelectionDialog extends DialogComponentProvider {
|
|||||||
private void buildEditor() {
|
private void buildEditor() {
|
||||||
removeWorkPanel();
|
removeWorkPanel();
|
||||||
|
|
||||||
editor = createEditor(pluginTool, allowedTypes);
|
editor = createEditor(serviceProvider, allowedTypes);
|
||||||
editor.setConsumeEnterKeyPress(false); // we want to handle Enter key presses
|
editor.setConsumeEnterKeyPress(false); // we want to handle Enter key presses
|
||||||
editor.addCellEditorListener(new CellEditorListener() {
|
editor.addCellEditorListener(new CellEditorListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -108,9 +108,9 @@ public class DataTypeSelectionDialog extends DialogComponentProvider {
|
|||||||
rootPanel.validate();
|
rootPanel.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DataTypeSelectionEditor createEditor(PluginTool tool,
|
protected DataTypeSelectionEditor createEditor(ServiceProvider sp,
|
||||||
AllowedDataTypes allowedDataTypes) {
|
AllowedDataTypes allowedDataTypes) {
|
||||||
return new DataTypeSelectionEditor(dtm, tool, allowedDataTypes);
|
return new DataTypeSelectionEditor(dtm, sp, allowedDataTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JComponent createEditorPanel(DataTypeSelectionEditor dtEditor) {
|
protected JComponent createEditorPanel(DataTypeSelectionEditor dtEditor) {
|
||||||
|
|||||||
@@ -352,6 +352,11 @@ public class FunctionSignatureParser {
|
|||||||
return service.getSortedDataTypeList();
|
return service.getSortedDataTypeList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CategoryPath> getSortedCategoryPathList() {
|
||||||
|
return service.getSortedCategoryPathList();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType getDataType(String filterText) {
|
public DataType getDataType(String filterText) {
|
||||||
return promptForDataType(filterText);
|
return promptForDataType(filterText);
|
||||||
|
|||||||
+3
-2
@@ -56,6 +56,7 @@ import ghidra.app.services.DataTypeManagerService;
|
|||||||
import ghidra.app.services.ProgramManager;
|
import ghidra.app.services.ProgramManager;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.program.database.ProgramBuilder;
|
import ghidra.program.database.ProgramBuilder;
|
||||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
@@ -123,9 +124,9 @@ public class DataTypeSelectionDialogTest extends AbstractGhidraHeadedIntegration
|
|||||||
dialog = new DataTypeSelectionDialog(tool, program.getDataTypeManager(), -1,
|
dialog = new DataTypeSelectionDialog(tool, program.getDataTypeManager(), -1,
|
||||||
AllowedDataTypes.ALL) {
|
AllowedDataTypes.ALL) {
|
||||||
@Override
|
@Override
|
||||||
protected DataTypeSelectionEditor createEditor(PluginTool pluginTool,
|
protected DataTypeSelectionEditor createEditor(ServiceProvider sp,
|
||||||
AllowedDataTypes allowedDataTypes) {
|
AllowedDataTypes allowedDataTypes) {
|
||||||
return new DataTypeSelectionEditor(null, pluginTool, allowedDataTypes) {
|
return new DataTypeSelectionEditor(null, sp, allowedDataTypes) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DropDownSelectionTextField<DataType> createDropDownSelectionTextField(
|
protected DropDownSelectionTextField<DataType> createDropDownSelectionTextField(
|
||||||
|
|||||||
+11
-1
@@ -50,7 +50,7 @@ public class TestDoubleDataTypeManagerService implements DataTypeManagerService
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType getDataType(String filterText) {
|
public List<CategoryPath> getSortedCategoryPathList() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,11 +161,21 @@ public class TestDoubleDataTypeManagerService implements DataTypeManagerService
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataType getDataType(String filterText) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType getDataType(TreePath selectedPath) {
|
public DataType getDataType(TreePath selectedPath) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CategoryPath getCategoryPath(TreePath selectedPath) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getPossibleEquateNames(long value) {
|
public Set<String> getPossibleEquateNames(long value) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|||||||
Reference in New Issue
Block a user