mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
GP-3992 fixed various issues/bugs related to the new askValues() script method
This commit is contained in:
parent
134806cbe4
commit
9cd2666799
22 changed files with 556 additions and 383 deletions
|
@ -17,7 +17,6 @@
|
|||
// @category Examples
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.features.base.values.GhidraValuesMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.MessageType;
|
||||
|
||||
|
@ -28,20 +27,12 @@ public class AskValuesExampleScript extends GhidraScript {
|
|||
GhidraValuesMap values = new GhidraValuesMap();
|
||||
|
||||
values.defineString("Name");
|
||||
values.defineAddress("Address", currentProgram);
|
||||
values.defineInt("Count");
|
||||
values.defineInt("Max Results", 100);
|
||||
values.defineChoice("Priority", "Low", "Low", "Medium", "High");
|
||||
|
||||
// When asking for a program, you must supply a consumer that you will use
|
||||
// to release the program. Since programs share open instances, Ghidra uses
|
||||
// consumers to keep track of these uses. Scripts can just add themselves
|
||||
// as the consumer (The askProgram() method does this for you). It is
|
||||
// important to release it when you are done with. Optionally, you can also
|
||||
// provide a tool in which case the program will also be opened in the tool (and the
|
||||
// tool would then also add itself as a consumer). Otherwise, the program will not
|
||||
// show up in the tool and when you release the consumer, it will be closed.
|
||||
values.defineProgram("Other Program", this, state.getTool());
|
||||
values.defineProgram("Other Program");
|
||||
values.defineProjectFile("Project File");
|
||||
values.defineProjectFolder("Project Folder");
|
||||
|
||||
// Optional validator that can be set to validate values before the dialog returns. It
|
||||
// is called when the "Ok" button is pushed and must return true before the dialog exits.
|
||||
|
@ -70,14 +61,23 @@ public class AskValuesExampleScript extends GhidraScript {
|
|||
//dialog. The values map returned may or may not be the same instance as the one passed in.
|
||||
|
||||
String name = values.getString("Name");
|
||||
Address address = values.getAddress("Address");
|
||||
int age = values.getInt("Count");
|
||||
int max = values.getInt("Max Results");
|
||||
String priority = values.getChoice("Priority");
|
||||
Program program = values.getProgram("Other Program");
|
||||
|
||||
// When asking for a program, you must supply a consumer that you will use
|
||||
// to release the program. Since programs share open instances, Ghidra uses
|
||||
// consumers to keep track of these uses. Scripts can just add themselves
|
||||
// as the consumer (The askProgram() method does this for you). It is
|
||||
// important to release it when you are done with it. Optionally, you can also
|
||||
// provide a tool in which case the program will also be opened in the tool (and the
|
||||
// tool would then also add itself as a consumer). Otherwise, the program will not
|
||||
// show up in the tool and when you release the consumer, it will be closed.
|
||||
// NOTE: if you call getProgram() more than once, the consumer will be added multiple times
|
||||
// and you must release it multiple times
|
||||
Program program = values.getProgram("Other Program", this, state.getTool());
|
||||
|
||||
println("Name = " + name);
|
||||
println("Address = " + address);
|
||||
println("Count = " + age);
|
||||
println("Max Results = " + max);
|
||||
println("Priority = " + priority);
|
||||
|
|
|
@ -2360,6 +2360,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
|||
|
||||
public GhidraValuesMap askValues(String title, String optionalMessage, GhidraValuesMap values)
|
||||
throws CancelledException {
|
||||
values.setTaskMonitor(monitor);
|
||||
for (AbstractValue<?> value : values.getValues()) {
|
||||
String key = join(title, value.getName());
|
||||
loadAskValue(value.getValue(), s -> value.setAsText(s), key);
|
||||
|
|
|
@ -39,6 +39,7 @@ import ghidra.framework.*;
|
|||
import ghidra.framework.client.ClientUtil;
|
||||
import ghidra.framework.client.RepositoryAdapter;
|
||||
import ghidra.framework.data.*;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.project.DefaultProject;
|
||||
import ghidra.framework.project.DefaultProjectManager;
|
||||
|
@ -424,6 +425,7 @@ public class HeadlessAnalyzer {
|
|||
|
||||
if (locator.getProjectDir().exists()) {
|
||||
project = openProject(locator);
|
||||
AppInfo.setActiveProject(project);
|
||||
}
|
||||
else {
|
||||
if (options.runScriptsNoImport) {
|
||||
|
@ -440,6 +442,7 @@ public class HeadlessAnalyzer {
|
|||
Msg.info(this, "Creating " + (options.deleteProject ? "temporary " : "") +
|
||||
"project: " + locator);
|
||||
project = getProjectManager().createProject(locator, null, false);
|
||||
AppInfo.setActiveProject(project);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -457,6 +460,7 @@ public class HeadlessAnalyzer {
|
|||
}
|
||||
finally {
|
||||
project.close();
|
||||
AppInfo.setActiveProject(null);
|
||||
if (!options.runScriptsNoImport && options.deleteProject) {
|
||||
FileUtilities.deleteDir(locator.getProjectDir());
|
||||
locator.getMarkerFile().delete();
|
||||
|
@ -1546,8 +1550,7 @@ public class HeadlessAnalyzer {
|
|||
|
||||
// Analyze the primary program, and determine if we should save.
|
||||
// TODO: Analyze non-primary programs (GP-2965).
|
||||
boolean doSave =
|
||||
analyzeProgram(fsrl.toString(), primaryProgram) && !options.readOnly;
|
||||
boolean doSave = analyzeProgram(fsrl.toString(), primaryProgram) && !options.readOnly;
|
||||
|
||||
// The act of marking the program as temporary by a script will signal
|
||||
// us to discard any changes
|
||||
|
@ -1746,7 +1749,6 @@ public class HeadlessAnalyzer {
|
|||
|
||||
storage.clear();
|
||||
|
||||
|
||||
if (inputDirFiles != null && !inputDirFiles.isEmpty()) {
|
||||
Msg.info(this, "REPORT: Processing input files: ");
|
||||
Msg.info(this, " project: " + project.getProjectLocator());
|
||||
|
|
|
@ -16,102 +16,91 @@
|
|||
package ghidra.features.base.values;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.widgets.button.BrowseButton;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.main.DataTreeDialog;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.store.FileSystem;
|
||||
|
||||
/**
|
||||
* Component used by Values that use the DataTreeDialog for picking DomainFiles and DomainFolders
|
||||
* Base class for either project file chooser or project folder chooser
|
||||
*/
|
||||
class ProjectBrowserPanel extends JPanel {
|
||||
private JTextField textField;
|
||||
abstract class AbstractProjectBrowserPanel extends JPanel {
|
||||
protected Project project;
|
||||
protected JTextField textField;
|
||||
private JButton browseButton;
|
||||
private boolean selectFolders;
|
||||
private DomainFolder startFolder;
|
||||
private int type;
|
||||
protected DomainFileFilter filter = null;
|
||||
|
||||
ProjectBrowserPanel(String name, boolean selectFolders) {
|
||||
AbstractProjectBrowserPanel(int type, Project project, String name, String startPath) {
|
||||
super(new BorderLayout());
|
||||
this.selectFolders = selectFolders;
|
||||
this.type = type;
|
||||
this.project = Objects.requireNonNull(project);
|
||||
this.startFolder = parseDomainFolder(project, startPath);
|
||||
setName(name);
|
||||
textField = new JTextField(20);
|
||||
browseButton = new BrowseButton();
|
||||
browseButton.addActionListener(e -> showDomainFileChooser());
|
||||
browseButton.addActionListener(e -> showProjectChooser());
|
||||
add(textField, BorderLayout.CENTER);
|
||||
add(browseButton, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
void setDomainFile(DomainFile value) {
|
||||
String text = value == null ? "" : value.getPathname();
|
||||
textField.setText(text);
|
||||
}
|
||||
private void showProjectChooser() {
|
||||
DataTreeDialog dialog =
|
||||
new DataTreeDialog(null, "Choose " + getName(), type, filter, project);
|
||||
|
||||
void setDomainFolder(DomainFolder value) {
|
||||
String text = value == null ? "" : value.getPathname();
|
||||
textField.setText(text);
|
||||
}
|
||||
if (startFolder != null) {
|
||||
dialog.selectFolder(startFolder);
|
||||
}
|
||||
intializeCurrentValue(dialog);
|
||||
|
||||
private void showDomainFileChooser() {
|
||||
DataTreeDialog dialog = new DataTreeDialog(null, "Choose " + getName(),
|
||||
selectFolders ? DataTreeDialog.CHOOSE_FOLDER : DataTreeDialog.OPEN);
|
||||
dialog.show();
|
||||
|
||||
if (dialog.wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
String text = selectFolders ? dialog.getDomainFolder().getPathname()
|
||||
: dialog.getDomainFile().getPathname();
|
||||
String text = getSelectedPath(dialog);
|
||||
textField.setText(text);
|
||||
dialog.dispose();
|
||||
}
|
||||
|
||||
DomainFile getDomainFile() {
|
||||
String text = textField.getText().trim();
|
||||
if (text.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
return parseDomainFile(text);
|
||||
}
|
||||
protected abstract String getSelectedPath(DataTreeDialog dialog);
|
||||
|
||||
protected abstract void intializeCurrentValue(DataTreeDialog dialog);
|
||||
|
||||
String getText() {
|
||||
return textField.getText().trim();
|
||||
}
|
||||
|
||||
DomainFolder getDomainFolder() {
|
||||
String text = textField.getText().trim();
|
||||
if (text.isBlank()) {
|
||||
return parseDomainFolder("/");
|
||||
}
|
||||
return parseDomainFolder(text);
|
||||
}
|
||||
|
||||
static DomainFile parseDomainFile(String val) {
|
||||
static DomainFile parseDomainFile(Project project, String val) {
|
||||
// Add the slash to make it an absolute path
|
||||
if (!val.isEmpty() && val.charAt(0) != FileSystem.SEPARATOR_CHAR) {
|
||||
val = FileSystem.SEPARATOR_CHAR + val;
|
||||
}
|
||||
Project activeProject = AppInfo.getActiveProject();
|
||||
DomainFile df = activeProject.getProjectData().getFile(val);
|
||||
DomainFile df = project.getProjectData().getFile(val);
|
||||
if (df != null) {
|
||||
return df;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static DomainFolder parseDomainFolder(String path) {
|
||||
static DomainFolder parseDomainFolder(Project project, String path) {
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
path = path.trim();
|
||||
// Add the slash to make it an absolute path
|
||||
if (path.isEmpty() || path.charAt(0) != FileSystem.SEPARATOR_CHAR) {
|
||||
path = FileSystem.SEPARATOR_CHAR + path;
|
||||
}
|
||||
Project activeProject = AppInfo.getActiveProject();
|
||||
DomainFolder df = activeProject.getProjectData().getFolder(path);
|
||||
DomainFolder df = project.getProjectData().getFolder(path);
|
||||
if (df != null) {
|
||||
return df;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.features.base.values;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import docking.Tool;
|
||||
import docking.widgets.values.GValuesMap;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
|
@ -23,12 +25,24 @@ import ghidra.program.model.address.Address;
|
|||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.lang.LanguageCompilerSpecPair;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Extends GValuesMap to add Ghidra specific types such as Address and Program
|
||||
*/
|
||||
public class GhidraValuesMap extends GValuesMap {
|
||||
private TaskMonitor monitor = TaskMonitor.DUMMY;
|
||||
|
||||
/**
|
||||
* Sets a task monitor to be used when opening programs. Otherwise, {@link TaskMonitor#DUMMY} is
|
||||
* used.
|
||||
* @param monitor the TaskMonitor to use for opening programs
|
||||
*/
|
||||
public void setTaskMonitor(TaskMonitor monitor) {
|
||||
this.monitor = TaskMonitor.dummyIfNull(monitor);
|
||||
}
|
||||
//==================================================================================================
|
||||
// Define Value Methods
|
||||
//==================================================================================================
|
||||
|
@ -88,36 +102,23 @@ public class GhidraValuesMap extends GValuesMap {
|
|||
}
|
||||
|
||||
/**
|
||||
* Defines a value of type Program. This method opens programs using the given
|
||||
* consumer and must be properly released when it is no longer needed. This is true
|
||||
* even if the program is also opened in the tool.
|
||||
* Defines a value of type Program file.
|
||||
* @param name the name for this value
|
||||
* @param consumer the consumer to be used to open the program
|
||||
* @param tool if non-null, the program will also be opened in the given tool
|
||||
* @return the user-selected Program if a program was
|
||||
* not selected or null. NOTE: It is very important that the program instance
|
||||
* returned by this method ALWAYS be properly released from the consumer when no
|
||||
* longer needed (i.e., {@code program.release(consumer) } - failure to
|
||||
* properly release the program may result in improper project disposal. If the program was
|
||||
* also opened in the tool, the tool will be a second consumer responsible for its
|
||||
* own release.
|
||||
* @return the new ProgramFileValue defined
|
||||
*/
|
||||
public ProgramValue defineProgram(String name, Object consumer, Tool tool) {
|
||||
return defineProgram(name, null, consumer, tool);
|
||||
public ProgramFileValue defineProgram(String name) {
|
||||
return defineProgram(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a value of type Program.
|
||||
* Defines a value of type Program file.
|
||||
* @param name the name for this value
|
||||
* @param defaultValue the initial value
|
||||
* @param consumer the consumer to be used to open the program
|
||||
* @param tool if non-null, the program will also be opened in the given tool
|
||||
* @return the new ProgramValue that was defined
|
||||
* @param startPath the starting folder to display when picking programs from the chooser
|
||||
* @return the new ProgramFileValue that was defined
|
||||
*/
|
||||
public ProgramValue defineProgram(String name, Program defaultValue, Object consumer,
|
||||
Tool tool) {
|
||||
public ProgramFileValue defineProgram(String name, String startPath) {
|
||||
checkDup(name);
|
||||
ProgramValue value = new ProgramValue(name, defaultValue, consumer, tool);
|
||||
ProgramFileValue value = new ProgramFileValue(name, startPath);
|
||||
valuesMap.put(name, value);
|
||||
return value;
|
||||
}
|
||||
|
@ -134,12 +135,12 @@ public class GhidraValuesMap extends GValuesMap {
|
|||
/**
|
||||
* Defines a value of type DomainFile (files in a Ghidra project).
|
||||
* @param name the name for this value
|
||||
* @param defaultValue the initial value
|
||||
* @param startingPath the initial folder path for the chooser widget
|
||||
* @return the new ProjectFileValue that was defined
|
||||
*/
|
||||
public ProjectFileValue defineProjectFile(String name, DomainFile defaultValue) {
|
||||
public ProjectFileValue defineProjectFile(String name, String startingPath) {
|
||||
checkDup(name);
|
||||
ProjectFileValue value = new ProjectFileValue(name, defaultValue);
|
||||
ProjectFileValue value = new ProjectFileValue(name, startingPath);
|
||||
valuesMap.put(name, value);
|
||||
return value;
|
||||
}
|
||||
|
@ -156,12 +157,12 @@ public class GhidraValuesMap extends GValuesMap {
|
|||
/**
|
||||
* Defines a value of type DomainFolder (files in a Ghidra project).
|
||||
* @param name the name for this value
|
||||
* @param defaultValue the initial value (can be null)
|
||||
* @param defaultValuePath the path for the initial value (can be null)
|
||||
* @return the new ProjectFolderValue that was defined
|
||||
*/
|
||||
public ProjectFolderValue defineProjectFolder(String name, DomainFolder defaultValue) {
|
||||
public ProjectFolderValue defineProjectFolder(String name, String defaultValuePath) {
|
||||
checkDup(name);
|
||||
ProjectFolderValue value = new ProjectFolderValue(name, defaultValue);
|
||||
ProjectFolderValue value = new ProjectFolderValue(name, defaultValuePath);
|
||||
valuesMap.put(name, value);
|
||||
return value;
|
||||
}
|
||||
|
@ -192,14 +193,33 @@ public class GhidraValuesMap extends GValuesMap {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Program} value for the given name.
|
||||
* @param name the name of a previously defined project folder value
|
||||
* Gets (opens) the {@link Program} value for the given name. If the program is already open,
|
||||
* then the consumer will be added to the program. The caller of this method is responsible
|
||||
* for calling {@link Program#release(Object)} with the same consumer when it is done using this
|
||||
* program. Program are only closed after all consumers are released. If multiple calls
|
||||
* are made to this method, then the consumer will be added multiple times and must be released
|
||||
* multiple times.
|
||||
* <P>
|
||||
* The consumer can be any object, but since the consumer's purpose is to keep the program open
|
||||
* while some object is using it, the object itself is typically passed in as
|
||||
* the consumer. For example, when used in a script, passing in the java keyword "this" as the
|
||||
* consumer will make the script itself the consumer.
|
||||
* <P>
|
||||
* @param name the name of a previously defined program value
|
||||
* @param consumer the consumer to be used to open the program
|
||||
* @param tool if non-null, the program will also be opened in the given tool. Note: the
|
||||
* program will only be added to the tool once even if this method is called multiple times.
|
||||
* @return the project folder value
|
||||
* @throws VersionException if the Program being opened is an older version than the
|
||||
* current Ghidra Program version.
|
||||
* @throws IOException if there is an error accessing the Program's DomainObject
|
||||
* @throws CancelledException if the operation is cancelled
|
||||
* @throws IllegalArgumentException if the name hasn't been defined as a project folder type
|
||||
*/
|
||||
public Program getProgram(String name) {
|
||||
ProgramValue programValue = getValue(name, ProgramValue.class, "Program");
|
||||
return programValue.getValue();
|
||||
public Program getProgram(String name, Object consumer, Tool tool)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
ProgramFileValue programFileValue = getValue(name, ProgramFileValue.class, "Program");
|
||||
return programFileValue.openProgram(consumer, tool, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,8 +278,8 @@ public class GhidraValuesMap extends GValuesMap {
|
|||
* @throws IllegalArgumentException if the name hasn't been defined as a Program type
|
||||
*/
|
||||
public void setProgram(String name, Program program) {
|
||||
ProgramValue programValue = getValue(name, ProgramValue.class, "Program");
|
||||
programValue.setValue(program);
|
||||
ProgramFileValue programFileValue = getValue(name, ProgramFileValue.class, "Program");
|
||||
programFileValue.setValue(program == null ? null : program.getDomainFile());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -91,33 +91,33 @@ public class LanguageValue extends AbstractValue<LanguageCompilerSpecPair> {
|
|||
/**
|
||||
* Parses a LanguageCompilerSpecPair from a string.
|
||||
*
|
||||
* @param val The string to parse.
|
||||
* @param languageString The string to parse.
|
||||
* @return The LanguageCompilerSpecPair parsed from a string or null if the string does
|
||||
* not parse to a known language-compiler pair.
|
||||
* @throws ValuesMapParseException
|
||||
* @throws ValuesMapParseException if the value can't be parsed into a LanguageComilerSpecPair
|
||||
*/
|
||||
public LanguageCompilerSpecPair parseLanguageCompileSpecPair(String val)
|
||||
public LanguageCompilerSpecPair parseLanguageCompileSpecPair(String languageString)
|
||||
throws ValuesMapParseException {
|
||||
|
||||
if (val.isBlank()) {
|
||||
if (languageString.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
// Split on last colon to get separated languageID and compilerSpecID
|
||||
int lastColon = val.lastIndexOf(':');
|
||||
int lastColon = languageString.lastIndexOf(':');
|
||||
if (lastColon < 1) {
|
||||
throw new ValuesMapParseException(getName(), "Language/Compiler Spec",
|
||||
"Could not parse \"" + val + "\".");
|
||||
"Could not parse \"" + languageString + "\".");
|
||||
}
|
||||
|
||||
Set<LanguageCompilerSpecPair> languages = getLanguagesCompilerPairs();
|
||||
|
||||
String langId = val.substring(0, lastColon);
|
||||
String compilerId = val.substring(lastColon + 1);
|
||||
String langId = languageString.substring(0, lastColon);
|
||||
String compilerId = languageString.substring(lastColon + 1);
|
||||
|
||||
LanguageCompilerSpecPair storedLCS = new LanguageCompilerSpecPair(langId, compilerId);
|
||||
if (!languages.contains(storedLCS)) {
|
||||
throw new ValuesMapParseException(getName(), "Language/Compiler Spec",
|
||||
"Unknown language/Compiler Pair for \"" + val + "\"");
|
||||
"Unknown language/Compiler Pair for \"" + languageString + "\"");
|
||||
}
|
||||
return storedLCS;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/* ###
|
||||
* 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.features.base.values;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import docking.Tool;
|
||||
import docking.widgets.values.*;
|
||||
import ghidra.app.services.ProgramManager;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.main.DataTreeDialog;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.Project;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Value class for {@link Program} files. The editor component consists of the {@link JTextField}
|
||||
* and a browse button for bringing up a {@link DataTreeDialog} for picking programs from the
|
||||
* current project. This class also provides a convenience method for opening a program.
|
||||
* <P>
|
||||
* This class and other subclasses of {@link AbstractValue} are part of a subsystem for easily
|
||||
* defining a set of values that can be displayed in an input dialog ({@link ValuesMapDialog}).
|
||||
* Typically, these values are created indirectly using a {@link GValuesMap} which is then
|
||||
* given to the constructor of the dialog. However, an alternate approach is to create the
|
||||
* dialog without a ValuesMap and then use its {@link ValuesMapDialog#addValue(AbstractValue)}
|
||||
* method directly.
|
||||
*/
|
||||
public class ProgramFileValue extends ProjectFileValue {
|
||||
|
||||
/**
|
||||
* Constructor for creating a new ProgramFileValue with the given name.
|
||||
* @param name the name of the value
|
||||
*/
|
||||
public ProgramFileValue(String name) {
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for creating a new ProgramFileValue with the given name and a starting
|
||||
* folder when using the project file chooser.
|
||||
* @param name the name of the value
|
||||
* @param startingPath the path to a starting folder
|
||||
*/
|
||||
public ProgramFileValue(String name, String startingPath) {
|
||||
this(name, AppInfo.getActiveProject(), startingPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for ProgramValue when wanting to pick from a different project than the
|
||||
* active project, such as a read-only project.
|
||||
* @param name the name of the value
|
||||
* @param project The project from which to pick a project.
|
||||
* @param startingPath the path to a starting folder (Can also be a path to program)
|
||||
*/
|
||||
public ProgramFileValue(String name, Project project, String startingPath) {
|
||||
super(name, project, startingPath, Program.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for opening the program for the current program file value. If the program
|
||||
* is already open, then the consumer will be added to the program. The caller of this method is
|
||||
* responsible for calling {@link Program#release(Object)} with the same consumer when it is
|
||||
* done using this program. Program are only closed after all consumers are released. If
|
||||
* multiple calls are made to this method, then the consumer will be added multiple times
|
||||
* and must be released multiple times.
|
||||
* <P>
|
||||
* The consumer can be any object, but since the consumer's purpose is to keep the program open
|
||||
* while some object is using it, the object itself is typically passed in as
|
||||
* the consumer. For example, when used in a script, passing in the java keyword "this" as the
|
||||
* consumer will make the script itself the consumer.
|
||||
* <P>
|
||||
* @param consumer the consumer to be used to open the program
|
||||
* @param tool optional tool that if non-null, the program will also be opened in the tool
|
||||
* @param monitor task monitor for cancelling the open program.
|
||||
* @return a program for the current program value value. If the current program file value
|
||||
* is null, then null will be returned.
|
||||
* @throws VersionException if the Program being opened is an older version than the
|
||||
* current Ghidra Program version.
|
||||
* @throws IOException if there is an error accessing the Program's DomainObject
|
||||
* @throws CancelledException if the operation is cancelled
|
||||
*/
|
||||
public Program openProgram(Object consumer, Tool tool, TaskMonitor monitor)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
|
||||
DomainFile domainFile = getValue();
|
||||
if (domainFile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Program program = (Program) domainFile.getDomainObject(consumer, false, false, monitor);
|
||||
|
||||
if (tool != null && program != null) {
|
||||
tool.getService(ProgramManager.class).openProgram(program);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
/* ###
|
||||
* 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.features.base.values;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import docking.Tool;
|
||||
import docking.widgets.values.*;
|
||||
import ghidra.app.services.ProgramManager;
|
||||
import ghidra.framework.main.DataTreeDialog;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Value class for {@link Program}s. The editor component consists of the {@link JTextField} and
|
||||
* a browse button for bringing up a {@link DataTreeDialog} for picking programs from the
|
||||
* current project.
|
||||
* <P>
|
||||
* This class and other subclasses of {@link AbstractValue} are part of a subsystem for easily
|
||||
* defining a set of values that can be displayed in an input dialog ({@link ValuesMapDialog}).
|
||||
* Typically, these values are created indirectly using a {@link GValuesMap} which is then
|
||||
* given to the constructor of the dialog. However, an alternate approach is to create the
|
||||
* dialog without a ValuesMap and then use its {@link ValuesMapDialog#addValue(AbstractValue)}
|
||||
* method directly.
|
||||
*/
|
||||
public class ProgramValue extends AbstractValue<Program> {
|
||||
|
||||
private ProjectBrowserPanel domainFilePanel;
|
||||
private Tool tool;
|
||||
private Object consumer;
|
||||
|
||||
/**
|
||||
* Construct for ProgramValue
|
||||
* @param name the name of the value
|
||||
* @param consumer the program consumer to be used to open a program
|
||||
* @param tool if non null, the program will also be opened in this tool
|
||||
*/
|
||||
public ProgramValue(String name, Object consumer, Tool tool) {
|
||||
this(name, null, consumer, tool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for ProgramValue
|
||||
* @param name the name of the value
|
||||
* @param defaultValue the program to use as the default value
|
||||
* @param consumer the program consumer to be used to open a program
|
||||
* @param tool if non null, the program will also be opened in this tool
|
||||
*/
|
||||
public ProgramValue(String name, Program defaultValue, Object consumer, Tool tool) {
|
||||
super(name, defaultValue);
|
||||
this.consumer = consumer;
|
||||
this.tool = tool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
if (domainFilePanel == null) {
|
||||
domainFilePanel = new ProjectBrowserPanel(getName(), false);
|
||||
}
|
||||
return domainFilePanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateValueFromComponent() throws ValuesMapParseException {
|
||||
if (domainFilePanel != null) {
|
||||
DomainFile domainFile = domainFilePanel.getDomainFile();
|
||||
if (domainFile == null) {
|
||||
String text = domainFilePanel.getText();
|
||||
if (text.isBlank()) {
|
||||
setValue(null);
|
||||
return;
|
||||
}
|
||||
throw new ValuesMapParseException(getName(), "Program",
|
||||
"No file found for \"" + text + "\"");
|
||||
}
|
||||
Program program = openProgram(domainFile);
|
||||
setValue(program);
|
||||
}
|
||||
}
|
||||
|
||||
private Program openProgram(DomainFile domainFile) throws ValuesMapParseException {
|
||||
if (domainFile == null) {
|
||||
return null;
|
||||
}
|
||||
Class<? extends DomainObject> domainObjectClass = domainFile.getDomainObjectClass();
|
||||
if (!Program.class.isAssignableFrom(domainObjectClass)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Program program =
|
||||
(Program) domainFile.getDomainObject(consumer, false, false, TaskMonitor.DUMMY);
|
||||
|
||||
if (tool != null && program != null) {
|
||||
tool.getService(ProgramManager.class).openProgram(program);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
catch (VersionException | CancelledException | IOException e) {
|
||||
throw new ValuesMapParseException(getName(), "Program", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateComponentFromValue() {
|
||||
Program program = getValue();
|
||||
DomainFile df = program == null ? null : program.getDomainFile();
|
||||
domainFilePanel.setDomainFile(df);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Program fromString(String valueString) {
|
||||
DomainFile programFile = ProjectBrowserPanel.parseDomainFile(valueString);
|
||||
if (programFile == null) {
|
||||
throw new IllegalArgumentException("Could not find program " + valueString);
|
||||
}
|
||||
try {
|
||||
Program program = openProgram(programFile);
|
||||
if (program == null) {
|
||||
throw new IllegalArgumentException("Can't open program: " + valueString);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
catch (ValuesMapParseException e) {
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toString(Program v) {
|
||||
return v.getDomainFile().getPathname();
|
||||
}
|
||||
|
||||
}
|
|
@ -21,12 +21,11 @@ import javax.swing.JTextField;
|
|||
import docking.widgets.values.*;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.main.DataTreeDialog;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.Project;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.store.FileSystem;
|
||||
|
||||
/**
|
||||
* Value class for project files ({@link DomainFile}). The editor component consists of the
|
||||
* Value class for project files ({@link DomainFile}). The editor component consists of a
|
||||
* {@link JTextField} and a browse button for bringing up a {@link DataTreeDialog} for picking
|
||||
* project files from the current project.
|
||||
* <P>
|
||||
|
@ -39,20 +38,61 @@ import ghidra.framework.store.FileSystem;
|
|||
*/
|
||||
public class ProjectFileValue extends AbstractValue<DomainFile> {
|
||||
|
||||
private ProjectBrowserPanel domainFilePanel;
|
||||
private ProjectFileBrowserPanel domainFilePanel;
|
||||
private String startingPath;
|
||||
private Project project;
|
||||
private Class<? extends DomainObject> projectFileClass;
|
||||
|
||||
/**
|
||||
* Constructor for creating a new ProjectFileValue with the given name.
|
||||
* @param name the name of the value
|
||||
*/
|
||||
public ProjectFileValue(String name) {
|
||||
this(name, null);
|
||||
this(name, AppInfo.getActiveProject(), null, DomainObject.class);
|
||||
}
|
||||
|
||||
public ProjectFileValue(String name, DomainFile defaultValue) {
|
||||
super(name, defaultValue);
|
||||
/**
|
||||
* Constructor for creating a new ProgramFileValue with the given name and {@link DomainObject}
|
||||
* class to filter on (All other types will be filtered out in the chooser).
|
||||
* @param name the name of the value
|
||||
* @param projectFileClass the DomainObject class to filter
|
||||
*/
|
||||
public ProjectFileValue(String name, Class<? extends DomainObject> projectFileClass) {
|
||||
this(name, AppInfo.getActiveProject(), null, projectFileClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for creating a new ProjectFileValue with the given name and a starting
|
||||
* folder when using the project file chooser.
|
||||
* @param name the name of the value
|
||||
* @param startingPath the path to a starting folder
|
||||
*/
|
||||
public ProjectFileValue(String name, String startingPath) {
|
||||
this(name, AppInfo.getActiveProject(), startingPath, DomainObject.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for ProgramValue when wanting to pick from a different project than the
|
||||
* active project, such as a read-only project.
|
||||
* @param name the name of the value
|
||||
* @param project The project from which to pick a project.
|
||||
* @param startingPath the path to a starting folder (Can also be a path to program)
|
||||
* @param projectFileClass a {@link DomainFile} class to filter on. (Only those types
|
||||
* will appear in the chooser)
|
||||
*/
|
||||
public ProjectFileValue(String name, Project project, String startingPath,
|
||||
Class<? extends DomainObject> projectFileClass) {
|
||||
super(name, null);
|
||||
this.project = project;
|
||||
this.startingPath = startingPath;
|
||||
this.projectFileClass = projectFileClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
if (domainFilePanel == null) {
|
||||
domainFilePanel = new ProjectBrowserPanel(getName(), false);
|
||||
domainFilePanel =
|
||||
new ProjectFileBrowserPanel(project, getName(), startingPath, projectFileClass);
|
||||
}
|
||||
return domainFilePanel;
|
||||
}
|
||||
|
@ -70,6 +110,11 @@ public class ProjectFileValue extends AbstractValue<DomainFile> {
|
|||
throw new ValuesMapParseException(getName(), "Project File",
|
||||
"No file found for \"" + text + "\"");
|
||||
}
|
||||
Class<? extends DomainObject> domainObjectClass = domainFile.getDomainObjectClass();
|
||||
if (!projectFileClass.isAssignableFrom(domainObjectClass)) {
|
||||
throw new ValuesMapParseException(getName(), "Project File",
|
||||
"Selected path is not a " + projectFileClass.getSimpleName());
|
||||
}
|
||||
setValue(domainFile);
|
||||
}
|
||||
}
|
||||
|
@ -87,6 +132,11 @@ public class ProjectFileValue extends AbstractValue<DomainFile> {
|
|||
if (df == null) {
|
||||
throw new IllegalArgumentException("Can't find domain file: " + valueString);
|
||||
}
|
||||
Class<? extends DomainObject> domainObjectClass = df.getDomainObjectClass();
|
||||
if (!projectFileClass.isAssignableFrom(domainObjectClass)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Specified file path is not a " + projectFileClass.getSimpleName());
|
||||
}
|
||||
return df;
|
||||
}
|
||||
|
||||
|
@ -110,4 +160,44 @@ public class ProjectFileValue extends AbstractValue<DomainFile> {
|
|||
protected String toString(DomainFile v) {
|
||||
return v.getPathname();
|
||||
}
|
||||
|
||||
/**
|
||||
* Component used by ProjectFileValues for picking project files
|
||||
*/
|
||||
class ProjectFileBrowserPanel extends AbstractProjectBrowserPanel {
|
||||
|
||||
ProjectFileBrowserPanel(Project project, String name, String startPath,
|
||||
Class<? extends DomainObject> projectFileClass) {
|
||||
super(DataTreeDialog.OPEN, project, name, startPath);
|
||||
filter = df -> projectFileClass.isAssignableFrom(df.getDomainObjectClass());
|
||||
}
|
||||
|
||||
void setDomainFile(DomainFile value) {
|
||||
String text = value == null ? "" : value.getPathname();
|
||||
textField.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void intializeCurrentValue(DataTreeDialog dialog) {
|
||||
DomainFile current = getDomainFile();
|
||||
if (current != null) {
|
||||
dialog.selectDomainFile(current);
|
||||
dialog.setNameText(current.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSelectedPath(DataTreeDialog dialog) {
|
||||
return dialog.getDomainFile().getPathname();
|
||||
}
|
||||
|
||||
DomainFile getDomainFile() {
|
||||
String text = textField.getText().trim();
|
||||
if (text.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
return parseDomainFile(project, text);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,9 +19,9 @@ import javax.swing.JComponent;
|
|||
import javax.swing.JTextField;
|
||||
|
||||
import docking.widgets.values.*;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.main.DataTreeDialog;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainFolder;
|
||||
import ghidra.framework.model.*;
|
||||
|
||||
/**
|
||||
* Value class for project folders ({@link DomainFile}). The editor component consists of the
|
||||
|
@ -37,20 +37,42 @@ import ghidra.framework.model.DomainFolder;
|
|||
*/
|
||||
public class ProjectFolderValue extends AbstractValue<DomainFolder> {
|
||||
|
||||
private ProjectBrowserPanel domainFilePanel;
|
||||
private Project project;
|
||||
private ProjectFolderBrowserPanel domainFilePanel;
|
||||
|
||||
/**
|
||||
* Constructor for ProjectFolderValues with the given name.
|
||||
* @param name the name of the value
|
||||
*/
|
||||
public ProjectFolderValue(String name) {
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
public ProjectFolderValue(String name, DomainFolder defaultValue) {
|
||||
super(name, defaultValue);
|
||||
/**
|
||||
* Constructor for creating a new ProjectFolderValue with the given name and a path
|
||||
* for a default folder value.
|
||||
* @param name the name of the value
|
||||
* @param defaultValuePath the path for a default folder value
|
||||
*/
|
||||
public ProjectFolderValue(String name, String defaultValuePath) {
|
||||
this(name, AppInfo.getActiveProject(), defaultValuePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for creating ProjectFolderValues for projects other than the active project.
|
||||
* @param name the name of the value
|
||||
* @param project the project to find a folder from
|
||||
* @param defaultValuePath the path of a default folder value
|
||||
*/
|
||||
public ProjectFolderValue(String name, Project project, String defaultValuePath) {
|
||||
super(name, AbstractProjectBrowserPanel.parseDomainFolder(project, defaultValuePath));
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
if (domainFilePanel == null) {
|
||||
domainFilePanel = new ProjectBrowserPanel(getName(), true);
|
||||
domainFilePanel = new ProjectFolderBrowserPanel(project, getName(), null);
|
||||
}
|
||||
return domainFilePanel;
|
||||
}
|
||||
|
@ -83,7 +105,7 @@ public class ProjectFolderValue extends AbstractValue<DomainFolder> {
|
|||
|
||||
@Override
|
||||
protected DomainFolder fromString(String valueString) {
|
||||
DomainFolder df = ProjectBrowserPanel.parseDomainFolder(valueString);
|
||||
DomainFolder df = AbstractProjectBrowserPanel.parseDomainFolder(project, valueString);
|
||||
if (df == null) {
|
||||
throw new IllegalArgumentException("Can't find domain folder: " + valueString);
|
||||
}
|
||||
|
@ -95,4 +117,38 @@ public class ProjectFolderValue extends AbstractValue<DomainFolder> {
|
|||
return v.getPathname();
|
||||
}
|
||||
|
||||
/**
|
||||
* Component used by ProjectFolderValues for picking project folders
|
||||
*/
|
||||
class ProjectFolderBrowserPanel extends AbstractProjectBrowserPanel {
|
||||
|
||||
ProjectFolderBrowserPanel(Project project, String name, String startPath) {
|
||||
super(DataTreeDialog.CHOOSE_FOLDER, project, name, startPath);
|
||||
}
|
||||
|
||||
void setDomainFolder(DomainFolder value) {
|
||||
String text = value == null ? "" : value.getPathname();
|
||||
textField.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void intializeCurrentValue(DataTreeDialog dialog) {
|
||||
DomainFolder current = getDomainFolder();
|
||||
dialog.selectFolder(current);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSelectedPath(DataTreeDialog dialog) {
|
||||
return dialog.getDomainFolder().getPathname();
|
||||
}
|
||||
|
||||
DomainFolder getDomainFolder() {
|
||||
String text = textField.getText().trim();
|
||||
if (text.isBlank()) {
|
||||
return parseDomainFolder(project, "/");
|
||||
}
|
||||
return parseDomainFolder(project, text);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -91,10 +91,11 @@ public class DataTreeDialog extends DialogComponentProvider
|
|||
private ProjectDataNewFolderAction<DialogProjectTreeContext> newFolderAction;
|
||||
|
||||
private Integer treeSelectionMode;
|
||||
private final Project project;
|
||||
|
||||
/**
|
||||
* Construct a new DataTreeDialog. This chooser will show all project files.
|
||||
* Following linked-folders will only be allowed if a type of {@link #CHOOSE_FOLDER}
|
||||
* 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
|
||||
* be specified using the other constructor.
|
||||
*
|
||||
|
@ -104,11 +105,11 @@ public class DataTreeDialog extends DialogComponentProvider
|
|||
* @throws IllegalArgumentException if invalid type is specified
|
||||
*/
|
||||
public DataTreeDialog(Component parent, String title, int type) {
|
||||
this(parent, title, type, getDefaultFilter(type));
|
||||
this(parent, title, type, getDefaultFilter(type), AppInfo.getActiveProject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new DataTreeDialog.
|
||||
* Construct a new DataTreeDialog for the active project.
|
||||
*
|
||||
* @param parent dialog's parent
|
||||
* @param title title to use
|
||||
|
@ -117,7 +118,23 @@ public class DataTreeDialog extends DialogComponentProvider
|
|||
* @throws IllegalArgumentException if invalid type is specified
|
||||
*/
|
||||
public DataTreeDialog(Component parent, String title, int type, DomainFileFilter filter) {
|
||||
this(parent, title, type, filter, AppInfo.getActiveProject());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public DataTreeDialog(Component parent, String title, int type, DomainFileFilter filter,
|
||||
Project project) {
|
||||
super(title, true, true, true, false);
|
||||
this.project = project;
|
||||
this.parent = parent;
|
||||
initDataTreeDialog(type, filter);
|
||||
}
|
||||
|
@ -230,7 +247,6 @@ public class DataTreeDialog extends DialogComponentProvider
|
|||
|
||||
comboModelInitialized = true;
|
||||
// repopulate the tree
|
||||
Project project = AppInfo.getActiveProject();
|
||||
ProjectData pd = project.getProjectData();
|
||||
treePanel.setProjectData(project.getName(), pd);
|
||||
|
||||
|
@ -373,7 +389,7 @@ public class DataTreeDialog extends DialogComponentProvider
|
|||
nameField.setText(domainFolder.getName());
|
||||
}
|
||||
else {
|
||||
domainFolder = AppInfo.getActiveProject().getProjectData().getRootFolder();
|
||||
domainFolder = project.getProjectData().getRootFolder();
|
||||
folderNameLabel.setText(domainFolder.getPathname());
|
||||
nameField.setText(domainFolder.getName());
|
||||
}
|
||||
|
@ -389,7 +405,7 @@ public class DataTreeDialog extends DialogComponentProvider
|
|||
else {
|
||||
domainFolder = treePanel.getSelectedDomainFolder();
|
||||
if (domainFolder == null) {
|
||||
domainFolder = AppInfo.getActiveProject().getProjectData().getRootFolder();
|
||||
domainFolder = project.getProjectData().getRootFolder();
|
||||
}
|
||||
|
||||
folderNameLabel.setText(domainFolder.getPathname());
|
||||
|
@ -415,7 +431,6 @@ public class DataTreeDialog extends DialogComponentProvider
|
|||
return;
|
||||
}
|
||||
|
||||
Project project = AppInfo.getActiveProject();
|
||||
ProjectLocator projectLocator = projectLocators[index];
|
||||
ProjectData pd = project.getProjectData(projectLocator);
|
||||
String projectName = projectLocator.getName();
|
||||
|
@ -511,7 +526,6 @@ public class DataTreeDialog extends DialogComponentProvider
|
|||
|
||||
JPanel panel = new JPanel();
|
||||
panel.setLayout(new BorderLayout());
|
||||
Project project = AppInfo.getActiveProject();
|
||||
ProjectData pd = project.getProjectData();
|
||||
|
||||
treePanel = new ProjectDataTreePanel(project.getName(), true, // is for the active project
|
||||
|
@ -646,7 +660,6 @@ public class DataTreeDialog extends DialogComponentProvider
|
|||
}
|
||||
|
||||
private void populateProjectModel() {
|
||||
Project project = AppInfo.getActiveProject();
|
||||
ProjectLocator[] views = project.getProjectViews();
|
||||
|
||||
projectLocators = new ProjectLocator[views.length + 1];
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.features.base.values;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
|
@ -25,13 +27,14 @@ import docking.DialogComponentProvider;
|
|||
import docking.DockingWindowManager;
|
||||
import docking.widgets.values.AbstractValue;
|
||||
import docking.widgets.values.ValuesMapDialog;
|
||||
import ghidra.features.base.values.GhidraValuesMap;
|
||||
import ghidra.features.base.values.ProjectBrowserPanel;
|
||||
import ghidra.features.base.values.ProjectFileValue.ProjectFileBrowserPanel;
|
||||
import ghidra.features.base.values.ProjectFolderValue.ProjectFolderBrowserPanel;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.main.DataTreeDialog;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.test.TestEnv;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -43,30 +46,47 @@ public abstract class AbstractValueIntegrationTest extends AbstractGhidraHeadedI
|
|||
|
||||
protected TestEnv env;
|
||||
protected DomainFolder rootFolder;
|
||||
protected DomainFolder folder;
|
||||
protected DomainFolder folderA;
|
||||
protected DomainFolder folderB;
|
||||
protected DomainFile fileA;
|
||||
protected DomainFile fileB;
|
||||
protected ProgramDB programA;
|
||||
protected ProgramDB programB;
|
||||
protected DomainFile fileC;
|
||||
protected Program programA;
|
||||
protected Program programB;
|
||||
protected Project project;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
env = new TestEnv();
|
||||
Project project = env.getProject();
|
||||
runSwing(() -> env.getFrontEndTool().setActiveProject(project));
|
||||
project = env.getProject();
|
||||
AppInfo.setActiveProject(project);
|
||||
rootFolder = project.getProjectData().getRootFolder();
|
||||
folder = rootFolder.createFolder("A");
|
||||
ProgramBuilder programBuilderA = new ProgramBuilder("A", ProgramBuilder._TOY);
|
||||
ProgramBuilder programBuilderB = new ProgramBuilder("B", ProgramBuilder._TOY);
|
||||
folderA = rootFolder.createFolder("A");
|
||||
folderB = rootFolder.createFolder("B");
|
||||
ProgramBuilder programBuilderA = new ProgramBuilder("A", ProgramBuilder._TOY, this);
|
||||
ProgramBuilder programBuilderB = new ProgramBuilder("B", ProgramBuilder._TOY, this);
|
||||
ProgramBuilder programBuilderC = new ProgramBuilder("C", ProgramBuilder._TOY, this);
|
||||
programA = programBuilderA.getProgram();
|
||||
programB = programBuilderB.getProgram();
|
||||
fileA = folder.createFile("A", programA, TaskMonitor.DUMMY);
|
||||
fileB = folder.createFile("B", programB, TaskMonitor.DUMMY);
|
||||
Program programC = programBuilderC.getProgram();
|
||||
fileA = folderA.createFile("A", programA, TaskMonitor.DUMMY);
|
||||
fileB = folderA.createFile("B", programB, TaskMonitor.DUMMY);
|
||||
fileC = folderA.createFile("C", programC, TaskMonitor.DUMMY);
|
||||
programBuilderC.dispose(); // closes program C
|
||||
programC.release(this);
|
||||
assertTrue(programC.isClosed());
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
// some tests close the programs
|
||||
if (!programA.isClosed()) {
|
||||
programA.release(this);
|
||||
}
|
||||
if (!programB.isClosed()) {
|
||||
programB.release(this);
|
||||
}
|
||||
env.dispose();
|
||||
}
|
||||
|
||||
|
@ -91,7 +111,7 @@ public abstract class AbstractValueIntegrationTest extends AbstractGhidraHeadedI
|
|||
}
|
||||
|
||||
protected void setProjectFileOnProjectTree(AbstractValue<?> value, DomainFile file) {
|
||||
ProjectBrowserPanel projectWidget = (ProjectBrowserPanel) value.getComponent();
|
||||
ProjectFileBrowserPanel projectWidget = (ProjectFileBrowserPanel) value.getComponent();
|
||||
pressButtonByName(projectWidget, "BrowseButton", false);
|
||||
|
||||
DataTreeDialog dataTreeDialog = waitForDialogComponent(DataTreeDialog.class);
|
||||
|
@ -104,7 +124,7 @@ public abstract class AbstractValueIntegrationTest extends AbstractGhidraHeadedI
|
|||
}
|
||||
|
||||
protected void setProjectFolderOnProjectTree(AbstractValue<?> value, DomainFolder folder) {
|
||||
ProjectBrowserPanel projectWidget = (ProjectBrowserPanel) value.getComponent();
|
||||
ProjectFolderBrowserPanel projectWidget = (ProjectFolderBrowserPanel) value.getComponent();
|
||||
pressButtonByName(projectWidget, "BrowseButton", false);
|
||||
|
||||
DataTreeDialog dataTreeDialog = waitForDialogComponent(DataTreeDialog.class);
|
||||
|
|
|
@ -20,16 +20,15 @@ import static org.junit.Assert.*;
|
|||
import org.junit.Test;
|
||||
|
||||
import ghidra.app.services.ProgramManager;
|
||||
import ghidra.features.base.values.ProgramValue;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
public class ProgramValueTest extends AbstractValueIntegrationTest {
|
||||
public class ProgramFileValueTest extends AbstractValueIntegrationTest {
|
||||
private static final String NAME = "Program";
|
||||
|
||||
@Test
|
||||
public void testProgramValueNoDefault() {
|
||||
values.defineProgram(NAME, this, null);
|
||||
public void testProgramValueNoDefault() throws Exception {
|
||||
values.defineProgram(NAME);
|
||||
|
||||
assertTrue(values.isDefined(NAME));
|
||||
assertFalse(values.hasValue(NAME));
|
||||
|
@ -37,38 +36,41 @@ public class ProgramValueTest extends AbstractValueIntegrationTest {
|
|||
values.setProgram(NAME, programA);
|
||||
assertTrue(values.hasValue(NAME));
|
||||
|
||||
assertEquals(programA, values.getProgram(NAME));
|
||||
assertEquals(programA, values.getProgram(NAME, this, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProgramValueWithDefault() {
|
||||
values.defineProgram(NAME, programA, this, null);
|
||||
public void testSetValue() throws Exception {
|
||||
values.defineProgram(NAME);
|
||||
values.setProgram(NAME, programA);
|
||||
|
||||
assertTrue(values.isDefined(NAME));
|
||||
assertTrue(values.hasValue(NAME));
|
||||
assertEquals(programA, values.getProgram(NAME));
|
||||
assertEquals(programA, values.getProgram(NAME, this, null));
|
||||
|
||||
values.setProgram(NAME, programB);
|
||||
assertTrue(values.hasValue(NAME));
|
||||
|
||||
assertEquals(programB, values.getProgram(NAME));
|
||||
assertEquals(programB, values.getProgram(NAME, this, null));
|
||||
|
||||
values.setProgram(NAME, null);
|
||||
assertFalse(values.hasValue(NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAsText() {
|
||||
ProgramValue value1 = new ProgramValue(NAME, this, null);
|
||||
ProgramValue value2 = new ProgramValue(NAME, programA, this, null);
|
||||
assertNull(value1.getAsText());
|
||||
assertEquals("/A/A", value2.getAsText());
|
||||
public void testGetAsText() throws Exception {
|
||||
ProgramFileValue value = values.defineProgram(NAME);
|
||||
assertNull(value.getAsText());
|
||||
|
||||
values.setProgram(NAME, programA);
|
||||
|
||||
assertEquals("/A/A", value.getAsText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAsText() {
|
||||
ProgramValue v = new ProgramValue(NAME, this, null);
|
||||
assertEquals(programA, v.setAsText("/A/A"));
|
||||
ProgramFileValue v = new ProgramFileValue(NAME);
|
||||
assertEquals(programA.getDomainFile(), v.setAsText("/A/A"));
|
||||
try {
|
||||
v.setAsText(null);
|
||||
fail("Expected exception");
|
||||
|
@ -86,20 +88,20 @@ public class ProgramValueTest extends AbstractValueIntegrationTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testNoDefaultValueWithNoDialogInput() {
|
||||
values.defineProgram(NAME, this, null);
|
||||
public void testNoDefaultValueWithNoDialogInput() throws Exception {
|
||||
values.defineProgram(NAME);
|
||||
assertFalse(values.hasValue(NAME));
|
||||
|
||||
showDialogOnSwingWithoutBlocking();
|
||||
pressOk();
|
||||
|
||||
assertFalse(values.hasValue(NAME));
|
||||
assertNull(values.getProgram(NAME));
|
||||
assertNull(values.getProgram(NAME, this, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoDefaultValueWithDialogInput() {
|
||||
values.defineProgram(NAME, this, null);
|
||||
public void testNoDefaultValueWithDialogInput() throws Exception {
|
||||
values.defineProgram(NAME);
|
||||
assertFalse(values.hasValue(NAME));
|
||||
|
||||
showDialogOnSwingWithoutBlocking();
|
||||
|
@ -107,49 +109,67 @@ public class ProgramValueTest extends AbstractValueIntegrationTest {
|
|||
pressOk();
|
||||
|
||||
assertTrue(values.hasValue(NAME));
|
||||
assertEquals(programA, values.getProgram(NAME));
|
||||
assertEquals(programA, values.getProgram(NAME, this, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultValueWithNoDialogInput() {
|
||||
values.defineProgram(NAME, programA, this, null);
|
||||
assertTrue(values.hasValue(NAME));
|
||||
public void testExistingValueWithNoDialogInput() throws Exception {
|
||||
values.defineProgram(NAME);
|
||||
values.setProgram(NAME, programA);
|
||||
|
||||
showDialogOnSwingWithoutBlocking();
|
||||
pressOk();
|
||||
|
||||
assertTrue(values.hasValue(NAME));
|
||||
assertEquals(programA, values.getProgram(NAME));
|
||||
assertEquals(programA, values.getProgram(NAME, this, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultValueWithDialogInput() {
|
||||
values.defineProgram(NAME, programA, this, null);
|
||||
assertTrue(values.hasValue(NAME));
|
||||
public void testDefaultValueWithDialogInput() throws Exception {
|
||||
values.defineProgram(NAME);
|
||||
values.setProgram(NAME, programA);
|
||||
|
||||
showDialogOnSwingWithoutBlocking();
|
||||
setProjectFileOnProjectTree(values.getAbstractValue(NAME), programB.getDomainFile());
|
||||
pressOk();
|
||||
|
||||
assertTrue(values.hasValue(NAME));
|
||||
assertEquals(programB, values.getProgram(NAME));
|
||||
assertEquals(programB, values.getProgram(NAME, this, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenProgramInTool() {
|
||||
public void testOpenProgramInTool() throws Exception {
|
||||
PluginTool tool = env.createDefaultTool();
|
||||
ProgramManager programManagerService = tool.getService(ProgramManager.class);
|
||||
Program[] allOpenPrograms = programManagerService.getAllOpenPrograms();
|
||||
assertEquals(0, allOpenPrograms.length);
|
||||
|
||||
values.defineProgram(NAME, this, tool);
|
||||
values.defineProgram(NAME);
|
||||
showDialogOnSwingWithoutBlocking();
|
||||
setProjectFileOnProjectTree(values.getAbstractValue(NAME), programA.getDomainFile());
|
||||
pressOk();
|
||||
|
||||
Program p = values.getProgram(NAME, this, tool);
|
||||
|
||||
allOpenPrograms = programManagerService.getAllOpenPrograms();
|
||||
assertEquals(1, allOpenPrograms.length);
|
||||
assertEquals(programA, allOpenPrograms[0]);
|
||||
assertEquals(p, allOpenPrograms[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenProgramMutltipleTimes() throws Exception {
|
||||
values.defineProgram(NAME);
|
||||
assertEquals(1, programA.getConsumerList().size());
|
||||
showDialogOnSwingWithoutBlocking();
|
||||
setProjectFileOnProjectTree(values.getAbstractValue(NAME), programA.getDomainFile());
|
||||
pressOk();
|
||||
|
||||
Program p1 = values.getProgram(NAME, this, null);
|
||||
assertEquals(2, programA.getConsumerList().size());
|
||||
Program p2 = values.getProgram(NAME, this, null);
|
||||
assertEquals(p1, p2);
|
||||
assertEquals(3, programA.getConsumerList().size());
|
||||
p1.release(this);
|
||||
p2.release(this);
|
||||
}
|
||||
}
|
|
@ -19,8 +19,6 @@ import static org.junit.Assert.*;
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.features.base.values.ProjectFileValue;
|
||||
|
||||
public class ProjectFileValueTest extends AbstractValueIntegrationTest {
|
||||
private static final String NAME = "Project File";
|
||||
|
||||
|
@ -39,7 +37,8 @@ public class ProjectFileValueTest extends AbstractValueIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testProjectFileValueWithDefault() {
|
||||
values.defineProjectFile(NAME, fileA);
|
||||
values.defineProjectFile(NAME);
|
||||
values.setProjectFile(NAME, fileA);
|
||||
|
||||
assertTrue(values.isDefined(NAME));
|
||||
assertTrue(values.hasValue(NAME));
|
||||
|
@ -57,7 +56,9 @@ public class ProjectFileValueTest extends AbstractValueIntegrationTest {
|
|||
@Test
|
||||
public void testGetAsText() {
|
||||
ProjectFileValue value1 = new ProjectFileValue(NAME);
|
||||
ProjectFileValue value2 = new ProjectFileValue(NAME, fileA);
|
||||
ProjectFileValue value2 = new ProjectFileValue(NAME);
|
||||
value2.setValue(fileA);
|
||||
|
||||
assertNull(value1.getAsText());
|
||||
assertEquals("/A/A", value2.getAsText());
|
||||
}
|
||||
|
@ -109,7 +110,8 @@ public class ProjectFileValueTest extends AbstractValueIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testDefaultValueWithNoDialogInput() {
|
||||
values.defineProjectFile(NAME, fileA);
|
||||
values.defineProjectFile(NAME);
|
||||
values.setProjectFile(NAME, fileA);
|
||||
assertTrue(values.hasValue(NAME));
|
||||
|
||||
showDialogOnSwingWithoutBlocking();
|
||||
|
@ -121,7 +123,8 @@ public class ProjectFileValueTest extends AbstractValueIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testDefaultValueWithDialogInput() {
|
||||
values.defineProjectFile(NAME, fileA);
|
||||
values.defineProjectFile(NAME);
|
||||
values.setProjectFile(NAME, fileA);
|
||||
assertTrue(values.hasValue(NAME));
|
||||
|
||||
showDialogOnSwingWithoutBlocking();
|
||||
|
|
|
@ -19,8 +19,6 @@ import static org.junit.Assert.*;
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.features.base.values.ProjectFolderValue;
|
||||
|
||||
public class ProjectFolderValueTest extends AbstractValueIntegrationTest {
|
||||
private static final String NAME = "Project File";
|
||||
|
||||
|
@ -31,24 +29,24 @@ public class ProjectFolderValueTest extends AbstractValueIntegrationTest {
|
|||
assertTrue(values.isDefined(NAME));
|
||||
assertFalse(values.hasValue(NAME));
|
||||
|
||||
values.setProjectFolder(NAME, folder);
|
||||
values.setProjectFolder(NAME, folderA);
|
||||
assertTrue(values.hasValue(NAME));
|
||||
|
||||
assertEquals(folder, values.getProjectFolder(NAME));
|
||||
assertEquals(folderA, values.getProjectFolder(NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProjectFolderValueWithDefault() {
|
||||
values.defineProjectFolder(NAME, rootFolder);
|
||||
values.defineProjectFolder(NAME, "/A");
|
||||
|
||||
assertTrue(values.isDefined(NAME));
|
||||
assertTrue(values.hasValue(NAME));
|
||||
assertEquals(rootFolder, values.getProjectFolder(NAME));
|
||||
assertEquals(folderA, values.getProjectFolder(NAME));
|
||||
|
||||
values.setProjectFolder(NAME, folder);
|
||||
values.setProjectFolder(NAME, folderB);
|
||||
assertTrue(values.hasValue(NAME));
|
||||
|
||||
assertEquals(folder, values.getProjectFolder(NAME));
|
||||
assertEquals(folderB, values.getProjectFolder(NAME));
|
||||
|
||||
values.setProjectFolder(NAME, null);
|
||||
assertFalse(values.hasValue(NAME));
|
||||
|
@ -57,7 +55,7 @@ public class ProjectFolderValueTest extends AbstractValueIntegrationTest {
|
|||
@Test
|
||||
public void testGetAsText() {
|
||||
ProjectFolderValue value1 = new ProjectFolderValue(NAME);
|
||||
ProjectFolderValue value2 = new ProjectFolderValue(NAME, folder);
|
||||
ProjectFolderValue value2 = new ProjectFolderValue(NAME, "/A");
|
||||
assertNull(value1.getAsText());
|
||||
assertEquals("/A", value2.getAsText());
|
||||
}
|
||||
|
@ -65,7 +63,7 @@ public class ProjectFolderValueTest extends AbstractValueIntegrationTest {
|
|||
@Test
|
||||
public void testSetAsText() {
|
||||
ProjectFolderValue v = new ProjectFolderValue(NAME);
|
||||
assertEquals(folder, v.setAsText("/A"));
|
||||
assertEquals(folderA, v.setAsText("/A"));
|
||||
try {
|
||||
v.setAsText(null);
|
||||
fail("Expected exception");
|
||||
|
@ -102,36 +100,36 @@ public class ProjectFolderValueTest extends AbstractValueIntegrationTest {
|
|||
assertFalse(values.hasValue(NAME));
|
||||
|
||||
showDialogOnSwingWithoutBlocking();
|
||||
setProjectFolderOnProjectTree(values.getAbstractValue(NAME), folder);
|
||||
setProjectFolderOnProjectTree(values.getAbstractValue(NAME), folderA);
|
||||
pressOk();
|
||||
|
||||
assertTrue(values.hasValue(NAME));
|
||||
assertEquals(folder, values.getProjectFolder(NAME));
|
||||
assertEquals(folderA, values.getProjectFolder(NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultValueWithNoDialogInput() {
|
||||
values.defineProjectFolder(NAME, folder);
|
||||
values.defineProjectFolder(NAME, "/A");
|
||||
assertTrue(values.hasValue(NAME));
|
||||
|
||||
showDialogOnSwingWithoutBlocking();
|
||||
pressOk();
|
||||
|
||||
assertTrue(values.hasValue(NAME));
|
||||
assertEquals(folder, values.getProjectFolder(NAME));
|
||||
assertEquals(folderA, values.getProjectFolder(NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultValueWithDialogInput() {
|
||||
values.defineProjectFolder(NAME, rootFolder);
|
||||
values.defineProjectFolder(NAME, "/A");
|
||||
assertTrue(values.hasValue(NAME));
|
||||
|
||||
showDialogOnSwingWithoutBlocking();
|
||||
setProjectFolderOnProjectTree(values.getAbstractValue(NAME), folder);
|
||||
setProjectFolderOnProjectTree(values.getAbstractValue(NAME), folderB);
|
||||
pressOk();
|
||||
|
||||
assertTrue(values.hasValue(NAME));
|
||||
assertEquals(folder, values.getProjectFolder(NAME));
|
||||
assertEquals(folderB, values.getProjectFolder(NAME));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import javax.swing.JComponent;
|
|||
public abstract class AbstractValue<T> {
|
||||
private final String name;
|
||||
private T value;
|
||||
private T originalValue;
|
||||
|
||||
/**
|
||||
* Constructor that assigned a name and optional initial value for this object.
|
||||
|
@ -49,6 +50,7 @@ public abstract class AbstractValue<T> {
|
|||
protected AbstractValue(String name, T defaultValue) {
|
||||
this.name = Objects.requireNonNull(name);
|
||||
this.value = defaultValue;
|
||||
this.originalValue = defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,6 +118,13 @@ public abstract class AbstractValue<T> {
|
|||
return value == null ? null : toString(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the value to its original value when constructed
|
||||
*/
|
||||
protected void reset() {
|
||||
value = originalValue;
|
||||
}
|
||||
|
||||
protected String toString(T t) {
|
||||
return t.toString();
|
||||
}
|
||||
|
|
|
@ -553,4 +553,14 @@ public class GValuesMap {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the values back to their original values when constructed. Used by the dialog
|
||||
* when the user cancels.
|
||||
*/
|
||||
protected void reset() {
|
||||
for (AbstractValue<?> inputValue : valuesMap.values()) {
|
||||
inputValue.reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -133,6 +133,7 @@ public class ValuesMapDialog extends DialogComponentProvider {
|
|||
|
||||
@Override
|
||||
protected void cancelCallback() {
|
||||
valuesMap.reset();
|
||||
cancelled = true;
|
||||
super.cancelCallback();
|
||||
}
|
||||
|
|
|
@ -313,11 +313,6 @@ public class DomainFileProxy implements DomainFile {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean isUsedExclusivelyBy(Object consumer) {
|
||||
DomainObjectAdapter dobj = getDomainObject();
|
||||
return dobj != null ? dobj.isUsedExclusivelyBy(consumer) : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<?> getConsumers() {
|
||||
DomainObjectAdapter dobj = getDomainObject();
|
||||
|
|
|
@ -333,19 +333,12 @@ public abstract class DomainObjectAdapter implements DomainObject {
|
|||
|
||||
@Override
|
||||
public boolean addConsumer(Object consumer) {
|
||||
if (consumer == null) {
|
||||
throw new IllegalArgumentException("Consumer must not be null");
|
||||
}
|
||||
Objects.requireNonNull(consumer);
|
||||
|
||||
synchronized (consumers) {
|
||||
if (isClosed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (consumers.contains(consumer)) {
|
||||
throw new IllegalArgumentException("Attempted to acquire the " +
|
||||
"domain object more than once by the same consumer: " + consumer);
|
||||
}
|
||||
consumers.add(consumer);
|
||||
}
|
||||
|
||||
|
@ -359,18 +352,7 @@ public abstract class DomainObjectAdapter implements DomainObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns true if the this file is used only by the given consumer
|
||||
* @param consumer the consumer
|
||||
* @return true if the this file is used only by the given consumer
|
||||
*/
|
||||
boolean isUsedExclusivelyBy(Object consumer) {
|
||||
synchronized (consumers) {
|
||||
return (consumers.size() == 1) && (consumers.contains(consumer));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given tool is using this object.
|
||||
* Returns true if the given consumer is using this object.
|
||||
*/
|
||||
@Override
|
||||
public boolean isUsedBy(Object consumer) {
|
||||
|
|
|
@ -31,7 +31,7 @@ public class AppInfo {
|
|||
tool = t;
|
||||
}
|
||||
|
||||
static void setActiveProject(Project p) {
|
||||
public static void setActiveProject(Project p) {
|
||||
activeProject = p;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@ package ghidra.framework.model;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.util.ReadOnlyException;
|
||||
|
@ -216,7 +217,7 @@ public interface DomainObject {
|
|||
* Returns the list of consumers on this domainObject
|
||||
* @return the list of consumers.
|
||||
*/
|
||||
public ArrayList<Object> getConsumerList();
|
||||
public List<Object> getConsumerList();
|
||||
|
||||
/**
|
||||
* Returns true if the given consumer is using (has open) this domain object.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue