mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-10 07:08:21 +08:00
Merge remote-tracking branch 'origin/Ghidra_12.1'
This commit is contained in:
+7
@@ -35,6 +35,7 @@ public class DtFilterDialog extends DialogComponentProvider {
|
||||
private TypeComponent arraysComponent = new TypeComponent("Arrays");
|
||||
private TypeComponent enumsComponent = new TypeComponent("Enums");
|
||||
private TypeComponent functionsComponent = new TypeComponent("Functions");
|
||||
private TypeComponent otherComponent = new TypeComponent("Other");
|
||||
private TypeComponent pointersComponent = new TypeComponent("Pointers");
|
||||
private TypeComponent structuresComponent = new TypeComponent("Structures");
|
||||
private TypeComponent unionsComponent = new TypeComponent("Unions");
|
||||
@@ -77,6 +78,7 @@ public class DtFilterDialog extends DialogComponentProvider {
|
||||
newState.setArraysFilter(arraysComponent.getFilter());
|
||||
newState.setEnumsFilter(enumsComponent.getFilter());
|
||||
newState.setFunctionsFilter(functionsComponent.getFilter());
|
||||
newState.setOtherFilter(otherComponent.getFilter());
|
||||
newState.setPointersFilter(pointersComponent.getFilter());
|
||||
newState.setStructuresFilter(structuresComponent.getFilter());
|
||||
newState.setUnionsFilter(unionsComponent.getFilter());
|
||||
@@ -108,6 +110,8 @@ public class DtFilterDialog extends DialogComponentProvider {
|
||||
panel.add(structuresComponent.getRight());
|
||||
panel.add(unionsComponent.getLeft());
|
||||
panel.add(unionsComponent.getRight());
|
||||
panel.add(otherComponent.getLeft());
|
||||
panel.add(otherComponent.getRight());
|
||||
|
||||
GButton selectAll = new GButton("Select All");
|
||||
GButton deselectAll = new GButton("Deselect All");
|
||||
@@ -145,6 +149,8 @@ public class DtFilterDialog extends DialogComponentProvider {
|
||||
return List.of(
|
||||
arraysComponent.typeCb,
|
||||
arraysComponent.typeDefCb,
|
||||
otherComponent.typeCb,
|
||||
otherComponent.typeDefCb,
|
||||
enumsComponent.typeCb,
|
||||
enumsComponent.typeDefCb,
|
||||
functionsComponent.typeCb,
|
||||
@@ -161,6 +167,7 @@ public class DtFilterDialog extends DialogComponentProvider {
|
||||
|
||||
private void initCheckBoxes() {
|
||||
arraysComponent.init(filterState.getArraysFilter());
|
||||
otherComponent.init(filterState.getOtherFilter());
|
||||
enumsComponent.init(filterState.getEnumsFilter());
|
||||
functionsComponent.init(filterState.getFunctionsFilter());
|
||||
pointersComponent.init(filterState.getPointersFilter());
|
||||
|
||||
+21
-5
@@ -21,7 +21,6 @@ import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
/**
|
||||
* A simple object to store various filter settings for the data type provider.
|
||||
@@ -34,6 +33,7 @@ public class DtFilterState {
|
||||
private DtTypeFilter enumsFilter = new DtTypeFilter("Enums");
|
||||
private DtTypeFilter functionsFilter = new DtTypeFilter("Functions");
|
||||
private DtTypeFilter structuresFilter = new DtTypeFilter("Structures");
|
||||
private DtTypeFilter otherFilter = new DtTypeFilter("Other");
|
||||
private DtTypeFilter pointersFilter = new DtTypeFilter("Pointers");
|
||||
private DtTypeFilter unionsFilter = new DtTypeFilter("Unions");
|
||||
|
||||
@@ -46,6 +46,7 @@ public class DtFilterState {
|
||||
public DtFilterState copy() {
|
||||
DtFilterState filterState = new DtFilterState();
|
||||
filterState.arraysFilter = arraysFilter.copy();
|
||||
filterState.otherFilter = otherFilter.copy();
|
||||
filterState.enumsFilter = enumsFilter.copy();
|
||||
filterState.functionsFilter = functionsFilter.copy();
|
||||
filterState.structuresFilter = structuresFilter.copy();
|
||||
@@ -66,6 +67,18 @@ public class DtFilterState {
|
||||
this.arraysFilter = filter;
|
||||
}
|
||||
|
||||
public boolean isShowOther() {
|
||||
return otherFilter.isTypeActive();
|
||||
}
|
||||
|
||||
public DtTypeFilter getOtherFilter() {
|
||||
return otherFilter;
|
||||
}
|
||||
|
||||
public void setOtherFilter(DtTypeFilter filter) {
|
||||
this.otherFilter = filter;
|
||||
}
|
||||
|
||||
public boolean isShowEnums() {
|
||||
return enumsFilter.isTypeActive();
|
||||
}
|
||||
@@ -155,7 +168,7 @@ public class DtFilterState {
|
||||
return passes(enumsFilter, dt);
|
||||
}
|
||||
|
||||
if (baseDt instanceof Function) {
|
||||
if (baseDt instanceof FunctionDefinition) {
|
||||
return passes(functionsFilter, dt);
|
||||
}
|
||||
|
||||
@@ -167,7 +180,7 @@ public class DtFilterState {
|
||||
return passes(unionsFilter, dt);
|
||||
}
|
||||
|
||||
return true;
|
||||
return passes(otherFilter, dt);
|
||||
}
|
||||
|
||||
private boolean passes(DtTypeFilter filter, DataType dt) {
|
||||
@@ -184,6 +197,7 @@ public class DtFilterState {
|
||||
ss.putSaveState(arraysFilter.getName(), arraysFilter.save());
|
||||
ss.putSaveState(enumsFilter.getName(), enumsFilter.save());
|
||||
ss.putSaveState(functionsFilter.getName(), functionsFilter.save());
|
||||
ss.putSaveState(otherFilter.getName(), otherFilter.save());
|
||||
ss.putSaveState(pointersFilter.getName(), pointersFilter.save());
|
||||
ss.putSaveState(structuresFilter.getName(), structuresFilter.save());
|
||||
ss.putSaveState(unionsFilter.getName(), unionsFilter.save());
|
||||
@@ -201,6 +215,7 @@ public class DtFilterState {
|
||||
arraysFilter = DtTypeFilter.restore("Arrays", ss.getSaveState("Arrays"));
|
||||
enumsFilter = DtTypeFilter.restore("Enums", ss.getSaveState("Enums"));
|
||||
functionsFilter = DtTypeFilter.restore("Functions", ss.getSaveState("Functions"));
|
||||
otherFilter = DtTypeFilter.restore("Other", ss.getSaveState("Other"));
|
||||
pointersFilter = DtTypeFilter.restore("Pointers", ss.getSaveState("Pointers"));
|
||||
structuresFilter = DtTypeFilter.restore("Structures", ss.getSaveState("Structures"));
|
||||
unionsFilter = DtTypeFilter.restore("Unions", ss.getSaveState("Unions"));
|
||||
@@ -208,8 +223,8 @@ public class DtFilterState {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(arraysFilter, enumsFilter, functionsFilter, pointersFilter,
|
||||
structuresFilter, unionsFilter);
|
||||
return Objects.hash(arraysFilter, enumsFilter, functionsFilter,
|
||||
otherFilter, pointersFilter, structuresFilter, unionsFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -227,6 +242,7 @@ public class DtFilterState {
|
||||
return Objects.equals(arraysFilter, other.arraysFilter) &&
|
||||
Objects.equals(enumsFilter, other.enumsFilter) &&
|
||||
Objects.equals(functionsFilter, other.functionsFilter) &&
|
||||
Objects.equals(otherFilter, other.otherFilter) &&
|
||||
Objects.equals(pointersFilter, other.pointersFilter) &&
|
||||
Objects.equals(structuresFilter, other.structuresFilter) &&
|
||||
Objects.equals(unionsFilter, other.unionsFilter);
|
||||
|
||||
+6
-2
@@ -214,10 +214,14 @@ class ProgramSaveManager {
|
||||
}
|
||||
try {
|
||||
DataTreeDialog dialog = getSaveDialog();
|
||||
String filename = program.getDomainFile().getName();
|
||||
DomainFile domainFile = program.getDomainFile();
|
||||
String filename = domainFile.getName();
|
||||
dialog.setTitle("Save As (" + filename + ")");
|
||||
dialog.setNameText(filename + ".1");
|
||||
dialog.setSelectedFolder(program.getDomainFile().getParent());
|
||||
|
||||
DomainFolder parent = domainFile.getParent();
|
||||
dialog.setSelectedFolder(parent);
|
||||
|
||||
treeDialogCancelled = true;
|
||||
tool.showDialog(dialog);
|
||||
if (!treeDialogCancelled) {
|
||||
|
||||
+109
-70
@@ -189,6 +189,10 @@ public abstract class AbstractDataTreeDialog extends DialogComponentProvider
|
||||
return nameField.getText();
|
||||
}
|
||||
|
||||
public String getFolderText() {
|
||||
return folderNameLabel.getText();
|
||||
}
|
||||
|
||||
public void setNameText(String name) {
|
||||
// We need to run this code in a task since the tree may already be processing other tasks
|
||||
// that would override this setting when they are run. But putting this task in the queue,
|
||||
@@ -242,89 +246,124 @@ public abstract class AbstractDataTreeDialog extends DialogComponentProvider
|
||||
return domainFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* TreeSelectionListener method that is called whenever the value of the selection changes.
|
||||
* @param e the event that characterizes the change.
|
||||
*/
|
||||
@Override
|
||||
public void valueChanged(GTreeSelectionEvent e) {
|
||||
clearStatusText();
|
||||
|
||||
if (type == CHOOSE_FOLDER) {
|
||||
domainFolder = treePanel.getSelectedDomainFolder();
|
||||
if (domainFolder != null) {
|
||||
DomainFolder folderParent = domainFolder.getParent();
|
||||
if (folderParent != null) {
|
||||
folderNameLabel.setText(folderParent.getPathname());
|
||||
}
|
||||
else {
|
||||
folderNameLabel.setText(" ");
|
||||
}
|
||||
|
||||
nameField.setText(domainFolder.getName());
|
||||
}
|
||||
else {
|
||||
domainFile = treePanel.getSelectedDomainFile();
|
||||
if (domainFile != null) {
|
||||
domainFolder = domainFile.getParent();
|
||||
DomainFolder grandParent = domainFolder.getParent();
|
||||
if (grandParent != null) {
|
||||
folderNameLabel.setText(grandParent.getPathname());
|
||||
}
|
||||
else {
|
||||
folderNameLabel.setText("");
|
||||
}
|
||||
|
||||
nameField.setText(domainFolder.getName());
|
||||
}
|
||||
else {
|
||||
domainFolder = project.getProjectData().getRootFolder();
|
||||
folderNameLabel.setText(domainFolder.getPathname());
|
||||
nameField.setText(domainFolder.getName());
|
||||
}
|
||||
}
|
||||
updateFromTreeSelectionInFolderMode();
|
||||
}
|
||||
else {
|
||||
domainFile = treePanel.getSelectedDomainFile();
|
||||
if (domainFile != null) {
|
||||
LinkFileInfo linkInfo = domainFile.getLinkInfo();
|
||||
if (linkInfo != null && linkInfo.isFolderLink()) {
|
||||
// Ensure we don't have a folder name conflict
|
||||
if (domainFile.getParent().getFolder(domainFile.getName()) == null) {
|
||||
domainFolder = linkInfo.getLinkedFolder();
|
||||
domainFile = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
folderNameLabel.setText(domainFile.getParent().getPathname());
|
||||
nameField.setText(domainFile.getName());
|
||||
domainFolder = domainFile.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
if (domainFile == null) {
|
||||
if (domainFolder == null) {
|
||||
domainFolder = treePanel.getSelectedDomainFolder();
|
||||
if (domainFolder == null) {
|
||||
domainFolder = project.getProjectData().getRootFolder();
|
||||
}
|
||||
}
|
||||
folderNameLabel.setText(domainFolder.getPathname());
|
||||
if (nameField.isEditable()) {
|
||||
if (nameField.getText().length() > 0) {
|
||||
nameField.selectAll();
|
||||
}
|
||||
}
|
||||
else {
|
||||
nameField.setText("");
|
||||
}
|
||||
}
|
||||
updateFromTreeSelectionInFileMode();
|
||||
}
|
||||
|
||||
String text = nameField.getText();
|
||||
setOkEnabled((text != null) && !text.isEmpty());
|
||||
}
|
||||
|
||||
private void updateFromTreeSelectionInFileMode() {
|
||||
DomainFile newFile = treePanel.getSelectedDomainFile();
|
||||
if (isFolderLink(newFile)) {
|
||||
updateFromFolderLink(newFile);
|
||||
return;
|
||||
}
|
||||
|
||||
// not a folder link; see if we have a new file selected
|
||||
if (newFile != null) {
|
||||
domainFile = newFile;
|
||||
domainFolder = domainFile.getParent();
|
||||
String pathname = domainFolder.getPathname();
|
||||
folderNameLabel.setText(pathname);
|
||||
String filename = domainFile.getName();
|
||||
nameField.setText(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
// No selected domain file
|
||||
domainFile = null;
|
||||
domainFolder = getSelectedFolder();
|
||||
String pathname = domainFolder.getPathname();
|
||||
folderNameLabel.setText(pathname);
|
||||
updateNameFieldTextForNoFileSelected();
|
||||
}
|
||||
|
||||
private void updateNameFieldTextForNoFileSelected() {
|
||||
if (!nameField.isEditable()) {
|
||||
nameField.setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nameField.getText().length() > 0) {
|
||||
nameField.selectAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFromFolderLink(DomainFile newFile) {
|
||||
|
||||
LinkFileInfo linkInfo = newFile.getLinkInfo();
|
||||
DomainFolder folder = newFile.getParent();
|
||||
String filename = newFile.getName();
|
||||
|
||||
// Ensure we don't have a folder name conflict
|
||||
if (folder.getFolder(filename) == null) {
|
||||
domainFolder = linkInfo.getLinkedFolder();
|
||||
if (domainFolder == null) {
|
||||
domainFolder = getSelectedFolder();
|
||||
}
|
||||
|
||||
domainFile = null;
|
||||
folderNameLabel.setText(domainFolder.getPathname());
|
||||
updateNameFieldTextForNoFileSelected();
|
||||
return;
|
||||
}
|
||||
|
||||
domainFile = newFile;
|
||||
folderNameLabel.setText(folder.getPathname());
|
||||
nameField.setText(filename);
|
||||
domainFolder = folder;
|
||||
}
|
||||
|
||||
private boolean isFolderLink(DomainFile file) {
|
||||
if (file == null) {
|
||||
return false;
|
||||
}
|
||||
LinkFileInfo linkInfo = file.getLinkInfo();
|
||||
return linkInfo != null && linkInfo.isFolderLink();
|
||||
}
|
||||
|
||||
private void updateFromTreeSelectionInFolderMode() {
|
||||
|
||||
// The tree selection has changed and we are in FOLDER mode. Update the folder selection
|
||||
// based on type of node selected.
|
||||
domainFolder = getSelectedFolder();
|
||||
DomainFolder folderParent = domainFolder.getParent();
|
||||
if (folderParent == null) {
|
||||
folderParent = domainFolder; // root folder; no parent
|
||||
}
|
||||
|
||||
folderNameLabel.setText(folderParent.getPathname());
|
||||
nameField.setText(domainFolder.getName());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selected folder, or the selected file's parent or the root folder.
|
||||
* @return the folder
|
||||
*/
|
||||
private DomainFolder getSelectedFolder() {
|
||||
DomainFolder folder = treePanel.getSelectedDomainFolder();
|
||||
if (folder != null) {
|
||||
return folder;
|
||||
}
|
||||
|
||||
DomainFile file = treePanel.getSelectedDomainFile();
|
||||
if (file != null) {
|
||||
return file.getParent();
|
||||
}
|
||||
|
||||
return project.getProjectData().getRootFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
int index = projectComboBox.getSelectedIndex();
|
||||
|
||||
+52
-6
@@ -41,6 +41,8 @@ import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private static final String TEST_FOLDER_NAME = "TestFolder";
|
||||
|
||||
private TestEnv env;
|
||||
private FrontEndTool frontEndTool;
|
||||
private DataTreeDialog dialog;
|
||||
@@ -70,6 +72,10 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
DomainFolder domainFolder = ProjectDataUtils.createDomainFolderPath(rootFolder, path);
|
||||
result.add(domainFolder.createFile(filename, p, TaskMonitor.DUMMY));
|
||||
}
|
||||
|
||||
// add a test folder
|
||||
ProjectDataUtils.createDomainFolderPath(rootFolder, "/" + TEST_FOLDER_NAME);
|
||||
|
||||
builder.dispose();
|
||||
waitForSwing();
|
||||
return result;
|
||||
@@ -116,7 +122,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertNameHasText(true);
|
||||
|
||||
// select a folder--text remains; button enabled
|
||||
selectFolder();
|
||||
selectRootFolder();
|
||||
assertOK(true);
|
||||
assertNameHasText(true);
|
||||
|
||||
@@ -125,6 +131,16 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertOK(true);
|
||||
assertNameHasText(true);
|
||||
|
||||
// select a non-root folder--text remains; button enabled
|
||||
selectTestFolder();
|
||||
assertOK(true);
|
||||
assertNameHasText(true);
|
||||
assertFolderText("/" + TEST_FOLDER_NAME);
|
||||
|
||||
deselectFolder();
|
||||
assertOK(true);
|
||||
assertNameHasText(true);
|
||||
|
||||
// clear text--disabled
|
||||
clearText();
|
||||
assertOK(false);
|
||||
@@ -147,7 +163,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertNameHasText(true);
|
||||
|
||||
// select a folder--text remains; button enabled
|
||||
selectFolder();
|
||||
selectRootFolder();
|
||||
assertOK(true);
|
||||
assertNameHasText(true);
|
||||
|
||||
@@ -185,7 +201,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertNameHasText(true); // "/"
|
||||
|
||||
// select a folder--enabled
|
||||
selectFolder();
|
||||
selectRootFolder();
|
||||
assertOK(true);
|
||||
assertNameHasText(true);
|
||||
|
||||
@@ -212,7 +228,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertNameHasText(false);
|
||||
|
||||
// select a folder--disabled
|
||||
selectFolder();
|
||||
selectRootFolder();
|
||||
assertOK(false);
|
||||
|
||||
// de-select a folder--disabled
|
||||
@@ -237,7 +253,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertNameHasText(false);
|
||||
|
||||
// select a folder--disabled
|
||||
selectFolder();
|
||||
selectRootFolder();
|
||||
assertOK(false);
|
||||
|
||||
// de-select a folder--disabled
|
||||
@@ -321,7 +337,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
});
|
||||
}
|
||||
|
||||
private void selectFolder() {
|
||||
private void selectRootFolder() {
|
||||
final AtomicBoolean result = new AtomicBoolean(false);
|
||||
final GTree gTree = getGTree();
|
||||
runSwing(() -> {
|
||||
@@ -340,6 +356,31 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
waitForTree(gTree);
|
||||
}
|
||||
|
||||
private void selectTestFolder() {
|
||||
|
||||
AtomicBoolean result = new AtomicBoolean(false);
|
||||
GTree gTree = getGTree();
|
||||
runSwing(() -> {
|
||||
GTreeNode root = gTree.getViewRoot();
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
GTreeNode folderNode = root.getChild(TEST_FOLDER_NAME);
|
||||
if (folderNode != null) {
|
||||
gTree.expandPath(root);
|
||||
gTree.setSelectedNode(folderNode);
|
||||
result.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
if (!result.get()) {
|
||||
Assert.fail("Unable to select root folder");
|
||||
}
|
||||
|
||||
waitForTree(gTree);
|
||||
}
|
||||
|
||||
private void deselectFile() {
|
||||
clearSelection();
|
||||
}
|
||||
@@ -350,6 +391,11 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
waitForTree(gTree);
|
||||
}
|
||||
|
||||
private void assertFolderText(String expectedName) {
|
||||
String actualName = runSwing(() -> dialog.getFolderText());
|
||||
assertEquals("Dialog folder path not correct", expectedName, actualName);
|
||||
}
|
||||
|
||||
private void assertNameHasText(boolean hasText) {
|
||||
final AtomicBoolean result = new AtomicBoolean();
|
||||
runSwing(() -> {
|
||||
|
||||
Reference in New Issue
Block a user