mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-2897 Allow Diff with another open program within same tool. Modified
OpenVersionedFileDialog to faciltate the program selection.
This commit is contained in:
parent
dcf147150e
commit
d377b9642b
17 changed files with 536 additions and 281 deletions
|
@ -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="->" border="0">
|
||||
|
@ -70,9 +70,9 @@
|
|||
<img src="../../shared/arrow.gif" alt="->" 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>></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>></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 |
Binary file not shown.
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 33 KiB |
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue