GP-4583 Fixed issue where open program were not being shown when the OpenVersionedFileDialog was being shown from diff

This commit is contained in:
ghidragon 2024-05-10 13:19:21 -04:00
parent c4ea004218
commit a3f16ff05f
30 changed files with 790 additions and 661 deletions

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.debug.gui.modules;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.event.MouseEvent;
import java.io.File;
import java.lang.invoke.MethodHandles;
@ -1190,7 +1192,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
DomainFileFilter filter = df -> Program.class.isAssignableFrom(df.getDomainObjectClass());
return new DataTreeDialog(null, "Map Module to Program", DataTreeDialog.OPEN, filter);
return new DataTreeDialog(null, "Map Module to Program", OPEN, filter);
}
public DomainFile askProgram(Program program) {

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.debug.service.tracemgr;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.ConnectException;
@ -430,7 +432,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
}
};
return new DataTreeDialog(null, OpenTraceAction.NAME, DataTreeDialog.OPEN, filter);
return new DataTreeDialog(null, OpenTraceAction.NAME, OPEN, filter);
}
public DomainFile askTrace(Trace trace) {

View File

@ -15,6 +15,8 @@
*/
package ghidra.machinelearning.functionfinding;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.BorderLayout;
import java.util.*;
import java.util.stream.Collectors;
@ -483,10 +485,11 @@ public class FunctionStartRFParamsDialog extends ReusableDialogComponentProvider
}
private void searchOtherProgram(RandomForestRowObject modelRow) {
DataTreeDialog dtd = new DataTreeDialog(null, "Select Program", DataTreeDialog.OPEN, f -> {
Class<?> c = f.getDomainObjectClass();
return Program.class.isAssignableFrom(c);
});
DataTreeDialog dtd =
new DataTreeDialog(null, "Select Program", OPEN, f -> {
Class<?> c = f.getDomainObjectClass();
return Program.class.isAssignableFrom(c);
});
dtd.show();
DomainFile dFile = dtd.getDomainFile();
if (dFile == null) {

View File

@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import static ghidra.framework.main.DataTreeDialogType.*;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@ -137,7 +139,7 @@ public class FixLangId extends GhidraScript {
public DomainFile askProgramFile(String title) {
final DomainFile[] domainFile = new DomainFile[] { null };
final DataTreeDialog dtd = new DataTreeDialog(null, title, DataTreeDialog.OPEN);
final DataTreeDialog dtd = new DataTreeDialog(null, title, OPEN);
dtd.addOkActionListener(e -> {
dtd.close();
domainFile[0] = dtd.getDomainFile();

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.analysis;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.Component;
import java.awt.event.MouseListener;
import java.beans.PropertyEditorSupport;
@ -126,7 +128,7 @@ public class ProjectPathChooserEditor extends PropertyEditorSupport {
private void displayFileChooser() {
AtomicReference<String> result = new AtomicReference<>();
DataTreeDialog dataTreeDialog =
new DataTreeDialog(this, title, DataTreeDialog.OPEN, filter);
new DataTreeDialog(this, title, OPEN, filter);
dataTreeDialog.addOkActionListener(e -> {
dataTreeDialog.close();
DomainFile df = dataTreeDialog.getDomainFile();

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.datamgr.archive;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.Component;
import java.awt.event.ActionListener;
import java.io.*;
@ -31,6 +33,7 @@ import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
import ghidra.app.util.HelpTopics;
import ghidra.framework.client.*;
import ghidra.framework.main.DataTreeDialog;
import ghidra.framework.main.DataTreeDialogType;
import ghidra.framework.model.*;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.PluginTool;
@ -1410,7 +1413,7 @@ public class DataTypeManagerHandler {
private DataTreeDialog getSaveDialog() {
DataTreeDialog dialog =
new DataTreeDialog(null, "Save As", DataTreeDialog.SAVE, createArchiveFileFilter);
new DataTreeDialog(null, "Save As", SAVE, createArchiveFileFilter);
ActionListener listener = event -> {
DomainFolder folder = dialog.getDomainFolder();
@ -1442,7 +1445,7 @@ public class DataTypeManagerHandler {
private CreateDataTypeArchiveDataTreeDialog getCreateDialog() {
CreateDataTypeArchiveDataTreeDialog dialog = new CreateDataTypeArchiveDataTreeDialog(null,
"Create", DataTreeDialog.CREATE, createArchiveFileFilter);
"Create", CREATE, createArchiveFileFilter);
ActionListener listener = event -> {
DomainFolder folder = dialog.getDomainFolder();
@ -1498,7 +1501,7 @@ public class DataTypeManagerHandler {
private DataTypeArchiveDB dataTypeArchiveDB;
CreateDataTypeArchiveDataTreeDialog(Component parent, String title, int type,
CreateDataTypeArchiveDataTreeDialog(Component parent, String title, DataTreeDialogType type,
DomainFileFilter filter) {
super(parent, title, type, filter);
}

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.gotoquery;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.util.Stack;
import org.apache.commons.lang3.StringUtils;
@ -437,7 +439,7 @@ public class GoToHelper {
}
DataTreeDialog dialog = new DataTreeDialog(null,
"Choose External Program (" + extProgName + ")", DataTreeDialog.OPEN);
"Choose External Program (" + extProgName + ")", OPEN);
dialog.setSearchText(extProgName);
dialog.setHelpLocation(new HelpLocation("ReferencesPlugin", "ChooseExternalProgram"));
tool.showDialog(dialog);

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.progmgr;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.rmi.ConnectException;
@ -442,7 +444,7 @@ class ProgramSaveManager {
private DataTreeDialog getSaveDialog() {
DataTreeDialog dialog =
new DataTreeDialog(null, "Save As", DataTreeDialog.SAVE, domainFileFilter);
new DataTreeDialog(null, "Save As", SAVE, domainFileFilter);
ActionListener listener = event -> {
DomainFolder folder = dialog.getDomainFolder();

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.references;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.*;
@ -186,7 +188,7 @@ class EditExternalReferencePanel extends EditReferencePanel {
*/
private void popupProgramChooser() {
DataTreeDialog d =
new DataTreeDialog(this.getParent(), "Choose External Program", DataTreeDialog.OPEN);
new DataTreeDialog(this.getParent(), "Choose External Program", OPEN);
final DataTreeDialog dialog = d;
d.addOkActionListener(new ActionListener() {
@Override

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.references;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.BorderLayout;
import java.awt.event.MouseEvent;
import java.util.*;
@ -236,7 +238,7 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
List<String> selectedExternalNames = getSelectedExternalNames();
String externalName = selectedExternalNames.get(0); // must be exactly one for us to be enabled.
DataTreeDialog dialog = new DataTreeDialog(mainPanel,
"Choose External Program (" + externalName + ")", DataTreeDialog.OPEN);
"Choose External Program (" + externalName + ")", OPEN);
dialog.setSearchText(externalName);

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.symboltree;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.*;
import java.awt.event.ItemListener;
import java.util.Arrays;
@ -269,7 +271,7 @@ class EditExternalLocationPanel extends JPanel {
*/
private void popupProgramChooser() {
DataTreeDialog d =
new DataTreeDialog(this.getParent(), "Choose External Program", DataTreeDialog.OPEN);
new DataTreeDialog(this.getParent(), "Choose External Program", OPEN);
final DataTreeDialog dialog = d;
d.addOkActionListener(e -> {
DomainFile df = dialog.getDomainFile();

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.symboltree.actions;
import static ghidra.framework.main.DataTreeDialogType.*;
import javax.swing.Icon;
import javax.swing.SwingUtilities;
import javax.swing.tree.TreePath;
@ -81,7 +83,7 @@ public class SetExternalProgramAction extends SymbolTreeContextAction {
final String externalLibraryPath = externalManager.getExternalLibraryPath(externalName);
final DataTreeDialog dialog = new DataTreeDialog(provider.getComponent(),
"Choose External Program (" + externalName + ")", DataTreeDialog.OPEN);
"Choose External Program (" + externalName + ")", OPEN);
dialog.setSearchText(externalName);

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.script;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.Color;
import java.io.*;
import java.rmi.ConnectException;
@ -2304,7 +2306,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
DomainFolder choice = doAsk(Program.class, title, "", existingValue, lastValue -> {
DataTreeDialog dtd = new DataTreeDialog(null, title, DataTreeDialog.CHOOSE_FOLDER);
DataTreeDialog dtd = new DataTreeDialog(null, title, CHOOSE_FOLDER);
dtd.show();
if (dtd.wasCancelled()) {
throw new CancelledException();
@ -2834,7 +2836,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
if (!isRunningHeadless()) {
choice = doAsk(Program.class, title, "", choice, lastValue -> {
DataTreeDialog dtd = new DataTreeDialog(null, title, DataTreeDialog.OPEN);
DataTreeDialog dtd = new DataTreeDialog(null, title, OPEN);
dtd.show();
if (dtd.wasCancelled()) {
return null;
@ -2939,7 +2941,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
String message = "";
DomainFile choice = doAsk(DomainFile.class, title, message, existingValue, lastValue -> {
DataTreeDialog dtd = new DataTreeDialog(null, title, DataTreeDialog.OPEN);
DataTreeDialog dtd = new DataTreeDialog(null, title, OPEN);
dtd.show();
if (dtd.wasCancelled()) {
throw new CancelledException();

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.util;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.*;
import java.util.*;
import java.util.List;
@ -276,7 +278,7 @@ public class OptionsEditorPanel extends JPanel {
JButton button = new BrowseButton();
button.addActionListener(e -> {
DataTreeDialog dataTreeDialog =
new DataTreeDialog(this, "Choose a project folder", DataTreeDialog.CHOOSE_FOLDER);
new DataTreeDialog(this, "Choose a project folder", CHOOSE_FOLDER);
String folderPath = lastFolderPath.isBlank() ? "/" : lastFolderPath;
dataTreeDialog.setSelectedFolder(project.getProjectData().getFolder(folderPath));
dataTreeDialog.showComponent();

View File

@ -22,6 +22,7 @@ import javax.swing.*;
import docking.widgets.button.BrowseButton;
import ghidra.framework.main.DataTreeDialog;
import ghidra.framework.main.DataTreeDialogType;
import ghidra.framework.model.*;
import ghidra.framework.store.FileSystem;
@ -33,10 +34,11 @@ abstract class AbstractProjectBrowserPanel extends JPanel {
protected JTextField textField;
private JButton browseButton;
private DomainFolder startFolder;
private int type;
private DataTreeDialogType type;
protected DomainFileFilter filter = null;
AbstractProjectBrowserPanel(int type, Project project, String name, String startPath) {
AbstractProjectBrowserPanel(DataTreeDialogType type, Project project, String name,
String startPath) {
super(new BorderLayout());
this.type = type;
this.project = Objects.requireNonNull(project);

View File

@ -15,6 +15,8 @@
*/
package ghidra.features.base.values;
import static ghidra.framework.main.DataTreeDialogType.*;
import javax.swing.JComponent;
import javax.swing.JTextField;
@ -168,7 +170,7 @@ public class ProjectFileValue extends AbstractValue<DomainFile> {
ProjectFileBrowserPanel(Project project, String name, String startPath,
Class<? extends DomainObject> projectFileClass) {
super(DataTreeDialog.OPEN, project, name, startPath);
super(OPEN, project, name, startPath);
filter = df -> projectFileClass.isAssignableFrom(df.getDomainObjectClass());
}

View File

@ -15,6 +15,8 @@
*/
package ghidra.features.base.values;
import static ghidra.framework.main.DataTreeDialogType.*;
import javax.swing.JComponent;
import javax.swing.JTextField;
@ -123,7 +125,7 @@ public class ProjectFolderValue extends AbstractValue<DomainFolder> {
class ProjectFolderBrowserPanel extends AbstractProjectBrowserPanel {
ProjectFolderBrowserPanel(Project project, String name, String startPath) {
super(DataTreeDialog.CHOOSE_FOLDER, project, name, startPath);
super(CHOOSE_FOLDER, project, name, startPath);
}
void setDomainFolder(DomainFolder value) {

View File

@ -0,0 +1,602 @@
/* ###
* 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.framework.main;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.*;
import java.awt.event.*;
import java.util.HashSet;
import java.util.Set;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import docking.*;
import docking.event.mouse.GMouseListenerAdapter;
import docking.widgets.combobox.GComboBox;
import docking.widgets.label.GDLabel;
import docking.widgets.label.GLabel;
import docking.widgets.tree.support.GTreeSelectionEvent;
import docking.widgets.tree.support.GTreeSelectionListener;
import ghidra.framework.main.datatree.DialogProjectTreeContext;
import ghidra.framework.main.datatree.ProjectDataTreePanel;
import ghidra.framework.main.projectdata.actions.*;
import ghidra.framework.model.*;
import ghidra.util.Msg;
import ghidra.util.Swing;
import ghidra.util.exception.AssertException;
import ghidra.util.layout.PairLayout;
/**
* Base dialog for choosing DomainFiles. Provides and manages the base data tree panel. Subclasses
* should call the buildDataTreePanel() when they are constructing their main panels. They should
* also call the initializeFocusedComponent() method so that default focus for the dialog is in
* the text field if it is enabled or otherwise the focus should be the tree.
*/
public abstract class AbstractDataTreeDialog extends DialogComponentProvider
implements GTreeSelectionListener, ActionListener {
protected final static int WIDTH = 350;
protected final static int HEIGHT = 500;
protected ProjectDataTreePanel treePanel;
private JComboBox<String> projectComboBox; // used for open data
private ProjectLocator[] projectLocators;
private DomainFileFilter filter;
private JTextField nameField;
private JLabel folderNameLabel;
private ActionListener okActionListener;
private DomainFolder domainFolder;
private DomainFile domainFile;
private DataTreeDialogType type;
private Component parent;
private String searchString;
private boolean cancelled = false;
private ProjectDataExpandAction<DialogProjectTreeContext> expandAction;
private ProjectDataCollapseAction<DialogProjectTreeContext> collapseAction;
private ProjectDataNewFolderAction<DialogProjectTreeContext> newFolderAction;
private Integer treeSelectionMode;
private final Project project;
/**
* Construct a new DataTreeDialog for the given project.
*
* @param parent dialog's parent
* @param title title to use
* @param type specify OPEN, SAVE, CHOOSE_FOLDER, or CHOOSE_USER_FOLDER
* @param filter filter used to control what is displayed in the data tree
* @param project the project to browse
* @throws IllegalArgumentException if invalid type is specified
*/
protected AbstractDataTreeDialog(Component parent, String title, DataTreeDialogType type,
DomainFileFilter filter, Project project) {
super(title, true, true, true, false);
this.project = project;
this.parent = parent;
this.type = type;
this.filter = filter;
initializeButtons();
rootPanel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
createActions();
}
protected void initializeFocusedComponent() {
Component focusComponent = nameField;
if (!nameField.isEditable()) {
focusComponent = treePanel.getFilterField();
}
setFocusComponent(focusComponent);
}
public void setTreeSelectionMode(int mode) {
if (treePanel != null) {
treePanel.getTreeSelectionModel().setSelectionMode(mode);
}
treeSelectionMode = mode;
}
private void initializeButtons() {
addOKButton();
addCancelButton();
if (type == SAVE) {
okButton.setText("Save");
okButton.setMnemonic('S');
}
else if (type == CREATE) {
okButton.setText("Create");
okButton.setMnemonic('C');
}
setOkEnabled(false);
}
private void createActions() {
String owner = "DataTreeDialogActions";
String groupName = "Cut/copy/paste/new";
newFolderAction = new DialogProjectDataNewFolderAction(owner, groupName);
groupName = "Expand/Collapse";
expandAction = new DialogProjectDataExpandAction(owner, groupName);
collapseAction = new DialogProjectDataCollapseAction(owner, groupName);
addAction(newFolderAction);
addAction(expandAction);
addAction(collapseAction);
}
/**
* Add action listener that is called when the OK button is hit.
* @param l listener to add
*/
public void addOkActionListener(ActionListener l) {
okActionListener = l;
}
@Override
public ActionContext getActionContext(MouseEvent event) {
if (treePanel == null) {
// must have been closed; some kind of timing issue
return super.getActionContext(event);
}
return treePanel.getActionContext(null, event);
}
public void show() {
DockingWindowManager.showDialog(parent, this);
}
/**
* Shows this dialog. The preferred show method is {@link #show()}, as it is the preferred
* nomenclature.
*/
public void showComponent() {
show();
}
public String getNameText() {
return nameField.getText();
}
public void setNameText(String name) {
nameField.setText(name.trim());
nameField.selectAll();
}
/**
* Sets a domain folder as the initially selected folder when the dialog is first shown.
*
* @param folder {@link DomainFolder} to select when showing the dialog
*/
public void setSelectedFolder(DomainFolder folder) {
if (folder != null) {
treePanel.selectDomainFolder(folder);
}
}
/**
* Get the selected domain file.
* @return null if there was no domain file selected
*/
public DomainFile getDomainFile() {
if (domainFile != null) {
return domainFile;
}
if (cancelled) {
return null;
}
if (treePanel != null) {
domainFile = treePanel.getSelectedDomainFile();
}
return domainFile;
}
/**
* Get the selected folder.
* @return null if there was no domain folder selected
*/
public DomainFolder getDomainFolder() {
if (cancelled) {
return null;
}
if (domainFolder == null) {
domainFolder = treePanel.getSelectedDomainFolder();
}
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());
}
}
}
else {
domainFile = treePanel.getSelectedDomainFile();
if (domainFile != null) {
folderNameLabel.setText(domainFile.getParent().getPathname());
nameField.setText(domainFile.getName());
domainFolder = domainFile.getParent();
}
else {
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("");
}
}
}
String text = nameField.getText();
setOkEnabled((text != null) && !text.isEmpty());
}
@Override
public void actionPerformed(ActionEvent event) {
int index = projectComboBox.getSelectedIndex();
if (index < 0) {
return;
}
ProjectLocator projectLocator = projectLocators[index];
ProjectData pd = project.getProjectData(projectLocator);
String projectName = projectLocator.getName();
if (pd == null) {
Msg.showError(this, getComponent(), "Error Getting Project Data",
"Could not get project data for " + projectName);
}
else {
treePanel.setProjectData(projectName, pd);
}
}
/**
* Select the root folder in the tree.
*/
public void selectRootDataFolder() {
Swing.runLater(() -> treePanel.selectRootDataFolder());
}
/**
* Select a folder in the tree.
* @param folder the folder to select
*/
public void selectFolder(DomainFolder folder) {
Swing.runLater(() -> treePanel.selectDomainFolder(folder));
}
/**
* Select the node that corresponds to the given domain file.
* @param file the file
*/
public void selectDomainFile(DomainFile file) {
Swing.runLater(() -> treePanel.selectDomainFile(file));
}
@Override
public void close() {
super.close();
removeWorkPanel();
if (treePanel != null) {
treePanel.dispose();
}
treePanel = null;
}
protected JPanel buildDataTreePanel() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
JPanel namePanel = createNamePanel();
// data tree panel must be created before the combo box
JPanel dataTreePanel = createDataTreePanel();
ProjectData pd = project.getProjectData();
treePanel.setProjectData(project.getName(), pd);
treePanel.selectRootDataFolder();
if (type == OPEN) {
JPanel comboPanel = createComboBoxPanel();
panel.add(comboPanel, BorderLayout.NORTH);
populateProjectModel();
}
panel.add(dataTreePanel, BorderLayout.CENTER);
panel.add(namePanel, BorderLayout.SOUTH);
// can't add tree listeners until everything is built
addTreeListeners();
return panel;
}
@Override
protected void okCallback() {
cancelled = false;
if (okActionListener == null) {
close();
return;
}
okActionListener.actionPerformed(new ActionEvent(okButton, 0, okButton.getActionCommand()));
}
public boolean wasCancelled() {
return cancelled;
}
@Override
protected void cancelCallback() {
cancelled = true;
close();
}
/**
* Create the data tree panel.
*/
private JPanel createDataTreePanel() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
ProjectData pd = project.getProjectData();
treePanel = new ProjectDataTreePanel(project.getName(), true, // is for the active project
null, filter);
if (treeSelectionMode != null) {
treePanel.getTreeSelectionModel().setSelectionMode(treeSelectionMode);
}
treePanel.setProjectData(project.getName(), pd);
treePanel.addTreeSelectionListener(this);
treePanel.setPreferredTreePanelSize(new Dimension(150, 150));
// don't put the filter in the dialog when the user can/must type a name, as it's confusing
boolean userChoosesName = (type == SAVE) || (type == CREATE);
treePanel.setTreeFilterEnabled(!userChoosesName);
panel.add(treePanel, BorderLayout.CENTER);
return panel;
}
protected void addTreeListeners() {
if (type == OPEN) {
treePanel.addTreeMouseListener(new GMouseListenerAdapter() {
@Override
public void doubleClickTriggered(MouseEvent e) {
if (okButton.isEnabled()) {
okCallback();
}
}
});
}
}
/**
* Create the combo box panel that shows list of project names that
* are currently open, including the active project.
*/
private JPanel createComboBoxPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setBorder(new TitledBorder("Current Projects"));
projectComboBox = new GComboBox<>();
DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
projectComboBox.setModel(model);
model.addElement("defaultProject");
panel.add(projectComboBox, BorderLayout.CENTER);
projectComboBox.addActionListener(this);
return panel;
}
private JPanel createNamePanel() {
JPanel outerPanel = new JPanel();
outerPanel.setLayout(new BorderLayout(5, 0));
nameField = new JTextField(12);
nameField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
update();
}
private void update() {
String text = nameField.getText();
switch (type) {
case OPEN:
// handled by valueChanged()
break;
case SAVE:
if (text == null || text.isEmpty()) {
DomainFile file = treePanel.getSelectedDomainFile();
okButton.setEnabled(file != null);
}
break;
case CREATE:
if (text == null || text.isEmpty()) {
DomainFile file = treePanel.getSelectedDomainFile();
okButton.setEnabled(file != null);
}
break;
case CHOOSE_FOLDER:
// handled by valueChanged()
break;
default:
throw new AssertException("Must handle new type!: " + type);
}
setOkEnabled((text != null) && !text.isEmpty());
}
@Override
public void insertUpdate(DocumentEvent e) {
update();
}
@Override
public void changedUpdate(DocumentEvent e) {
update();
}
});
boolean userChoosesName = (type == SAVE) || (type == CREATE);
nameField.setEditable(userChoosesName);
nameField.setEnabled(userChoosesName);
JPanel namePanel = new JPanel(new PairLayout(2, 5, 100));
if (!userChoosesName) {
namePanel.setBorder(BorderFactory.createEmptyBorder(20, 5, 5, 5));
}
namePanel.add(new GLabel("Folder Path:", SwingConstants.RIGHT));
folderNameLabel = new GDLabel(" ");
namePanel.add(folderNameLabel);
namePanel.add(
new GLabel(type == CHOOSE_FOLDER ? "Folder Name:" : "Name:", SwingConstants.RIGHT));
namePanel.add(nameField);
outerPanel.add(namePanel, BorderLayout.CENTER);
FieldKeyListener l = new FieldKeyListener();
nameField.addKeyListener(l);
nameField.addActionListener(e -> okCallback());
return outerPanel;
}
private void populateProjectModel() {
ProjectLocator[] views = project.getProjectViews();
projectLocators = new ProjectLocator[views.length + 1];
// make the current project the first in the list
projectLocators[0] = project.getProjectLocator();
for (int i = 0; i < views.length; i++) {
projectLocators[i + 1] = views[i];
}
// populate the combo box
DefaultComboBoxModel<String> model =
(DefaultComboBoxModel<String>) projectComboBox.getModel();
model.removeAllElements();
Set<String> map = new HashSet<>();
for (ProjectLocator projectLocator : projectLocators) {
String name = projectLocator.getName();
if (map.contains(name)) {
model.addElement(name + " (" + projectLocator.getLocation() + ")");
}
else {
map.add(name);
model.addElement(name);
}
}
map = null;
}
public void setSearchText(String s) {
if (searchString != null) {
treePanel.findAndSelect(s);
}
}
protected static DomainFileFilter getDefaultFilter(DataTreeDialogType type) {
if (type == CHOOSE_FOLDER || type == OPEN) {
// return filter which forces folder selection and allow navigation into linked-folders
return new DomainFileFilter() {
@Override
public boolean accept(DomainFile df) {
return true; // show all files (legacy behavior)
}
};
}
return null;
}
private class FieldKeyListener extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
clearStatusText();
}
}
}

View File

@ -15,85 +15,26 @@
*/
package ghidra.framework.main;
import java.awt.*;
import java.awt.event.*;
import java.util.HashSet;
import java.util.Set;
import java.awt.Component;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import docking.*;
import docking.event.mouse.GMouseListenerAdapter;
import docking.widgets.combobox.GComboBox;
import docking.widgets.label.GDLabel;
import docking.widgets.label.GLabel;
import docking.widgets.tree.support.GTreeSelectionEvent;
import docking.widgets.tree.support.GTreeSelectionListener;
import ghidra.framework.main.datatree.DialogProjectTreeContext;
import ghidra.framework.main.datatree.ProjectDataTreePanel;
import ghidra.framework.main.projectdata.actions.*;
import ghidra.framework.model.*;
import ghidra.util.Msg;
import ghidra.util.Swing;
import ghidra.util.exception.AssertException;
import ghidra.util.layout.PairLayout;
import ghidra.framework.model.DomainFileFilter;
import ghidra.framework.model.Project;
/**
* Dialog to open or save domain data items to a new location or name.
*/
public class DataTreeDialog extends DialogComponentProvider
implements GTreeSelectionListener, ActionListener {
public class DataTreeDialog extends AbstractDataTreeDialog {
/**
* Dialog type for opening domain data files.
*/
public final static int OPEN = 0;
/**
* Dialog type for saving domain data files.
*/
public final static int SAVE = 1;
/**
* Dialog type for choosing a user folder.
*/
public final static int CHOOSE_FOLDER = 2;
/**
* Dialog type for creating domain data files.
*/
public final static int CREATE = 3;
protected final static int WIDTH = 350;
protected final static int HEIGHT = 500;
protected ProjectDataTreePanel treePanel;
private JComboBox<String> projectComboBox; // used for open data
private ProjectLocator[] projectLocators;
private DomainFileFilter filter;
private JTextField nameField;
private JLabel folderNameLabel;
private ActionListener okActionListener;
private DomainFolder domainFolder;
private DomainFile domainFile;
private int type;
private Component parent;
private String searchString;
private boolean cancelled = false;
private ProjectDataExpandAction<DialogProjectTreeContext> expandAction;
private ProjectDataCollapseAction<DialogProjectTreeContext> collapseAction;
private ProjectDataNewFolderAction<DialogProjectTreeContext> newFolderAction;
private Integer treeSelectionMode;
private final Project project;
// These are here for backwards compatibility with legacy code
public final static DataTreeDialogType OPEN = DataTreeDialogType.OPEN;
public final static DataTreeDialogType SAVE = DataTreeDialogType.SAVE;
public final static DataTreeDialogType CHOOSE_FOLDER = DataTreeDialogType.CHOOSE_FOLDER;
public final static DataTreeDialogType CREATE = DataTreeDialogType.CREATE;
/**
* Construct a new DataTreeDialog for the active project. This chooser will show all project
* files. Following linked-folders will only be allowed if a type of {@link #CHOOSE_FOLDER}
* or {@link #OPEN} is specified. If different behavior is required a filter should
* files. Following linked-folders will only be allowed if a type of CHOOSE_FOLDER
* or OPEN is specified. If different behavior is required a filter should
* be specified using the other constructor.
*
* @param parent dialog's parent
@ -101,8 +42,8 @@ public class DataTreeDialog extends DialogComponentProvider
* @param type specify OPEN, SAVE, CHOOSE_FOLDER, CHOOSE_USER_FOLDER, or CREATE
* @throws IllegalArgumentException if invalid type is specified
*/
public DataTreeDialog(Component parent, String title, int type) {
this(parent, title, type, getDefaultFilter(type), AppInfo.getActiveProject());
public DataTreeDialog(Component parent, String title, DataTreeDialogType type) {
this(parent, title, type, getDefaultFilter(type));
}
/**
@ -110,11 +51,12 @@ public class DataTreeDialog extends DialogComponentProvider
*
* @param parent dialog's parent
* @param title title to use
* @param type specify OPEN, SAVE, CHOOSE_FOLDER, or CHOOSE_USER_FOLDER
* @param type specify OPEN, SAVE, CHOOSE_FOLDER, or CREATE
* @param filter filter used to control what is displayed in the data tree
* @throws IllegalArgumentException if invalid type is specified
*/
public DataTreeDialog(Component parent, String title, int type, DomainFileFilter filter) {
public DataTreeDialog(Component parent, String title, DataTreeDialogType type,
DomainFileFilter filter) {
this(parent, title, type, filter, AppInfo.getActiveProject());
}
@ -123,527 +65,17 @@ public class DataTreeDialog extends DialogComponentProvider
*
* @param parent dialog's parent
* @param title title to use
* @param type specify OPEN, SAVE, CHOOSE_FOLDER, or CHOOSE_USER_FOLDER
* @param type specify OPEN, SAVE, CHOOSE_FOLDER, or CREATE
* @param filter filter used to control what is displayed in the data tree
* @param project the project to browse
* @throws IllegalArgumentException if invalid type is specified
*/
public DataTreeDialog(Component parent, String title, int type, DomainFileFilter filter,
Project project) {
super(title, true, true, true, false);
if (type < 0 || type > CREATE) {
throw new IllegalArgumentException("Invalid type specified: " + type);
}
this.project = project;
this.parent = parent;
this.type = type;
this.filter = filter;
addWorkPanel(buildMainPanel());
initializeButtons();
rootPanel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
public DataTreeDialog(Component parent, String title, DataTreeDialogType type,
DomainFileFilter filter, Project project) {
super(parent, title, type, filter, project);
addWorkPanel(buildDataTreePanel());
initializeFocusedComponent();
createActions();
}
private void initializeFocusedComponent() {
Component focusComponent = nameField;
if (!nameField.isEditable()) {
focusComponent = treePanel.getFilterField();
}
setFocusComponent(focusComponent);
}
public void setTreeSelectionMode(int mode) {
if (treePanel != null) {
treePanel.getTreeSelectionModel().setSelectionMode(mode);
}
treeSelectionMode = mode;
}
private void initializeButtons() {
addOKButton();
addCancelButton();
if (type == SAVE) {
okButton.setText("Save");
okButton.setMnemonic('S');
}
else if (type == CREATE) {
okButton.setText("Create");
okButton.setMnemonic('C');
}
setOkEnabled(false);
}
private void createActions() {
String owner = "DataTreeDialogActions";
String groupName = "Cut/copy/paste/new";
newFolderAction = new DialogProjectDataNewFolderAction(owner, groupName);
groupName = "Expand/Collapse";
expandAction = new DialogProjectDataExpandAction(owner, groupName);
collapseAction = new DialogProjectDataCollapseAction(owner, groupName);
addAction(newFolderAction);
addAction(expandAction);
addAction(collapseAction);
}
/**
* Add action listener that is called when the OK button is hit.
* @param l listener to add
*/
public void addOkActionListener(ActionListener l) {
okActionListener = l;
}
@Override
public ActionContext getActionContext(MouseEvent event) {
if (treePanel == null) {
// must have been closed; some kind of timing issue
return super.getActionContext(event);
}
return treePanel.getActionContext(null, event);
}
public void show() {
DockingWindowManager.showDialog(parent, this);
}
/**
* Shows this dialog. The preferred show method is {@link #show()}, as it is the preferred
* nomenclature.
*/
public void showComponent() {
show();
}
public String getNameText() {
return nameField.getText();
}
public void setNameText(String name) {
nameField.setText(name.trim());
nameField.selectAll();
}
/**
* Sets a domain folder as the initially selected folder when the dialog is first shown.
*
* @param folder {@link DomainFolder} to select when showing the dialog
*/
public void setSelectedFolder(DomainFolder folder) {
if (folder != null) {
treePanel.selectDomainFolder(folder);
}
}
/**
* Get the selected domain file.
* @return null if there was no domain file selected
*/
public DomainFile getDomainFile() {
if (domainFile != null) {
return domainFile;
}
if (cancelled) {
return null;
}
if (treePanel != null) {
domainFile = treePanel.getSelectedDomainFile();
}
return domainFile;
}
/**
* Get the selected folder.
* @return null if there was no domain folder selected
*/
public DomainFolder getDomainFolder() {
if (cancelled) {
return null;
}
if (domainFolder == null) {
domainFolder = treePanel.getSelectedDomainFolder();
}
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());
}
}
}
else {
domainFile = treePanel.getSelectedDomainFile();
if (domainFile != null) {
folderNameLabel.setText(domainFile.getParent().getPathname());
nameField.setText(domainFile.getName());
domainFolder = domainFile.getParent();
}
else {
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("");
}
}
}
String text = nameField.getText();
setOkEnabled((text != null) && !text.isEmpty());
}
@Override
public void actionPerformed(ActionEvent event) {
int index = projectComboBox.getSelectedIndex();
if (index < 0) {
return;
}
ProjectLocator projectLocator = projectLocators[index];
ProjectData pd = project.getProjectData(projectLocator);
String projectName = projectLocator.getName();
if (pd == null) {
Msg.showError(this, getComponent(), "Error Getting Project Data",
"Could not get project data for " + projectName);
}
else {
treePanel.setProjectData(projectName, pd);
}
}
/**
* Select the root folder in the tree.
*/
public void selectRootDataFolder() {
Swing.runLater(() -> treePanel.selectRootDataFolder());
}
/**
* Select a folder in the tree.
* @param folder the folder to select
*/
public void selectFolder(DomainFolder folder) {
Swing.runLater(() -> treePanel.selectDomainFolder(folder));
}
/**
* Select the node that corresponds to the given domain file.
* @param file the file
*/
public void selectDomainFile(DomainFile file) {
Swing.runLater(() -> treePanel.selectDomainFile(file));
}
@Override
public void close() {
super.close();
removeWorkPanel();
if (treePanel != null) {
treePanel.dispose();
}
treePanel = null;
}
protected JPanel buildMainPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
JPanel namePanel = createNamePanel();
// data tree panel must be created before the combo box
JPanel dataTreePanel = createDataTreePanel();
ProjectData pd = project.getProjectData();
treePanel.setProjectData(project.getName(), pd);
treePanel.selectRootDataFolder();
if (type == OPEN) {
JPanel comboPanel = createComboBoxPanel();
panel.add(comboPanel, BorderLayout.NORTH);
populateProjectModel();
}
panel.add(dataTreePanel, BorderLayout.CENTER);
panel.add(namePanel, BorderLayout.SOUTH);
// can't add tree listeners until everything is built
addTreeListeners();
return panel;
}
@Override
protected void okCallback() {
cancelled = false;
if (okActionListener == null) {
close();
return;
}
okActionListener.actionPerformed(new ActionEvent(okButton, 0, okButton.getActionCommand()));
}
public boolean wasCancelled() {
return cancelled;
}
@Override
protected void cancelCallback() {
cancelled = true;
close();
}
/**
* Create the data tree panel.
*/
private JPanel createDataTreePanel() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
ProjectData pd = project.getProjectData();
treePanel = new ProjectDataTreePanel(project.getName(), true, // is for the active project
null, filter);
if (treeSelectionMode != null) {
treePanel.getTreeSelectionModel().setSelectionMode(treeSelectionMode);
}
treePanel.setProjectData(project.getName(), pd);
treePanel.addTreeSelectionListener(this);
treePanel.setPreferredTreePanelSize(new Dimension(150, 150));
// don't put the filter in the dialog when the user can/must type a name, as it's confusing
boolean userChoosesName = (type == SAVE) || (type == CREATE);
treePanel.setTreeFilterEnabled(!userChoosesName);
panel.add(treePanel, BorderLayout.CENTER);
return panel;
}
protected void addTreeListeners() {
if (type == OPEN) {
treePanel.addTreeMouseListener(new GMouseListenerAdapter() {
@Override
public void doubleClickTriggered(MouseEvent e) {
if (okButton.isEnabled()) {
okCallback();
}
}
});
}
}
/**
* Create the combo box panel that shows list of project names that
* are currently open, including the active project.
*/
private JPanel createComboBoxPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setBorder(new TitledBorder("Current Projects"));
projectComboBox = new GComboBox<>();
DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
projectComboBox.setModel(model);
model.addElement("defaultProject");
panel.add(projectComboBox, BorderLayout.CENTER);
projectComboBox.addActionListener(this);
return panel;
}
private JPanel createNamePanel() {
JPanel outerPanel = new JPanel();
outerPanel.setLayout(new BorderLayout(5, 0));
nameField = new JTextField(12);
nameField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
update();
}
private void update() {
String text = nameField.getText();
switch (type) {
case OPEN:
// handled by valueChanged()
break;
case SAVE:
if (text == null || text.isEmpty()) {
DomainFile file = treePanel.getSelectedDomainFile();
okButton.setEnabled(file != null);
}
break;
case CREATE:
if (text == null || text.isEmpty()) {
DomainFile file = treePanel.getSelectedDomainFile();
okButton.setEnabled(file != null);
}
break;
case CHOOSE_FOLDER:
// handled by valueChanged()
break;
default:
throw new AssertException("Must handle new type!: " + type);
}
setOkEnabled((text != null) && !text.isEmpty());
}
@Override
public void insertUpdate(DocumentEvent e) {
update();
}
@Override
public void changedUpdate(DocumentEvent e) {
update();
}
});
boolean userChoosesName = (type == SAVE) || (type == CREATE);
nameField.setEditable(userChoosesName);
nameField.setEnabled(userChoosesName);
JPanel namePanel = new JPanel(new PairLayout(2, 5, 100));
if (!userChoosesName) {
namePanel.setBorder(BorderFactory.createEmptyBorder(20, 5, 5, 5));
}
namePanel.add(new GLabel("Folder Path:", SwingConstants.RIGHT));
folderNameLabel = new GDLabel(" ");
namePanel.add(folderNameLabel);
namePanel.add(
new GLabel(type == CHOOSE_FOLDER ? "Folder Name:" : "Name:", SwingConstants.RIGHT));
namePanel.add(nameField);
outerPanel.add(namePanel, BorderLayout.CENTER);
FieldKeyListener l = new FieldKeyListener();
nameField.addKeyListener(l);
nameField.addActionListener(e -> okCallback());
return outerPanel;
}
private void populateProjectModel() {
ProjectLocator[] views = project.getProjectViews();
projectLocators = new ProjectLocator[views.length + 1];
// make the current project the first in the list
projectLocators[0] = project.getProjectLocator();
for (int i = 0; i < views.length; i++) {
projectLocators[i + 1] = views[i];
}
// populate the combo box
DefaultComboBoxModel<String> model =
(DefaultComboBoxModel<String>) projectComboBox.getModel();
model.removeAllElements();
Set<String> map = new HashSet<>();
for (ProjectLocator projectLocator : projectLocators) {
String name = projectLocator.getName();
if (map.contains(name)) {
model.addElement(name + " (" + projectLocator.getLocation() + ")");
}
else {
map.add(name);
model.addElement(name);
}
}
map = null;
}
public void setSearchText(String s) {
if (searchString != null) {
treePanel.findAndSelect(s);
}
}
private static DomainFileFilter getDefaultFilter(int type) {
if (type == CHOOSE_FOLDER || type == OPEN) {
// return filter which forces folder selection and allow navigation into linked-folders
return new DomainFileFilter() {
@Override
public boolean accept(DomainFile df) {
return true; // show all files (legacy behavior)
}
};
}
return null;
}
private class FieldKeyListener extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
clearStatusText();
}
}
}

View File

@ -0,0 +1,38 @@
/* ###
* 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.framework.main;
/**
* Types of ways to use a DataTreeDialog.
*/
public enum DataTreeDialogType {
/**
* Dialog type for opening domain data files
*/
OPEN,
/**
* Dialog type for saving domain data files
*/
SAVE,
/**
* Dialog type for choosing a user folder
*/
CHOOSE_FOLDER,
/**
* Dialog type for creating domain data files
*/
CREATE
}

View File

@ -15,10 +15,11 @@
*/
package ghidra.framework.main;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -40,7 +41,7 @@ import ghidra.util.Msg;
* opened.
* @param <T> domain object class
*/
public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDialog {
public class OpenVersionedFileDialog<T extends DomainObject> extends AbstractDataTreeDialog {
private static final String SHOW_HISTORY_PREFERENCES_KEY = "OPEN_PROGRAM_DIALOG.SHOW_HISTORY";
private static final String HEIGHT_PREFERENCES_KEY = "OPEN_PROGRAM_DIALOG.HEIGHT";
private static final String WIDTH_NO_HISTORY_PREFERENCES_KEY =
@ -76,12 +77,30 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
* @param domainObjectClass allowed domain object class which corresponds to {@code <T>}
*/
public OpenVersionedFileDialog(PluginTool tool, String title, Class<T> domainObjectClass) {
super(tool.getToolFrame(), title, DataTreeDialog.OPEN, f -> {
this(tool, title, domainObjectClass, null);
}
/**
* Constructor
* @param tool tool where the file is being opened.
* @param title title to use
* @param domainObjectClass allowed domain object class which corresponds to {@code <T>}
* @param openDomainObjects if non-null, will cause an additional tab showing the given
* list of open domain objects that the user can select from
*/
public OpenVersionedFileDialog(PluginTool tool, String title, Class<T> domainObjectClass,
List<T> openDomainObjects) {
super(tool.getToolFrame(), title, OPEN, f -> {
return domainObjectClass.isAssignableFrom(f.getDomainObjectClass());
});
}, AppInfo.getActiveProject());
this.tool = tool;
this.domainObjectClass = domainObjectClass;
this.openDomainObjects = openDomainObjects;
addWorkPanel(buildMainPanel());
initializeFocusedComponent();
updateOkTooltip();
checkIfHistoryWasOpen();
}
@ -95,20 +114,6 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
}
}
/**
* Set an optional list of already open domain objects of type {@code <T>} which may be
* selected instead of a project domain file. The {@link #getDomainObject(Object, boolean)}
* method should be used when this optional list has been set. If this dialog is reused
* the list should be set null if previously set. This method must be invoked prior to
* showing the dialog.
* @param openDomainObjects list of open domain objects from which a selection may be made.
*/
public void setOpenObjectChoices(List<T> openDomainObjects) {
this.openDomainObjects = (openDomainObjects != null && !openDomainObjects.isEmpty())
? new ArrayList<>(openDomainObjects)
: null;
}
/**
* Get the selected domain object for read-only or immutable use.
* If an existing open object is selected its original mode applies but consumer will
@ -173,7 +178,6 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
return super.getDomainFolder();
}
@Override
protected JPanel buildMainPanel() {
historyButton = new JButton("History>>");
historyButton.addActionListener(e -> showHistoryPanel(!historyIsShowing));
@ -181,7 +185,7 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
rootPanel.setPreferredSize(getPreferredSizeForHistoryState());
mainPanel = new JPanel(new BorderLayout());
mainPanel.add(super.buildMainPanel(), BorderLayout.CENTER);
mainPanel.add(buildDataTreePanel(), BorderLayout.CENTER);
JPanel historyButtonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
historyButtonPanel.add(historyButton);
mainPanel.add(historyButtonPanel, BorderLayout.SOUTH);
@ -201,7 +205,7 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
openObjectsTable = null;
tabbedPane = null;
if (openDomainObjects == null) {
if (openDomainObjects == null || openDomainObjects.isEmpty()) {
return projectFilePanel; // return Project File selection panel only
}

View File

@ -15,6 +15,8 @@
*/
package ghidra.plugin.importer;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
@ -571,7 +573,7 @@ public class ImporterDialog extends DialogComponentProvider {
private void chooseProjectFolder() {
DataTreeDialog dataTreeDialog = new DataTreeDialog(getComponent(),
"Choose a project folder", DataTreeDialog.CHOOSE_FOLDER);
"Choose a project folder", CHOOSE_FOLDER);
dataTreeDialog.setSelectedFolder(destinationFolder);
dataTreeDialog.showComponent();
DomainFolder folder = dataTreeDialog.getDomainFolder();

View File

@ -21,8 +21,7 @@ import javax.swing.*;
import docking.widgets.button.BrowseButton;
import docking.widgets.label.GDLabel;
import ghidra.framework.main.AppInfo;
import ghidra.framework.main.DataTreeDialog;
import ghidra.framework.main.*;
import ghidra.framework.model.*;
class BatchProjectDestinationPanel extends JPanel {
@ -96,7 +95,7 @@ class BatchProjectDestinationPanel extends JPanel {
private void browseFolders() {
DataTreeDialog dataTreeDialog =
new DataTreeDialog(parent, "Choose a project folder", DataTreeDialog.CHOOSE_FOLDER);
new DataTreeDialog(parent, "Choose a project folder", DataTreeDialogType.CHOOSE_FOLDER);
dataTreeDialog.addOkActionListener(e -> {
dataTreeDialog.close();
setFolder(dataTreeDialog.getDomainFolder());

View File

@ -15,6 +15,7 @@
*/
package ghidra.framework.main;
import static ghidra.framework.main.DataTreeDialogType.*;
import static org.junit.Assert.*;
import java.util.*;
@ -110,7 +111,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testOKButtonDisabled_Type_SAVE() {
// no initial selection--button disabled
show(DataTreeDialog.SAVE);
show(SAVE);
assertOK(false);
// select a file--enabled; name field populated
@ -141,7 +142,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testOKButtonDisabled_Type_CREATE() {
// no initial selection--button disabled
show(DataTreeDialog.CREATE);
show(CREATE);
assertOK(false);
// select a file--enabled; name field populated
@ -172,7 +173,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testOKButtonAlwaysEnabled_Type_CHOOSE_FOLDER() {
// no initial selection--button disabled
show(DataTreeDialog.CHOOSE_FOLDER);
show(CHOOSE_FOLDER);
assertOK(true);
// select a file--enabled; name field populated
@ -199,7 +200,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testOKButtonDisabled_Type_OPEN() {
// no initial selection--button disabled
show(DataTreeDialog.OPEN);
show(OPEN);
assertOK(false);
// select a file--enabled; name field populated
@ -224,7 +225,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testOKButtonEnabledWithInitialSelection_Type_OPEN() {
// initial selection--button enabled
show(DataTreeDialog.OPEN, "x07");
show(OPEN, "x07");
assertOK(true);
// select a file--enabled; name field populated
@ -250,7 +251,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
public void testSelectFiles() throws Exception {
List<DomainFile> createdFiles = createBlankProgramsInProject(
List.of("/dir1/dir2/file1", "/dir1/dir2a/dir3a/file2", "/file3"));
show(DataTreeDialog.OPEN);
show(OPEN);
Set<DomainFile> selectedProjectElements = new HashSet<>();
ProjectDataTreePanel projectDataTreePanel = getProjectDataTreePanel();
@ -280,7 +281,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
public void testSelectFolder() throws Exception {
List<DomainFile> createdFiles = createBlankProgramsInProject(
List.of("/dir1/dir2/file1", "/dir1/dir2a/dir3a/file2", "/file3"));
show(DataTreeDialog.OPEN);
show(OPEN);
Set<DomainFolder> selectedProjectElements = new HashSet<>();
ProjectDataTreePanel projectDataTreePanel = getProjectDataTreePanel();
@ -398,7 +399,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
waitForTree(gTree);
}
private void show(final int type) {
private void show(DataTreeDialogType type) {
SwingUtilities.invokeLater(() -> {
dialog = new DataTreeDialog(frontEndTool.getToolFrame(), "Test Data Tree Dialog", type);
@ -408,7 +409,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
assertNotNull(dialog);
}
private void show(final int type, final String name) {
private void show(DataTreeDialogType type, final String name) {
SwingUtilities.invokeLater(() -> {
dialog = new DataTreeDialog(frontEndTool.getToolFrame(), "Test Data Tree Dialog", type);
@ -424,7 +425,7 @@ public class DataTreeDialogTest extends AbstractGhidraHeadedIntegrationTest {
private void showFiltered(final String startsWith) {
SwingUtilities.invokeLater(() -> {
dialog = new DataTreeDialog(frontEndTool.getToolFrame(), "Test Data Tree Dialog",
DataTreeDialog.OPEN, f -> f.getName().startsWith(startsWith));
OPEN, f -> f.getName().startsWith(startsWith));
dialog.showComponent();
});
waitForSwing();

View File

@ -15,6 +15,8 @@
*/
package ghidra.feature.fid.plugin;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.BorderLayout;
import java.awt.Component;
import java.io.File;
@ -225,7 +227,7 @@ public class PopulateFidDialog extends DialogComponentProvider {
JButton browseButton = new BrowseButton();
browseButton.addActionListener(e -> {
final DataTreeDialog dialog = new DataTreeDialog(tool.getToolFrame(),
"Choose Root Folder", DataTreeDialog.CHOOSE_FOLDER);
"Choose Root Folder", CHOOSE_FOLDER);
tool.showDialog(dialog);
DomainFolder domainFolder = dialog.getDomainFolder();
if (domainFolder != null) {

View File

@ -150,6 +150,8 @@ public class ProgramDiffPlugin extends ProgramPlugin
DiffApplySettingsOptionManager applySettingsMgr;
private boolean isHighlightCursorLine;
private Program activeProgram;
// this is used for test injection only. In actual use, the dialog is not reused
private OpenVersionedFileDialog<Program> openVersionedFileDialog;
/**
@ -1141,10 +1143,9 @@ public class ProgramDiffPlugin extends ProgramPlugin
return;
}
final OpenVersionedFileDialog<Program> dialog = getOpenVersionedFileDialog();
List<Program> openProgramList = getOpenProgramList();
dialog.setOpenObjectChoices(openProgramList.isEmpty() ? null : openProgramList);
OpenVersionedFileDialog<Program> dialog = getOpenVersionedFileDialog(openProgramList);
dialog.addOkActionListener(e -> {
tool.clearStatusInfo();
@ -1186,14 +1187,17 @@ public class ProgramDiffPlugin extends ProgramPlugin
return (rc != OptionDialog.OPTION_ONE);
}
private OpenVersionedFileDialog<Program> getOpenVersionedFileDialog() {
private OpenVersionedFileDialog<Program> getOpenVersionedFileDialog(
List<Program> openPrograms) {
// This will always be null except during testing.
if (openVersionedFileDialog != null) {
return openVersionedFileDialog;
}
OpenVersionedFileDialog<Program> dialog =
new OpenVersionedFileDialog<>(tool, "Select Other Program", Program.class);
new OpenVersionedFileDialog<>(tool, "Select Other Program", Program.class,
openPrograms);
dialog.setTreeSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
dialog.setHelpLocation(new HelpLocation("Diff", "Open_Close_Program_View"));
return dialog;

View File

@ -15,6 +15,8 @@
*/
package ghidra.feature.vt.gui.actions;
import static ghidra.framework.main.DataTreeDialogType.*;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.MenuData;
@ -45,8 +47,8 @@ public class OpenVersionTrackingSessionAction extends DockingAction {
public void actionPerformed(ActionContext context) {
PluginTool tool = controller.getTool();
DataTreeDialog dialog =
new DataTreeDialog(tool.getToolFrame(), "Open Version Tracking Session",
DataTreeDialog.OPEN, new VTDomainFileFilter());
new DataTreeDialog(tool.getToolFrame(), "Open Version Tracking Session", OPEN,
new VTDomainFileFilter());
tool.showDialog(dialog);
if (!dialog.wasCancelled()) {
@ -56,6 +58,7 @@ public class OpenVersionTrackingSessionAction extends DockingAction {
}
class VTDomainFileFilter implements DomainFileFilter {
@Override
public boolean accept(DomainFile f) {
Class<?> c = f.getDomainObjectClass();
return VTSession.class.isAssignableFrom(c);

View File

@ -15,6 +15,8 @@
*/
package ghidra.feature.vt.gui.wizard;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.*;
import java.util.*;
@ -236,7 +238,7 @@ public class NewSessionPanel extends AbstractMageJPanel<VTWizardStateKey> {
*/
private void browseDataTreeFolders() {
final DataTreeDialog dataTreeDialog =
new DataTreeDialog(this, "Choose a project folder", DataTreeDialog.CHOOSE_FOLDER);
new DataTreeDialog(this, "Choose a project folder", CHOOSE_FOLDER);
dataTreeDialog.addOkActionListener(e -> {
dataTreeDialog.close();

View File

@ -15,6 +15,8 @@
*/
package ghidra.feature.vt.gui.wizard;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@ -55,8 +57,8 @@ public class VTWizardUtils {
static DomainFile chooseDomainFile(Component parent, String domainIdentifier,
DomainFileFilter filter, DomainFile fileToSelect) {
final DataTreeDialog dataTreeDialog = filter == null
? new DataTreeDialog(parent, "Choose " + domainIdentifier, DataTreeDialog.OPEN)
: new DataTreeDialog(parent, "Choose " + domainIdentifier, DataTreeDialog.OPEN,
? new DataTreeDialog(parent, "Choose " + domainIdentifier, OPEN)
: new DataTreeDialog(parent, "Choose " + domainIdentifier, OPEN,
filter);
final DomainFileBox box = new DomainFileBox();
dataTreeDialog.addOkActionListener(new ActionListener() {

View File

@ -15,6 +15,8 @@
*/
package help.screenshot;
import static ghidra.framework.main.DataTreeDialogType.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
@ -61,7 +63,7 @@ public class ReferencesPluginScreenShots extends GhidraScreenShotGenerator {
runSwing(() -> {
DataTreeDialog dialog = new DataTreeDialog(tool.getToolFrame(),
"Choose External Program (" + "Kernel32.dll" + ")", DataTreeDialog.OPEN);
"Choose External Program (" + "Kernel32.dll" + ")", OPEN);
tool.showDialog(dialog);
}, false);
captureDialog();