GP-2897 Allow Diff with another open program within same tool. Modified

OpenVersionedFileDialog to faciltate the program selection.
This commit is contained in:
ghidra1 2022-12-07 17:09:00 -05:00
parent dcf147150e
commit d377b9642b
17 changed files with 536 additions and 281 deletions

View file

@ -21,14 +21,14 @@
program in order to get another user's changes into your program.
</p>
<h2>
<a name="Open_Close_Program_View"></a>
Opening and Closing the Second Program
<a name="Open_Close_Diff_View"></a>
Opening and Closing the Diff View
</h2>
<blockquote>
<p>The <b>Open/Close Diff View</b> icon
<img src="images/table_relationship.png" alt="">
in the Code Browser tool bar is used for both opening and closing
the second program in the Code Browser. This is one of two ways to open the Diff
a second program in the Code Browser Diff panel. This is one of two ways to open the Diff
tool. The other is the menu action, <span style="font-weight: bold;">Tools</span>
<b>
<img src="../../shared/arrow.gif" alt="-&gt;" border="0">
@ -70,9 +70,9 @@
<img src="../../shared/arrow.gif" alt="-&gt;" border="0">
Program Differences...
</b>. This is one of two ways to open the Diff
tool. The other is the <b>Open/Close Program Diff </b> icon
tool. The other is the <b>Open/Close Diff View</b> icon
<img src="images/table_relationship.png" alt="">
in the Code Browser tool bar which is described above in <b>Open/Close Diff View</b>.
in the Code Browser tool bar which is described above in <b>Opening and Closing the Diff View</b>.
The following describes using the menu action to open the Diff tool.
</p>
<p>With a program open in the Code Browser tool, do the following to
@ -100,14 +100,27 @@
defined. In other words, they should be the same type of program
(i.e. based on the same program language).<br>
<img src="../../shared/tip.png" alt="">
If you wish to Diff against a previous version of a
<b>versioned program, </b>select the <b>History&gt;&gt;</b>
button of a program. Select the versioned program from the tree.
Next select the desired version of the program from the history
list on the right side of the dialog.<br>
If you wish to Diff against a specific version of a
<b>versioned program</b>, a specific version may be seleected from the
<b>Version History</b> table. The project file history panel is displayed
when the <b>History&gt;&gt;</b> button is clicked.
Select the versioned program from the tree.
Next select the desired version of the program from the <b>Version History</b>
table on the right side of the dialog.<br>
<div align="center">
<img src="images/SelectOtherVersionedProgram.png" alt=""> <br>
</div>
<img src="../../shared/tip.png" alt="">
If you wish to Diff against another program which is already open in the same tool
you can select a compatible program from the <b>Open Programs</b> tab. Programs
which are not compatible (e.g., different architecture) are not shown in the table.
The <b>Open Programs</b> tab is not available if compatible open programs are not
found. You may return to the project file tree selection panel by clicking the
<b>Project Files</b> tab.
<div align="center">
<img src="images/SelectOpenProgram.png" alt=""> <br>
</div>
</li>
<li>Click the <b>OK</b> button.</li>
<li>The <i>Determine Program Differences</i> dialog is displayed.
@ -269,7 +282,7 @@
</tr>
<tr>
<td align="left" valign="top" width="16">
<a href="#Open_Close_Program_View">
<a href="#Open_Close_Diff_View">
<img src="images/table_relationship.png" alt="" border="0">
</a>
</td>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Before After
Before After

View file

@ -56,7 +56,7 @@ class DiffActionManager {
static final String GET_DIFFS_ACTION = "Get Differences";
static final String SELECT_ALL_DIFFS_ACTION = "Select All Differences";
static final String P1_SELECT_TO_P2_ACTION = "Set Program1 Selection On Program2";
static final String OPEN_CLOSE_PROGRAM2_ACTION = "Open/Close Program View";
static final String OPEN_CLOSE_DIFF_VIEW_ACTION = "Open/Close Diff View";
static final String VIEW_PROGRAM_DIFF_ACTION = "View Program Differences";
private DockingAction applyDiffsAction;
@ -69,11 +69,12 @@ class DiffActionManager {
private DockingAction getDiffsAction;
private DockingAction selectAllDiffsAction;
private DockingAction p1SelectToP2Action;
private ToggleDockingAction openCloseProgram2Action;
private OpenCloseDiffViewAction openCloseDiffViewAction;
private DockingAction viewProgramDiffAction;
/**
* Creates an action manager for the Program Diff plugin.
* @param plugin Diff plugin
*/
public DiffActionManager(ProgramDiffPlugin plugin) {
this.plugin = plugin;
@ -86,7 +87,7 @@ class DiffActionManager {
*/
void setCodeViewerService(CodeViewerService codeViewerService) {
this.codeViewerService = codeViewerService;
codeViewerService.addLocalAction(openCloseProgram2Action);
codeViewerService.addLocalAction(openCloseDiffViewAction);
}
/**
@ -127,7 +128,7 @@ class DiffActionManager {
*/
void programClosed(Program program) {
boolean hasProgram = (plugin.getCurrentProgram() != null);
openCloseProgram2Action.setEnabled(hasProgram && !plugin.isTaskInProgress());
openCloseDiffViewAction.setEnabled(hasProgram && !plugin.isTaskInProgress());
}
/**
@ -136,26 +137,27 @@ class DiffActionManager {
* @param program the newly active program
*/
void setActiveProgram(Program program) {
viewProgramDiffAction.setEnabled(program != null);
boolean enabled = program != null && !plugin.isTaskInProgress();
openCloseProgram2Action.setEnabled(enabled);
openCloseDiffViewAction.setEnabled(enabled);
if (enabled) {
if (openCloseProgram2Action.isSelected()) {
if (openCloseDiffViewAction.isSelected()) {
// we are diffing--is the current program the diff program?
Program firstProgram = plugin.getFirstProgram();
if (firstProgram == program) {
openCloseProgram2Action.setDescription("Close Diff View");
openCloseDiffViewAction.setDescription("Close Diff View");
}
else {
openCloseProgram2Action.setDescription("Bring Diff View to Front");
openCloseDiffViewAction.setDescription("Bring Diff View to Front");
}
}
}
else {
// no active diff
openCloseProgram2Action.setDescription("Open Diff View");
openCloseDiffViewAction.setDescription("Open Diff View");
}
}
@ -164,16 +166,16 @@ class DiffActionManager {
* second program to the program Diff. Actions are adjusted accordingly.
*/
void secondProgramOpened() {
openCloseProgram2Action.setSelected(true);
openCloseProgram2Action.setDescription("Close Diff View");
openCloseDiffViewAction.setSelected(true);
openCloseDiffViewAction.setDescription("Close Diff View");
Program firstProgram = plugin.getFirstProgram();
Program secondProgram = plugin.getSecondProgram();
String firstName = firstProgram.getName();
String secondName = secondProgram.getName();
String firstName = firstProgram.getDomainFile().getName();
String secondName = secondProgram.getDomainFile().getName();
//@formatter:off
openCloseProgram2Action.setDescription(
openCloseDiffViewAction.setDescription(
"<html><center>Close Diff View</center><br>" +
"Current diff: " +
"<b>"+HTMLUtilities.escapeHTML(firstName)+"</b> to <b>" +HTMLUtilities.escapeHTML(secondName)+"</b>");
@ -185,8 +187,8 @@ class DiffActionManager {
* program Diff was closed. Actions are adjusted accordingly.
*/
void secondProgramClosed() {
openCloseProgram2Action.setSelected(false);
openCloseProgram2Action.setDescription("Open Diff View");
openCloseDiffViewAction.setSelected(false);
openCloseDiffViewAction.setDescription("Open Diff View");
showDiffSettingsAction.setEnabled(false);
diffDetailsAction.setEnabled(false);
removeActions();
@ -197,7 +199,7 @@ class DiffActionManager {
}
void setOpenCloseActionSelected(boolean selected) {
openCloseProgram2Action.setSelected(selected);
openCloseDiffViewAction.setSelected(selected);
}
void updateActions(boolean taskInProgress, boolean inDiff, boolean hasSelectionInView,
@ -217,32 +219,34 @@ class DiffActionManager {
Program currentProgram = plugin.getCurrentProgram();
boolean hasProgram = (currentProgram != null);
openCloseProgram2Action.setEnabled(hasProgram && !taskInProgress);
openCloseDiffViewAction.setEnabled(hasProgram && !taskInProgress);
}
/**
* Removes all the actions.
*/
void dispose() {
codeViewerService.removeLocalAction(openCloseProgram2Action);
codeViewerService.removeLocalAction(openCloseDiffViewAction);
plugin.getTool().removeAction(viewProgramDiffAction);
removeActions();
}
private void createActions() {
viewProgramDiffAction = new DockingAction(VIEW_PROGRAM_DIFF_ACTION, plugin.getName()) {
@Override
public void actionPerformed(ActionContext context) {
plugin.selectProgram2();
}
};
String[] menuPath = { ToolConstants.MENU_TOOLS, "Program &Differences..." };
viewProgramDiffAction =
new DockingAction(VIEW_PROGRAM_DIFF_ACTION, plugin.getName()) {
@Override
public void actionPerformed(ActionContext context) {
plugin.selectProgram2();
}
};
viewProgramDiffAction.setEnabled(plugin.getCurrentProgram() != null);
viewProgramDiffAction.setMenuBarData(new MenuData(menuPath, "View"));
viewProgramDiffAction.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_TOOLS, VIEW_PROGRAM_DIFF_ACTION + "..." },
"ProgramDiff"));
viewProgramDiffAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_2, 0));
viewProgramDiffAction.setHelpLocation(
new HelpLocation(HelpTopics.DIFF, "Program_Differences"));
viewProgramDiffAction
.setHelpLocation(new HelpLocation(HelpTopics.DIFF, "Program_Differences"));
plugin.getTool().addAction(viewProgramDiffAction);
applyDiffsAction = new DiffAction(APPLY_DIFFS_ACTION) {
@ -377,72 +381,7 @@ class DiffActionManager {
"Select Program 2 highlights using selection in Program 1.");
p1SelectToP2Action.setToolBarData(new ToolBarData(icon, SELECT_GROUP));
openCloseProgram2Action =
new ToggleDockingAction(OPEN_CLOSE_PROGRAM2_ACTION, plugin.getName()) {
@Override
public void actionPerformed(ActionContext context) {
//
// No active diff--start one.
//
if (openCloseProgram2Action.isSelected()) {
plugin.selectProgram2();
return;
}
//
// We have a diff session--is the current program the one for the diff session?
// If not, simply make the diff program the active program (this is useful for
// users when they were diffing, but then opened a different program).
//
if (activateDiffProgram()) {
// clicking the action will change the selected state--keep it selected
setSelected(true);
setDescription("Close Diff View");
return;
}
//
// Otherwise, close the diff.
//
closeDiff();
}
private void closeDiff() {
int choice = OptionDialog.showYesNoCancelDialog(null, "Close Diff Session",
"Close the current diff session?");
if (choice == OptionDialog.YES_OPTION) {
plugin.closeProgram2();
setDescription("Open Diff View");
}
else {
// clicking the action will change the selected state--keep it selected
setSelected(true);
setDescription("Close Diff View");
}
}
private boolean activateDiffProgram() {
Program currentProgram = plugin.getCurrentProgram();
Program firstProgram = plugin.getFirstProgram();
boolean isFirstProgram = (firstProgram == currentProgram);
if (isFirstProgram) {
return false; // already active--nothing to do!
}
plugin.activeProgram(firstProgram);
return true;
}
};
icon = new GIcon("icon.plugin.programdiff.open.close.program");
openCloseProgram2Action.setEnabled(false);
openCloseProgram2Action.setKeyBindingData(
new KeyBindingData('C', InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK));
openCloseProgram2Action.setToolBarData(new ToolBarData(icon, "zzz"));
openCloseProgram2Action.setHelpLocation(
new HelpLocation(HelpTopics.DIFF, OPEN_CLOSE_PROGRAM2_ACTION));
openCloseProgram2Action.setSelected(false);
openCloseProgram2Action.setDescription("Open Diff View");
openCloseDiffViewAction = new OpenCloseDiffViewAction();
}
private abstract class DiffAction extends DockingAction {
@ -457,4 +396,73 @@ class DiffActionManager {
return (context instanceof OtherPanelContext);
}
}
private class OpenCloseDiffViewAction extends ToggleDockingAction {
OpenCloseDiffViewAction() {
super(OPEN_CLOSE_DIFF_VIEW_ACTION, plugin.getName());
GIcon icon = new GIcon("icon.plugin.programdiff.open.close.program");
setEnabled(false);
setToolBarData(new ToolBarData(icon, "zzz"));
setHelpLocation(
new HelpLocation(HelpTopics.DIFF, OPEN_CLOSE_DIFF_VIEW_ACTION));
setSelected(false);
setDescription("Open Diff View");
}
@Override
public void actionPerformed(ActionContext context) {
//
// No active diff--start one.
//
if (openCloseDiffViewAction.isSelected()) {
plugin.selectProgram2();
return;
}
//
// We have a diff session--is the current program the one for the diff session?
// If not, simply make the diff program the active program (this is useful for
// users when they were diffing, but then opened a different program).
//
if (activateDiffProgram()) {
// clicking the action will change the selected state--keep it selected
setSelected(true);
setDescription("Close Diff View");
return;
}
//
// Otherwise, close the diff.
//
closeDiff();
}
private void closeDiff() {
int choice = OptionDialog.showYesNoCancelDialog(null, "Close Diff Session",
"Close the current diff session?");
if (choice == OptionDialog.YES_OPTION) {
plugin.closeProgram2();
setDescription("Open Diff View");
}
else {
// clicking the action will change the selected state--keep it selected
setSelected(true);
setDescription("Close Diff View");
}
}
private boolean activateDiffProgram() {
Program currentProgram = plugin.getCurrentProgram();
Program firstProgram = plugin.getFirstProgram();
boolean isFirstProgram = (firstProgram == currentProgram);
if (isFirstProgram) {
return false; // already active--nothing to do!
}
plugin.activeProgram(firstProgram);
return true;
}
}
}

View file

@ -20,6 +20,7 @@ import java.awt.event.*;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.text.*;
@ -59,8 +60,7 @@ import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.util.*;
import ghidra.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.exception.*;
import ghidra.util.task.*;
import help.Help;
import help.HelpService;
@ -82,7 +82,8 @@ import help.HelpService;
"the current program. This plugin also computes differences between the two " +
"programs and allows the user to apply differences from the second program onto" +
"the first.",
servicesRequired = { GoToService.class, CodeViewerService.class, MarkerService.class },
servicesRequired = { GoToService.class, CodeViewerService.class, MarkerService.class,
ProgramManager.class },
servicesProvided = { DiffService.class },
eventsProduced = { ProgramSelectionPluginEvent.class, ViewChangedPluginEvent.class },
eventsConsumed = { ProgramClosedPluginEvent.class, ViewChangedPluginEvent.class }
@ -101,6 +102,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
private Color cursorHighlightColor = GhidraOptions.DEFAULT_CURSOR_LINE_COLOR;
protected static final HelpService help = Help.getHelpService();
private ProgramManager programManagerService;
private GoToService goToService;
private CodeViewerService codeViewerService;
private MarkerManager markerManager;
@ -139,7 +141,6 @@ public class ProgramDiffPlugin extends ProgramPlugin
private DiffDetailsProvider diffDetailsProvider;
private boolean settingLocation;
private ActionListener okListener;
private DiffTaskListener diffTaskListener = DiffTaskListener.NULL_LISTENER;
private ProgramLocation previousP1Location;
@ -148,7 +149,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
DiffApplySettingsOptionManager applySettingsMgr;
private boolean isHighlightCursorLine;
private Program activeProgram;
private OpenVersionedFileDialog openProgramDialog;
private OpenVersionedFileDialog<Program> openVersionedFileDialog;
/**
* Creates the plugin for indicating program differences to the user.
@ -289,7 +290,11 @@ public class ProgramDiffPlugin extends ProgramPlugin
ProgramSelection previousP2DiffHighlight = p2DiffHighlight;
ProgramSelection previousP2Selection = p2Selection;
AddressSet p2ViewAddrSet =
DiffUtility.getCompatibleAddressSet(p1ViewAddrSet, secondaryDiffProgram);
diffListingPanel.setView(p2ViewAddrSet);
FieldPanel fp = diffListingPanel.getFieldPanel();
AddressSet p1AddressSetAsP2 =
DiffUtility.getCompatibleAddressSet(p1AddressSet, secondaryDiffProgram);
AddressIndexMap p2IndexMap = new AddressIndexMap(p1AddressSetAsP2);
@ -327,8 +332,8 @@ public class ProgramDiffPlugin extends ProgramPlugin
}
@Override
public boolean inProgress() {
return taskInProgress;
public boolean isDiffActive() {
return secondaryDiffProgram != null;
}
private boolean launchDiffOnOpenProgram() {
@ -336,7 +341,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
if (diffControl != null) { // There is currently a Diff already so clear it.
clearDiff();
}
diff(p1ViewAddrSet);
diff();
return true;
}
catch (Exception e) {
@ -347,6 +352,13 @@ public class ProgramDiffPlugin extends ProgramPlugin
@Override
public boolean launchDiff(DomainFile otherProgram) {
if (taskInProgress) {
Msg.error(this, "Diff is busy and can't be launched");
return false;
}
if (isDiffActive()) {
closeProgram2();
}
if (openSecondProgram(otherProgram)) {
return launchDiffOnOpenProgram();
}
@ -355,20 +367,18 @@ public class ProgramDiffPlugin extends ProgramPlugin
@Override
public boolean launchDiff(Program otherProgram) {
try {
if (diffControl != null) { // There is currently a Diff already so clear it.
clearDiff();
}
if (openSecondProgram(otherProgram, null)) {
secondaryDiffProgram.addConsumer(this);
diff(p1ViewAddrSet);
}
return true;
}
catch (Exception e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
if (taskInProgress) {
Msg.error(this, "Diff is busy and can't be launched");
return false;
}
if (isDiffActive()) {
closeProgram2();
}
otherProgram.addConsumer(this);
if (openSecondProgram(otherProgram, null)) {
launchDiffOnOpenProgram();
}
return true;
}
@Override
@ -487,8 +497,12 @@ public class ProgramDiffPlugin extends ProgramPlugin
}
}
void setOpenDiffProgramDialog(OpenVersionedFileDialog dialog) {
this.openProgramDialog = dialog;
/**
* Used for testing to force file selection dialog instance.
* @param dialog project file selection dialog
*/
void setDiffOpenVersionedFileDialog(OpenVersionedFileDialog<Program> dialog) {
this.openVersionedFileDialog = dialog;
}
private void setActiveProgram(Program newActiveProgram) {
@ -575,6 +589,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
protected void init() {
codeViewerService = tool.getService(CodeViewerService.class);
goToService = tool.getService(GoToService.class);
programManagerService = tool.getService(ProgramManager.class);
FormatManager formatManager = codeViewerService.getFormatManager();
ServiceProvider diffServiceProvider =
@ -934,21 +949,11 @@ public class ProgramDiffPlugin extends ProgramPlugin
updatePgm2Enablement();
}
/**
* Computes the differences between program1 and program2 that are displayed in the browser
* using the current Limiting set. It allows the user to specify the Diff settings to use.
*/
void diff() {
diff(createLimitingSet());
}
/**
* Computes the differences between program1 and program2 that are displayed in the browser. It
* allows the user to specify the Diff settings to use.
*
* @param p1LimitSet an address set to use to limit the extent of the Diff.
*/
void diff(AddressSetView p1LimitSet) {
void diff() {
if (taskInProgress) {
Msg.showInfo(getClass(), tool.getToolFrame(), "Can't Start Another Diff",
"A Diff or Apply is already in progress.");
@ -956,10 +961,10 @@ public class ProgramDiffPlugin extends ProgramPlugin
}
boolean reload = diffControl != null;
if (reload) {
reloadDiff(p1LimitSet);
reloadDiff();
}
else {
createDiff(p1LimitSet);
createDiff();
}
}
@ -1087,23 +1092,60 @@ public class ProgramDiffPlugin extends ProgramPlugin
return;
}
final OpenVersionedFileDialog dialog = getOpenProgramDialog();
okListener = e -> {
selectAndOpenProgram2();
actionManager.setOpenCloseActionSelected(secondaryDiffProgram != null);
getDiffDetailsProvider();
}
/**
* Generate a list of programs which are currently open in the tool which are compatible
* with the primaryProgram to be diff'd. The top/primary entries correspond to this
* programs which have the same name (see {@link Program#getName()}) as the primaryProgram,
* while the remaining compatible programs will be considered secondary. Each of these
* two groups will be sorted by its domain file name then concatenated to form a single list.
* @return ordered open program list for use with the {@link OpenVersionedFileDialog}.
*/
private List<Program> getOpenProgramList() {
List<Program> primaryList = new ArrayList<>();
List<Program> secondaryList = new ArrayList<>();
for (Program p : programManagerService.getAllOpenPrograms()) {
if (!programManagerService.isVisible(p) || p == activeProgram ||
!ProgramMemoryComparator.similarPrograms(activeProgram, p)) {
continue;
}
if (p.getName().equals(activeProgram.getName())) {
primaryList.add(p);
}
else {
secondaryList.add(p);
}
}
Comparator<Program> programComparator = (a, b) -> {
return a.getDomainFile().getName().compareTo(b.getDomainFile().getName());
};
Collections.sort(primaryList, programComparator);
Collections.sort(secondaryList, programComparator);
List<Program> programList = new ArrayList<>();
programList.addAll(primaryList);
programList.addAll(secondaryList);
return programList;
}
private void selectAndOpenProgram2() {
final OpenVersionedFileDialog<Program> dialog = getOpenVersionedFileDialog();
List<Program> openProgramList = getOpenProgramList();
dialog.setOpenObjectChoices(openProgramList.isEmpty() ? null : openProgramList);
dialog.addOkActionListener(e -> {
tool.clearStatusInfo();
JComponent component = dialog.getComponent();
DomainObject dobj = dialog.getVersionedDomainObject(ProgramDiffPlugin.this, false);
Program dobj = dialog.getDomainObject(ProgramDiffPlugin.this, false);
if (dobj != null) {
if (openSecondProgram((Program) dobj, component)) {
dialog.close();
launchDiffOnOpenProgram();
}
return;
}
DomainFile df = dialog.getDomainFile();
if (df != null) {
if (openSecondProgram(df)) {
if (openSecondProgram(dobj, component)) {
dialog.close();
launchDiffOnOpenProgram();
}
@ -1112,25 +1154,18 @@ public class ProgramDiffPlugin extends ProgramPlugin
displayStatus(component, "Can't Open Selected Program",
"Please select a file, not a folder.", OptionDialog.INFORMATION_MESSAGE);
};
dialog.addOkActionListener(okListener);
});
dialog.showComponent();
actionManager.setOpenCloseActionSelected(secondaryDiffProgram != null);
getDiffDetailsProvider();
}
private OpenVersionedFileDialog getOpenProgramDialog() {
private OpenVersionedFileDialog<Program> getOpenVersionedFileDialog() {
if (openProgramDialog != null) {
return openProgramDialog;
if (openVersionedFileDialog != null) {
return openVersionedFileDialog;
}
OpenVersionedFileDialog dialog =
new OpenVersionedFileDialog(tool, "Select Other Program", f -> {
Class<?> c = f.getDomainObjectClass();
return Program.class.isAssignableFrom(c);
});
OpenVersionedFileDialog<Program> dialog =
new OpenVersionedFileDialog<>(tool, "Select Other Program", Program.class);
dialog.setTreeSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
dialog.setHelpLocation(new HelpLocation("Diff", "Open_Close_Program_View"));
return dialog;
@ -1144,12 +1179,10 @@ public class ProgramDiffPlugin extends ProgramPlugin
executeDiffDialog = new ExecuteDiffDialog();
executeDiffDialog.addActionListener(new DiffActionListener());
}
if (executeDiffDialog != null) {
executeDiffDialog.configure(primaryProgram, secondaryDiffProgram, currentSelection,
execDiffFilter);
executeDiffDialog.setPgmContextEnabled(sameProgramContext);
tool.showDialog(executeDiffDialog);
}
executeDiffDialog.configure(primaryProgram, secondaryDiffProgram, currentSelection,
execDiffFilter);
executeDiffDialog.setPgmContextEnabled(sameProgramContext);
tool.showDialog(executeDiffDialog);
}
void setP1SelectionOnP2() {
@ -1252,7 +1285,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
if (primaryProgram == null) {
return null;
}
if (executeDiffDialog != null) {
if (executeDiffDialog != null) { // TODO: don't reuse if it could change
return executeDiffDialog.getAddressSet();
}
AddressSet limitSet = new AddressSet(primaryProgram.getMemory());
@ -1266,38 +1299,29 @@ public class ProgramDiffPlugin extends ProgramPlugin
/**
* Reload the marked differences in the diff panel.
*/
private void reloadDiff(AddressSetView p1LimitSet) {
private void reloadDiff() {
if (diffControl == null) {
createDiff(p1LimitSet);
createDiff();
}
else {
tool.clearStatusInfo();
if (p1LimitSet == null) {
p1LimitSet = createLimitingSet();
}
displayExecuteDiff();
}
}
private void createDiff(AddressSetView p1LimitSet) {
private void createDiff() {
Frame frame = tool.getToolFrame();
try {
frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
tool.clearStatusInfo();
if (secondaryDiffProgram == null) {
selectProgram2();
if (secondaryDiffProgram == null) {
return;
}
throw new AssertException("Expected secondaryDiffProgram");
}
if (executeDiffDialog != null) {
executeDiffDialog.close();
executeDiffDialog = null;
}
if (p1LimitSet == null) {
p1LimitSet = createLimitingSet();
}
displayExecuteDiff();
}
finally {
@ -1521,29 +1545,29 @@ public class ProgramDiffPlugin extends ProgramPlugin
return false;
}
private boolean openSecondProgram(Program newProgram, JComponent selectDialog) {
private boolean openSecondProgram(Program newProgram, JComponent popupParent) {
if (newProgram == null) {
displayStatus(selectDialog, "Can't Open Selected Program",
displayStatus(popupParent, "Can't Open Selected Program",
"Couldn't open second program.", OptionDialog.ERROR_MESSAGE);
return false;
}
if (!ProgramMemoryComparator.similarPrograms(currentProgram, newProgram)) {
newProgram.release(this);
String message = "Programs languages don't match.\n" + currentProgram.getName() + " (" +
currentProgram.getLanguageID() + ")\n" + newProgram.getName() + " (" +
newProgram.getLanguageID() + ")";
displayStatus(selectDialog, "Can't Open Selected Program", message,
displayStatus(popupParent, "Can't Open Selected Program", message,
OptionDialog.ERROR_MESSAGE);
newProgram.release(this);
return false;
}
ProgramMemoryComparator programMemoryComparator = null;
try {
programMemoryComparator = new ProgramMemoryComparator(currentProgram, newProgram);
}
catch (ProgramConflictException e) {
Msg.error(this, "Unexpected exception creating memory comparator", e);
newProgram.release(this);
return false;
}
addressesOnlyInP1 = programMemoryComparator.getAddressesOnlyInOne();
@ -1552,7 +1576,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
AddressSet combinedAddresses =
ProgramMemoryComparator.getCombinedAddresses(currentProgram, newProgram);
if (addressesInCommon.isEmpty()) {
int selectedOption = OptionDialog.showYesNoDialog(selectDialog, "No Memory In Common",
int selectedOption = OptionDialog.showYesNoDialog(popupParent, "No Memory In Common",
"The two programs have no memory addresses in common.\n" +
"Do you want to continue?");
if (selectedOption != OptionDialog.YES_OPTION) {

View file

@ -30,23 +30,29 @@ public interface DiffService {
/**
* Launch the Diff dialog and display differences between the current program
* and the otherProgram.
* and the otherProgram. This will force the current Diff, if active, to be terminated.
* @param otherProgram a domain file for the program to Diff the current program against.
* @return true if the second program is opened and successfully Diffed.
* @return true if the second program is opened and successfully Diffed. A false will be
* returned if the Diff fails to launch.
*/
public boolean launchDiff(DomainFile otherProgram);
/**
* Launch the Diff dialog and display differences between the current program
* and the otherProgram.
* and the otherProgram. This will force the current Diff, if active, to be terminated.
* This Diff service will be added as a consumer on the specified otherProgram while the Diff
* remains active.
* @param otherProgram the program to Diff the current program against.
* @return true if the second program is opened and successfully Diffed.
* @return true if the second program is opened and successfully Diffed. A false will be
* returned if the Diff fails to launch.
*/
public boolean launchDiff(Program otherProgram);
/**
* Determine if the Diff service is currently displaying a Diff.
* Determine if the Diff service is currently displaying a Diff within the Tool associated with
* this service.
* @return true if a Diff is currently active
*/
public boolean inProgress();
public boolean isDiffActive();
}

View file

@ -56,7 +56,7 @@ public class DiffSaveSettingsTest extends DiffApplyTestAdapter {
diffListingPanel = diffPlugin.getListingPanel();
fp1 = cb.getFieldPanel();
fp2 = diffListingPanel.getFieldPanel();
openClosePgm2 = (ToggleDockingAction) getAction(diffPlugin, "Open/Close Program View");
openClosePgm2 = (ToggleDockingAction) getAction(diffPlugin, "Open/Close Diff View");
}
private void showNewTool() throws Exception {
@ -73,7 +73,7 @@ public class DiffSaveSettingsTest extends DiffApplyTestAdapter {
diffListingPanel = diffPlugin.getListingPanel();
fp1 = cb.getFieldPanel();
fp2 = diffListingPanel.getFieldPanel();
openClosePgm2 = (ToggleDockingAction) getAction(diffPlugin, "Open/Close Program View");
openClosePgm2 = (ToggleDockingAction) getAction(diffPlugin, "Open/Close Diff View");
}
@Override

View file

@ -659,7 +659,7 @@ public class DiffTest extends DiffTestAdapter {
assertEquals(true, isShowingDiff());
// Check action enablement.
checkDiffAction("View Program Differences", true, true);
checkDiffAction("Open/Close Program View", true, true);
checkDiffAction("Open/Close Diff View", true, true);
checkDiffAction("Apply Differences", true, false);
checkDiffAction("Apply Differences and Goto Next Difference", true, false);
checkDiffAction("Ignore Selection and Goto Next Difference", true, false);
@ -777,13 +777,13 @@ public class DiffTest extends DiffTestAdapter {
assertEquals(true, isDiffing());
assertEquals(true, isShowingDiff());
checkDiffAction("Open/Close Program View", true, true);
checkDiffAction("Open/Close Diff View", true, true);
//
// Different tab--still enabled
//
selectTab(panel, program3);
checkDiffAction("Open/Close Program View", true, true);
checkDiffAction("Open/Close Diff View", true, true);
clickDiffButton();
assertTrue("Not diffing after clicking the diff button when on a non-diff tab",
@ -794,7 +794,7 @@ public class DiffTest extends DiffTestAdapter {
//
// Diff tab--still enabled
//
checkDiffAction("Open/Close Program View", true, true);
checkDiffAction("Open/Close Diff View", true, true);
clickDiffButton();

View file

@ -43,7 +43,8 @@ import ghidra.app.plugin.core.programtree.ProgramTreePlugin;
import ghidra.app.services.ProgramManager;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.framework.main.*;
import ghidra.framework.model.*;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainFolder;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
@ -479,7 +480,7 @@ public class DiffTestAdapter extends AbstractGhidraHeadedIntegrationTest {
diffListingPanel = diffPlugin.getListingPanel();
fp1 = cb.getFieldPanel();
fp2 = diffListingPanel.getFieldPanel();
openClosePgm2 = (ToggleDockingAction) getAction(diffPlugin, "Open/Close Program View");
openClosePgm2 = (ToggleDockingAction) getAction(diffPlugin, "Open/Close Diff View");
tool.addPlugin(ProgramTreePlugin.class.getName());
pt = env.getPlugin(ProgramTreePlugin.class);
@ -664,10 +665,8 @@ public class DiffTestAdapter extends AbstractGhidraHeadedIntegrationTest {
void pickSecondProgram(final Program program2) {
program2.addConsumer(diffPlugin);
OpenVersionedFileDialogTestFake dialog = new OpenVersionedFileDialogTestFake(program2);
diffPlugin.setOpenDiffProgramDialog(dialog);
diffPlugin.setDiffOpenVersionedFileDialog(dialog);
launchDiffByAction();
@ -1154,13 +1153,13 @@ public class DiffTestAdapter extends AbstractGhidraHeadedIntegrationTest {
// Inner Classes
//==================================================================================================
private class OpenVersionedFileDialogTestFake extends OpenVersionedFileDialog {
private class OpenVersionedFileDialogTestFake extends OpenVersionedFileDialog<Program> {
private ActionListener listener;
private Program chosenProgram;
OpenVersionedFileDialogTestFake(Program program) {
super(tool, "Select Other Program", null);
super(tool, "Select Other Program", Program.class);
this.chosenProgram = program;
}
@ -1183,7 +1182,10 @@ public class DiffTestAdapter extends AbstractGhidraHeadedIntegrationTest {
}
@Override
public DomainObject getVersionedDomainObject(Object consumer, boolean readOnly) {
public Program getDomainObject(Object consumer, boolean readOnly) {
if (chosenProgram != null) {
chosenProgram.addConsumer(consumer);
}
return chosenProgram;
}