mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/GP-2903_ghidra1_ImmutableDomainObjects--SQUASHED'
This commit is contained in:
commit
b707c2ea6b
11 changed files with 226 additions and 256 deletions
|
@ -169,18 +169,7 @@ public class OpenProgramTask extends Task {
|
||||||
String path = url != null ? url.toString() : domainFile.getPathname();
|
String path = url != null ? url.toString() : domainFile.getPathname();
|
||||||
Object obj = null;
|
Object obj = null;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
obj = domainFile.getReadOnlyDomainObject(consumer, version, taskMonitor);
|
obj = domainFile.getReadOnlyDomainObject(consumer, version, taskMonitor);
|
||||||
|
|
||||||
if (obj == null) {
|
|
||||||
String errorMessage = "Can't open " + contentType + " - \"" + path + "\"";
|
|
||||||
if (version != DomainFile.DEFAULT_VERSION) {
|
|
||||||
errorMessage += " version " + version;
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.showError(this, null, "File Not Found", errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException e) {
|
||||||
// we don't care, the task has been cancelled
|
// we don't care, the task has been cancelled
|
||||||
|
|
|
@ -100,13 +100,17 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
|
||||||
/**
|
/**
|
||||||
* Get the selected domain object for read-only or immutable use.
|
* 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
|
* If an existing open object is selected its original mode applies but consumer will
|
||||||
* be added.
|
* be added. The caller/consumer is responsible for releasing the returned domain object
|
||||||
* @param consumer consumer
|
* when done using it (see {@link DomainObject#release(Object)}).
|
||||||
* @param readOnly true if the domain object should be opened read only, versus immutable
|
* @param consumer domain object consumer
|
||||||
* @return null if a file was not selected
|
* @param immutable true if the domain object should be opened immutable, else false for
|
||||||
|
* read-only. Immutable mode should not be used for content that will be modified. If
|
||||||
|
* read-only indicated an upgrade will always be performed if required.
|
||||||
|
* @return opened domain object or null if a file was not selected or if open failed to
|
||||||
|
* complete.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked") // relies on content class filter
|
@SuppressWarnings("unchecked") // relies on content class filter
|
||||||
public T getDomainObject(Object consumer, boolean readOnly) {
|
public T getDomainObject(Object consumer, boolean immutable) {
|
||||||
T dobj = null;
|
T dobj = null;
|
||||||
if (usingOpenProgramList()) {
|
if (usingOpenProgramList()) {
|
||||||
dobj = getSelectedOpenDomainObject();
|
dobj = getSelectedOpenDomainObject();
|
||||||
|
@ -115,20 +119,19 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
|
||||||
}
|
}
|
||||||
return dobj;
|
return dobj;
|
||||||
}
|
}
|
||||||
|
int version = DomainFile.DEFAULT_VERSION;
|
||||||
if (historyPanel != null) {
|
if (historyPanel != null) {
|
||||||
dobj = (T) historyPanel.getSelectedVersion(consumer, readOnly);
|
version = historyPanel.getSelectedVersionNumber();
|
||||||
}
|
}
|
||||||
if (dobj == null) {
|
|
||||||
DomainFile domainFile = getDomainFile();
|
DomainFile domainFile = getDomainFile();
|
||||||
if (domainFile != null) {
|
if (domainFile != null) {
|
||||||
GetVersionedObjectTask task =
|
GetDomainObjectTask task =
|
||||||
new GetVersionedObjectTask(consumer, domainFile, DomainFile.DEFAULT_VERSION,
|
new GetDomainObjectTask(consumer, domainFile, version, immutable);
|
||||||
readOnly);
|
tool.execute(task, 1000);
|
||||||
tool.execute(task, 1000);
|
return (T) task.getDomainObject();
|
||||||
return (T) task.getVersionedObject();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return dobj;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,7 +17,6 @@ package ghidra.app.plugin.core.diff;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -51,6 +50,7 @@ import ghidra.app.util.viewer.format.FormatManager;
|
||||||
import ghidra.app.util.viewer.listingpanel.*;
|
import ghidra.app.util.viewer.listingpanel.*;
|
||||||
import ghidra.app.util.viewer.util.AddressIndexMap;
|
import ghidra.app.util.viewer.util.AddressIndexMap;
|
||||||
import ghidra.app.util.viewer.util.FieldNavigator;
|
import ghidra.app.util.viewer.util.FieldNavigator;
|
||||||
|
import ghidra.framework.main.GetDomainObjectTask;
|
||||||
import ghidra.framework.main.OpenVersionedFileDialog;
|
import ghidra.framework.main.OpenVersionedFileDialog;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.options.*;
|
import ghidra.framework.options.*;
|
||||||
|
@ -60,7 +60,8 @@ import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.util.*;
|
import ghidra.program.util.*;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.AssertException;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.*;
|
import ghidra.util.task.*;
|
||||||
import help.Help;
|
import help.Help;
|
||||||
import help.HelpService;
|
import help.HelpService;
|
||||||
|
@ -1143,7 +1144,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
||||||
tool.clearStatusInfo();
|
tool.clearStatusInfo();
|
||||||
JComponent component = dialog.getComponent();
|
JComponent component = dialog.getComponent();
|
||||||
|
|
||||||
Program dobj = dialog.getDomainObject(ProgramDiffPlugin.this, false);
|
Program dobj = dialog.getDomainObject(ProgramDiffPlugin.this, true);
|
||||||
if (dobj != null) {
|
if (dobj != null) {
|
||||||
if (openSecondProgram(dobj, component)) {
|
if (openSecondProgram(dobj, component)) {
|
||||||
dialog.close();
|
dialog.close();
|
||||||
|
@ -1151,9 +1152,6 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
displayStatus(component, "Can't Open Selected Program",
|
|
||||||
"Please select a file, not a folder.", OptionDialog.INFORMATION_MESSAGE);
|
|
||||||
});
|
});
|
||||||
dialog.showComponent();
|
dialog.showComponent();
|
||||||
}
|
}
|
||||||
|
@ -1531,16 +1529,19 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean openSecondProgram(DomainFile df) {
|
private boolean openSecondProgram(DomainFile df) {
|
||||||
|
if (!Program.class.isAssignableFrom(df.getDomainObjectClass())) {
|
||||||
|
Msg.error(this, "Failed to launch Diff for non-Program file: " + df.getName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
OpenSecondProgramTask task = new OpenSecondProgramTask(df);
|
GetDomainObjectTask task =
|
||||||
|
new GetDomainObjectTask(this, df, DomainFile.DEFAULT_VERSION, true);
|
||||||
new TaskLauncher(task, tool.getToolFrame(), 500);
|
new TaskLauncher(task, tool.getToolFrame(), 500);
|
||||||
// block until the task completes
|
// block until the task completes
|
||||||
|
|
||||||
if (!task.wasCanceled()) {
|
Program newProgram = (Program) task.getDomainObject();
|
||||||
Program newProgram = task.getDiffProgram();
|
if (newProgram != null) {
|
||||||
if (newProgram != null) {
|
return openSecondProgram(newProgram, null);
|
||||||
return openSecondProgram(newProgram, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1851,71 +1852,6 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OpenSecondProgramTask extends Task {
|
|
||||||
private DomainFile domainFile;
|
|
||||||
private Program diffProgram;
|
|
||||||
private TaskMonitor monitor;
|
|
||||||
|
|
||||||
OpenSecondProgramTask(DomainFile domainFile) {
|
|
||||||
super("Opening Program for Diff", true, true, true);
|
|
||||||
this.domainFile = domainFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(TaskMonitor tm) {
|
|
||||||
this.monitor = tm;
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
monitor.setMessage("Waiting on program file...");
|
|
||||||
diffProgram =
|
|
||||||
(Program) domainFile.getImmutableDomainObject(ProgramDiffPlugin.this,
|
|
||||||
DomainFile.DEFAULT_VERSION, monitor);
|
|
||||||
}
|
|
||||||
catch (VersionException e) {
|
|
||||||
if (e.isUpgradable()) {
|
|
||||||
try {
|
|
||||||
diffProgram =
|
|
||||||
(Program) domainFile.getReadOnlyDomainObject(ProgramDiffPlugin.this,
|
|
||||||
DomainFile.DEFAULT_VERSION, monitor);
|
|
||||||
}
|
|
||||||
catch (VersionException exc) {
|
|
||||||
Msg.showError(this, null, "Error Getting Diff Program",
|
|
||||||
"Getting read only file failed");
|
|
||||||
}
|
|
||||||
catch (IOException exc) {
|
|
||||||
if (!monitor.isCancelled()) {
|
|
||||||
Msg.showError(this, null, "Error Getting Diff Program",
|
|
||||||
"Getting read only file failed", exc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Msg.showError(this, null, "Error Getting Diff Program",
|
|
||||||
"File cannot be upgraded.");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
Msg.showError(this, null, "Error Getting Diff Program",
|
|
||||||
"Getting read only file failed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (CancelledException e) {
|
|
||||||
// For now do nothing if user cancels
|
|
||||||
}
|
|
||||||
|
|
||||||
monitor.setMessage("");
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean wasCanceled() {
|
|
||||||
return monitor.isCancelled();
|
|
||||||
}
|
|
||||||
|
|
||||||
Program getDiffProgram() {
|
|
||||||
return diffProgram;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void domainObjectChanged(DomainObjectChangedEvent event) {
|
public void domainObjectChanged(DomainObjectChangedEvent event) {
|
||||||
if (secondaryDiffProgram != null && diffDetailsProvider != null) {
|
if (secondaryDiffProgram != null && diffDetailsProvider != null) {
|
||||||
|
|
|
@ -20,7 +20,6 @@ import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.help.UnsupportedOperationException;
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
|
@ -45,9 +44,6 @@ import ghidra.util.task.TaskMonitor;
|
||||||
*/
|
*/
|
||||||
public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBContentHandler<T> {
|
public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBContentHandler<T> {
|
||||||
|
|
||||||
// TODO: Need to improve by making this meta data on file instead of database content.
|
|
||||||
// Metadata use would eliminate need for DB but we lack support for non-DB files.
|
|
||||||
|
|
||||||
public static final String URL_METADATA_KEY = "link.url";
|
public static final String URL_METADATA_KEY = "link.url";
|
||||||
|
|
||||||
// 16x16 link icon where link is placed in lower-left corner
|
// 16x16 link icon where link is placed in lower-left corner
|
||||||
|
@ -76,15 +72,29 @@ public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBCon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public final T getReadOnlyObject(FolderItem item, int version, boolean okToUpgrade,
|
public final T getReadOnlyObject(FolderItem item, int version, boolean okToUpgrade,
|
||||||
Object consumer, TaskMonitor monitor)
|
Object consumer, TaskMonitor monitor)
|
||||||
throws IOException, VersionException, CancelledException {
|
throws IOException, VersionException, CancelledException {
|
||||||
|
|
||||||
if (!okToUpgrade) {
|
if (!okToUpgrade) {
|
||||||
throw new IllegalArgumentException("okToUpgrade must be true");
|
throw new UnsupportedOperationException("okToUpgrade must be true for link-file");
|
||||||
}
|
}
|
||||||
|
return getObject(item, version, consumer, monitor, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getImmutableObject(FolderItem item, Object consumer, int version, int minChangeVersion,
|
||||||
|
TaskMonitor monitor) throws IOException, CancelledException, VersionException {
|
||||||
|
if (minChangeVersion != -1) {
|
||||||
|
throw new UnsupportedOperationException("minChangeVersion must be -1 for link-file");
|
||||||
|
}
|
||||||
|
return getObject(item, version, consumer, monitor, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private T getObject(FolderItem item, int version, Object consumer, TaskMonitor monitor,
|
||||||
|
boolean immutable)
|
||||||
|
throws IOException, VersionException, CancelledException {
|
||||||
|
|
||||||
URL url = getURL(item);
|
URL url = getURL(item);
|
||||||
|
|
||||||
|
@ -112,10 +122,11 @@ public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBCon
|
||||||
DomainFile linkedFile = (DomainFile) content;
|
DomainFile linkedFile = (DomainFile) content;
|
||||||
if (!getDomainObjectClass().isAssignableFrom(linkedFile.getDomainObjectClass())) {
|
if (!getDomainObjectClass().isAssignableFrom(linkedFile.getDomainObjectClass())) {
|
||||||
throw new BadLinkException(
|
throw new BadLinkException(
|
||||||
"Excepted " + getDomainObjectClass() + " but linked to " +
|
"Expected " + getDomainObjectClass() + " but linked to " +
|
||||||
linkedFile.getDomainObjectClass());
|
linkedFile.getDomainObjectClass());
|
||||||
}
|
}
|
||||||
return (T) linkedFile.getReadOnlyDomainObject(consumer, version, monitor);
|
return immutable ? (T) linkedFile.getImmutableDomainObject(consumer, version, monitor)
|
||||||
|
: (T) linkedFile.getReadOnlyDomainObject(consumer, version, monitor);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
|
@ -128,16 +139,8 @@ public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBCon
|
||||||
public final T getDomainObject(FolderItem item, FileSystem userfs, long checkoutId,
|
public final T getDomainObject(FolderItem item, FileSystem userfs, long checkoutId,
|
||||||
boolean okToUpgrade, boolean okToRecover, Object consumer, TaskMonitor monitor)
|
boolean okToUpgrade, boolean okToRecover, Object consumer, TaskMonitor monitor)
|
||||||
throws IOException, CancelledException, VersionException {
|
throws IOException, CancelledException, VersionException {
|
||||||
// Always upgrade if needed for read-only object
|
// getReadOnlyObject or getImmutableObject should be used
|
||||||
return getReadOnlyObject(item, DomainFile.DEFAULT_VERSION, true, consumer, monitor);
|
throw new UnsupportedOperationException("link-file does not support getDomainObject");
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T getImmutableObject(FolderItem item, Object consumer, int version, int minChangeVersion,
|
|
||||||
TaskMonitor monitor) throws IOException, CancelledException, VersionException {
|
|
||||||
//throw new UnsupportedOperationException("link-file does not support getImmutableObject");
|
|
||||||
// See GP-2903
|
|
||||||
return getReadOnlyObject(item, version, true, consumer, monitor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
/* ###
|
||||||
|
* 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 java.io.IOException;
|
||||||
|
|
||||||
|
import docking.widgets.OptionDialog;
|
||||||
|
import ghidra.framework.client.ClientUtil;
|
||||||
|
import ghidra.framework.model.DomainFile;
|
||||||
|
import ghidra.framework.model.DomainObject;
|
||||||
|
import ghidra.util.VersionExceptionHandler;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.exception.VersionException;
|
||||||
|
import ghidra.util.task.Task;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A modal task that gets a domain object for a specified version.
|
||||||
|
* Object is either open read-only or immutable.
|
||||||
|
*
|
||||||
|
* NOTE: This task is not intended to open a domain file for modification and saving back
|
||||||
|
* to a project.
|
||||||
|
*
|
||||||
|
* A file open for read-only use will be upgraded if needed and is possible. Once open it is
|
||||||
|
* important that the specified consumer be released from the domain object when done using
|
||||||
|
* the open object (see {@link DomainObject#release(Object)}).
|
||||||
|
*/
|
||||||
|
public class GetDomainObjectTask extends Task {
|
||||||
|
|
||||||
|
private Object consumer;
|
||||||
|
private DomainFile domainFile;
|
||||||
|
private int versionNumber;
|
||||||
|
private boolean immutable;
|
||||||
|
|
||||||
|
private DomainObject versionedObj;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct task open specified domainFile read only.
|
||||||
|
* An upgrade is performed if needed and is possible.
|
||||||
|
* @param consumer consumer of the domain object
|
||||||
|
* @param domainFile domain file
|
||||||
|
* @param versionNumber version
|
||||||
|
*/
|
||||||
|
public GetDomainObjectTask(Object consumer, DomainFile domainFile, int versionNumber) {
|
||||||
|
this(consumer, domainFile, versionNumber, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct task open specified domainFile read only or immutable. Immutable mode should not
|
||||||
|
* be used for content that will be modified.
|
||||||
|
* If read-only an upgrade is performed if needed, if immutable the user will be prompted
|
||||||
|
* if an upgrade should be performed if possible in which case it will open read-only.
|
||||||
|
* @param consumer consumer of the domain object
|
||||||
|
* @param domainFile domain file
|
||||||
|
* @param versionNumber version
|
||||||
|
* @param immutable true if the object should be open immutable, else read-only.
|
||||||
|
*/
|
||||||
|
public GetDomainObjectTask(Object consumer, DomainFile domainFile, int versionNumber,
|
||||||
|
boolean immutable) {
|
||||||
|
super("Get Versioned Domain Object", true, false, true);
|
||||||
|
this.consumer = consumer;
|
||||||
|
this.domainFile = domainFile;
|
||||||
|
this.versionNumber = versionNumber;
|
||||||
|
this.immutable = immutable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(TaskMonitor monitor) {
|
||||||
|
String contentType = domainFile.getContentType();
|
||||||
|
try {
|
||||||
|
monitor.setMessage("Getting Version " + versionNumber + " for " + domainFile.getName());
|
||||||
|
if (immutable) {
|
||||||
|
versionedObj =
|
||||||
|
domainFile.getImmutableDomainObject(consumer, versionNumber, monitor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Upgrade will be performed if required
|
||||||
|
versionedObj = domainFile.getReadOnlyDomainObject(consumer, versionNumber, monitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (CancelledException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
ClientUtil.handleException(AppInfo.getActiveProject().getRepository(), e,
|
||||||
|
contentType + " Open", null);
|
||||||
|
} catch (VersionException e) {
|
||||||
|
if (immutable && e.isUpgradable()) {
|
||||||
|
String detailMessage =
|
||||||
|
e.getDetailMessage() == null ? "" : "\n" + e.getDetailMessage();
|
||||||
|
String title = "Upgrade " + contentType + " Data? " + domainFile.getName();
|
||||||
|
String message = "The " + contentType + " file you are attempting to open" +
|
||||||
|
" is an older version." + detailMessage + "\n \n" +
|
||||||
|
"Would you like to Upgrade it now?";
|
||||||
|
int rc = OptionDialog.showOptionDialog(null, title, message, "Upgrade",
|
||||||
|
OptionDialog.QUESTION_MESSAGE);
|
||||||
|
if (rc == OptionDialog.OPTION_ONE) {
|
||||||
|
// try again as read-only
|
||||||
|
immutable = false;
|
||||||
|
run(monitor);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VersionExceptionHandler.showVersionError(null, domainFile.getName(),
|
||||||
|
domainFile.getContentType(), contentType + " Open", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the domain object instance.
|
||||||
|
* @return domain object which was opened or null if task cancelled or failed
|
||||||
|
*/
|
||||||
|
public DomainObject getDomainObject() {
|
||||||
|
return versionedObj;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,104 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
|
||||||
* 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 java.io.IOException;
|
|
||||||
|
|
||||||
import ghidra.framework.client.ClientUtil;
|
|
||||||
import ghidra.framework.model.DomainFile;
|
|
||||||
import ghidra.framework.model.DomainObject;
|
|
||||||
import ghidra.util.Msg;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
|
||||||
import ghidra.util.exception.VersionException;
|
|
||||||
import ghidra.util.task.Task;
|
|
||||||
import ghidra.util.task.TaskMonitor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A modal task that gets a domain object for a specific version.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class GetVersionedObjectTask extends Task {
|
|
||||||
|
|
||||||
private Object consumer;
|
|
||||||
private DomainFile domainFile;
|
|
||||||
private int versionNumber;
|
|
||||||
private DomainObject versionedObj;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor; task will get a read only domain object
|
|
||||||
* @param consumer consumer of the domain object
|
|
||||||
* @param domainFile domain file
|
|
||||||
* @param versionNumber version
|
|
||||||
*/
|
|
||||||
public GetVersionedObjectTask(Object consumer, DomainFile domainFile,
|
|
||||||
int versionNumber) {
|
|
||||||
this(consumer, domainFile, versionNumber, true);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* @param consumer consumer of the domain object
|
|
||||||
* @param domainFile domain file
|
|
||||||
* @param versionNumber version
|
|
||||||
* @param readOnly true if the object should be read only versus
|
|
||||||
* immutable
|
|
||||||
*/
|
|
||||||
public GetVersionedObjectTask(Object consumer, DomainFile domainFile,
|
|
||||||
int versionNumber, boolean readOnly) {
|
|
||||||
|
|
||||||
super("Get Versioned Domain Object", true, false, true);
|
|
||||||
this.consumer = consumer;
|
|
||||||
this.domainFile = domainFile;
|
|
||||||
this.versionNumber = versionNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see ghidra.util.task.Task#run(ghidra.util.task.TaskMonitor)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void run(TaskMonitor monitor) {
|
|
||||||
try {
|
|
||||||
monitor.setMessage("Getting Version " + versionNumber +
|
|
||||||
" for " + domainFile.getName());
|
|
||||||
versionedObj =
|
|
||||||
domainFile.getReadOnlyDomainObject(consumer, versionNumber,
|
|
||||||
monitor);
|
|
||||||
}catch (CancelledException e) {
|
|
||||||
}catch (IOException e) {
|
|
||||||
if (domainFile.isInWritableProject()) {
|
|
||||||
ClientUtil.handleException(AppInfo.getActiveProject().getRepository(), e,
|
|
||||||
"Get Versioned Object", null);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Msg.showError(this, null,
|
|
||||||
"Error Getting Versioned Object", "Could not get version " + versionNumber +
|
|
||||||
" for " + domainFile.getName() + ": " + e, e);
|
|
||||||
}
|
|
||||||
} catch (VersionException e) {
|
|
||||||
Msg.showError(this,
|
|
||||||
null,
|
|
||||||
"Error Getting Versioned Object", "Could not get version " + versionNumber +
|
|
||||||
" for " + domainFile.getName() + ": " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Return the versioned domain object.
|
|
||||||
*/
|
|
||||||
public DomainObject getVersionedObject() {
|
|
||||||
return versionedObj;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -370,9 +370,9 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DomainObject getVersionedObject(DomainFile file, int versionNumber) {
|
private DomainObject getVersionedObject(DomainFile file, int versionNumber) {
|
||||||
GetVersionedObjectTask task = new GetVersionedObjectTask(this, file, versionNumber);
|
GetDomainObjectTask task = new GetDomainObjectTask(this, file, versionNumber);
|
||||||
plugin.getTool().execute(task, 250);
|
plugin.getTool().execute(task, 250);
|
||||||
return task.getVersionedObject();
|
return task.getDomainObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
|
@ -22,7 +22,7 @@ import java.io.IOException;
|
||||||
import docking.widgets.tree.GTreeNode;
|
import docking.widgets.tree.GTreeNode;
|
||||||
import ghidra.app.util.FileOpenDataFlavorHandler;
|
import ghidra.app.util.FileOpenDataFlavorHandler;
|
||||||
import ghidra.framework.client.*;
|
import ghidra.framework.client.*;
|
||||||
import ghidra.framework.main.GetVersionedObjectTask;
|
import ghidra.framework.main.GetDomainObjectTask;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.util.task.TaskLauncher;
|
import ghidra.util.task.TaskLauncher;
|
||||||
|
@ -35,15 +35,18 @@ public final class LocalVersionInfoHandler
|
||||||
VersionInfo info = (VersionInfo) obj;
|
VersionInfo info = (VersionInfo) obj;
|
||||||
|
|
||||||
DomainFile file = tool.getProject().getProjectData().getFile(info.getDomainFilePath());
|
DomainFile file = tool.getProject().getProjectData().getFile(info.getDomainFilePath());
|
||||||
GetVersionedObjectTask task =
|
GetDomainObjectTask task =
|
||||||
new GetVersionedObjectTask(this, file, info.getVersionNumber());
|
new GetDomainObjectTask(this, file, info.getVersionNumber());
|
||||||
tool.execute(task, 250);
|
tool.execute(task, 250);
|
||||||
DomainObject versionedObj = task.getVersionedObject();
|
DomainObject versionedObj = task.getDomainObject();
|
||||||
|
|
||||||
if (versionedObj != null) {
|
if (versionedObj != null) {
|
||||||
DomainFile vfile = versionedObj.getDomainFile();
|
try {
|
||||||
tool.acceptDomainFiles(new DomainFile[] { vfile });
|
DomainFile vfile = versionedObj.getDomainFile();
|
||||||
versionedObj.release(this);
|
tool.acceptDomainFiles(new DomainFile[] { vfile });
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
versionedObj.release(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.table.*;
|
import docking.widgets.table.*;
|
||||||
import ghidra.app.util.GenericHelpTopics;
|
import ghidra.app.util.GenericHelpTopics;
|
||||||
import ghidra.framework.client.ClientUtil;
|
import ghidra.framework.client.ClientUtil;
|
||||||
import ghidra.framework.main.GetVersionedObjectTask;
|
import ghidra.framework.main.GetDomainObjectTask;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.store.ItemCheckoutStatus;
|
import ghidra.framework.store.ItemCheckoutStatus;
|
||||||
|
@ -143,31 +143,36 @@ public class VersionHistoryPanel extends JPanel implements Draggable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the domain object for the selected version.
|
* Get the selected {@link Version}.
|
||||||
* @param consumer the consumer
|
* @return selected {@link Version} or null if no selection
|
||||||
* @param readOnly true if read only
|
|
||||||
* @return null if there is no selection
|
|
||||||
*/
|
*/
|
||||||
public DomainObject getSelectedVersion(Object consumer, boolean readOnly) {
|
public Version getSelectedVersion() {
|
||||||
int row = table.getSelectedRow();
|
int row = table.getSelectedRow();
|
||||||
if (row >= 0) {
|
if (row >= 0) {
|
||||||
Version version = tableModel.getVersionAt(row);
|
return tableModel.getVersionAt(row);
|
||||||
return getVersionedObject(consumer, version.getVersion(), readOnly);
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a version selection has been made.
|
||||||
|
* @return true if version selection has been made, esle false
|
||||||
|
*/
|
||||||
public boolean isVersionSelected() {
|
public boolean isVersionSelected() {
|
||||||
return !table.getSelectionModel().isSelectionEmpty();
|
return !table.getSelectionModel().isSelectionEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the selected version number or {@link DomainFile#DEFAULT_VERSION} if no selection.
|
||||||
|
* @return selected version number
|
||||||
|
*/
|
||||||
public int getSelectedVersionNumber() {
|
public int getSelectedVersionNumber() {
|
||||||
int row = table.getSelectedRow();
|
int row = table.getSelectedRow();
|
||||||
if (row >= 0) {
|
if (row >= 0) {
|
||||||
Version version = tableModel.getVersionAt(row);
|
Version version = tableModel.getVersionAt(row);
|
||||||
return version.getVersion();
|
return version.getVersion();
|
||||||
}
|
}
|
||||||
return -1;
|
return DomainFile.DEFAULT_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -260,11 +265,11 @@ public class VersionHistoryPanel extends JPanel implements Draggable {
|
||||||
dragSource.createDefaultDragGestureRecognizer(table, dragAction, dragGestureAdapter);
|
dragSource.createDefaultDragGestureRecognizer(table, dragAction, dragGestureAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DomainObject getVersionedObject(Object consumer, int versionNumber, boolean readOnly) {
|
private DomainObject getVersionedObject(Object consumer, int versionNumber, boolean immutable) {
|
||||||
GetVersionedObjectTask task =
|
GetDomainObjectTask task =
|
||||||
new GetVersionedObjectTask(consumer, domainFile, versionNumber, readOnly);
|
new GetDomainObjectTask(consumer, domainFile, versionNumber, immutable);
|
||||||
tool.execute(task, 1000);
|
tool.execute(task, 1000);
|
||||||
return task.getVersionedObject();
|
return task.getDomainObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void delete() {
|
private void delete() {
|
||||||
|
@ -337,13 +342,17 @@ public class VersionHistoryPanel extends JPanel implements Draggable {
|
||||||
Version version = tableModel.getVersionAt(row);
|
Version version = tableModel.getVersionAt(row);
|
||||||
DomainObject versionedObj = getVersionedObject(this, version.getVersion(), true);
|
DomainObject versionedObj = getVersionedObject(this, version.getVersion(), true);
|
||||||
if (versionedObj != null) {
|
if (versionedObj != null) {
|
||||||
if (toolName != null) {
|
try {
|
||||||
tool.getToolServices().launchTool(toolName, versionedObj.getDomainFile());
|
if (toolName != null) {
|
||||||
|
tool.getToolServices().launchTool(toolName, versionedObj.getDomainFile());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tool.getToolServices().launchDefaultTool(versionedObj.getDomainFile());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
finally {
|
||||||
tool.getToolServices().launchDefaultTool(versionedObj.getDomainFile());
|
versionedObj.release(this);
|
||||||
}
|
}
|
||||||
versionedObj.release(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -187,6 +187,9 @@ public interface DomainFile extends Comparable<DomainFile> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new DomainObject that cannot be changed or saved to its original file.
|
* Returns a new DomainObject that cannot be changed or saved to its original file.
|
||||||
|
* NOTE: The use of this method should generally be avoided since it can't
|
||||||
|
* handle version changes that may have occured and require a data upgrade
|
||||||
|
* (e.g., DB schema change).
|
||||||
* @param consumer consumer of the domain object which is responsible for
|
* @param consumer consumer of the domain object which is responsible for
|
||||||
* releasing it after use.
|
* releasing it after use.
|
||||||
* @param version the domain object version requested. DEFAULT_VERSION should be
|
* @param version the domain object version requested. DEFAULT_VERSION should be
|
||||||
|
|
|
@ -145,7 +145,6 @@ public class ProgramContentHandler extends DBWithUserDataContentHandler<ProgramD
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable t) {
|
||||||
Msg.error(this, "getReadOnlyObject failed", t);
|
Msg.error(this, "getReadOnlyObject failed", t);
|
||||||
t.printStackTrace();
|
|
||||||
String msg = t.getMessage();
|
String msg = t.getMessage();
|
||||||
if (msg == null) {
|
if (msg == null) {
|
||||||
msg = t.toString();
|
msg = t.toString();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue