mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +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
|
@ -95,7 +95,7 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
|||
|
||||
private DataTypeManagerHandler dataTypeManagerHandler;
|
||||
private DataTypesProvider provider;
|
||||
private OpenVersionedFileDialog openDialog;
|
||||
private OpenVersionedFileDialog<DataTypeArchive> openDialog;
|
||||
|
||||
private Map<String, DockingAction> recentlyOpenedArchiveMap;
|
||||
private Map<String, DockingAction> installArchiveMap;
|
||||
|
@ -587,8 +587,8 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
|||
}
|
||||
};
|
||||
openDialog =
|
||||
new OpenVersionedFileDialog(tool, "Open Project Data Type Archive",
|
||||
df -> DataTypeArchive.class.isAssignableFrom(df.getDomainObjectClass()));
|
||||
new OpenVersionedFileDialog<>(tool, "Open Project Data Type Archive",
|
||||
DataTypeArchive.class);
|
||||
openDialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Open_File_Dialog"));
|
||||
openDialog.addOkActionListener(listener);
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||
private MultiProgramManager programMgr;
|
||||
private ProgramSaveManager programSaveMgr;
|
||||
private int transactionID = -1;
|
||||
private OpenVersionedFileDialog openDialog;
|
||||
private OpenVersionedFileDialog<Program> openDialog;
|
||||
private boolean locked = false;
|
||||
private UndoAction undoAction;
|
||||
private RedoAction redoAction;
|
||||
|
@ -617,9 +617,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||
doOpenProgram(domainFile, version, OPEN_CURRENT);
|
||||
}
|
||||
};
|
||||
openDialog = new OpenVersionedFileDialog(tool, "Open Program", f -> {
|
||||
return Program.class.isAssignableFrom(f.getDomainObjectClass());
|
||||
});
|
||||
openDialog = new OpenVersionedFileDialog<>(tool, "Open Program", Program.class);
|
||||
openDialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Open_File_Dialog"));
|
||||
openDialog.addOkActionListener(listener);
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
*/
|
||||
package ghidra.framework.main;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -26,6 +26,8 @@ import javax.swing.*;
|
|||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.event.mouse.GMouseListenerAdapter;
|
||||
import docking.widgets.table.*;
|
||||
import ghidra.framework.main.datatree.VersionHistoryPanel;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
|
@ -35,10 +37,9 @@ import ghidra.util.Msg;
|
|||
/**
|
||||
* Dialog to open a file that is versioned and allow a version to be
|
||||
* opened.
|
||||
*
|
||||
*
|
||||
* @param <T> domain object class
|
||||
*/
|
||||
public class OpenVersionedFileDialog extends DataTreeDialog {
|
||||
public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDialog {
|
||||
private static final String SHOW_HISTORY_PREFERENCES_KEY = "OPEN_PROGRAM_DIALOG.SHOW_HISTORY";
|
||||
private static final String HEIGHT_PREFERENCES_KEY = "OPEN_PROGRAM_DIALOG.HEIGHT";
|
||||
private static final String WIDTH_NO_HISTORY_PREFERENCES_KEY =
|
||||
|
@ -50,6 +51,10 @@ public class OpenVersionedFileDialog extends DataTreeDialog {
|
|||
private final static int DEFAULT_WIDTH_WITH_HISTORY = 800;
|
||||
private final static int DIVIDER_SIZE = 2;
|
||||
|
||||
private final static int PROJECT_FILES_TAB = 0;
|
||||
private final static int OPEN_OBJECT_LIST_TAB = 1;
|
||||
|
||||
private JTabbedPane tabbedPane; // null if openDomainObjects not specified
|
||||
private JSplitPane splitPane;
|
||||
private JButton historyButton;
|
||||
private JPanel mainPanel;
|
||||
|
@ -59,30 +64,71 @@ public class OpenVersionedFileDialog extends DataTreeDialog {
|
|||
private VersionHistoryPanel historyPanel;
|
||||
private List<DockingActionIf> popupActions = Collections.emptyList();
|
||||
|
||||
private Class<T> domainObjectClass;
|
||||
private List<T> openDomainObjects; // list of allowed domain object which are already open
|
||||
private GFilterTable<T> openObjectsTable;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param tool tool where the file is being opened.
|
||||
* @param title title to use
|
||||
* @param filter filter used to control what is displayed in data tree.
|
||||
* @param domainObjectClass allowed domain object class which corresponds to {@code <T>}
|
||||
*/
|
||||
public OpenVersionedFileDialog(PluginTool tool, String title, DomainFileFilter filter) {
|
||||
super(tool.getToolFrame(), title, DataTreeDialog.OPEN, filter);
|
||||
public OpenVersionedFileDialog(PluginTool tool, String title, Class<T> domainObjectClass) {
|
||||
super(tool.getToolFrame(), title, DataTreeDialog.OPEN, f -> {
|
||||
return domainObjectClass.isAssignableFrom(f.getDomainObjectClass());
|
||||
});
|
||||
this.tool = tool;
|
||||
this.domainObjectClass = domainObjectClass;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the domain object for the selected version.
|
||||
* @param consumer consumer
|
||||
* @param readOnly true if the domain object should be opened read only,
|
||||
* versus immutable
|
||||
* @return null if a versioned file was not selected
|
||||
* Set an optional list of already open domain objects of type {@code <T>} which may be
|
||||
* selected instead of a project domain file. The {@link #getDomainObject(Object, boolean)}
|
||||
* method should be used when this optional list has been set. If this dialog is reused
|
||||
* the list should be set null if previously set. This method must be invoked prior to
|
||||
* showing the dialog.
|
||||
* @param openDomainObjects list of open domain objects from which a selection may be made.
|
||||
*/
|
||||
public DomainObject getVersionedDomainObject(Object consumer, boolean readOnly) {
|
||||
if (historyPanel != null) {
|
||||
return historyPanel.getSelectedVersion(consumer, readOnly);
|
||||
public void setOpenObjectChoices(List<T> openDomainObjects) {
|
||||
this.openDomainObjects = (openDomainObjects != null && !openDomainObjects.isEmpty())
|
||||
? new ArrayList<>(openDomainObjects)
|
||||
: null;
|
||||
}
|
||||
return null;
|
||||
|
||||
/**
|
||||
* Get the selected domain object for read-only or immutable use.
|
||||
* If an existing open object is selected its original mode applies but consumer will
|
||||
* be added.
|
||||
* @param consumer consumer
|
||||
* @param readOnly true if the domain object should be opened read only, versus immutable
|
||||
* @return null if a file was not selected
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // relies on content class filter
|
||||
public T getDomainObject(Object consumer, boolean readOnly) {
|
||||
T dobj = null;
|
||||
if (usingOpenProgramList()) {
|
||||
dobj = getSelectedOpenDomainObject();
|
||||
if (dobj != null) {
|
||||
dobj.addConsumer(consumer);
|
||||
}
|
||||
return dobj;
|
||||
}
|
||||
if (historyPanel != null) {
|
||||
dobj = (T) historyPanel.getSelectedVersion(consumer, readOnly);
|
||||
}
|
||||
if (dobj == null) {
|
||||
DomainFile domainFile = getDomainFile();
|
||||
if (domainFile != null) {
|
||||
GetVersionedObjectTask task =
|
||||
new GetVersionedObjectTask(consumer, domainFile, DomainFile.DEFAULT_VERSION,
|
||||
readOnly);
|
||||
tool.execute(task, 1000);
|
||||
return (T) task.getVersionedObject();
|
||||
}
|
||||
}
|
||||
return dobj;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,18 +136,36 @@ public class OpenVersionedFileDialog extends DataTreeDialog {
|
|||
* @return -1 if a version history was not selected
|
||||
*/
|
||||
public int getVersion() {
|
||||
if (historyPanel != null) {
|
||||
if (historyPanel != null && !usingOpenProgramList()) {
|
||||
return historyPanel.getSelectedVersionNumber();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.main.DataTreeDialog#buildMainPanel()
|
||||
*/
|
||||
@Override
|
||||
public DomainFile getDomainFile() {
|
||||
if (usingOpenProgramList()) {
|
||||
return null;
|
||||
}
|
||||
return super.getDomainFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainFolder getDomainFolder() {
|
||||
if (usingOpenProgramList()) {
|
||||
return null;
|
||||
}
|
||||
return super.getDomainFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JPanel buildMainPanel() {
|
||||
mainPanel = super.buildMainPanel();
|
||||
|
||||
mainPanel = new JPanel(new BorderLayout());
|
||||
mainPanel.add(super.buildMainPanel(), BorderLayout.CENTER);
|
||||
JPanel historyButtonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
||||
historyButtonPanel.add(historyButton);
|
||||
mainPanel.add(historyButtonPanel, BorderLayout.SOUTH);
|
||||
mainPanel.setMinimumSize(new Dimension(200, HEIGHT));
|
||||
|
||||
splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
|
||||
|
@ -112,8 +176,8 @@ public class OpenVersionedFileDialog extends DataTreeDialog {
|
|||
splitPane.setDividerLocation(1.0);
|
||||
splitPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
|
||||
|
||||
JPanel outerPanel = new JPanel(new BorderLayout());
|
||||
outerPanel.add(splitPane);
|
||||
JPanel projectFilePanel = new JPanel(new BorderLayout());
|
||||
projectFilePanel.add(splitPane);
|
||||
|
||||
String showHistory =
|
||||
Preferences.getProperty(SHOW_HISTORY_PREFERENCES_KEY, Boolean.FALSE.toString(), true);
|
||||
|
@ -122,26 +186,91 @@ public class OpenVersionedFileDialog extends DataTreeDialog {
|
|||
showHistoryPanel(true);
|
||||
}
|
||||
|
||||
return outerPanel;
|
||||
openObjectsTable = null;
|
||||
tabbedPane = null;
|
||||
|
||||
updateOkTooltip();
|
||||
|
||||
if (openDomainObjects == null) {
|
||||
return projectFilePanel; // return Project File selection panel only
|
||||
}
|
||||
|
||||
private void advancedButtonCallback() {
|
||||
showHistoryPanel(!historyIsShowing);
|
||||
// Create tabbed pane with "Project Files" and "Open Program" tabs
|
||||
// NOTE: actual tab name reflects domainObjectClass name
|
||||
tabbedPane = new JTabbedPane();
|
||||
tabbedPane.setName("Tabs");
|
||||
tabbedPane.add("Project Files", projectFilePanel);
|
||||
tabbedPane.add("Open " + domainObjectClass.getSimpleName() + "s",
|
||||
buildOpenObjectsTable());
|
||||
|
||||
tabbedPane.addChangeListener(e -> {
|
||||
int selectedTabIndex = tabbedPane.getModel().getSelectedIndex();
|
||||
if (selectedTabIndex == PROJECT_FILES_TAB) {
|
||||
// Project tree and History use
|
||||
String nameText = getNameText();
|
||||
setOkEnabled((nameText != null) && !nameText.isEmpty());
|
||||
}
|
||||
else { // OPEN_OBJECT_LIST_TAB
|
||||
setOkEnabled(getSelectedOpenDomainObject() != null);
|
||||
}
|
||||
updateOkTooltip();
|
||||
});
|
||||
|
||||
JPanel tabbedPanel = new JPanel();
|
||||
tabbedPanel.setLayout(new BorderLayout());
|
||||
tabbedPanel.add(tabbedPane, BorderLayout.CENTER);
|
||||
|
||||
tabbedPane.setSelectedIndex(PROJECT_FILES_TAB);
|
||||
return tabbedPanel;
|
||||
}
|
||||
|
||||
private boolean usingOpenProgramList() {
|
||||
return tabbedPane != null &&
|
||||
tabbedPane.getModel().getSelectedIndex() == OPEN_OBJECT_LIST_TAB;
|
||||
}
|
||||
|
||||
private T getSelectedOpenDomainObject() {
|
||||
if (!usingOpenProgramList()) {
|
||||
return null;
|
||||
}
|
||||
return openObjectsTable.getSelectedRowObject();
|
||||
}
|
||||
|
||||
private Component buildOpenObjectsTable() {
|
||||
|
||||
openObjectsTable = new GFilterTable<>(new OpenObjectsTableModel());
|
||||
GTable table = openObjectsTable.getTable();
|
||||
table.getSelectionModel()
|
||||
.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
openObjectsTable.addSelectionListener(e -> {
|
||||
setOkEnabled(true);
|
||||
okButton.setToolTipText("Use the selected " + domainObjectClass.getSimpleName());
|
||||
});
|
||||
|
||||
table.addMouseListener(new GMouseListenerAdapter() {
|
||||
@Override
|
||||
public void doubleClickTriggered(MouseEvent e) {
|
||||
if (okButton.isEnabled()) {
|
||||
okCallback();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return openObjectsTable;
|
||||
}
|
||||
|
||||
private void showHistoryPanel(boolean showHistory) {
|
||||
historyIsShowing = showHistory;
|
||||
if (showHistory) {
|
||||
createHistoryPanel();
|
||||
historyButton.setText("No History");
|
||||
historyButton.setText("Hide History");
|
||||
DomainFile df = treePanel.getSelectedDomainFile();
|
||||
historyPanel.setDomainFile(df);
|
||||
splitPane.setDividerSize(DIVIDER_SIZE);
|
||||
splitPane.setDividerLocation(DEFAULT_WIDTH_NO_HISTORY - 4);
|
||||
}
|
||||
else {
|
||||
historyButton.setText("History>>");
|
||||
historyButton.setText("Show History>>");
|
||||
splitPane.setDividerSize(0);
|
||||
splitPane.setRightComponent(null);
|
||||
historyPanel = null;
|
||||
|
@ -175,7 +304,6 @@ public class OpenVersionedFileDialog extends DataTreeDialog {
|
|||
|
||||
Preferences.setProperty(SHOW_HISTORY_PREFERENCES_KEY, Boolean.toString(historyIsShowing));
|
||||
Preferences.store();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -203,6 +331,25 @@ public class OpenVersionedFileDialog extends DataTreeDialog {
|
|||
}
|
||||
}
|
||||
|
||||
private void updateOkTooltip() {
|
||||
String tip;
|
||||
if (usingOpenProgramList()) {
|
||||
tip = "Use selected " + domainObjectClass.getSimpleName();
|
||||
}
|
||||
else {
|
||||
tip = "Open the selected file";
|
||||
if (historyPanel != null && historyIsShowing) {
|
||||
int versionNumber = historyPanel.getSelectedVersionNumber();
|
||||
if (versionNumber >= 0) {
|
||||
DomainFile df = OpenVersionedFileDialog.super.getDomainFile();
|
||||
okButton.setToolTipText(
|
||||
"Open version " + versionNumber + " for " + df.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
okButton.setToolTipText(tip);
|
||||
}
|
||||
|
||||
private boolean createHistoryPanel() {
|
||||
try {
|
||||
historyPanel = new VersionHistoryPanel(tool, null);
|
||||
|
@ -220,24 +367,16 @@ public class OpenVersionedFileDialog extends DataTreeDialog {
|
|||
if (e.getValueIsAdjusting()) {
|
||||
return;
|
||||
}
|
||||
okButton.setToolTipText("Open the selected file");
|
||||
int versionNumber = historyPanel.getSelectedVersionNumber();
|
||||
if (versionNumber >= 0) {
|
||||
DomainFile df = OpenVersionedFileDialog.super.getDomainFile();
|
||||
okButton.setToolTipText("Open version " + versionNumber + " for " + df.getName());
|
||||
}
|
||||
updateOkTooltip();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
historyButton = new JButton("History>>");
|
||||
historyButton.addActionListener(e -> advancedButtonCallback());
|
||||
addButton(historyButton);
|
||||
historyButton.addActionListener(e -> showHistoryPanel(!historyIsShowing));
|
||||
|
||||
okButton.setToolTipText("Open the selected file");
|
||||
rootPanel.setPreferredSize(getPreferredSizeForHistoryState());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -249,6 +388,7 @@ public class OpenVersionedFileDialog extends DataTreeDialog {
|
|||
DomainFile df = treePanel.getSelectedDomainFile();
|
||||
historyPanel.setDomainFile(df);
|
||||
}
|
||||
updateOkTooltip();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -264,4 +404,44 @@ public class OpenVersionedFileDialog extends DataTreeDialog {
|
|||
|
||||
return actionContext;
|
||||
}
|
||||
|
||||
private class OpenObjectsTableModel extends AbstractGTableModel<T> {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Open DomainObject List";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getModelData() {
|
||||
return openDomainObjects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getColumnValueForRow(T t, int columnIndex) {
|
||||
// only one column
|
||||
return t.getDomainFile().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int columnIndex) {
|
||||
return "Program Path";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ src/main/help/help/topics/Diff/images/DiffApplySettings.png||GHIDRA||||END|
|
|||
src/main/help/help/topics/Diff/images/DiffApplySettingsPopup.png||GHIDRA||reviewed||END|
|
||||
src/main/help/help/topics/Diff/images/DiffDetails.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Diff/images/DiffSelect16.png||GHIDRA||reviewed||END|
|
||||
src/main/help/help/topics/Diff/images/SelectOpenProgram.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Diff/images/SelectOtherProgram.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Diff/images/SelectOtherVersionedProgram.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Diff/images/disk.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
|
@ -44,5 +45,4 @@ src/main/resources/images/eraser_arrow16.png||GHIDRA||||END|
|
|||
src/main/resources/images/pencil16.png||GHIDRA||reviewed||END|
|
||||
src/main/resources/images/pencil_arrow16.png||GHIDRA||reviewed||END|
|
||||
src/main/resources/images/settings16.gif||GHIDRA||reviewed||END|
|
||||
src/main/resources/images/table_relationship.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/resources/images/xmag.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END|
|
||||
|
|
|
@ -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()) {
|
||||
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.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,14 +381,41 @@ 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()) {
|
||||
openCloseDiffViewAction = new OpenCloseDiffViewAction();
|
||||
}
|
||||
|
||||
private abstract class DiffAction extends DockingAction {
|
||||
DiffAction(String name) {
|
||||
super(name, plugin.getName());
|
||||
setHelpLocation(new HelpLocation(HelpTopics.DIFF, name));
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAddToPopup(ActionContext context) {
|
||||
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 (openCloseProgram2Action.isSelected()) {
|
||||
if (openCloseDiffViewAction.isSelected()) {
|
||||
plugin.selectProgram2();
|
||||
return;
|
||||
}
|
||||
|
@ -433,28 +464,5 @@ class DiffActionManager {
|
|||
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");
|
||||
}
|
||||
|
||||
private abstract class DiffAction extends DockingAction {
|
||||
DiffAction(String name) {
|
||||
super(name, plugin.getName());
|
||||
setHelpLocation(new HelpLocation(HelpTopics.DIFF, name));
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAddToPopup(ActionContext context) {
|
||||
return (context instanceof OtherPanelContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
||||
if (openProgramDialog != null) {
|
||||
return openProgramDialog;
|
||||
}
|
||||
|
||||
OpenVersionedFileDialog dialog =
|
||||
new OpenVersionedFileDialog(tool, "Select Other Program", f -> {
|
||||
Class<?> c = f.getDomainObjectClass();
|
||||
return Program.class.isAssignableFrom(c);
|
||||
});
|
||||
dialog.showComponent();
|
||||
}
|
||||
|
||||
private OpenVersionedFileDialog<Program> getOpenVersionedFileDialog() {
|
||||
|
||||
if (openVersionedFileDialog != null) {
|
||||
return openVersionedFileDialog;
|
||||
}
|
||||
|
||||
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,13 +1179,11 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
void setP1SelectionOnP2() {
|
||||
if (!currentSelection.isEmpty()) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -135,7 +135,9 @@ public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBCon
|
|||
@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");
|
||||
//throw new UnsupportedOperationException("link-file does not support getImmutableObject");
|
||||
// See GP-2903
|
||||
return getReadOnlyObject(item, version, true, consumer, monitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -497,7 +497,8 @@ public class DefaultProject implements Project {
|
|||
addProjectView(url, true);
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.error(this, e.getMessage());
|
||||
Msg.error(this, "Project view not opended (" + GhidraURL.getDisplayString(url) +
|
||||
"): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
it = root.getChildren(OPEN_REPOSITORY_VIEW_XML_NAME).iterator();
|
||||
|
@ -509,7 +510,8 @@ public class DefaultProject implements Project {
|
|||
addProjectView(url, true);
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.error(this, e.getMessage());
|
||||
Msg.error(this, "Project view not opended (" + GhidraURL.getDisplayString(url) +
|
||||
"): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,7 @@ public class DiffScreenShots extends GhidraScreenShotGenerator {
|
|||
public void testSelectOtherProgram() throws Exception {
|
||||
addProgramsToProject();
|
||||
program = env.getProgram("WinHelloCPP.exe");
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Diff View", "ProgramDiffPlugin", false);
|
||||
waitForSwing();
|
||||
DialogComponentProvider dialog = getDialog();
|
||||
captureDialog(dialog.getPreferredSize().width, 500);
|
||||
|
@ -59,10 +58,10 @@ public class DiffScreenShots extends GhidraScreenShotGenerator {
|
|||
addProgramsToProject();
|
||||
createProgramVersions();
|
||||
waitForSwing();
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Diff View", "ProgramDiffPlugin", false);
|
||||
waitForSwing();
|
||||
OpenVersionedFileDialog dialog = (OpenVersionedFileDialog) getDialog();
|
||||
@SuppressWarnings("unchecked")
|
||||
OpenVersionedFileDialog<Program> dialog = (OpenVersionedFileDialog<Program>) getDialog();
|
||||
DataTree dataTree = (DataTree) findComponentByName(dialog.getComponent(), "Data Tree");
|
||||
selectPath(dataTree, env.getProject().getName(), "WinHelloCpp.exe");
|
||||
JButton historyButton = findButtonByText(dialog.getComponent(), "History>>");
|
||||
|
@ -70,13 +69,34 @@ public class DiffScreenShots extends GhidraScreenShotGenerator {
|
|||
captureDialog();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectOpenProgram() throws Exception {
|
||||
addProgramsToProject();
|
||||
createProgramVersions();
|
||||
runSwing(() -> {
|
||||
Project project = env.getProject();
|
||||
ProjectData projectData = project.getProjectData();
|
||||
DomainFile file = projectData.getRootFolder().getFile("OldWinHelloCpp.exe");
|
||||
ProgramManager pm = tool.getService(ProgramManager.class);
|
||||
pm.openProgram(file);
|
||||
});
|
||||
waitForSwing();
|
||||
performAction("Open/Close Diff View", "ProgramDiffPlugin", false);
|
||||
waitForSwing();
|
||||
@SuppressWarnings("unchecked")
|
||||
OpenVersionedFileDialog<Program> dialog = (OpenVersionedFileDialog<Program>) getDialog();
|
||||
JTabbedPane tabPane = (JTabbedPane) findComponentByName(dialog.getComponent(), "Tabs");
|
||||
runSwing(() -> tabPane.setSelectedIndex(1)); // select Open Programs tab
|
||||
captureDialog(dialog.getPreferredSize().width, 500);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetermineDiffs() throws Exception {
|
||||
addProgramsToProject();
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Diff View", "ProgramDiffPlugin", false);
|
||||
waitForSwing();
|
||||
OpenVersionedFileDialog dialog = (OpenVersionedFileDialog) getDialog();
|
||||
@SuppressWarnings("unchecked")
|
||||
OpenVersionedFileDialog<Program> dialog = (OpenVersionedFileDialog<Program>) getDialog();
|
||||
DataTree dataTree = (DataTree) findComponentByName(dialog.getComponent(), "Data Tree");
|
||||
selectPath(dataTree, env.getProject().getName(), "WinHelloCpp.exe");
|
||||
waitForSwing();
|
||||
|
@ -89,10 +109,10 @@ public class DiffScreenShots extends GhidraScreenShotGenerator {
|
|||
public void testDiff() throws Exception {
|
||||
addProgramsToProject();
|
||||
createDifferences();
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Diff View", "ProgramDiffPlugin", false);
|
||||
waitForSwing();
|
||||
OpenVersionedFileDialog dialog = (OpenVersionedFileDialog) getDialog();
|
||||
@SuppressWarnings("unchecked")
|
||||
OpenVersionedFileDialog<Program> dialog = (OpenVersionedFileDialog<Program>) getDialog();
|
||||
DataTree dataTree = (DataTree) findComponentByName(dialog.getComponent(), "Data Tree");
|
||||
selectPath(dataTree, env.getProject().getName(), "WinHelloCpp.exe");
|
||||
waitForSwing();
|
||||
|
@ -111,10 +131,10 @@ public class DiffScreenShots extends GhidraScreenShotGenerator {
|
|||
public void testDiffApplySettings() throws Exception {
|
||||
addProgramsToProject();
|
||||
createDifferences();
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Diff View", "ProgramDiffPlugin", false);
|
||||
waitForSwing();
|
||||
OpenVersionedFileDialog dialog = (OpenVersionedFileDialog) getDialog();
|
||||
@SuppressWarnings("unchecked")
|
||||
OpenVersionedFileDialog<Program> dialog = (OpenVersionedFileDialog<Program>) getDialog();
|
||||
DataTree dataTree = (DataTree) findComponentByName(dialog.getComponent(), "Data Tree");
|
||||
selectPath(dataTree, env.getProject().getName(), "WinHelloCpp.exe");
|
||||
waitForSwing();
|
||||
|
@ -149,10 +169,10 @@ public class DiffScreenShots extends GhidraScreenShotGenerator {
|
|||
public void testDiffDetails() throws Exception {
|
||||
addProgramsToProject();
|
||||
createDifferencesAt401417();
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Program View", "ProgramDiffPlugin", false);
|
||||
performAction("Open/Close Diff View", "ProgramDiffPlugin", false);
|
||||
waitForSwing();
|
||||
OpenVersionedFileDialog dialog = (OpenVersionedFileDialog) getDialog();
|
||||
@SuppressWarnings("unchecked")
|
||||
OpenVersionedFileDialog<Program> dialog = (OpenVersionedFileDialog<Program>) getDialog();
|
||||
DataTree dataTree = (DataTree) findComponentByName(dialog.getComponent(), "Data Tree");
|
||||
selectPath(dataTree, env.getProject().getName(), "WinHelloCpp.exe");
|
||||
waitForSwing();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue