GP-4151 fixing wizard pattern to better handle expensive checks between panels.
|
@ -312,11 +312,11 @@ src/main/help/help/topics/FrontEndPlugin/images/SelectSharedProjectType.png||GHI
|
||||||
src/main/help/help/topics/FrontEndPlugin/images/ServerInfo.png||GHIDRA||||END|
|
src/main/help/help/topics/FrontEndPlugin/images/ServerInfo.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/FrontEndPlugin/images/SharedProjectInfo.png||GHIDRA||||END|
|
src/main/help/help/topics/FrontEndPlugin/images/SharedProjectInfo.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/FrontEndPlugin/images/UsersPanel.png||GHIDRA||||END|
|
src/main/help/help/topics/FrontEndPlugin/images/UsersPanel.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/FrontEndPlugin/images/UsersPanelMini.png||GHIDRA||||END|
|
|
||||||
src/main/help/help/topics/FrontEndPlugin/images/VersionedFileCOnoServer.png||GHIDRA||||END|
|
src/main/help/help/topics/FrontEndPlugin/images/VersionedFileCOnoServer.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/FrontEndPlugin/images/VersionedFileCOwithServer.png||GHIDRA||||END|
|
src/main/help/help/topics/FrontEndPlugin/images/VersionedFileCOwithServer.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/FrontEndPlugin/images/VersionedFileIcon.png||GHIDRA||||END|
|
src/main/help/help/topics/FrontEndPlugin/images/VersionedFileIcon.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/FrontEndPlugin/images/ViewOtherProjects.png||GHIDRA||||END|
|
src/main/help/help/topics/FrontEndPlugin/images/ViewOtherProjects.png||GHIDRA||||END|
|
||||||
|
src/main/help/help/topics/FrontEndPlugin/images/ViewProjectAccessPanel.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/FrontEndPlugin/images/hijack_file.png||GHIDRA||||END|
|
src/main/help/help/topics/FrontEndPlugin/images/hijack_file.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/FunctionComparison/FunctionComparison.htm||GHIDRA||||END|
|
src/main/help/help/topics/FunctionComparison/FunctionComparison.htm||GHIDRA||||END|
|
||||||
src/main/help/help/topics/FunctionComparison/images/AddFunctionsPanel.png||GHIDRA||||END|
|
src/main/help/help/topics/FunctionComparison/images/AddFunctionsPanel.png||GHIDRA||||END|
|
||||||
|
|
|
@ -917,7 +917,7 @@
|
||||||
"help/shared/arrow.gif" border="0">View Project Access List</B> will be enabled, which will display
|
"help/shared/arrow.gif" border="0">View Project Access List</B> will be enabled, which will display
|
||||||
the following dialog and allow the user to view the project users and their current access privileges only.</P>
|
the following dialog and allow the user to view the project users and their current access privileges only.</P>
|
||||||
|
|
||||||
<P align="center"><IMG src="images/UsersPanelMini.png" border="0"></P>
|
<P align="center"><IMG src="images/ViewProjectAccessPanel.png" border="0"></P>
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 9.5 KiB |
|
@ -601,6 +601,8 @@ public class ListingCodeComparisonPanel
|
||||||
private void updateProgramViews() {
|
private void updateProgramViews() {
|
||||||
displays.get(LEFT).setProgramView(getProgram(LEFT), getAddresses(LEFT), "listing1");
|
displays.get(LEFT).setProgramView(getProgram(LEFT), getAddresses(LEFT), "listing1");
|
||||||
displays.get(RIGHT).setProgramView(getProgram(RIGHT), getAddresses(RIGHT), "listing2");
|
displays.get(RIGHT).setProgramView(getProgram(RIGHT), getAddresses(RIGHT), "listing2");
|
||||||
|
displays.get(LEFT).goTo(comparisonData.get(LEFT).getInitialLocation());
|
||||||
|
displays.get(RIGHT).goTo(comparisonData.get(LEFT).getInitialLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void nextAreaDiff(boolean forward) {
|
private void nextAreaDiff(boolean forward) {
|
||||||
|
|
|
@ -174,10 +174,6 @@ public class ListingDisplay implements ListingDiffChangeListener {
|
||||||
markerManager.getOverviewProvider().setProgram(program, indexMap);
|
markerManager.getOverviewProvider().setProgram(program, indexMap);
|
||||||
listingPanel.setBackgroundColorModel(
|
listingPanel.setBackgroundColorModel(
|
||||||
new MarkerServiceBackgroundColorModel(markerManager, program, indexMap));
|
new MarkerServiceBackgroundColorModel(markerManager, program, indexMap));
|
||||||
setUpAreaMarkerSets(program, name);
|
|
||||||
if (!view.isEmpty()) {
|
|
||||||
goTo(new ProgramLocation(program, view.getMinAddress()));
|
|
||||||
}
|
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,8 +185,9 @@ public class ListingDisplay implements ListingDiffChangeListener {
|
||||||
Color unmatchedColor = comparisonOptions.getUnmatchedCodeUnitsBackgroundColor();
|
Color unmatchedColor = comparisonOptions.getUnmatchedCodeUnitsBackgroundColor();
|
||||||
|
|
||||||
AddressIndexMap indexMap = listingPanel.getAddressIndexMap();
|
AddressIndexMap indexMap = listingPanel.getAddressIndexMap();
|
||||||
listingPanel.getFieldPanel().setBackgroundColorModel(new MarkerServiceBackgroundColorModel(
|
listingPanel.getFieldPanel()
|
||||||
markerManager, program, indexMap));
|
.setBackgroundColorModel(new MarkerServiceBackgroundColorModel(
|
||||||
|
markerManager, program, indexMap));
|
||||||
|
|
||||||
unmatchedMarkers = markerManager.createAreaMarker(name + " Unmatched Code",
|
unmatchedMarkers = markerManager.createAreaMarker(name + " Unmatched Code",
|
||||||
"Instructions that are not matched to an instruction in the other function.",
|
"Instructions that are not matched to an instruction in the other function.",
|
||||||
|
@ -307,8 +304,9 @@ public class ListingDisplay implements ListingDiffChangeListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setViewerPosition(ViewerPosition position) {
|
public void setViewerPosition(ViewerPosition position) {
|
||||||
listingPanel.getFieldPanel().setViewerPosition(position.getIndex(), position.getXOffset(),
|
listingPanel.getFieldPanel()
|
||||||
position.getYOffset());
|
.setViewerPosition(position.getIndex(), position.getXOffset(),
|
||||||
|
position.getYOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMouseNavigationEnabled(boolean enabled) {
|
public void setMouseNavigationEnabled(boolean enabled) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.HTMLUtilities;
|
import ghidra.util.HTMLUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,4 +78,9 @@ public class AddressSetComparisonData implements ComparisonData {
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return addresses.isEmpty();
|
return addresses.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProgramLocation getInitialLocation() {
|
||||||
|
return new ProgramLocation(program, addresses.getMinAddress());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import generic.theme.GThemeDefaults.Colors.Palette;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ComparisonData is an abstract of items that can be compared in a {@link CodeComparisonPanel}.
|
* ComparisonData is an abstract of items that can be compared in a {@link CodeComparisonPanel}.
|
||||||
|
@ -68,4 +69,9 @@ public interface ComparisonData {
|
||||||
*/
|
*/
|
||||||
public boolean isEmpty();
|
public boolean isEmpty();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the initial program location to put the cursor when the panel is first displayed
|
||||||
|
*/
|
||||||
|
public ProgramLocation getInitialLocation();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Objects;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.HTMLUtilities;
|
import ghidra.util.HTMLUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,4 +109,9 @@ public class DataComparisonData implements ComparisonData {
|
||||||
}
|
}
|
||||||
return endAddress;
|
return endAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProgramLocation getInitialLocation() {
|
||||||
|
return new ProgramLocation(data.getProgram(), data.getMinAddress());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import ghidra.program.model.address.AddressSet;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
|
||||||
public class EmptyComparisonData implements ComparisonData {
|
public class EmptyComparisonData implements ComparisonData {
|
||||||
|
|
||||||
|
@ -51,4 +52,9 @@ public class EmptyComparisonData implements ComparisonData {
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProgramLocation getInitialLocation() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ import ghidra.program.model.address.AddressSet;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.util.FunctionSignatureFieldLocation;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.HTMLUtilities;
|
import ghidra.util.HTMLUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,4 +86,9 @@ public class FunctionComparisonData implements ComparisonData {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProgramLocation getInitialLocation() {
|
||||||
|
return new FunctionSignatureFieldLocation(function.getProgram(), function.getEntryPoint());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 94 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 59 KiB |
|
@ -20,11 +20,11 @@ import javax.swing.Icon;
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import docking.tool.ToolConstants;
|
import docking.tool.ToolConstants;
|
||||||
import docking.wizard.WizardManager;
|
import docking.wizard.WizardDialog;
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
import ghidra.feature.vt.gui.plugin.VTController;
|
import ghidra.feature.vt.gui.plugin.VTController;
|
||||||
import ghidra.feature.vt.gui.plugin.VTPlugin;
|
import ghidra.feature.vt.gui.plugin.VTPlugin;
|
||||||
import ghidra.feature.vt.gui.wizard.VTAddToSessionWizardManager;
|
import ghidra.feature.vt.gui.wizard.add.VTAddToSessionWizardModel;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
public class AddToVersionTrackingSessionAction extends DockingAction {
|
public class AddToVersionTrackingSessionAction extends DockingAction {
|
||||||
|
@ -46,10 +46,9 @@ public class AddToVersionTrackingSessionAction extends DockingAction {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
VTAddToSessionWizardManager vtWizardManager = new VTAddToSessionWizardManager(controller);
|
VTAddToSessionWizardModel model = new VTAddToSessionWizardModel(controller);
|
||||||
WizardManager wizardManager =
|
WizardDialog wizardDialog = new WizardDialog(model);
|
||||||
new WizardManager("Version Tracking Wizard", true, vtWizardManager);
|
wizardDialog.show(controller.getParentComponent());
|
||||||
wizardManager.showWizard(controller.getParentComponent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,11 +21,11 @@ import docking.ActionContext;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import docking.tool.ToolConstants;
|
import docking.tool.ToolConstants;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.wizard.WizardManager;
|
import docking.wizard.WizardDialog;
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
import ghidra.feature.vt.gui.plugin.VTController;
|
import ghidra.feature.vt.gui.plugin.VTController;
|
||||||
import ghidra.feature.vt.gui.plugin.VTPlugin;
|
import ghidra.feature.vt.gui.plugin.VTPlugin;
|
||||||
import ghidra.feature.vt.gui.wizard.VTNewSessionWizardManager;
|
import ghidra.feature.vt.gui.wizard.session.VTNewSessionWizardModel;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
public class CreateVersionTrackingSessionAction extends DockingAction {
|
public class CreateVersionTrackingSessionAction extends DockingAction {
|
||||||
|
@ -58,10 +58,9 @@ public class CreateVersionTrackingSessionAction extends DockingAction {
|
||||||
if (!controller.closeVersionTrackingSession()) {
|
if (!controller.closeVersionTrackingSession()) {
|
||||||
return; // user cancelled during save dialog
|
return; // user cancelled during save dialog
|
||||||
}
|
}
|
||||||
VTNewSessionWizardManager vtWizardManager = new VTNewSessionWizardManager(controller);
|
VTNewSessionWizardModel model = new VTNewSessionWizardModel(controller);
|
||||||
WizardManager wizardManager =
|
WizardDialog wizardDialog = new WizardDialog(model);
|
||||||
new WizardManager("Version Tracking Wizard", true, vtWizardManager);
|
wizardDialog.show(controller.getParentComponent());
|
||||||
wizardManager.showWizard(controller.getParentComponent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import javax.swing.JFrame;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import docking.tool.ToolConstants;
|
import docking.tool.ToolConstants;
|
||||||
import docking.wizard.WizardManager;
|
import docking.wizard.WizardDialog;
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
import ghidra.GhidraOptions;
|
import ghidra.GhidraOptions;
|
||||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||||
|
@ -37,7 +37,7 @@ import ghidra.feature.vt.gui.provider.functionassociation.VTFunctionAssociationP
|
||||||
import ghidra.feature.vt.gui.provider.impliedmatches.*;
|
import ghidra.feature.vt.gui.provider.impliedmatches.*;
|
||||||
import ghidra.feature.vt.gui.provider.markuptable.VTMarkupItemsTableProvider;
|
import ghidra.feature.vt.gui.provider.markuptable.VTMarkupItemsTableProvider;
|
||||||
import ghidra.feature.vt.gui.provider.matchtable.VTMatchTableProvider;
|
import ghidra.feature.vt.gui.provider.matchtable.VTMatchTableProvider;
|
||||||
import ghidra.feature.vt.gui.wizard.VTNewSessionWizardManager;
|
import ghidra.feature.vt.gui.wizard.session.VTNewSessionWizardModel;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
|
@ -268,11 +268,10 @@ public class VTPlugin extends Plugin {
|
||||||
if (!controller.closeVersionTrackingSession()) {
|
if (!controller.closeVersionTrackingSession()) {
|
||||||
return false; // user cancelled during save dialog
|
return false; // user cancelled during save dialog
|
||||||
}
|
}
|
||||||
VTNewSessionWizardManager vtWizardManager =
|
VTNewSessionWizardModel model =
|
||||||
new VTNewSessionWizardManager(controller, programFile1, programFile2);
|
new VTNewSessionWizardModel(controller, programFile1, programFile2);
|
||||||
WizardManager wizardManager =
|
WizardDialog wizardDialog = new WizardDialog(model);
|
||||||
new WizardManager("Version Tracking Wizard", true, vtWizardManager);
|
wizardDialog.show(tool.getToolFrame());
|
||||||
wizardManager.showWizard(tool.getToolFrame());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.gui.task;
|
package ghidra.feature.vt.gui.task;
|
||||||
|
|
||||||
import ghidra.feature.vt.gui.wizard.VTWizardUtils;
|
import ghidra.feature.vt.gui.wizard.session.VTWizardUtils;
|
||||||
import ghidra.framework.model.DomainFile;
|
import ghidra.framework.model.DomainFile;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.feature.vt.gui.wizard;
|
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
|
||||||
|
|
||||||
public interface AddressRangeListener {
|
|
||||||
|
|
||||||
public void processAddressRange(Address minAddress, Address maxAddress);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,152 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.feature.vt.gui.wizard;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
|
|
||||||
import docking.widgets.checkbox.GCheckBox;
|
|
||||||
import docking.wizard.*;
|
|
||||||
import ghidra.feature.vt.api.main.VTProgramCorrelatorAddressRestrictionPreference;
|
|
||||||
import ghidra.feature.vt.api.main.VTProgramCorrelatorFactory;
|
|
||||||
import ghidra.program.model.address.AddressSetView;
|
|
||||||
import ghidra.util.HTMLUtilities;
|
|
||||||
import ghidra.util.HelpLocation;
|
|
||||||
import ghidra.util.layout.VerticalLayout;
|
|
||||||
|
|
||||||
public class AddressSetOptionsPanel extends AbstractMageJPanel<VTWizardStateKey> {
|
|
||||||
|
|
||||||
private JCheckBox excludeCheckbox;
|
|
||||||
private JCheckBox showAddressSetPanelsCheckbox;
|
|
||||||
|
|
||||||
public AddressSetOptionsPanel() { //
|
|
||||||
setBorder(BorderFactory.createEmptyBorder(40, 40, 0, 0));
|
|
||||||
|
|
||||||
excludeCheckbox = new GCheckBox("Exclude accepted matches", false);
|
|
||||||
String excludeAcceptedTooltip = "This option will cause the correlator algorithm " +
|
|
||||||
"to <b>not</b> consider any functions or data that have already been " +
|
|
||||||
"accepted. Using this option can greatly speed up the processing time " +
|
|
||||||
"of the correlator algorithm; however, this options should only be " +
|
|
||||||
"used when you trust that your accepted matches are correct.";
|
|
||||||
excludeCheckbox.setToolTipText(HTMLUtilities.toWrappedHTML(excludeAcceptedTooltip));
|
|
||||||
|
|
||||||
showAddressSetPanelsCheckbox = new GCheckBox("Limit source and destination address sets");
|
|
||||||
String manuallyLimitTooltip = "Selecting this checkbox will trigger additional wizard " +
|
|
||||||
" panels allowing you to customize the address sets used " +
|
|
||||||
" by the selected algorithm. When not selected, the entire address space is used.";
|
|
||||||
|
|
||||||
showAddressSetPanelsCheckbox.setToolTipText(
|
|
||||||
HTMLUtilities.toWrappedHTML(manuallyLimitTooltip));
|
|
||||||
|
|
||||||
add(excludeCheckbox);
|
|
||||||
add(showAddressSetPanelsCheckbox);
|
|
||||||
setLayout(new VerticalLayout(20));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDependencies(WizardState<VTWizardStateKey> state) {
|
|
||||||
// none
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enterPanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<VTProgramCorrelatorFactory> list = (List<VTProgramCorrelatorFactory>) state.get(
|
|
||||||
VTWizardStateKey.PROGRAM_CORRELATOR_FACTORY_LIST);
|
|
||||||
|
|
||||||
Boolean value = (Boolean) state.get(VTWizardStateKey.EXCLUDE_ACCEPTED_MATCHES);
|
|
||||||
if (value != null) {
|
|
||||||
excludeCheckbox.setSelected(value.booleanValue());
|
|
||||||
}
|
|
||||||
value = (Boolean) state.get(VTWizardStateKey.SHOW_ADDRESS_SET_PANELS);
|
|
||||||
if (value != null) {
|
|
||||||
showAddressSetPanelsCheckbox.setSelected(value.booleanValue());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
AddressSetView sourceSelection =
|
|
||||||
(AddressSetView) state.get(VTWizardStateKey.SOURCE_SELECTION);
|
|
||||||
AddressSetView destinationSelection =
|
|
||||||
(AddressSetView) state.get(VTWizardStateKey.DESTINATION_SELECTION);
|
|
||||||
boolean somethingSelected = (sourceSelection != null && !sourceSelection.isEmpty()) ||
|
|
||||||
(destinationSelection != null && !destinationSelection.isEmpty());
|
|
||||||
showAddressSetPanelsCheckbox.setSelected(somethingSelected);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allowRestrictions(list)) {
|
|
||||||
excludeCheckbox.setEnabled(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
excludeCheckbox.setSelected(false);
|
|
||||||
excludeCheckbox.setEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean allowRestrictions(List<VTProgramCorrelatorFactory> list) {
|
|
||||||
for (VTProgramCorrelatorFactory factory : list) {
|
|
||||||
if (factory.getAddressRestrictionPreference() != VTProgramCorrelatorAddressRestrictionPreference.RESTRICTION_NOT_ALLOWED) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WizardPanelDisplayability getPanelDisplayabilityAndUpdateState(
|
|
||||||
WizardState<VTWizardStateKey> state) {
|
|
||||||
return WizardPanelDisplayability.CAN_BE_DISPLAYED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leavePanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
updateStateObjectWithPanelInfo(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateStateObjectWithPanelInfo(WizardState<VTWizardStateKey> state) {
|
|
||||||
state.put(VTWizardStateKey.EXCLUDE_ACCEPTED_MATCHES, excludeCheckbox.isSelected());
|
|
||||||
state.put(VTWizardStateKey.SHOW_ADDRESS_SET_PANELS,
|
|
||||||
showAddressSetPanelsCheckbox.isSelected());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HelpLocation getHelpLocation() {
|
|
||||||
return new HelpLocation("VersionTrackingPlugin", "Address_Set_Panel");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTitle() {
|
|
||||||
return "Address Set Options";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValidInformation() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,156 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.feature.vt.gui.wizard;
|
|
||||||
|
|
||||||
import ghidra.feature.vt.gui.wizard.ChooseAddressSetEditorPanel.AddressSetChoice;
|
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
|
||||||
import ghidra.program.model.address.*;
|
|
||||||
import ghidra.program.model.listing.Program;
|
|
||||||
import ghidra.util.HelpLocation;
|
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
|
|
||||||
import docking.wizard.*;
|
|
||||||
|
|
||||||
public class AddressSetPanel extends AbstractMageJPanel<VTWizardStateKey> {
|
|
||||||
|
|
||||||
private final PluginTool tool;
|
|
||||||
private final String name;
|
|
||||||
private final VTWizardStateKey programDependencyKey;
|
|
||||||
private final VTWizardStateKey addressSetViewKey;
|
|
||||||
private final VTWizardStateKey selectionKey;
|
|
||||||
private final VTWizardStateKey addressSetChoiceKey;
|
|
||||||
private ChooseAddressSetEditorPanel panel;
|
|
||||||
private Program program;
|
|
||||||
|
|
||||||
public AddressSetPanel(PluginTool tool, String name, VTWizardStateKey programFileDependencyKey,
|
|
||||||
VTWizardStateKey programDependencyKey, VTWizardStateKey addressSetViewKey,
|
|
||||||
VTWizardStateKey selectionKey, VTWizardStateKey addressSetChoiceKey) {
|
|
||||||
this.tool = tool;
|
|
||||||
this.name = name;
|
|
||||||
this.programDependencyKey = programDependencyKey;
|
|
||||||
this.addressSetViewKey = addressSetViewKey;
|
|
||||||
this.selectionKey = selectionKey;
|
|
||||||
this.addressSetChoiceKey = addressSetChoiceKey;
|
|
||||||
setLayout(new BorderLayout());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDependencies(WizardState<VTWizardStateKey> state) {
|
|
||||||
// no dependencies
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep this method for now in case we want it as the default for the entire program address set
|
|
||||||
// instead of the program's memory address set.
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private AddressSet getAddressFactoryAddressSet(WizardState<VTWizardStateKey> state) {
|
|
||||||
Program programFromState = (Program) state.get(programDependencyKey);
|
|
||||||
AddressFactory factory = programFromState.getAddressFactory();
|
|
||||||
AddressSet everything = new AddressSet();
|
|
||||||
AddressSpace[] addressSpaces = factory.getAddressSpaces();
|
|
||||||
for (AddressSpace addressSpace : addressSpaces) {
|
|
||||||
Address minAddress = addressSpace.getMinAddress();
|
|
||||||
Address maxAddress = addressSpace.getMaxAddress();
|
|
||||||
AddressRangeImpl range = new AddressRangeImpl(minAddress, maxAddress);
|
|
||||||
everything.add(range);
|
|
||||||
}
|
|
||||||
return everything;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HelpLocation getHelpLocation() {
|
|
||||||
return new HelpLocation("VersionTrackingPlugin", "Address_Set_Panel");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enterPanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
if (panel != null) {
|
|
||||||
remove(panel);
|
|
||||||
}
|
|
||||||
program = (Program) state.get(programDependencyKey);
|
|
||||||
AddressSetView addressSetView = (AddressSetView) state.get(addressSetViewKey);
|
|
||||||
AddressSetView selection = (AddressSetView) state.get(selectionKey);
|
|
||||||
AddressSetChoice addressSetChoice = (AddressSetChoice) state.get(addressSetChoiceKey);
|
|
||||||
if (addressSetChoice == null) {
|
|
||||||
if (selection != null && !selection.isEmpty()) {
|
|
||||||
addressSetChoice = AddressSetChoice.SELECTION;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
addressSetChoice = AddressSetChoice.ENTIRE_PROGRAM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panel =
|
|
||||||
new ChooseAddressSetEditorPanel(tool, name, program, selection, addressSetView,
|
|
||||||
addressSetChoice);
|
|
||||||
panel.addChangeListener(new ChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e) {
|
|
||||||
notifyListenersOfValidityChanged();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(panel, BorderLayout.CENTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WizardPanelDisplayability getPanelDisplayabilityAndUpdateState(
|
|
||||||
WizardState<VTWizardStateKey> state) {
|
|
||||||
Boolean value = (Boolean) state.get(VTWizardStateKey.SHOW_ADDRESS_SET_PANELS);
|
|
||||||
boolean showPanel = value == null ? false : value.booleanValue();
|
|
||||||
if (!showPanel) {
|
|
||||||
return WizardPanelDisplayability.DO_NOT_DISPLAY;
|
|
||||||
}
|
|
||||||
return WizardPanelDisplayability.CAN_BE_DISPLAYED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leavePanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
updateStateObjectWithPanelInfo(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateStateObjectWithPanelInfo(WizardState<VTWizardStateKey> state) {
|
|
||||||
AddressSetView addressSetView = panel.getAddressSetView();
|
|
||||||
state.put(addressSetViewKey, addressSetView);
|
|
||||||
state.put(addressSetChoiceKey, panel.getAddressSetChoice());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTitle() {
|
|
||||||
return "Select " + name + " Address Range(s)";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
// not sure if we need this
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValidInformation() {
|
|
||||||
boolean empty = panel.getAddressSetView().isEmpty();
|
|
||||||
String msg = empty ? "At least one address range is required" : "";
|
|
||||||
notifyListenersOfStatusMessage(msg);
|
|
||||||
return !empty;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,109 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.feature.vt.gui.wizard;
|
|
||||||
|
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
|
||||||
import ghidra.util.HelpLocation;
|
|
||||||
|
|
||||||
import java.awt.GridLayout;
|
|
||||||
|
|
||||||
import docking.wizard.*;
|
|
||||||
|
|
||||||
public class LimitAddressSetsPanel extends AbstractMageJPanel<VTWizardStateKey> {
|
|
||||||
|
|
||||||
private AddressSetPanel sourcePanel;
|
|
||||||
private AddressSetPanel destinationPanel;
|
|
||||||
|
|
||||||
public LimitAddressSetsPanel(PluginTool tool) {
|
|
||||||
|
|
||||||
setLayout(new GridLayout());
|
|
||||||
sourcePanel =
|
|
||||||
new AddressSetPanel(tool, "Source", VTWizardStateKey.SOURCE_PROGRAM_FILE,
|
|
||||||
VTWizardStateKey.SOURCE_PROGRAM, VTWizardStateKey.SOURCE_ADDRESS_SET_VIEW,
|
|
||||||
VTWizardStateKey.SOURCE_SELECTION, VTWizardStateKey.SOURCE_ADDRESS_SET_CHOICE);
|
|
||||||
destinationPanel =
|
|
||||||
new AddressSetPanel(tool, "Destination", VTWizardStateKey.DESTINATION_PROGRAM_FILE,
|
|
||||||
VTWizardStateKey.DESTINATION_PROGRAM,
|
|
||||||
VTWizardStateKey.DESTINATION_ADDRESS_SET_VIEW,
|
|
||||||
VTWizardStateKey.DESTINATION_SELECTION,
|
|
||||||
VTWizardStateKey.DESTINATION_ADDRESS_SET_CHOICE);
|
|
||||||
add(sourcePanel);
|
|
||||||
add(destinationPanel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HelpLocation getHelpLocation() {
|
|
||||||
return new HelpLocation("VersionTrackingPlugin", "Select_Address_Ranges_Panel");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDependencies(WizardState<VTWizardStateKey> state) {
|
|
||||||
sourcePanel.addDependencies(state);
|
|
||||||
destinationPanel.addDependencies(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
sourcePanel.dispose();
|
|
||||||
destinationPanel.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enterPanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
sourcePanel.enterPanel(state);
|
|
||||||
destinationPanel.enterPanel(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WizardPanelDisplayability getPanelDisplayabilityAndUpdateState(
|
|
||||||
WizardState<VTWizardStateKey> state) {
|
|
||||||
WizardPanelDisplayability sourceDisplayability =
|
|
||||||
sourcePanel.getPanelDisplayabilityAndUpdateState(state);
|
|
||||||
destinationPanel.getPanelDisplayabilityAndUpdateState(state);
|
|
||||||
// Use the displayability of the source panel as that of the source/destination combined.
|
|
||||||
return sourceDisplayability;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leavePanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
sourcePanel.leavePanel(state);
|
|
||||||
destinationPanel.leavePanel(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateStateObjectWithPanelInfo(WizardState<VTWizardStateKey> state) {
|
|
||||||
sourcePanel.updateStateObjectWithPanelInfo(state);
|
|
||||||
destinationPanel.updateStateObjectWithPanelInfo(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTitle() {
|
|
||||||
return "Select Address Range(s)";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
sourcePanel.initialize();
|
|
||||||
destinationPanel.initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValidInformation() {
|
|
||||||
return sourcePanel.isValidInformation() && destinationPanel.isValidInformation();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,611 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.feature.vt.gui.wizard;
|
|
||||||
|
|
||||||
import static ghidra.framework.main.DataTreeDialogType.*;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.DocumentEvent;
|
|
||||||
import javax.swing.event.DocumentListener;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import docking.widgets.button.BrowseButton;
|
|
||||||
import docking.widgets.label.GDLabel;
|
|
||||||
import docking.wizard.*;
|
|
||||||
import generic.theme.GIcon;
|
|
||||||
import generic.theme.GThemeDefaults.Ids.Fonts;
|
|
||||||
import generic.theme.Gui;
|
|
||||||
import ghidra.app.util.task.OpenProgramRequest;
|
|
||||||
import ghidra.app.util.task.OpenProgramTask;
|
|
||||||
import ghidra.feature.vt.api.util.VTSessionFileUtil;
|
|
||||||
import ghidra.framework.main.DataTreeDialog;
|
|
||||||
import ghidra.framework.model.DomainFile;
|
|
||||||
import ghidra.framework.model.DomainFolder;
|
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
|
||||||
import ghidra.program.model.listing.Program;
|
|
||||||
import ghidra.util.*;
|
|
||||||
import ghidra.util.task.TaskLauncher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Version tracking wizard panel to create a new session.
|
|
||||||
*/
|
|
||||||
public class NewSessionPanel extends AbstractMageJPanel<VTWizardStateKey> {
|
|
||||||
|
|
||||||
// The maximum length to allow for each program's name portion of the session name.
|
|
||||||
// In the filesystem API, when saved, the session name is restricted to 60 characters.
|
|
||||||
// The default VTSession name combines the two program names so split the length between them,
|
|
||||||
// minus text we add below.
|
|
||||||
private static final int VTSESSION_NAME_PROGRAM_NAME_MAX_LENGTH = 28;
|
|
||||||
private static final int TEXT_FIELD_LENGTH = 40;
|
|
||||||
private static final Icon SWAP_ICON = new GIcon("icon.version.tracking.new.session.swap");
|
|
||||||
private static final Icon INFO_ICON = new GIcon("icon.version.tracking.new.session.info");
|
|
||||||
|
|
||||||
private JTextField sourceField;
|
|
||||||
private JTextField destinationField;
|
|
||||||
private JButton sourceBrowseButton;
|
|
||||||
private JButton destinationBrowseButton;
|
|
||||||
private JButton swapProgramsButton;
|
|
||||||
private JTextField sessionNameField;
|
|
||||||
private JTextField folderNameField;
|
|
||||||
private DomainFolder folder;
|
|
||||||
private PluginTool tool;
|
|
||||||
|
|
||||||
// All program info objects that the user may have opened while using the wizard. We keep
|
|
||||||
// these around to avoid reopening them and any accompanying upgrading that may be required.
|
|
||||||
// These will be released when the wizard is finished.
|
|
||||||
private Map<DomainFile, ProgramInfo> allProgramInfos = new HashMap<>();
|
|
||||||
private ProgramInfo sourceProgramInfo;
|
|
||||||
private ProgramInfo destinationProgramInfo;
|
|
||||||
|
|
||||||
NewSessionPanel(PluginTool tool) {
|
|
||||||
|
|
||||||
this.tool = tool;
|
|
||||||
setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
|
|
||||||
|
|
||||||
JLabel folderLabel = new GDLabel("Project folder ");
|
|
||||||
folderLabel.setHorizontalAlignment(SwingConstants.RIGHT);
|
|
||||||
folderLabel.setToolTipText("The folder to store the new Version Tracking Session");
|
|
||||||
folderNameField = new JTextField();
|
|
||||||
Gui.registerFont(folderNameField, Fonts.MONOSPACED);
|
|
||||||
folderNameField.setEditable(false); // force user to browse to choose
|
|
||||||
|
|
||||||
JButton browseFolderButton = new BrowseButton();
|
|
||||||
browseFolderButton.addActionListener(e -> browseDataTreeFolders());
|
|
||||||
|
|
||||||
JLabel newSessionLabel = new GDLabel("New Session Name: ");
|
|
||||||
newSessionLabel.setToolTipText("The name for the new Version Tracking Session");
|
|
||||||
newSessionLabel.setHorizontalAlignment(SwingConstants.RIGHT);
|
|
||||||
|
|
||||||
sessionNameField = new JTextField(TEXT_FIELD_LENGTH);
|
|
||||||
sessionNameField.getDocument().addDocumentListener(new DocumentListener() {
|
|
||||||
@Override
|
|
||||||
public void changedUpdate(DocumentEvent e) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void insertUpdate(DocumentEvent e) {
|
|
||||||
notifyListenersOfValidityChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeUpdate(DocumentEvent e) {
|
|
||||||
notifyListenersOfValidityChanged();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
JLabel sourceLabel = new GDLabel("Source Program: ");
|
|
||||||
sourceLabel.setIcon(INFO_ICON);
|
|
||||||
sourceLabel.setToolTipText("Analyzed program with markup to transfer");
|
|
||||||
sourceLabel.setHorizontalAlignment(SwingConstants.RIGHT);
|
|
||||||
|
|
||||||
JLabel destinationLabel = new GDLabel("Destination Program: ");
|
|
||||||
destinationLabel.setIcon(INFO_ICON);
|
|
||||||
destinationLabel.setToolTipText("New program that receives the transferred markup");
|
|
||||||
destinationLabel.setHorizontalAlignment(SwingConstants.RIGHT);
|
|
||||||
|
|
||||||
sourceField = new JTextField(TEXT_FIELD_LENGTH);
|
|
||||||
sourceField.setEditable(false);
|
|
||||||
|
|
||||||
destinationField = new JTextField(TEXT_FIELD_LENGTH);
|
|
||||||
destinationField.setEditable(false);
|
|
||||||
|
|
||||||
sourceBrowseButton = createSourceBrowseButton();
|
|
||||||
destinationBrowseButton = createDestinationBrowseButton();
|
|
||||||
|
|
||||||
swapProgramsButton = new JButton(SWAP_ICON);
|
|
||||||
swapProgramsButton.setText("swap");
|
|
||||||
swapProgramsButton.setName("SWAP_BUTTON");
|
|
||||||
swapProgramsButton.addActionListener(arg0 -> swapPrograms());
|
|
||||||
|
|
||||||
JPanel mainPanel = new JPanel(new GridBagLayout());
|
|
||||||
GridBagConstraints gbc = new GridBagConstraints();
|
|
||||||
|
|
||||||
gbc.gridx = 0;
|
|
||||||
gbc.gridy = 0;
|
|
||||||
mainPanel.add(Box.createVerticalStrut(15), gbc);
|
|
||||||
|
|
||||||
gbc.gridy++;
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
mainPanel.add(folderLabel, gbc);
|
|
||||||
|
|
||||||
gbc.gridx++;
|
|
||||||
mainPanel.add(folderNameField, gbc);
|
|
||||||
|
|
||||||
gbc.gridx++;
|
|
||||||
mainPanel.add(Box.createHorizontalStrut(5), gbc);
|
|
||||||
|
|
||||||
gbc.gridx++;
|
|
||||||
mainPanel.add(browseFolderButton, gbc);
|
|
||||||
|
|
||||||
gbc.gridx = 0;
|
|
||||||
gbc.gridy++;
|
|
||||||
mainPanel.add(Box.createVerticalStrut(10), gbc);
|
|
||||||
|
|
||||||
gbc.gridy++;
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
mainPanel.add(newSessionLabel, gbc);
|
|
||||||
|
|
||||||
gbc.gridx++;
|
|
||||||
mainPanel.add(sessionNameField, gbc);
|
|
||||||
|
|
||||||
gbc.gridx = 0;
|
|
||||||
gbc.gridy++;
|
|
||||||
mainPanel.add(Box.createVerticalStrut(15), gbc);
|
|
||||||
|
|
||||||
gbc.gridy++;
|
|
||||||
gbc.gridwidth = 4;
|
|
||||||
mainPanel.add(new JSeparator(), gbc);
|
|
||||||
|
|
||||||
gbc.gridy++;
|
|
||||||
gbc.gridwidth = 1;
|
|
||||||
mainPanel.add(Box.createVerticalStrut(25), gbc);
|
|
||||||
|
|
||||||
gbc.gridy++;
|
|
||||||
mainPanel.add(sourceLabel, gbc);
|
|
||||||
|
|
||||||
gbc.gridx++;
|
|
||||||
mainPanel.add(sourceField, gbc);
|
|
||||||
|
|
||||||
gbc.gridx += 2;
|
|
||||||
mainPanel.add(sourceBrowseButton, gbc);
|
|
||||||
|
|
||||||
gbc.gridx = 0;
|
|
||||||
gbc.gridy++;
|
|
||||||
gbc.fill = GridBagConstraints.NONE;
|
|
||||||
gbc.gridwidth = 4;
|
|
||||||
mainPanel.add(swapProgramsButton, gbc);
|
|
||||||
|
|
||||||
gbc.gridwidth = 1;
|
|
||||||
gbc.gridy++;
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
mainPanel.add(destinationLabel, gbc);
|
|
||||||
|
|
||||||
gbc.gridx++;
|
|
||||||
mainPanel.add(destinationField, gbc);
|
|
||||||
|
|
||||||
gbc.gridx += 2;
|
|
||||||
mainPanel.add(destinationBrowseButton, gbc);
|
|
||||||
|
|
||||||
gbc.gridx = 0;
|
|
||||||
gbc.gridy++;
|
|
||||||
mainPanel.add(Box.createVerticalStrut(25), gbc);
|
|
||||||
|
|
||||||
gbc.gridy++;
|
|
||||||
gbc.gridwidth = 4;
|
|
||||||
mainPanel.add(new JSeparator(), gbc);
|
|
||||||
|
|
||||||
gbc.gridy++;
|
|
||||||
gbc.gridwidth = 1;
|
|
||||||
mainPanel.add(Box.createVerticalStrut(60), gbc);
|
|
||||||
|
|
||||||
setLayout(new BorderLayout());
|
|
||||||
add(mainPanel, BorderLayout.NORTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializePrograms(WizardState<VTWizardStateKey> state) {
|
|
||||||
DomainFile source = (DomainFile) state.get(VTWizardStateKey.SOURCE_PROGRAM_FILE);
|
|
||||||
DomainFile destintation = (DomainFile) state.get(VTWizardStateKey.DESTINATION_PROGRAM_FILE);
|
|
||||||
|
|
||||||
if (source != null) {
|
|
||||||
setSourceProgram(source);
|
|
||||||
}
|
|
||||||
if (destintation != null) {
|
|
||||||
setDestinationProgram(destintation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Presents the user with a tree of the existing project folders and allows
|
|
||||||
* them to pick one
|
|
||||||
*/
|
|
||||||
private void browseDataTreeFolders() {
|
|
||||||
final DataTreeDialog dataTreeDialog =
|
|
||||||
new DataTreeDialog(this, "Choose a project folder", CHOOSE_FOLDER);
|
|
||||||
|
|
||||||
dataTreeDialog.addOkActionListener(e -> {
|
|
||||||
dataTreeDialog.close();
|
|
||||||
setFolder(dataTreeDialog.getDomainFolder());
|
|
||||||
});
|
|
||||||
dataTreeDialog.showComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFolder(DomainFolder folder) {
|
|
||||||
this.folder = folder;
|
|
||||||
|
|
||||||
if (folder != null) {
|
|
||||||
folderNameField.setText(folder.toString());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
folderNameField.setText("< Choose a folder >");
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyListenersOfValidityChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setSourceProgram(DomainFile programFile) {
|
|
||||||
notifyListenersOfStatusMessage(" ");
|
|
||||||
|
|
||||||
String path;
|
|
||||||
if (programFile == null) {
|
|
||||||
sourceProgramInfo = null;
|
|
||||||
path = "";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sourceProgramInfo =
|
|
||||||
allProgramInfos.computeIfAbsent(programFile, file -> new ProgramInfo(file));
|
|
||||||
path = programFile.getPathname();
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceField.setText(path);
|
|
||||||
|
|
||||||
updateSessionNameIfBlank();
|
|
||||||
notifyListenersOfValidityChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateSessionNameIfBlank() {
|
|
||||||
if (!StringUtils.isBlank(sessionNameField.getText())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (sourceProgramInfo == null || destinationProgramInfo == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String defaultSessionName =
|
|
||||||
createVTSessionName(sourceProgramInfo.getName(), destinationProgramInfo.getName());
|
|
||||||
sessionNameField.setText(defaultSessionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String createVTSessionName(String sourceName, String destinationName) {
|
|
||||||
|
|
||||||
// if together they are within the bounds just return session name with both full names
|
|
||||||
if (sourceName.length() + destinationName.length() <= 2 *
|
|
||||||
VTSESSION_NAME_PROGRAM_NAME_MAX_LENGTH) {
|
|
||||||
return "VT_" + sourceName + "_" + destinationName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// give destination name all space not used by source name
|
|
||||||
if (sourceName.length() < VTSESSION_NAME_PROGRAM_NAME_MAX_LENGTH) {
|
|
||||||
int leftover = VTSESSION_NAME_PROGRAM_NAME_MAX_LENGTH - sourceName.length();
|
|
||||||
destinationName = StringUtilities.trimMiddle(destinationName,
|
|
||||||
VTSESSION_NAME_PROGRAM_NAME_MAX_LENGTH + leftover);
|
|
||||||
return "VT_" + sourceName + "_" + destinationName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// give source name all space not used by destination name
|
|
||||||
if (destinationName.length() < VTSESSION_NAME_PROGRAM_NAME_MAX_LENGTH) {
|
|
||||||
int leftover = VTSESSION_NAME_PROGRAM_NAME_MAX_LENGTH - destinationName.length();
|
|
||||||
sourceName = StringUtilities.trimMiddle(sourceName,
|
|
||||||
VTSESSION_NAME_PROGRAM_NAME_MAX_LENGTH + leftover);
|
|
||||||
return "VT_" + sourceName + "_" + destinationName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if both too long, shorten both of them
|
|
||||||
sourceName = StringUtilities.trimMiddle(sourceName, VTSESSION_NAME_PROGRAM_NAME_MAX_LENGTH);
|
|
||||||
destinationName =
|
|
||||||
StringUtilities.trimMiddle(destinationName, VTSESSION_NAME_PROGRAM_NAME_MAX_LENGTH);
|
|
||||||
|
|
||||||
return "VT_" + sourceName + "_" + destinationName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setDestinationProgram(DomainFile programFile) {
|
|
||||||
notifyListenersOfStatusMessage(" ");
|
|
||||||
|
|
||||||
String path;
|
|
||||||
if (programFile == null) {
|
|
||||||
destinationProgramInfo = null;
|
|
||||||
path = "";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
destinationProgramInfo =
|
|
||||||
allProgramInfos.computeIfAbsent(programFile, file -> new ProgramInfo(file));
|
|
||||||
path = programFile.getPathname();
|
|
||||||
}
|
|
||||||
|
|
||||||
destinationField.setText(path);
|
|
||||||
updateSessionNameIfBlank();
|
|
||||||
notifyListenersOfValidityChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void swapPrograms() {
|
|
||||||
notifyListenersOfStatusMessage(" ");
|
|
||||||
|
|
||||||
ProgramInfo temp = destinationProgramInfo;
|
|
||||||
destinationProgramInfo = sourceProgramInfo;
|
|
||||||
sourceProgramInfo = temp;
|
|
||||||
|
|
||||||
if (sourceProgramInfo != null) {
|
|
||||||
sourceField.setText(sourceProgramInfo.getPathname());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sourceField.setText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (destinationProgramInfo != null) {
|
|
||||||
destinationField.setText(destinationProgramInfo.getPathname());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
destinationField.setText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyListenersOfValidityChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HelpLocation getHelpLocation() {
|
|
||||||
return new HelpLocation("VersionTrackingPlugin", "New_Session_Panel");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void releaseConsumers() {
|
|
||||||
|
|
||||||
for (ProgramInfo info : allProgramInfos.values()) {
|
|
||||||
info.release(tool);
|
|
||||||
}
|
|
||||||
|
|
||||||
allProgramInfos.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enterPanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
initializePrograms(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WizardPanelDisplayability getPanelDisplayabilityAndUpdateState(
|
|
||||||
WizardState<VTWizardStateKey> state) {
|
|
||||||
return WizardPanelDisplayability.MUST_BE_DISPLAYED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leavePanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
updateStateObjectWithPanelInfo(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateStateObjectWithPanelInfo(WizardState<VTWizardStateKey> state) {
|
|
||||||
state.put(VTWizardStateKey.SOURCE_PROGRAM_FILE, sourceProgramInfo.getFile());
|
|
||||||
state.put(VTWizardStateKey.DESTINATION_PROGRAM_FILE, destinationProgramInfo.getFile());
|
|
||||||
state.put(VTWizardStateKey.SOURCE_PROGRAM, sourceProgramInfo.getProgram());
|
|
||||||
state.put(VTWizardStateKey.DESTINATION_PROGRAM, destinationProgramInfo.getProgram());
|
|
||||||
state.put(VTWizardStateKey.SESSION_NAME, sessionNameField.getText());
|
|
||||||
state.put(VTWizardStateKey.NEW_SESSION_FOLDER, folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean openProgram(ProgramInfo programInfo) {
|
|
||||||
|
|
||||||
if (programInfo.hasProgram()) {
|
|
||||||
return true; // already open
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenProgramTask openProgramTask = new OpenProgramTask(programInfo.getFile(), tool);
|
|
||||||
new TaskLauncher(openProgramTask, tool.getActiveWindow());
|
|
||||||
OpenProgramRequest openProgram = openProgramTask.getOpenProgram();
|
|
||||||
programInfo.setProgram(openProgram != null ? openProgram.getProgram() : null);
|
|
||||||
return programInfo.hasProgram();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTitle() {
|
|
||||||
return "New Version Tracking Session";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
sourceProgramInfo = null;
|
|
||||||
destinationProgramInfo = null;
|
|
||||||
sessionNameField.setText("");
|
|
||||||
sourceField.setText("");
|
|
||||||
destinationField.setText("");
|
|
||||||
setFolder(tool.getProject().getProjectData().getRootFolder());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValidInformation() {
|
|
||||||
|
|
||||||
if (folder == null) {
|
|
||||||
notifyListenersOfStatusMessage("Choose a project folder to continue!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sourceProgramInfo == null || destinationProgramInfo == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sourceProgramInfo.hasSameFile(destinationProgramInfo)) {
|
|
||||||
notifyListenersOfStatusMessage("Source and Destination Programs must be different");
|
|
||||||
releaseConsumers();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = sessionNameField.getText().trim();
|
|
||||||
if (StringUtils.isBlank(name)) {
|
|
||||||
notifyListenersOfStatusMessage("Please enter a name for this session");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
tool.getProject().getProjectData().testValidName(name, false);
|
|
||||||
}
|
|
||||||
catch (InvalidNameException e) {
|
|
||||||
notifyListenersOfStatusMessage("'" + name + "' contains invalid characters");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DomainFile file = folder.getFile(name);
|
|
||||||
if (file != null) {
|
|
||||||
notifyListenersOfStatusMessage(
|
|
||||||
"'" + file.getPathname() + "' is the name of an existing project file");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Known Issue: Opening programs before comitted to using them (i.e., Next is clicked) seems
|
|
||||||
// premature and will subject user to prompts about possible checkout and/or upgrades
|
|
||||||
// with possible slow re-disassembly (see GP-4151)
|
|
||||||
|
|
||||||
if (!isValidDestinationProgramFile() || !isValidSourceProgramFile()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!openProgram(sourceProgramInfo)) {
|
|
||||||
notifyListenersOfStatusMessage(
|
|
||||||
"Can't open source program " + sourceProgramInfo.getName());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!openProgram(destinationProgramInfo)) {
|
|
||||||
notifyListenersOfStatusMessage(
|
|
||||||
"Can't open destination program " + destinationProgramInfo.getName());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyListenersOfStatusMessage(" ");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isValidSourceProgramFile() {
|
|
||||||
try {
|
|
||||||
VTSessionFileUtil.validateSourceProgramFile(sourceProgramInfo.file, false);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
notifyListenersOfStatusMessage(e.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isValidDestinationProgramFile() {
|
|
||||||
try {
|
|
||||||
VTSessionFileUtil.validateDestinationProgramFile(destinationProgramInfo.file, false,
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
notifyListenersOfStatusMessage(e.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDependencies(WizardState<VTWizardStateKey> state) {
|
|
||||||
// none
|
|
||||||
}
|
|
||||||
|
|
||||||
private JButton createSourceBrowseButton() {
|
|
||||||
JButton button = new BrowseButton();
|
|
||||||
button.setName("SOURCE_BUTTON");
|
|
||||||
button.addActionListener(e -> {
|
|
||||||
DomainFile programFile = VTWizardUtils.chooseDomainFile(NewSessionPanel.this,
|
|
||||||
"a source program", VTWizardUtils.PROGRAM_FILTER, null);
|
|
||||||
if (programFile != null) {
|
|
||||||
setSourceProgram(programFile);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JButton createDestinationBrowseButton() {
|
|
||||||
JButton button = new BrowseButton();
|
|
||||||
button.setName("DESTINATION_BUTTON");
|
|
||||||
button.addActionListener(e -> {
|
|
||||||
DomainFile programFile = VTWizardUtils.chooseDomainFile(NewSessionPanel.this,
|
|
||||||
"a destination program", VTWizardUtils.PROGRAM_FILTER, null);
|
|
||||||
if (programFile != null) {
|
|
||||||
setDestinationProgram(programFile);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
releaseConsumers();
|
|
||||||
}
|
|
||||||
|
|
||||||
// simple object to track a domain file and its program
|
|
||||||
private class ProgramInfo {
|
|
||||||
|
|
||||||
private Program program;
|
|
||||||
private DomainFile file;
|
|
||||||
|
|
||||||
public ProgramInfo(DomainFile file) {
|
|
||||||
this.file = Objects.requireNonNull(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setProgram(Program program) {
|
|
||||||
this.program = program;
|
|
||||||
}
|
|
||||||
|
|
||||||
Program getProgram() {
|
|
||||||
return program;
|
|
||||||
}
|
|
||||||
|
|
||||||
DomainFile getFile() {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getPathname() {
|
|
||||||
return file.getPathname();
|
|
||||||
}
|
|
||||||
|
|
||||||
String getName() {
|
|
||||||
return file.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
void release(Object consumer) {
|
|
||||||
if (program == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (program.getConsumerList().contains(consumer)) {
|
|
||||||
program.release(consumer);
|
|
||||||
}
|
|
||||||
|
|
||||||
program = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean hasSameFile(ProgramInfo other) {
|
|
||||||
return file.getPathname().equals(other.getPathname());
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean hasProgram() {
|
|
||||||
return program != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,233 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.feature.vt.gui.wizard;
|
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.beans.PropertyChangeEvent;
|
|
||||||
import java.beans.PropertyChangeListener;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
|
|
||||||
import docking.options.editor.OptionsEditorPanel;
|
|
||||||
import docking.wizard.*;
|
|
||||||
import ghidra.feature.vt.api.main.VTProgramCorrelatorFactory;
|
|
||||||
import ghidra.feature.vt.api.util.VTOptions;
|
|
||||||
import ghidra.framework.options.EditorStateFactory;
|
|
||||||
import ghidra.framework.options.Options;
|
|
||||||
import ghidra.util.HelpLocation;
|
|
||||||
import ghidra.util.layout.MiddleLayout;
|
|
||||||
import ghidra.util.layout.VerticalLayout;
|
|
||||||
import util.CollectionUtils;
|
|
||||||
|
|
||||||
public class OptionsPanel extends AbstractMageJPanel<VTWizardStateKey> {
|
|
||||||
|
|
||||||
private static final Dimension DEFAULT_PREFERRED_SIZE = new Dimension(650, 350);
|
|
||||||
|
|
||||||
private List<OptionsEditorPanel> optionsEditorPanelList;
|
|
||||||
private List<VTOptions> optionsList = null;
|
|
||||||
private PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
|
||||||
notifyListenersOfValidityChanged();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
OptionsPanel() {
|
|
||||||
super(new BorderLayout());
|
|
||||||
// restricting use?
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HelpLocation getHelpLocation() {
|
|
||||||
if (optionsList != null) {
|
|
||||||
for (VTOptions options : optionsList) {
|
|
||||||
if (options != null) {
|
|
||||||
HelpLocation helpLocation = options.getOptionsHelpLocation();
|
|
||||||
if (helpLocation != null) {
|
|
||||||
return helpLocation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// default
|
|
||||||
return new HelpLocation("VersionTrackingPlugin", "Options_Panel");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension getPreferredSize() {
|
|
||||||
Dimension preferredSize = super.getPreferredSize();
|
|
||||||
if (preferredSize.width < DEFAULT_PREFERRED_SIZE.width) {
|
|
||||||
return DEFAULT_PREFERRED_SIZE;
|
|
||||||
}
|
|
||||||
return preferredSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
if (optionsEditorPanelList != null) {
|
|
||||||
removeAll();
|
|
||||||
optionsEditorPanelList = null;
|
|
||||||
optionsList = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enterPanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
dispose();
|
|
||||||
List<VTProgramCorrelatorFactory> correlatorFactoryList = getCorrelators(state);
|
|
||||||
|
|
||||||
optionsList = getCorrelatorOptions(state);
|
|
||||||
if (optionsList == null) {
|
|
||||||
optionsList = generateDefaultOptions(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
JPanel panel = new JPanel(new VerticalLayout(30));
|
|
||||||
|
|
||||||
optionsEditorPanelList = new ArrayList<OptionsEditorPanel>();
|
|
||||||
for (int i = 0; i < correlatorFactoryList.size(); i++) {
|
|
||||||
String correlatorName = correlatorFactoryList.get(i).getName();
|
|
||||||
String title = correlatorName + " Options";
|
|
||||||
if (optionsList.get(i) == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorStateFactory editorStateFactory = new EditorStateFactory();
|
|
||||||
Options options = optionsList.get(i);
|
|
||||||
List<String> optionNames = options.getLeafOptionNames();
|
|
||||||
if (optionNames.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Collections.sort(optionNames);
|
|
||||||
OptionsEditorPanel optionsPanel =
|
|
||||||
new OptionsEditorPanel(title, options, optionNames, editorStateFactory);
|
|
||||||
optionsPanel.setOptionsPropertyChangeListener(propertyChangeListener);
|
|
||||||
optionsEditorPanelList.add(optionsPanel);
|
|
||||||
panel.add(optionsPanel);
|
|
||||||
}
|
|
||||||
JPanel outerPanel = new JPanel(new MiddleLayout());
|
|
||||||
outerPanel.add(panel);
|
|
||||||
JScrollPane scrollPane = new JScrollPane(outerPanel);
|
|
||||||
scrollPane.getVerticalScrollBar().setUnitIncrement(5);
|
|
||||||
add(scrollPane);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<VTOptions> generateDefaultOptions(WizardState<VTWizardStateKey> state) {
|
|
||||||
List<VTOptions> list = new ArrayList<VTOptions>();
|
|
||||||
List<VTProgramCorrelatorFactory> correlatorFactoryList = getCorrelators(state);
|
|
||||||
for (VTProgramCorrelatorFactory vtProgramCorrelatorFactory : correlatorFactoryList) {
|
|
||||||
list.add(vtProgramCorrelatorFactory.createDefaultOptions());
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<VTOptions> getCorrelatorOptions(WizardState<VTWizardStateKey> state) {
|
|
||||||
List<?> list = (List<?>) state.get(VTWizardStateKey.PROGRAM_CORRELATOR_OPTIONS_LIST);
|
|
||||||
if (list == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return CollectionUtils.asList(list, VTOptions.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<VTProgramCorrelatorFactory> getCorrelators(WizardState<VTWizardStateKey> state) {
|
|
||||||
List<?> list = (List<?>) state.get(VTWizardStateKey.PROGRAM_CORRELATOR_FACTORY_LIST);
|
|
||||||
if (list == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return CollectionUtils.asList(list, VTProgramCorrelatorFactory.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WizardPanelDisplayability getPanelDisplayabilityAndUpdateState(
|
|
||||||
WizardState<VTWizardStateKey> state) {
|
|
||||||
|
|
||||||
List<VTOptions> tmpOptions = getCorrelatorOptions(state);
|
|
||||||
if (tmpOptions == null) {
|
|
||||||
tmpOptions = generateDefaultOptions(state);
|
|
||||||
}
|
|
||||||
for (VTOptions vtOptions : tmpOptions) {
|
|
||||||
if (vtOptions == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> names = vtOptions.getOptionNames();
|
|
||||||
if (names.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return WizardPanelDisplayability.MUST_BE_DISPLAYED;
|
|
||||||
}
|
|
||||||
return WizardPanelDisplayability.DO_NOT_DISPLAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leavePanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
updateStateObjectWithPanelInfo(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateStateObjectWithPanelInfo(WizardState<VTWizardStateKey> state) {
|
|
||||||
if (optionsList != null) {
|
|
||||||
applyOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<VTOptions> newOptions =
|
|
||||||
optionsList != null ? optionsList : generateDefaultOptions(state);
|
|
||||||
|
|
||||||
state.put(VTWizardStateKey.PROGRAM_CORRELATOR_OPTIONS_LIST, newOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTitle() {
|
|
||||||
return "Correlator Options";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValidInformation() {
|
|
||||||
applyOptions();
|
|
||||||
for (VTOptions options : optionsList) {
|
|
||||||
if (options != null) {
|
|
||||||
if (!options.validate()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyOptions() {
|
|
||||||
for (OptionsEditorPanel panel : optionsEditorPanelList) {
|
|
||||||
panel.apply();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDependencies(WizardState<VTWizardStateKey> state) {
|
|
||||||
state.addDependency(VTWizardStateKey.PROGRAM_CORRELATOR_OPTIONS_LIST,
|
|
||||||
VTWizardStateKey.PROGRAM_CORRELATOR_FACTORY_LIST);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,252 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.feature.vt.gui.wizard;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
import docking.widgets.conditiontestpanel.*;
|
|
||||||
import docking.wizard.*;
|
|
||||||
import ghidra.feature.vt.api.main.VTSession;
|
|
||||||
import ghidra.feature.vt.gui.validator.VTPreconditionValidator;
|
|
||||||
import ghidra.program.model.listing.Program;
|
|
||||||
import ghidra.util.HelpLocation;
|
|
||||||
import ghidra.util.Msg;
|
|
||||||
import ghidra.util.classfinder.ClassSearcher;
|
|
||||||
|
|
||||||
public class PreconditionsPanel extends AbstractMageJPanel<VTWizardStateKey> implements Scrollable {
|
|
||||||
private static final Dimension DEFAULT_SIZE = new Dimension(650, 480);
|
|
||||||
private ConditionTestPanel conditionsTestPanel;
|
|
||||||
private boolean testsDone = false;
|
|
||||||
private VTNewSessionWizardManager wizardManager;
|
|
||||||
|
|
||||||
public PreconditionsPanel(VTNewSessionWizardManager panelManager) {
|
|
||||||
|
|
||||||
this.wizardManager = panelManager;
|
|
||||||
setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
|
|
||||||
setLayout(new BorderLayout());
|
|
||||||
|
|
||||||
JPanel runButtonPanel = new JPanel();
|
|
||||||
runButtonPanel.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0));
|
|
||||||
runButtonPanel.setLayout(new FlowLayout());
|
|
||||||
JButton runTestsButton = new JButton("Run Precondition Checks");
|
|
||||||
runTestsButton.addActionListener(new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
conditionsTestPanel.runTests();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
runButtonPanel.add(runTestsButton);
|
|
||||||
|
|
||||||
JButton skipTestsButton = new JButton("Skip");
|
|
||||||
skipTestsButton.addActionListener(new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
conditionsTestPanel.skipTests();
|
|
||||||
wizardManager.getWizardManager().next();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
runButtonPanel.add(skipTestsButton);
|
|
||||||
|
|
||||||
add(runButtonPanel, BorderLayout.SOUTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HelpLocation getHelpLocation() {
|
|
||||||
return new HelpLocation("VersionTrackingPlugin", "Preconditions_Panel");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDependencies(WizardState<VTWizardStateKey> state) {
|
|
||||||
state.addDependency(VTWizardStateKey.PRECONDITION_CHECKS_RUN,
|
|
||||||
VTWizardStateKey.SOURCE_PROGRAM_FILE);
|
|
||||||
state.addDependency(VTWizardStateKey.PRECONDITION_CHECKS_RUN,
|
|
||||||
VTWizardStateKey.DESTINATION_PROGRAM_FILE);
|
|
||||||
|
|
||||||
state.addDependency(VTWizardStateKey.HIGHEST_PRECONDITION_STATUS,
|
|
||||||
VTWizardStateKey.PRECONDITION_CHECKS_RUN);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
if (conditionsTestPanel != null) {
|
|
||||||
conditionsTestPanel.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enterPanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
initializeRunState(state);
|
|
||||||
|
|
||||||
if (!testsDone) {
|
|
||||||
if (conditionsTestPanel != null) {
|
|
||||||
remove(conditionsTestPanel);
|
|
||||||
}
|
|
||||||
conditionsTestPanel = buildConditionPanel(state);
|
|
||||||
add(conditionsTestPanel, BorderLayout.CENTER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeRunState(WizardState<VTWizardStateKey> state) {
|
|
||||||
Boolean b = (Boolean) state.get(VTWizardStateKey.PRECONDITION_CHECKS_RUN);
|
|
||||||
testsDone = b == null ? false : b.booleanValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConditionTestPanel buildConditionPanel(final WizardState<VTWizardStateKey> state) {
|
|
||||||
|
|
||||||
Program sourceProgram = (Program) state.get(VTWizardStateKey.SOURCE_PROGRAM);
|
|
||||||
Program destinationProgram = (Program) state.get(VTWizardStateKey.DESTINATION_PROGRAM);
|
|
||||||
|
|
||||||
VTSession existingResults = (VTSession) state.get(VTWizardStateKey.EXISTING_SESSION);
|
|
||||||
|
|
||||||
List<ConditionTester> list =
|
|
||||||
getConditionTests(sourceProgram, destinationProgram, existingResults);
|
|
||||||
Collections.sort(list, new ConditionsComparator());
|
|
||||||
ConditionTestPanel panel = new ConditionTestPanel(list);
|
|
||||||
panel.addListener(new ConditionTestListener() {
|
|
||||||
@Override
|
|
||||||
public void testsCompleted() {
|
|
||||||
state.put(VTWizardStateKey.PRECONDITION_CHECKS_RUN, Boolean.valueOf(testsDone));
|
|
||||||
testsDone();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testsDone() {
|
|
||||||
testsDone = true;
|
|
||||||
notifyListenersOfValidityChanged();
|
|
||||||
if (hasAnyErrorStatus()) {
|
|
||||||
Msg.showError(getClass(), this, "Warning - Serious Precondition failures",
|
|
||||||
"The precondition checks discovered one or more serious problems. \n\n"
|
|
||||||
+ "If you continue, your version tracking results may be invalid.\n"
|
|
||||||
+ "You should review the errors, cancel this wizard, and correct the problems.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ConditionTester> getConditionTests(Program sourceProgram,
|
|
||||||
Program destinationProgram, VTSession existingResults) throws SecurityException {
|
|
||||||
List<ConditionTester> list = new ArrayList<ConditionTester>();
|
|
||||||
|
|
||||||
List<Class<? extends VTPreconditionValidator>> vtValidatorClasses =
|
|
||||||
ClassSearcher.getClasses(VTPreconditionValidator.class);
|
|
||||||
for (Class<? extends VTPreconditionValidator> validatorClass : vtValidatorClasses) {
|
|
||||||
try {
|
|
||||||
Constructor<? extends VTPreconditionValidator> ctor =
|
|
||||||
validatorClass.getConstructor(Program.class, Program.class, VTSession.class);
|
|
||||||
VTPreconditionValidator validator =
|
|
||||||
ctor.newInstance(sourceProgram, destinationProgram, existingResults);
|
|
||||||
list.add(validator);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
Msg.error(this, "error including VTPreconditionValidator " + validatorClass, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WizardPanelDisplayability getPanelDisplayabilityAndUpdateState(
|
|
||||||
WizardState<VTWizardStateKey> state) {
|
|
||||||
|
|
||||||
initializeRunState(state);
|
|
||||||
return testsDone ? WizardPanelDisplayability.CAN_BE_DISPLAYED
|
|
||||||
: WizardPanelDisplayability.MUST_BE_DISPLAYED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leavePanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
updateStateObjectWithPanelInfo(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateStateObjectWithPanelInfo(WizardState<VTWizardStateKey> state) {
|
|
||||||
state.put(VTWizardStateKey.PRECONDITION_CHECKS_RUN, Boolean.valueOf(testsDone));
|
|
||||||
state.put(VTWizardStateKey.HIGHEST_PRECONDITION_STATUS, hasAnyErrorStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Boolean hasAnyErrorStatus() {
|
|
||||||
return conditionsTestPanel.getErrorCount() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTitle() {
|
|
||||||
return "Precondition Checklist";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValidInformation() {
|
|
||||||
return testsDone;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
// Overridden to account for the fact that we don't know our preferred size until later in
|
|
||||||
// the wizard flow. At that point, the initial size of the wizard is already too small.
|
|
||||||
public Dimension getPreferredSize() {
|
|
||||||
Dimension superSize = super.getPreferredSize();
|
|
||||||
if (superSize.width > DEFAULT_SIZE.width && superSize.height > DEFAULT_SIZE.height) {
|
|
||||||
return superSize;
|
|
||||||
}
|
|
||||||
return DEFAULT_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension getPreferredScrollableViewportSize() {
|
|
||||||
return getPreferredSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
|
|
||||||
return 25;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getScrollableTracksViewportHeight() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getScrollableTracksViewportWidth() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==================================================================================================
|
|
||||||
// Inner Classes
|
|
||||||
//==================================================================================================
|
|
||||||
|
|
||||||
private class ConditionsComparator implements Comparator<ConditionTester> {
|
|
||||||
@Override
|
|
||||||
public int compare(ConditionTester o1, ConditionTester o2) {
|
|
||||||
return o1.getName().compareTo(o2.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,221 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.feature.vt.gui.wizard;
|
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
import docking.widgets.label.GDHtmlLabel;
|
|
||||||
import docking.wizard.*;
|
|
||||||
import ghidra.feature.vt.api.main.VTProgramCorrelatorFactory;
|
|
||||||
import ghidra.feature.vt.gui.wizard.ChooseAddressSetEditorPanel.AddressSetChoice;
|
|
||||||
import ghidra.framework.model.DomainFile;
|
|
||||||
import ghidra.util.HTMLUtilities;
|
|
||||||
import ghidra.util.HelpLocation;
|
|
||||||
import ghidra.util.layout.PairLayout;
|
|
||||||
import util.CollectionUtils;
|
|
||||||
|
|
||||||
public class SummaryPanel extends AbstractMageJPanel<VTWizardStateKey> {
|
|
||||||
private JLabel labelLabel;
|
|
||||||
private JLabel summaryLabel;
|
|
||||||
private static String NEW_SUMMARY_PANEL = "New_Session_Summary_Panel";
|
|
||||||
private static String ADD_SUMMARY_PANEL = "Add_To_Session_Summary_Panel";
|
|
||||||
private String helpName = ADD_SUMMARY_PANEL;
|
|
||||||
|
|
||||||
SummaryPanel() {
|
|
||||||
|
|
||||||
labelLabel = new GDHtmlLabel();
|
|
||||||
summaryLabel = new GDHtmlLabel();
|
|
||||||
|
|
||||||
JPanel mainPanel = new JPanel(new PairLayout(5, 10));
|
|
||||||
mainPanel.add(labelLabel);
|
|
||||||
mainPanel.add(summaryLabel);
|
|
||||||
|
|
||||||
setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
|
|
||||||
setLayout(new BorderLayout());
|
|
||||||
add(mainPanel, BorderLayout.CENTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HelpLocation getHelpLocation() {
|
|
||||||
return new HelpLocation("VersionTrackingPlugin", helpName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enterPanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
StringBuilder label = new StringBuilder();
|
|
||||||
StringBuilder summary = new StringBuilder();
|
|
||||||
|
|
||||||
label.append("<html>");
|
|
||||||
summary.append("<html>");
|
|
||||||
|
|
||||||
// session mode
|
|
||||||
|
|
||||||
label.append("Operation:");
|
|
||||||
String opDescription = (String) state.get(VTWizardStateKey.WIZARD_OP_DESCRIPTION);
|
|
||||||
helpName = ((opDescription != null) && opDescription.startsWith("New")) ? NEW_SUMMARY_PANEL
|
|
||||||
: ADD_SUMMARY_PANEL;
|
|
||||||
summary.append(opDescription);
|
|
||||||
label.append("<br>");
|
|
||||||
summary.append("<br>");
|
|
||||||
|
|
||||||
String sessionName = (String) state.get(VTWizardStateKey.SESSION_NAME);
|
|
||||||
|
|
||||||
label.append("Session Name:");
|
|
||||||
summary.append(sessionName);
|
|
||||||
label.append("<br>");
|
|
||||||
summary.append("<br>");
|
|
||||||
|
|
||||||
String sourceProgramName = null;
|
|
||||||
String destinationProgramName = null;
|
|
||||||
|
|
||||||
DomainFile sourceProgram = (DomainFile) state.get(VTWizardStateKey.SOURCE_PROGRAM_FILE);
|
|
||||||
sourceProgramName = sourceProgram.getName();
|
|
||||||
|
|
||||||
DomainFile destinationProgram =
|
|
||||||
(DomainFile) state.get(VTWizardStateKey.DESTINATION_PROGRAM_FILE);
|
|
||||||
destinationProgramName = destinationProgram.getName();
|
|
||||||
|
|
||||||
// source program
|
|
||||||
|
|
||||||
label.append("Source Program:");
|
|
||||||
summary.append(
|
|
||||||
sourceProgramName == null ? "(null)" : HTMLUtilities.escapeHTML(sourceProgramName));
|
|
||||||
label.append("<br>");
|
|
||||||
summary.append("<br>");
|
|
||||||
|
|
||||||
// destination program
|
|
||||||
|
|
||||||
label.append("Destination Program:");
|
|
||||||
summary.append(destinationProgramName == null ? "(null)"
|
|
||||||
: HTMLUtilities.escapeHTML(destinationProgramName));
|
|
||||||
label.append("<br>");
|
|
||||||
summary.append("<br>");
|
|
||||||
|
|
||||||
String correlatorLabel = "";
|
|
||||||
String correlatorName = null;
|
|
||||||
|
|
||||||
List<VTProgramCorrelatorFactory> correlators = getCorrelators(state);
|
|
||||||
if (correlators != null) {
|
|
||||||
for (VTProgramCorrelatorFactory correlatorFactory : correlators) {
|
|
||||||
correlatorName = correlatorFactory.getName();
|
|
||||||
|
|
||||||
label.append(correlatorLabel + "Program Correlator:");
|
|
||||||
summary.append(correlatorName == null ? "(null)" : correlatorName);
|
|
||||||
label.append("<br>");
|
|
||||||
summary.append("<br>");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Boolean excludeAcceptedMatches =
|
|
||||||
(Boolean) state.get(VTWizardStateKey.EXCLUDE_ACCEPTED_MATCHES);
|
|
||||||
if (excludeAcceptedMatches != null) {
|
|
||||||
label.append("Exclude Accepted Matches:");
|
|
||||||
summary.append(excludeAcceptedMatches.booleanValue() ? "Yes" : "No");
|
|
||||||
label.append("<br>");
|
|
||||||
summary.append("<br>");
|
|
||||||
}
|
|
||||||
|
|
||||||
Boolean showAddressSetPanels =
|
|
||||||
(Boolean) state.get(VTWizardStateKey.SHOW_ADDRESS_SET_PANELS);
|
|
||||||
if (showAddressSetPanels != null) {
|
|
||||||
boolean manuallySpecifiedAddresses = showAddressSetPanels.booleanValue();
|
|
||||||
AddressSetChoice sourceAddressSetChoice =
|
|
||||||
(AddressSetChoice) state.get(VTWizardStateKey.SOURCE_ADDRESS_SET_CHOICE);
|
|
||||||
AddressSetChoice destinationAddressSetChoice =
|
|
||||||
(AddressSetChoice) state.get(VTWizardStateKey.DESTINATION_ADDRESS_SET_CHOICE);
|
|
||||||
String sourceAddressesInfo =
|
|
||||||
(sourceAddressSetChoice == AddressSetChoice.MANUALLY_DEFINED) ? "Manually Defined"
|
|
||||||
: ((sourceAddressSetChoice == AddressSetChoice.SELECTION))
|
|
||||||
? "Source Tool Selection"
|
|
||||||
: "Entire Source Program";
|
|
||||||
String destinationAddressesInfo =
|
|
||||||
(destinationAddressSetChoice == AddressSetChoice.MANUALLY_DEFINED)
|
|
||||||
? "Manually Defined"
|
|
||||||
: ((destinationAddressSetChoice == AddressSetChoice.SELECTION))
|
|
||||||
? "Destination Tool Selection"
|
|
||||||
: "Entire Destination Program";
|
|
||||||
|
|
||||||
label.append("Source Address Set:");
|
|
||||||
summary.append(sourceAddressesInfo);
|
|
||||||
label.append("<br>");
|
|
||||||
summary.append("<br>");
|
|
||||||
|
|
||||||
label.append("Destination Address Set:");
|
|
||||||
summary.append(destinationAddressesInfo);
|
|
||||||
label.append("<br>");
|
|
||||||
summary.append("<br>");
|
|
||||||
}
|
|
||||||
|
|
||||||
label.append("</html>");
|
|
||||||
summary.append("</html>");
|
|
||||||
|
|
||||||
labelLabel.setText(label.toString());
|
|
||||||
summaryLabel.setText(summary.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<VTProgramCorrelatorFactory> getCorrelators(WizardState<VTWizardStateKey> state) {
|
|
||||||
List<?> list = (List<?>) state.get(VTWizardStateKey.PROGRAM_CORRELATOR_FACTORY_LIST);
|
|
||||||
if (list == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return CollectionUtils.asList(list, VTProgramCorrelatorFactory.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WizardPanelDisplayability getPanelDisplayabilityAndUpdateState(
|
|
||||||
WizardState<VTWizardStateKey> state) {
|
|
||||||
return WizardPanelDisplayability.CAN_BE_DISPLAYED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leavePanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
updateStateObjectWithPanelInfo(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateStateObjectWithPanelInfo(WizardState<VTWizardStateKey> state) {
|
|
||||||
// Do nothing. The summary panel only displays information.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTitle() {
|
|
||||||
return "Summary";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValidInformation() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDependencies(WizardState<VTWizardStateKey> state) {
|
|
||||||
// no dependencies; we just confirm what's going to happen
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.feature.vt.gui.wizard;
|
|
||||||
|
|
||||||
import ghidra.feature.vt.api.main.VTSession;
|
|
||||||
import ghidra.feature.vt.gui.plugin.VTController;
|
|
||||||
import ghidra.program.model.listing.Program;
|
|
||||||
import ghidra.util.task.Task;
|
|
||||||
import ghidra.util.task.TaskLauncher;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import docking.wizard.*;
|
|
||||||
|
|
||||||
public class VTAddToSessionWizardManager extends AbstractMagePanelManager<VTWizardStateKey> {
|
|
||||||
|
|
||||||
private final VTController controller;
|
|
||||||
|
|
||||||
public VTAddToSessionWizardManager(VTController controller) {
|
|
||||||
super(new WizardState<VTWizardStateKey>());
|
|
||||||
this.controller = controller;
|
|
||||||
Program sourceProgram = controller.getSourceProgram();
|
|
||||||
Program destinationProgram = controller.getDestinationProgram();
|
|
||||||
VTSession session = controller.getSession();
|
|
||||||
|
|
||||||
WizardState<VTWizardStateKey> state = getState();
|
|
||||||
state.put(VTWizardStateKey.SOURCE_PROGRAM, sourceProgram);
|
|
||||||
state.put(VTWizardStateKey.DESTINATION_PROGRAM, destinationProgram);
|
|
||||||
state.put(VTWizardStateKey.SOURCE_PROGRAM_FILE, sourceProgram.getDomainFile());
|
|
||||||
state.put(VTWizardStateKey.DESTINATION_PROGRAM_FILE, destinationProgram.getDomainFile());
|
|
||||||
state.put(VTWizardStateKey.EXISTING_SESSION, session);
|
|
||||||
state.put(VTWizardStateKey.SESSION_NAME, session.getName());
|
|
||||||
state.put(VTWizardStateKey.WIZARD_OP_DESCRIPTION, "Add to Version Tracking Session");
|
|
||||||
state.put(VTWizardStateKey.SOURCE_SELECTION, controller.getSelectionInSourceTool());
|
|
||||||
state.put(VTWizardStateKey.DESTINATION_SELECTION,
|
|
||||||
controller.getSelectionInDestinationTool());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ArrayList<MagePanel<VTWizardStateKey>> createPanels() {
|
|
||||||
ArrayList<MagePanel<VTWizardStateKey>> panels =
|
|
||||||
new ArrayList<MagePanel<VTWizardStateKey>>();
|
|
||||||
panels.add(new CorrelatorPanel(controller.getSession()));
|
|
||||||
panels.add(new OptionsPanel());
|
|
||||||
panels.add(new AddressSetOptionsPanel());
|
|
||||||
panels.add(new LimitAddressSetsPanel(controller.getTool()));
|
|
||||||
panels.add(new SummaryPanel());
|
|
||||||
return panels;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFinish() {
|
|
||||||
try {
|
|
||||||
Task task = new AddToSessionTask(controller, getState());
|
|
||||||
new TaskLauncher(task, getWizardManager().getComponent());
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
getWizardManager().completed(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.feature.vt.gui.wizard;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import docking.wizard.*;
|
|
||||||
import ghidra.feature.vt.gui.plugin.VTController;
|
|
||||||
import ghidra.framework.model.DomainFile;
|
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
|
||||||
import ghidra.util.task.Task;
|
|
||||||
import ghidra.util.task.TaskLauncher;
|
|
||||||
|
|
||||||
public class VTNewSessionWizardManager extends AbstractMagePanelManager<VTWizardStateKey> {
|
|
||||||
|
|
||||||
private final VTController controller;
|
|
||||||
|
|
||||||
public VTNewSessionWizardManager(VTController controller) {
|
|
||||||
super(new WizardState<VTWizardStateKey>());
|
|
||||||
this.controller = controller;
|
|
||||||
getState().put(VTWizardStateKey.WIZARD_OP_DESCRIPTION, "New Version Tracking Session");
|
|
||||||
}
|
|
||||||
|
|
||||||
public VTNewSessionWizardManager(VTController controller, DomainFile sourceFile,
|
|
||||||
DomainFile destinationFile) {
|
|
||||||
this(controller);
|
|
||||||
getState().put(VTWizardStateKey.SOURCE_PROGRAM_FILE, sourceFile);
|
|
||||||
getState().put(VTWizardStateKey.DESTINATION_PROGRAM_FILE, destinationFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<MagePanel<VTWizardStateKey>> createPanels() {
|
|
||||||
List<MagePanel<VTWizardStateKey>> panels = new ArrayList<>();
|
|
||||||
panels.add(new NewSessionPanel(controller.getTool()));
|
|
||||||
panels.add(new PreconditionsPanel(this));
|
|
||||||
panels.add(new SummaryPanel());
|
|
||||||
return panels;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFinish() {
|
|
||||||
try {
|
|
||||||
Task task = new CreateNewSessionTask(controller, getState());
|
|
||||||
new TaskLauncher(task, getWizardManager().getComponent());
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
getWizardManager().completed(true);
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cancel() {
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cleanup() {
|
|
||||||
List<MagePanel<VTWizardStateKey>> panels = getPanels();
|
|
||||||
for (MagePanel<VTWizardStateKey> magePanel : panels) {
|
|
||||||
magePanel.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginTool getTool() {
|
|
||||||
return controller.getTool();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.feature.vt.gui.wizard;
|
|
||||||
|
|
||||||
enum VTWizardStateKey {
|
|
||||||
WIZARD_OP_DESCRIPTION, EXISTING_SESSION, SESSION_NAME,
|
|
||||||
|
|
||||||
SOURCE_PROGRAM_FILE, DESTINATION_PROGRAM_FILE,
|
|
||||||
|
|
||||||
SOURCE_PROGRAM, DESTINATION_PROGRAM,
|
|
||||||
|
|
||||||
SOURCE_ADDRESS_SET_VIEW, DESTINATION_ADDRESS_SET_VIEW,
|
|
||||||
|
|
||||||
PRECONDITION_CHECKS_RUN,
|
|
||||||
|
|
||||||
NEW_SESSION_FOLDER,
|
|
||||||
|
|
||||||
ADDRESS_RANGES_MODE,
|
|
||||||
|
|
||||||
PROGRAM_CORRELATOR_FACTORY_LIST,
|
|
||||||
|
|
||||||
PROGRAM_CORRELATOR_OPTIONS_LIST, HIGHEST_PRECONDITION_STATUS,
|
|
||||||
|
|
||||||
SHOW_ADDRESS_SET_PANELS,
|
|
||||||
|
|
||||||
EXCLUDE_ACCEPTED_MATCHES,
|
|
||||||
|
|
||||||
SOURCE_SELECTION, DESTINATION_SELECTION,
|
|
||||||
|
|
||||||
SOURCE_ADDRESS_SET_CHOICE, DESTINATION_ADDRESS_SET_CHOICE;
|
|
||||||
}
|
|
|
@ -13,9 +13,11 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.gui.wizard;
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
@ -23,7 +25,7 @@ import docking.DialogComponentProvider;
|
||||||
import docking.widgets.label.GDLabel;
|
import docking.widgets.label.GDLabel;
|
||||||
import ghidra.app.util.AddressInput;
|
import ghidra.app.util.AddressInput;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.layout.PairLayout;
|
import ghidra.util.layout.PairLayout;
|
||||||
|
@ -31,7 +33,7 @@ import ghidra.util.layout.PairLayout;
|
||||||
public class AddRemoveAddressRangeDialog extends DialogComponentProvider {
|
public class AddRemoveAddressRangeDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
private Program program;
|
private Program program;
|
||||||
private AddressRangeListener listener;
|
private Consumer<AddressRange> addressRangeConsumer;
|
||||||
|
|
||||||
private JPanel addressRangePanel;
|
private JPanel addressRangePanel;
|
||||||
private JLabel minLabel;
|
private JLabel minLabel;
|
||||||
|
@ -40,10 +42,10 @@ public class AddRemoveAddressRangeDialog extends DialogComponentProvider {
|
||||||
private AddressInput maxAddressField;
|
private AddressInput maxAddressField;
|
||||||
|
|
||||||
protected AddRemoveAddressRangeDialog(String type, String programIndicator, Program program,
|
protected AddRemoveAddressRangeDialog(String type, String programIndicator, Program program,
|
||||||
AddressRangeListener listener) {
|
Consumer<AddressRange> addressRangeConsumer) {
|
||||||
super(programIndicator + " Address Range", true, true, true, false);
|
super(programIndicator + " Address Range", true, true, true, false);
|
||||||
this.program = program;
|
this.program = program;
|
||||||
this.listener = listener;
|
this.addressRangeConsumer = Objects.requireNonNull(addressRangeConsumer);
|
||||||
setHelpLocation(new HelpLocation(HelpTopics.LABEL, "AddEditDialog"));
|
setHelpLocation(new HelpLocation(HelpTopics.LABEL, "AddEditDialog"));
|
||||||
addWorkPanel(createAddressRangePanel());
|
addWorkPanel(createAddressRangePanel());
|
||||||
|
|
||||||
|
@ -99,9 +101,7 @@ public class AddRemoveAddressRangeDialog extends DialogComponentProvider {
|
||||||
@Override
|
@Override
|
||||||
protected void okCallback() {
|
protected void okCallback() {
|
||||||
if (isValidRange()) {
|
if (isValidRange()) {
|
||||||
if (listener != null) {
|
addressRangeConsumer.accept(new AddressRangeImpl(getMinAddress(), getMaxAddress()));
|
||||||
listener.processAddressRange(getMinAddress(), getMaxAddress());
|
|
||||||
}
|
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import ghidra.feature.vt.api.main.VTProgramCorrelatorFactory;
|
||||||
|
import ghidra.feature.vt.api.main.VTSession;
|
||||||
|
import ghidra.feature.vt.api.util.VTOptions;
|
||||||
|
import ghidra.framework.model.DomainFile;
|
||||||
|
import ghidra.program.model.address.AddressSetView;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wizard data used by the {@link VTAddToSessionWizardModel} and its steps for the "add to version
|
||||||
|
* tracking session" wizard.
|
||||||
|
*/
|
||||||
|
public class AddToSessionData {
|
||||||
|
public static enum AddressSetChoice {
|
||||||
|
ENTIRE_PROGRAM, SELECTION, MANUALLY_DEFINED
|
||||||
|
}
|
||||||
|
|
||||||
|
private Program sourceProgram;
|
||||||
|
private Program destinationProgram;
|
||||||
|
private VTSession session;
|
||||||
|
private AddressSetView customSourceAddressSet;
|
||||||
|
private AddressSetView customDestinationAddressSet;
|
||||||
|
private AddressSetView sourceSelection;
|
||||||
|
private AddressSetView destinationSelection;
|
||||||
|
private List<VTProgramCorrelatorFactory> correlators;
|
||||||
|
private Map<VTProgramCorrelatorFactory, VTOptions> optionsMap = new HashMap<>();
|
||||||
|
private boolean shouldExcludeAcceptedMatches;
|
||||||
|
private boolean shouldLimitAddressSets;
|
||||||
|
private AddressSetChoice sourceAddressSetChoice = AddressSetChoice.ENTIRE_PROGRAM;
|
||||||
|
private AddressSetChoice destinationAddressSetChoice = AddressSetChoice.ENTIRE_PROGRAM;
|
||||||
|
|
||||||
|
public void setSourceProgram(Program sourceProgram) {
|
||||||
|
this.sourceProgram = sourceProgram;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Program getSourceProgram() {
|
||||||
|
return sourceProgram;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestinationProgram(Program destinationProgram) {
|
||||||
|
this.destinationProgram = destinationProgram;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Program getDestinationProgram() {
|
||||||
|
return destinationProgram;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSession(VTSession session) {
|
||||||
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VTSession getSession() {
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DomainFile getSourceFile() {
|
||||||
|
return sourceProgram.getDomainFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DomainFile getDestinationFile() {
|
||||||
|
return destinationProgram.getDomainFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressSetChoice getSourceAddressSetChoice() {
|
||||||
|
return sourceAddressSetChoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressSetChoice getDestinationAddressSetChoice() {
|
||||||
|
return destinationAddressSetChoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceAddressSetChoice(AddressSetChoice choice) {
|
||||||
|
this.sourceAddressSetChoice = choice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestinationAddressSetChoice(AddressSetChoice choice) {
|
||||||
|
this.destinationAddressSetChoice = choice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceSelection(AddressSetView addressSet) {
|
||||||
|
this.sourceSelection = addressSet;
|
||||||
|
// if a source selection is set, the limit option defaults to true;
|
||||||
|
if (addressSet != null && !addressSet.isEmpty()) {
|
||||||
|
shouldLimitAddressSets = true;
|
||||||
|
sourceAddressSetChoice = AddressSetChoice.SELECTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestinationSelection(AddressSetView addresseSet) {
|
||||||
|
this.destinationSelection = addresseSet;
|
||||||
|
// if a destination selection is set, the limit option defaults to true;
|
||||||
|
if (addresseSet != null && !addresseSet.isEmpty()) {
|
||||||
|
shouldLimitAddressSets = true;
|
||||||
|
destinationAddressSetChoice = AddressSetChoice.SELECTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressSetView getCustomSourceAddressSet() {
|
||||||
|
return customSourceAddressSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomSourceAddressSet(AddressSetView addressSet) {
|
||||||
|
customSourceAddressSet = addressSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomDestinationAddressSet(AddressSetView addressSet) {
|
||||||
|
customDestinationAddressSet = addressSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressSetView getCustomDestinationAddressSet() {
|
||||||
|
return customDestinationAddressSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressSetView getSourceSelection() {
|
||||||
|
return sourceSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressSetView getDestinationSelection() {
|
||||||
|
return destinationSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VTProgramCorrelatorFactory> getCorrelators() {
|
||||||
|
return correlators;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCorrelators(List<VTProgramCorrelatorFactory> correlators) {
|
||||||
|
if (!correlators.equals(this.correlators)) {
|
||||||
|
this.correlators = correlators;
|
||||||
|
// whenever the set of correlators changes, reset the options to force options panel
|
||||||
|
// to show
|
||||||
|
optionsMap = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOptions(Map<VTProgramCorrelatorFactory, VTOptions> optionsMap) {
|
||||||
|
this.optionsMap = optionsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<VTProgramCorrelatorFactory, VTOptions> getOptions() {
|
||||||
|
return optionsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldExcludeAcceptedMatches() {
|
||||||
|
return shouldExcludeAcceptedMatches;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShouldExcludeAcceptedMatches(boolean b) {
|
||||||
|
shouldExcludeAcceptedMatches = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldLimitAddressSets() {
|
||||||
|
return shouldLimitAddressSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShouldLimitAddressSets(boolean b) {
|
||||||
|
shouldLimitAddressSets = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,16 +13,14 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.gui.wizard;
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import docking.wizard.WizardState;
|
|
||||||
import ghidra.feature.vt.api.main.*;
|
import ghidra.feature.vt.api.main.*;
|
||||||
import ghidra.feature.vt.api.util.VTMatchUtil;
|
import ghidra.feature.vt.api.util.VTMatchUtil;
|
||||||
import ghidra.feature.vt.api.util.VTOptions;
|
import ghidra.feature.vt.api.util.VTOptions;
|
||||||
import ghidra.feature.vt.gui.plugin.VTController;
|
import ghidra.feature.vt.gui.plugin.VTController;
|
||||||
import ghidra.feature.vt.gui.wizard.ChooseAddressSetEditorPanel.AddressSetChoice;
|
|
||||||
import ghidra.framework.data.DomainObjectAdapterDB;
|
import ghidra.framework.data.DomainObjectAdapterDB;
|
||||||
import ghidra.program.model.address.AddressSet;
|
import ghidra.program.model.address.AddressSet;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
|
@ -31,16 +29,15 @@ import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.Task;
|
import ghidra.util.task.Task;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import util.CollectionUtils;
|
|
||||||
|
|
||||||
public class AddToSessionTask extends Task {
|
public class AddToSessionTask extends Task {
|
||||||
private final WizardState<VTWizardStateKey> state;
|
private final AddToSessionData data;
|
||||||
private final VTController controller;
|
private final VTController controller;
|
||||||
|
|
||||||
public AddToSessionTask(VTController controller, WizardState<VTWizardStateKey> state) {
|
public AddToSessionTask(VTController controller, AddToSessionData data) {
|
||||||
super("Merge Version Tracking Session", true, true, true);
|
super("Merge Version Tracking Session", true, true, true);
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.state = state;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -51,49 +48,10 @@ public class AddToSessionTask extends Task {
|
||||||
Program sourceProgram = session.getSourceProgram();
|
Program sourceProgram = session.getSourceProgram();
|
||||||
Program destinationProgram = session.getDestinationProgram();
|
Program destinationProgram = session.getDestinationProgram();
|
||||||
|
|
||||||
Boolean value = (Boolean) state.get(VTWizardStateKey.EXCLUDE_ACCEPTED_MATCHES);
|
boolean excludeAcceptedMatches = data.shouldExcludeAcceptedMatches();
|
||||||
boolean excludeAcceptedMatches = (value == null) ? false : value.booleanValue();
|
|
||||||
|
|
||||||
AddressSetChoice sourceAddressSetChoice =
|
AddressSetView sourceAddressSet = getSourceAddressSet();
|
||||||
(AddressSetChoice) state.get(VTWizardStateKey.SOURCE_ADDRESS_SET_CHOICE);
|
AddressSetView destinationAddressSet = getDestinationAddressSet();
|
||||||
AddressSetChoice destinationAddressSetChoice =
|
|
||||||
(AddressSetChoice) state.get(VTWizardStateKey.DESTINATION_ADDRESS_SET_CHOICE);
|
|
||||||
if (sourceAddressSetChoice == null) {
|
|
||||||
sourceAddressSetChoice = AddressSetChoice.ENTIRE_PROGRAM;
|
|
||||||
}
|
|
||||||
if (destinationAddressSetChoice == null) {
|
|
||||||
destinationAddressSetChoice = AddressSetChoice.ENTIRE_PROGRAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddressSetView sourceAddressSet;
|
|
||||||
switch (sourceAddressSetChoice) {
|
|
||||||
case SELECTION:
|
|
||||||
sourceAddressSet = (AddressSetView) state.get(VTWizardStateKey.SOURCE_SELECTION);
|
|
||||||
break;
|
|
||||||
case MANUALLY_DEFINED:
|
|
||||||
sourceAddressSet =
|
|
||||||
(AddressSetView) state.get(VTWizardStateKey.SOURCE_ADDRESS_SET_VIEW);
|
|
||||||
break;
|
|
||||||
case ENTIRE_PROGRAM:
|
|
||||||
default:
|
|
||||||
sourceAddressSet = sourceProgram.getMemory();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
AddressSetView destinationAddressSet;
|
|
||||||
switch (destinationAddressSetChoice) {
|
|
||||||
case SELECTION:
|
|
||||||
destinationAddressSet =
|
|
||||||
(AddressSetView) state.get(VTWizardStateKey.DESTINATION_SELECTION);
|
|
||||||
break;
|
|
||||||
case MANUALLY_DEFINED:
|
|
||||||
destinationAddressSet =
|
|
||||||
(AddressSetView) state.get(VTWizardStateKey.DESTINATION_ADDRESS_SET_VIEW);
|
|
||||||
break;
|
|
||||||
case ENTIRE_PROGRAM:
|
|
||||||
default:
|
|
||||||
destinationAddressSet = destinationProgram.getMemory();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (excludeAcceptedMatches) {
|
if (excludeAcceptedMatches) {
|
||||||
sourceAddressSet = excludeAcceptedMatches(sourceAddressSet, true);
|
sourceAddressSet = excludeAcceptedMatches(sourceAddressSet, true);
|
||||||
|
@ -104,14 +62,14 @@ public class AddToSessionTask extends Task {
|
||||||
boolean completedSucessfully = false;
|
boolean completedSucessfully = false;
|
||||||
try {
|
try {
|
||||||
session.setEventsEnabled(false); // prevent table updates while busy
|
session.setEventsEnabled(false); // prevent table updates while busy
|
||||||
List<VTProgramCorrelatorFactory> correlatorFactories = getCorrelators(state);
|
List<VTProgramCorrelatorFactory> correlatorFactories = data.getCorrelators();
|
||||||
List<VTOptions> correlatorOptions = getCorrelatorOptions(state);
|
Map<VTProgramCorrelatorFactory, VTOptions> optionsMap = data.getOptions();
|
||||||
List<VTProgramCorrelator> noMatchList = new ArrayList<>();
|
List<VTProgramCorrelator> noMatchList = new ArrayList<>();
|
||||||
for (int i = 0; i < correlatorFactories.size(); i++) {
|
for (VTProgramCorrelatorFactory factory : correlatorFactories) {
|
||||||
VTProgramCorrelatorFactory factory = correlatorFactories.get(i);
|
VTOptions options = optionsMap.get(factory);
|
||||||
VTProgramCorrelator correlator =
|
VTProgramCorrelator correlator =
|
||||||
factory.createCorrelator(sourceProgram, sourceAddressSet, destinationProgram,
|
factory.createCorrelator(sourceProgram, sourceAddressSet, destinationProgram,
|
||||||
destinationAddressSet, correlatorOptions.get(i));
|
destinationAddressSet, options);
|
||||||
|
|
||||||
VTMatchSet resultSet = correlator.correlate(session, monitor);
|
VTMatchSet resultSet = correlator.correlate(session, monitor);
|
||||||
if (resultSet.getMatchCount() == 0) {
|
if (resultSet.getMatchCount() == 0) {
|
||||||
|
@ -150,6 +108,36 @@ public class AddToSessionTask extends Task {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AddressSetView getSourceAddressSet() {
|
||||||
|
if (!data.shouldLimitAddressSets()) {
|
||||||
|
return data.getSourceProgram().getMemory();
|
||||||
|
}
|
||||||
|
switch (data.getSourceAddressSetChoice()) {
|
||||||
|
case MANUALLY_DEFINED:
|
||||||
|
return data.getCustomSourceAddressSet();
|
||||||
|
case SELECTION:
|
||||||
|
return data.getSourceSelection();
|
||||||
|
case ENTIRE_PROGRAM:
|
||||||
|
default:
|
||||||
|
return data.getSourceProgram().getMemory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AddressSetView getDestinationAddressSet() {
|
||||||
|
if (!data.shouldLimitAddressSets()) {
|
||||||
|
return data.getDestinationProgram().getMemory();
|
||||||
|
}
|
||||||
|
switch (data.getDestinationAddressSetChoice()) {
|
||||||
|
case MANUALLY_DEFINED:
|
||||||
|
return data.getCustomDestinationAddressSet();
|
||||||
|
case SELECTION:
|
||||||
|
return data.getDestinationSelection();
|
||||||
|
case ENTIRE_PROGRAM:
|
||||||
|
default:
|
||||||
|
return data.getDestinationProgram().getMemory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void endTransaction(VTSession session, int transactionID,
|
private void endTransaction(VTSession session, int transactionID,
|
||||||
boolean completedSucessfully) {
|
boolean completedSucessfully) {
|
||||||
if (transactionID == -1) {
|
if (transactionID == -1) {
|
||||||
|
@ -165,21 +153,8 @@ public class AddToSessionTask extends Task {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<VTOptions> getCorrelatorOptions(WizardState<VTWizardStateKey> stateKey) {
|
|
||||||
return CollectionUtils.asList(
|
|
||||||
(List<?>) stateKey.get(VTWizardStateKey.PROGRAM_CORRELATOR_OPTIONS_LIST),
|
|
||||||
VTOptions.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<VTProgramCorrelatorFactory> getCorrelators(
|
|
||||||
WizardState<VTWizardStateKey> stateKey) {
|
|
||||||
return CollectionUtils.asList(
|
|
||||||
(List<?>) stateKey.get(VTWizardStateKey.PROGRAM_CORRELATOR_FACTORY_LIST),
|
|
||||||
VTProgramCorrelatorFactory.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AddressSet excludeAcceptedMatches(AddressSetView addrSetView, boolean source) {
|
private AddressSet excludeAcceptedMatches(AddressSetView addrSetView, boolean source) {
|
||||||
VTSession session = (VTSession) state.get(VTWizardStateKey.EXISTING_SESSION);
|
VTSession session = data.getSession();
|
||||||
AddressSet addrSet = new AddressSet(addrSetView);
|
AddressSet addrSet = new AddressSet(addrSetView);
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
List<VTMatchSet> matchSets = session.getMatchSets();
|
List<VTMatchSet> matchSets = session.getMatchSets();
|
|
@ -0,0 +1,90 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
|
import static ghidra.feature.vt.api.main.VTProgramCorrelatorAddressRestrictionPreference.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
import docking.widgets.checkbox.GCheckBox;
|
||||||
|
import ghidra.feature.vt.api.main.VTProgramCorrelatorFactory;
|
||||||
|
import ghidra.util.HTMLUtilities;
|
||||||
|
import ghidra.util.layout.VerticalLayout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Panel for choosing the address set to used for performing new correlations when adding to
|
||||||
|
* a version tracking session. Used by the {@link AddressSetOptionsStep}.
|
||||||
|
*/
|
||||||
|
public class AddressSetOptionsPanel extends JPanel {
|
||||||
|
|
||||||
|
private JCheckBox excludeCheckbox;
|
||||||
|
private JCheckBox limitAddressSetsCheckbox;
|
||||||
|
|
||||||
|
public AddressSetOptionsPanel() { //
|
||||||
|
setBorder(BorderFactory.createEmptyBorder(40, 40, 0, 0));
|
||||||
|
|
||||||
|
excludeCheckbox = new GCheckBox("Exclude accepted matches", false);
|
||||||
|
String excludeAcceptedTooltip = "This option will cause the correlator algorithm " +
|
||||||
|
"to <b>not</b> consider any functions or data that have already been " +
|
||||||
|
"accepted. Using this option can greatly speed up the processing time " +
|
||||||
|
"of the correlator algorithm; however, this options should only be " +
|
||||||
|
"used when you trust that your accepted matches are correct.";
|
||||||
|
excludeCheckbox.setToolTipText(HTMLUtilities.toWrappedHTML(excludeAcceptedTooltip));
|
||||||
|
|
||||||
|
limitAddressSetsCheckbox = new GCheckBox("Limit source and destination address sets");
|
||||||
|
String manuallyLimitTooltip = "Selecting this checkbox will trigger additional wizard " +
|
||||||
|
" panels allowing you to customize the address sets used " +
|
||||||
|
" by the selected algorithm. When not selected, the entire address space is used.";
|
||||||
|
|
||||||
|
limitAddressSetsCheckbox.setToolTipText(
|
||||||
|
HTMLUtilities.toWrappedHTML(manuallyLimitTooltip));
|
||||||
|
|
||||||
|
add(excludeCheckbox);
|
||||||
|
add(limitAddressSetsCheckbox);
|
||||||
|
setLayout(new VerticalLayout(20));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(AddToSessionData data) {
|
||||||
|
|
||||||
|
excludeCheckbox.setSelected(data.shouldExcludeAcceptedMatches());
|
||||||
|
limitAddressSetsCheckbox.setSelected(data.shouldLimitAddressSets());
|
||||||
|
|
||||||
|
if (allowRestrictions(data.getCorrelators())) {
|
||||||
|
excludeCheckbox.setEnabled(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
excludeCheckbox.setSelected(false);
|
||||||
|
excludeCheckbox.setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean allowRestrictions(List<VTProgramCorrelatorFactory> list) {
|
||||||
|
for (VTProgramCorrelatorFactory factory : list) {
|
||||||
|
if (factory.getAddressRestrictionPreference() != RESTRICTION_NOT_ALLOWED) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateChoices(AddToSessionData data) {
|
||||||
|
data.setShouldExcludeAcceptedMatches(excludeCheckbox.isSelected());
|
||||||
|
data.setShouldLimitAddressSets(limitAddressSetsCheckbox.isSelected());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
|
import docking.wizard.WizardModel;
|
||||||
|
import docking.wizard.WizardStep;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wizard step for configuring address sets when adding correlations to an existing version
|
||||||
|
* tracking session.
|
||||||
|
*/
|
||||||
|
public class AddressSetOptionsStep extends WizardStep<AddToSessionData> {
|
||||||
|
private AddressSetOptionsPanel panel;
|
||||||
|
|
||||||
|
protected AddressSetOptionsStep(WizardModel<AddToSessionData> model) {
|
||||||
|
super(model, "Address Set Options",
|
||||||
|
new HelpLocation("VersionTrackingPlugin", "Address_Set_Panel"));
|
||||||
|
panel = new AddressSetOptionsPanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(AddToSessionData data) {
|
||||||
|
panel.initialize(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void populateData(AddToSessionData data) {
|
||||||
|
panel.updateChoices(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canFinish(AddToSessionData data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(AddToSessionData data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JComponent getComponent() {
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.gui.wizard;
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
@ -28,18 +28,18 @@ import docking.widgets.button.GRadioButton;
|
||||||
import docking.widgets.label.GLabel;
|
import docking.widgets.label.GLabel;
|
||||||
import docking.widgets.list.GList;
|
import docking.widgets.list.GList;
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
|
import ghidra.feature.vt.gui.wizard.add.AddToSessionData.AddressSetChoice;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.layout.MiddleLayout;
|
import ghidra.util.layout.MiddleLayout;
|
||||||
import ghidra.util.layout.VerticalLayout;
|
import ghidra.util.layout.VerticalLayout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Panel for manually adjusting address sets.
|
||||||
|
*/
|
||||||
public class ChooseAddressSetEditorPanel extends JPanel {
|
public class ChooseAddressSetEditorPanel extends JPanel {
|
||||||
|
|
||||||
public static enum AddressSetChoice {
|
|
||||||
ENTIRE_PROGRAM, SELECTION, MANUALLY_DEFINED
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Icon ADD_ICON = new GIcon("icon.version.tracking.add");
|
private static Icon ADD_ICON = new GIcon("icon.version.tracking.add");
|
||||||
private static Icon SUBTRACT_ICON = new GIcon("icon.version.tracking.subtract");
|
private static Icon SUBTRACT_ICON = new GIcon("icon.version.tracking.subtract");
|
||||||
|
|
||||||
|
@ -210,18 +210,14 @@ public class ChooseAddressSetEditorPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void showAddRangeDialog() {
|
protected void showAddRangeDialog() {
|
||||||
AddressRangeListener addListener =
|
|
||||||
(minAddress, maxAddress) -> addRange(minAddress, maxAddress);
|
|
||||||
AddRemoveAddressRangeDialog addRangeDialog =
|
AddRemoveAddressRangeDialog addRangeDialog =
|
||||||
new AddRemoveAddressRangeDialog("Add", name, program, addListener);
|
new AddRemoveAddressRangeDialog("Add", name, program, r -> addRange(r));
|
||||||
tool.showDialog(addRangeDialog, this.getRootPane());
|
tool.showDialog(addRangeDialog, this.getRootPane());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void showSubtractRangeDialog() {
|
protected void showSubtractRangeDialog() {
|
||||||
AddressRangeListener subtractListener =
|
|
||||||
(minAddress, maxAddress) -> subtractRange(minAddress, maxAddress);
|
|
||||||
AddRemoveAddressRangeDialog removeRangeDialog =
|
AddRemoveAddressRangeDialog removeRangeDialog =
|
||||||
new AddRemoveAddressRangeDialog("Remove", name, program, subtractListener);
|
new AddRemoveAddressRangeDialog("Remove", name, program, r -> subtractRange(r));
|
||||||
tool.showDialog(removeRangeDialog, this.getRootPane());
|
tool.showDialog(removeRangeDialog, this.getRootPane());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,14 +242,14 @@ public class ChooseAddressSetEditorPanel extends JPanel {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void addRange(Address minAddress, Address maxAddress) {
|
private synchronized void addRange(AddressRange range) {
|
||||||
myCurrentAddressSet.addRange(minAddress, maxAddress);
|
myCurrentAddressSet.add(range);
|
||||||
listModel.setData(myCurrentAddressSet.toList());
|
listModel.setData(myCurrentAddressSet.toList());
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void subtractRange(Address minAddress, Address maxAddress) {
|
private synchronized void subtractRange(AddressRange range) {
|
||||||
myCurrentAddressSet.deleteRange(minAddress, maxAddress);
|
myCurrentAddressSet.delete(range);
|
||||||
listModel.setData(myCurrentAddressSet.toList());
|
listModel.setData(myCurrentAddressSet.toList());
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
|
@ -13,10 +13,11 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.gui.wizard;
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -25,21 +26,26 @@ import javax.swing.table.TableColumnModel;
|
||||||
|
|
||||||
import docking.widgets.table.GTableCellRenderer;
|
import docking.widgets.table.GTableCellRenderer;
|
||||||
import docking.widgets.table.GTableCellRenderingData;
|
import docking.widgets.table.GTableCellRenderingData;
|
||||||
import docking.wizard.*;
|
|
||||||
import ghidra.feature.vt.api.impl.VTProgramCorrelatorInfo;
|
import ghidra.feature.vt.api.impl.VTProgramCorrelatorInfo;
|
||||||
import ghidra.feature.vt.api.main.*;
|
import ghidra.feature.vt.api.main.*;
|
||||||
import ghidra.util.HelpLocation;
|
|
||||||
import ghidra.util.table.GhidraTable;
|
import ghidra.util.table.GhidraTable;
|
||||||
|
import utility.function.Callback;
|
||||||
|
|
||||||
public class CorrelatorPanel extends AbstractMageJPanel<VTWizardStateKey> implements Scrollable {
|
/**
|
||||||
|
* Panel for displaying and choosing from a list of version tracking correlators. Used by the
|
||||||
|
* {@link CorrelatorChooserStep} of the "add to version tracking session" wizard.
|
||||||
|
*/
|
||||||
|
public class CorrelatorChooserPanel extends JPanel {
|
||||||
|
|
||||||
private VTProgramTableCorrelatorModel model;
|
private VTProgramTableCorrelatorModel model;
|
||||||
private GhidraTable table;
|
private GhidraTable table;
|
||||||
|
private Callback statusChangedCallback;
|
||||||
|
|
||||||
CorrelatorPanel(VTSession session) {
|
CorrelatorChooserPanel(VTSession session, Callback statusChangedCallback) {
|
||||||
setLayout(new BorderLayout());
|
setLayout(new BorderLayout());
|
||||||
table = createBasicTable(getPreviouslyRunAlgorithms(session));
|
table = createBasicTable(getPreviouslyRunAlgorithms(session));
|
||||||
add(new JScrollPane(table), BorderLayout.CENTER);
|
add(new JScrollPane(table), BorderLayout.CENTER);
|
||||||
|
this.statusChangedCallback = statusChangedCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GhidraTable createBasicTable(Set<String> previouslyRunCorrelators) {
|
private GhidraTable createBasicTable(Set<String> previouslyRunCorrelators) {
|
||||||
|
@ -56,16 +62,16 @@ public class CorrelatorPanel extends AbstractMageJPanel<VTWizardStateKey> implem
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void notifyListenersOfValidityChanged() {
|
|
||||||
super.notifyListenersOfValidityChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dimension getPreferredSize() {
|
public Dimension getPreferredSize() {
|
||||||
return new Dimension(1000, 400);
|
return new Dimension(1000, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void notifyStatusChanged() {
|
||||||
|
statusChangedCallback.call();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void setColumnSizes() {
|
private void setColumnSizes() {
|
||||||
TableColumnModel columnModel = table.getColumnModel();
|
TableColumnModel columnModel = table.getColumnModel();
|
||||||
int width = 0;
|
int width = 0;
|
||||||
|
@ -102,87 +108,8 @@ public class CorrelatorPanel extends AbstractMageJPanel<VTWizardStateKey> implem
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public List<VTProgramCorrelatorFactory> getSelectedCorrelators() {
|
||||||
public void dispose() {
|
return model.getSelectedFactories();
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HelpLocation getHelpLocation() {
|
|
||||||
return new HelpLocation("VersionTrackingPlugin", "Correlator_Panel");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enterPanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
static WizardPanelDisplayability correlatorDisplayability(WizardState<VTWizardStateKey> state) {
|
|
||||||
return WizardPanelDisplayability.MUST_BE_DISPLAYED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WizardPanelDisplayability getPanelDisplayabilityAndUpdateState(
|
|
||||||
WizardState<VTWizardStateKey> state) {
|
|
||||||
return correlatorDisplayability(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leavePanel(WizardState<VTWizardStateKey> state) {
|
|
||||||
updateStateObjectWithPanelInfo(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateStateObjectWithPanelInfo(WizardState<VTWizardStateKey> state) {
|
|
||||||
java.util.List<VTProgramCorrelatorFactory> selectedFactories = model.getSelectedFactories();
|
|
||||||
if (!selectedFactories.isEmpty()) {
|
|
||||||
state.put(VTWizardStateKey.PROGRAM_CORRELATOR_FACTORY_LIST, selectedFactories);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTitle() {
|
|
||||||
return "Select Correlation Algorithm(s)";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValidInformation() {
|
|
||||||
return !model.getSelectedFactories().isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDependencies(WizardState<VTWizardStateKey> state) {
|
|
||||||
// no dependencies
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension getPreferredScrollableViewportSize() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
|
|
||||||
return 25;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getScrollableTracksViewportHeight() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getScrollableTracksViewportWidth() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
|
|
||||||
return 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
@ -209,4 +136,5 @@ public class CorrelatorPanel extends AbstractMageJPanel<VTWizardStateKey> implem
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
|
import docking.wizard.WizardStep;
|
||||||
|
import ghidra.feature.vt.api.main.VTProgramCorrelatorFactory;
|
||||||
|
import ghidra.feature.vt.api.main.VTSession;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wizard step for choosing which correlators to run when adding to an existing version
|
||||||
|
* tracking session.
|
||||||
|
*/
|
||||||
|
public class CorrelatorChooserStep extends WizardStep<AddToSessionData> {
|
||||||
|
private CorrelatorChooserPanel panel;
|
||||||
|
|
||||||
|
public CorrelatorChooserStep(VTAddToSessionWizardModel model, VTSession session) {
|
||||||
|
super(model, "Select Correlation Algorithm(s)",
|
||||||
|
new HelpLocation("VersionTrackingPlugin", "Correlator_Panel"));
|
||||||
|
|
||||||
|
panel = new CorrelatorChooserPanel(session, this::notifyStatusChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(AddToSessionData data) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
List<VTProgramCorrelatorFactory> correlators = panel.getSelectedCorrelators();
|
||||||
|
if (!correlators.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void populateData(AddToSessionData data) {
|
||||||
|
data.setCorrelators(panel.getSelectedCorrelators());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(AddToSessionData data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JComponent getComponent() {
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canFinish(AddToSessionData data) {
|
||||||
|
return data.getCorrelators() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
|
import java.awt.GridLayout;
|
||||||
|
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import ghidra.feature.vt.gui.wizard.add.AddToSessionData.AddressSetChoice;
|
||||||
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
import ghidra.program.model.address.AddressSetView;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Panel for adjusting address sets for both the source and destination programs at the same time.
|
||||||
|
* Used by the {@link LimitAddressSetsStep} of the "add to version tracking session wizard.
|
||||||
|
*/
|
||||||
|
public class LimitAddressSetsPanel extends JPanel {
|
||||||
|
|
||||||
|
private ChooseAddressSetEditorPanel sourcePanel;
|
||||||
|
private ChooseAddressSetEditorPanel destinationPanel;
|
||||||
|
private PluginTool tool;
|
||||||
|
|
||||||
|
public LimitAddressSetsPanel(PluginTool tool) {
|
||||||
|
|
||||||
|
this.tool = tool;
|
||||||
|
setLayout(new GridLayout());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(AddToSessionData data) {
|
||||||
|
removeAll();
|
||||||
|
|
||||||
|
sourcePanel = buildSourcePanel(data);
|
||||||
|
destinationPanel = buildDestinationPanel(data);
|
||||||
|
|
||||||
|
add(sourcePanel);
|
||||||
|
add(destinationPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChooseAddressSetEditorPanel buildSourcePanel(AddToSessionData data) {
|
||||||
|
Program program = data.getSourceProgram();
|
||||||
|
AddressSetView selection = data.getSourceSelection();
|
||||||
|
AddressSetView set = data.getCustomSourceAddressSet();
|
||||||
|
AddressSetChoice choice = data.getSourceAddressSetChoice();
|
||||||
|
return new ChooseAddressSetEditorPanel(tool, "Source", program, selection, set, choice);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChooseAddressSetEditorPanel buildDestinationPanel(AddToSessionData data) {
|
||||||
|
Program program = data.getDestinationProgram();
|
||||||
|
AddressSetView selection = data.getDestinationSelection();
|
||||||
|
AddressSetView set = data.getCustomDestinationAddressSet();
|
||||||
|
AddressSetChoice choice = data.getDestinationAddressSetChoice();
|
||||||
|
return new ChooseAddressSetEditorPanel(tool, "Destination", program, selection, set,
|
||||||
|
choice);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply(AddToSessionData data) {
|
||||||
|
AddressSetChoice sourceChoice = sourcePanel.getAddressSetChoice();
|
||||||
|
AddressSetChoice destinationChoice = destinationPanel.getAddressSetChoice();
|
||||||
|
data.setSourceAddressSetChoice(sourceChoice);
|
||||||
|
data.setDestinationAddressSetChoice(destinationChoice);
|
||||||
|
data.setCustomSourceAddressSet(null);
|
||||||
|
data.setCustomDestinationAddressSet(null);
|
||||||
|
if (sourceChoice == AddressSetChoice.MANUALLY_DEFINED) {
|
||||||
|
data.setCustomSourceAddressSet(sourcePanel.getAddressSetView());
|
||||||
|
}
|
||||||
|
if (destinationChoice == AddressSetChoice.MANUALLY_DEFINED) {
|
||||||
|
data.setCustomDestinationAddressSet(destinationPanel.getAddressSetView());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
|
import docking.wizard.WizardStep;
|
||||||
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wizard step for choosing the addresses to apply for adding correlation runs to an existing
|
||||||
|
* version tracking session.
|
||||||
|
*/
|
||||||
|
public class LimitAddressSetsStep extends WizardStep<AddToSessionData> {
|
||||||
|
private LimitAddressSetsPanel panel;
|
||||||
|
|
||||||
|
public LimitAddressSetsStep(VTAddToSessionWizardModel model, PluginTool tool) {
|
||||||
|
super(model, "Select Address Range(s)",
|
||||||
|
new HelpLocation("VersionTrackingPlugin", "Select_Address_Ranges_Panel"));
|
||||||
|
|
||||||
|
panel = new LimitAddressSetsPanel(tool);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(AddToSessionData data) {
|
||||||
|
panel.initialize(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(AddToSessionData data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void populateData(AddToSessionData data) {
|
||||||
|
panel.apply(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(AddToSessionData data) {
|
||||||
|
return data.shouldLimitAddressSets();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canFinish(AddToSessionData data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JComponent getComponent() {
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
import docking.options.editor.OptionsEditorPanel;
|
||||||
|
import ghidra.feature.vt.api.main.VTProgramCorrelatorFactory;
|
||||||
|
import ghidra.feature.vt.api.util.VTOptions;
|
||||||
|
import ghidra.framework.options.EditorStateFactory;
|
||||||
|
import ghidra.util.layout.VerticalLayout;
|
||||||
|
import utility.function.Callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Panel for displaying version tracking correlator options for selected correlators. Used by
|
||||||
|
* the {@link OptionsStep} of the "add to version tracking session" wizard to configure the
|
||||||
|
* selected correlators from a previous step.
|
||||||
|
*/
|
||||||
|
public class OptionsPanel extends JPanel {
|
||||||
|
|
||||||
|
private static final Dimension DEFAULT_PREFERRED_SIZE = new Dimension(650, 350);
|
||||||
|
|
||||||
|
private List<OptionsEditorPanel> optionsEditorPanelList = new ArrayList<>();
|
||||||
|
private Callback statusChangedCallback;
|
||||||
|
private Map<VTProgramCorrelatorFactory, VTOptions> optionsMap = new HashMap<>();
|
||||||
|
|
||||||
|
private JPanel stagingPanel;
|
||||||
|
|
||||||
|
OptionsPanel(Callback statusChangedCallback) {
|
||||||
|
super(new BorderLayout());
|
||||||
|
this.statusChangedCallback = statusChangedCallback;
|
||||||
|
|
||||||
|
stagingPanel = new JPanel(new BorderLayout());
|
||||||
|
stagingPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||||
|
JScrollPane scrollPane = new JScrollPane(stagingPanel);
|
||||||
|
scrollPane.getVerticalScrollBar().setUnitIncrement(5);
|
||||||
|
add(scrollPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
Dimension preferredSize = super.getPreferredSize();
|
||||||
|
if (preferredSize.width < DEFAULT_PREFERRED_SIZE.width) {
|
||||||
|
return DEFAULT_PREFERRED_SIZE;
|
||||||
|
}
|
||||||
|
return preferredSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isApplicable(List<VTProgramCorrelatorFactory> correlators) {
|
||||||
|
updateOptionsMap(correlators);
|
||||||
|
return !optionsMap.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateOptionsMap(List<VTProgramCorrelatorFactory> correlators) {
|
||||||
|
optionsMap.keySet().retainAll(correlators);
|
||||||
|
for (VTProgramCorrelatorFactory correlator : correlators) {
|
||||||
|
if (!optionsMap.containsKey(correlator)) {
|
||||||
|
VTOptions defaultOptions = correlator.createDefaultOptions();
|
||||||
|
if (defaultOptions != null) {
|
||||||
|
optionsMap.put(correlator, defaultOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialize(List<VTProgramCorrelatorFactory> correlators) {
|
||||||
|
updateOptionsMap(correlators);
|
||||||
|
JPanel panel = new JPanel(new VerticalLayout(30));
|
||||||
|
optionsEditorPanelList.clear();
|
||||||
|
for (VTProgramCorrelatorFactory correlator : correlators) {
|
||||||
|
OptionsEditorPanel optionsPanel = buildOptionsPanel(correlator);
|
||||||
|
if (optionsPanel != null) {
|
||||||
|
optionsEditorPanelList.add(optionsPanel);
|
||||||
|
optionsPanel.setOptionsPropertyChangeListener(e -> statusChangedCallback.call());
|
||||||
|
panel.add(optionsPanel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stagingPanel.removeAll();
|
||||||
|
stagingPanel.add(panel, BorderLayout.CENTER);
|
||||||
|
stagingPanel.revalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private OptionsEditorPanel buildOptionsPanel(VTProgramCorrelatorFactory factory) {
|
||||||
|
VTOptions options = optionsMap.get(factory);
|
||||||
|
if (options == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String title = factory.getName() + " Options";
|
||||||
|
|
||||||
|
EditorStateFactory editorStateFactory = new EditorStateFactory();
|
||||||
|
List<String> optionNames = options.getLeafOptionNames();
|
||||||
|
if (optionNames.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Collections.sort(optionNames);
|
||||||
|
return new OptionsEditorPanel(title, options, optionNames, editorStateFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasValidOptions() {
|
||||||
|
applyOptions();
|
||||||
|
for (VTOptions options : optionsMap.values()) {
|
||||||
|
if (options != null) {
|
||||||
|
if (!options.validate()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyOptions() {
|
||||||
|
for (OptionsEditorPanel panel : optionsEditorPanelList) {
|
||||||
|
panel.apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<VTProgramCorrelatorFactory, VTOptions> getOptionsMap() {
|
||||||
|
return optionsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
|
import docking.wizard.WizardModel;
|
||||||
|
import docking.wizard.WizardStep;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wizard step for configuring options for the selected correlators when adding to an existing
|
||||||
|
* version tracking session.
|
||||||
|
*/
|
||||||
|
public class OptionsStep extends WizardStep<AddToSessionData> {
|
||||||
|
private OptionsPanel panel;
|
||||||
|
|
||||||
|
protected OptionsStep(WizardModel<AddToSessionData> model) {
|
||||||
|
super(model, "Correlator Options",
|
||||||
|
new HelpLocation("VersionTrackingPlugin", "Options_Panel"));
|
||||||
|
|
||||||
|
panel = new OptionsPanel(this::notifyStatusChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(AddToSessionData data) {
|
||||||
|
panel.initialize(data.getCorrelators());
|
||||||
|
// set the options here so that we know this step was visited
|
||||||
|
data.setOptions(panel.getOptionsMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(AddToSessionData data) {
|
||||||
|
return panel.isApplicable(data.getCorrelators());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return panel.hasValidOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canFinish(AddToSessionData data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void populateData(AddToSessionData data) {
|
||||||
|
data.setOptions(panel.getOptionsMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(AddToSessionData data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JComponent getComponent() {
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
|
import docking.wizard.WizardModel;
|
||||||
|
import docking.wizard.WizardStep;
|
||||||
|
import ghidra.feature.vt.api.main.VTProgramCorrelatorFactory;
|
||||||
|
import ghidra.feature.vt.gui.wizard.add.AddToSessionData.AddressSetChoice;
|
||||||
|
import ghidra.feature.vt.gui.wizard.session.SummaryPanel;
|
||||||
|
import ghidra.framework.model.DomainFile;
|
||||||
|
import ghidra.util.HTMLUtilities;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wizard step in the "add to tracking session" wizard for summarizing the information that
|
||||||
|
* will be used to add correlations to a version tracking session.
|
||||||
|
*/
|
||||||
|
public class SummaryStep extends WizardStep<AddToSessionData> {
|
||||||
|
private SummaryPanel summaryPanel;
|
||||||
|
|
||||||
|
protected SummaryStep(WizardModel<AddToSessionData> model) {
|
||||||
|
super(model, "Summary",
|
||||||
|
new HelpLocation("VersionTrackingPlugin", "New_Session_Summary_Panel"));
|
||||||
|
|
||||||
|
summaryPanel = new SummaryPanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(AddToSessionData data) {
|
||||||
|
StringBuilder label = new StringBuilder();
|
||||||
|
StringBuilder summary = new StringBuilder();
|
||||||
|
|
||||||
|
label.append("<html>");
|
||||||
|
summary.append("<html>");
|
||||||
|
|
||||||
|
// session mode
|
||||||
|
|
||||||
|
label.append("Operation:");
|
||||||
|
summary.append("Add to Version Tracking Session");
|
||||||
|
label.append("<br>");
|
||||||
|
summary.append("<br>");
|
||||||
|
|
||||||
|
String sessionName = data.getSession().getName();
|
||||||
|
|
||||||
|
label.append("Session Name:");
|
||||||
|
summary.append(sessionName);
|
||||||
|
label.append("<br>");
|
||||||
|
summary.append("<br>");
|
||||||
|
|
||||||
|
String sourceProgramName = null;
|
||||||
|
String destinationProgramName = null;
|
||||||
|
|
||||||
|
DomainFile sourceProgram = data.getSourceFile();
|
||||||
|
sourceProgramName = sourceProgram.getName();
|
||||||
|
|
||||||
|
DomainFile destinationProgram = data.getDestinationFile();
|
||||||
|
destinationProgramName = destinationProgram.getName();
|
||||||
|
|
||||||
|
// source program
|
||||||
|
|
||||||
|
label.append("Source Program:");
|
||||||
|
summary.append(HTMLUtilities.escapeHTML(sourceProgramName));
|
||||||
|
label.append("<br>");
|
||||||
|
summary.append("<br>");
|
||||||
|
|
||||||
|
// destination program
|
||||||
|
|
||||||
|
label.append("Destination Program:");
|
||||||
|
summary.append(HTMLUtilities.escapeHTML(destinationProgramName));
|
||||||
|
label.append("<br>");
|
||||||
|
summary.append("<br>");
|
||||||
|
|
||||||
|
String correlatorLabel = "";
|
||||||
|
String correlatorName = null;
|
||||||
|
|
||||||
|
List<VTProgramCorrelatorFactory> correlators = data.getCorrelators();
|
||||||
|
for (VTProgramCorrelatorFactory correlatorFactory : correlators) {
|
||||||
|
correlatorName = correlatorFactory.getName();
|
||||||
|
|
||||||
|
label.append(correlatorLabel + "Program Correlator:");
|
||||||
|
summary.append(correlatorName == null ? "(null)" : correlatorName);
|
||||||
|
label.append("<br>");
|
||||||
|
summary.append("<br>");
|
||||||
|
}
|
||||||
|
boolean excludeAcceptedMatches = data.shouldExcludeAcceptedMatches();
|
||||||
|
label.append("Exclude Accepted Matches:");
|
||||||
|
summary.append(excludeAcceptedMatches ? "Yes" : "No");
|
||||||
|
label.append("<br>");
|
||||||
|
summary.append("<br>");
|
||||||
|
|
||||||
|
AddressSetChoice sourceAddressSetChoice = data.getSourceAddressSetChoice();
|
||||||
|
AddressSetChoice destinationAddressSetChoice = data.getDestinationAddressSetChoice();
|
||||||
|
String sourceAddressesInfo =
|
||||||
|
(sourceAddressSetChoice == AddressSetChoice.MANUALLY_DEFINED) ? "Manually Defined"
|
||||||
|
: ((sourceAddressSetChoice == AddressSetChoice.SELECTION))
|
||||||
|
? "Source Tool Selection"
|
||||||
|
: "Entire Source Program";
|
||||||
|
String destinationAddressesInfo =
|
||||||
|
(destinationAddressSetChoice == AddressSetChoice.MANUALLY_DEFINED)
|
||||||
|
? "Manually Defined"
|
||||||
|
: ((destinationAddressSetChoice == AddressSetChoice.SELECTION))
|
||||||
|
? "Destination Tool Selection"
|
||||||
|
: "Entire Destination Program";
|
||||||
|
|
||||||
|
label.append("Source Address Set:");
|
||||||
|
summary.append(sourceAddressesInfo);
|
||||||
|
label.append("<br>");
|
||||||
|
summary.append("<br>");
|
||||||
|
|
||||||
|
label.append("Destination Address Set:");
|
||||||
|
summary.append(destinationAddressesInfo);
|
||||||
|
label.append("<br>");
|
||||||
|
summary.append("<br>");
|
||||||
|
|
||||||
|
label.append("</html>");
|
||||||
|
summary.append("</html>");
|
||||||
|
|
||||||
|
summaryPanel.initialize(label.toString(), summary.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canFinish(AddToSessionData data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(AddToSessionData data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void populateData(AddToSessionData data) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JComponent getComponent() {
|
||||||
|
return summaryPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import docking.wizard.WizardModel;
|
||||||
|
import docking.wizard.WizardStep;
|
||||||
|
import ghidra.feature.vt.api.main.VTSession;
|
||||||
|
import ghidra.feature.vt.gui.plugin.VTController;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.util.task.Task;
|
||||||
|
import ghidra.util.task.TaskLauncher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wizard model for adding correlation runs to an existing version tracking session.
|
||||||
|
*/
|
||||||
|
public class VTAddToSessionWizardModel extends WizardModel<AddToSessionData> {
|
||||||
|
|
||||||
|
private final VTController controller;
|
||||||
|
|
||||||
|
public VTAddToSessionWizardModel(VTController controller) {
|
||||||
|
super("Add to Version Tracking Session", new AddToSessionData());
|
||||||
|
this.controller = controller;
|
||||||
|
Program sourceProgram = controller.getSourceProgram();
|
||||||
|
Program destinationProgram = controller.getDestinationProgram();
|
||||||
|
VTSession session = controller.getSession();
|
||||||
|
|
||||||
|
data.setSourceProgram(sourceProgram);
|
||||||
|
data.setDestinationProgram(destinationProgram);
|
||||||
|
data.setSession(session);
|
||||||
|
data.setSourceSelection(controller.getSelectionInSourceTool());
|
||||||
|
data.setDestinationSelection(controller.getSelectionInDestinationTool());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addWizardSteps(List<WizardStep<AddToSessionData>> list) {
|
||||||
|
list.add(new CorrelatorChooserStep(this, controller.getSession()));
|
||||||
|
list.add(new OptionsStep(this));
|
||||||
|
list.add(new AddressSetOptionsStep(this));
|
||||||
|
list.add(new LimitAddressSetsStep(this, controller.getTool()));
|
||||||
|
list.add(new SummaryStep(this));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean doFinish() {
|
||||||
|
Task task = new AddToSessionTask(controller, data);
|
||||||
|
new TaskLauncher(task, wizardDialog.getComponent());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.gui.wizard;
|
package ghidra.feature.vt.gui.wizard.add;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -26,6 +26,9 @@ import ghidra.feature.vt.api.util.VTAbstractProgramCorrelatorFactory;
|
||||||
import ghidra.util.classfinder.ClassSearcher;
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table model for showing version tracking correlators.
|
||||||
|
*/
|
||||||
public class VTProgramTableCorrelatorModel extends AbstractGTableModel<VTProgramCorrelatorFactory> {
|
public class VTProgramTableCorrelatorModel extends AbstractGTableModel<VTProgramCorrelatorFactory> {
|
||||||
|
|
||||||
static final String NAME_COLUMN_NAME = "Name";
|
static final String NAME_COLUMN_NAME = "Name";
|
||||||
|
@ -47,9 +50,9 @@ public class VTProgramTableCorrelatorModel extends AbstractGTableModel<VTProgram
|
||||||
private Set<String> previouslyRunCorrelators;
|
private Set<String> previouslyRunCorrelators;
|
||||||
private Set<VTProgramCorrelatorFactory> selectedFactories =
|
private Set<VTProgramCorrelatorFactory> selectedFactories =
|
||||||
new HashSet<>();
|
new HashSet<>();
|
||||||
private CorrelatorPanel panel;
|
private CorrelatorChooserPanel panel;
|
||||||
|
|
||||||
public VTProgramTableCorrelatorModel(CorrelatorPanel panel,
|
public VTProgramTableCorrelatorModel(CorrelatorChooserPanel panel,
|
||||||
Set<String> previouslyRunCorrelators) {
|
Set<String> previouslyRunCorrelators) {
|
||||||
this.panel = panel;
|
this.panel = panel;
|
||||||
this.previouslyRunCorrelators = previouslyRunCorrelators;
|
this.previouslyRunCorrelators = previouslyRunCorrelators;
|
||||||
|
@ -57,7 +60,9 @@ public class VTProgramTableCorrelatorModel extends AbstractGTableModel<VTProgram
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<VTProgramCorrelatorFactory> getSelectedFactories() {
|
public List<VTProgramCorrelatorFactory> getSelectedFactories() {
|
||||||
return new ArrayList<>(selectedFactories);
|
List<VTProgramCorrelatorFactory> factories = new ArrayList<>(selectedFactories);
|
||||||
|
factories.sort(comparator);
|
||||||
|
return factories;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<VTProgramCorrelatorFactory> generateList() {
|
private static List<VTProgramCorrelatorFactory> generateList() {
|
||||||
|
@ -136,7 +141,7 @@ public class VTProgramTableCorrelatorModel extends AbstractGTableModel<VTProgram
|
||||||
else {
|
else {
|
||||||
selectedFactories.remove(factory);
|
selectedFactories.remove(factory);
|
||||||
}
|
}
|
||||||
panel.notifyListenersOfValidityChanged();
|
panel.notifyStatusChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -13,11 +13,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.gui.wizard;
|
package ghidra.feature.vt.gui.wizard.session;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import docking.wizard.WizardState;
|
|
||||||
import ghidra.feature.vt.api.db.VTSessionDB;
|
import ghidra.feature.vt.api.db.VTSessionDB;
|
||||||
import ghidra.feature.vt.gui.plugin.VTController;
|
import ghidra.feature.vt.gui.plugin.VTController;
|
||||||
import ghidra.framework.model.DomainFolder;
|
import ghidra.framework.model.DomainFolder;
|
||||||
|
@ -29,13 +28,13 @@ import ghidra.util.task.Task;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class CreateNewSessionTask extends Task {
|
public class CreateNewSessionTask extends Task {
|
||||||
private final WizardState<VTWizardStateKey> state;
|
private final NewSessionData data;
|
||||||
private final VTController controller;
|
private final VTController controller;
|
||||||
|
|
||||||
public CreateNewSessionTask(VTController controller, WizardState<VTWizardStateKey> state) {
|
public CreateNewSessionTask(VTController controller, NewSessionData data) {
|
||||||
super("Create New Version Tracking Session", true, true, true);
|
super("Create New Version Tracking Session", true, true, true);
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.state = state;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -43,16 +42,16 @@ public class CreateNewSessionTask extends Task {
|
||||||
VTSessionDB session = null;
|
VTSessionDB session = null;
|
||||||
String name = null;
|
String name = null;
|
||||||
try {
|
try {
|
||||||
Program sourceProgram = (Program) state.get(VTWizardStateKey.SOURCE_PROGRAM);
|
Program sourceProgram = data.getSourceProgram();
|
||||||
Program destinationProgram = (Program) state.get(VTWizardStateKey.DESTINATION_PROGRAM);
|
Program destinationProgram = data.getDestinationProgram();
|
||||||
|
|
||||||
session = new VTSessionDB("New Session", sourceProgram, destinationProgram, this);
|
session = new VTSessionDB("New Session", sourceProgram, destinationProgram, this);
|
||||||
|
|
||||||
sourceProgram.release(controller.getTool());
|
sourceProgram.release(controller.getTool());
|
||||||
destinationProgram.release(controller.getTool());
|
destinationProgram.release(controller.getTool());
|
||||||
|
|
||||||
name = (String) state.get(VTWizardStateKey.SESSION_NAME);
|
name = data.getSessionName();
|
||||||
DomainFolder folder = (DomainFolder) state.get(VTWizardStateKey.NEW_SESSION_FOLDER);
|
DomainFolder folder = data.getSessionFolder();
|
||||||
try {
|
try {
|
||||||
folder.createFile(name, session, monitor);
|
folder.createFile(name, session, monitor);
|
||||||
}
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.session;
|
||||||
|
|
||||||
|
import ghidra.framework.model.DomainFile;
|
||||||
|
import ghidra.framework.model.DomainFolder;
|
||||||
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wizard data used by the {@link VTNewSessionWizardModel} and its steps for the "create new version
|
||||||
|
* tracking session" wizard.
|
||||||
|
*/
|
||||||
|
public class NewSessionData {
|
||||||
|
private Program sourceProgram;
|
||||||
|
private Program destinationProgram;
|
||||||
|
private DomainFile sourceFile;
|
||||||
|
private DomainFile destinationFile;
|
||||||
|
private DomainFolder sessionFolder;
|
||||||
|
private String sessionName;
|
||||||
|
private boolean preconditionChecksCompleted;
|
||||||
|
|
||||||
|
public DomainFile getSourceFile() {
|
||||||
|
return sourceFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DomainFile getDestinationFile() {
|
||||||
|
return destinationFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Program getSourceProgram() {
|
||||||
|
return sourceProgram;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Program getDestinationProgram() {
|
||||||
|
return destinationProgram;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSessionName() {
|
||||||
|
return sessionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DomainFolder getSessionFolder() {
|
||||||
|
return sessionFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceFile(DomainFile file, PluginTool tool) {
|
||||||
|
this.sourceFile = file;
|
||||||
|
if (isProgramInvalidForFile(file, sourceProgram)) {
|
||||||
|
sourceProgram.release(tool);
|
||||||
|
sourceProgram = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isProgramInvalidForFile(DomainFile file, Program program) {
|
||||||
|
|
||||||
|
if (program == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (program.getDomainFile().equals(file)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestinationFile(DomainFile file, PluginTool tool) {
|
||||||
|
this.destinationFile = file;
|
||||||
|
if (isProgramInvalidForFile(file, destinationProgram)) {
|
||||||
|
sourceProgram.release(tool);
|
||||||
|
sourceProgram = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceProgram(Program program) {
|
||||||
|
this.sourceProgram = program;
|
||||||
|
preconditionChecksCompleted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestinationProgram(Program program) {
|
||||||
|
this.destinationProgram = program;
|
||||||
|
preconditionChecksCompleted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSessionName(String name) {
|
||||||
|
this.sessionName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSessionFolder(DomainFolder folder) {
|
||||||
|
this.sessionFolder = folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPerformedPreconditionChecks() {
|
||||||
|
return preconditionChecksCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPerformedPreconditionChecks(boolean b) {
|
||||||
|
preconditionChecksCompleted = b;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.session;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
import docking.widgets.conditiontestpanel.*;
|
||||||
|
import docking.wizard.WizardModel;
|
||||||
|
import ghidra.feature.vt.api.main.VTSession;
|
||||||
|
import ghidra.feature.vt.gui.validator.VTPreconditionValidator;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
|
import utility.function.Callback;
|
||||||
|
|
||||||
|
public class PreconditionsPanel extends JPanel {
|
||||||
|
private static final Dimension DEFAULT_SIZE = new Dimension(650, 480);
|
||||||
|
private ConditionTestPanel conditionsTestPanel;
|
||||||
|
private boolean testsDone = false;
|
||||||
|
private Callback statusChangedCallback;
|
||||||
|
|
||||||
|
public PreconditionsPanel(WizardModel<NewSessionData> model,
|
||||||
|
Callback statusChangedCallback) {
|
||||||
|
this.statusChangedCallback = statusChangedCallback;
|
||||||
|
setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
|
||||||
|
setLayout(new BorderLayout());
|
||||||
|
|
||||||
|
JPanel runButtonPanel = new JPanel();
|
||||||
|
runButtonPanel.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0));
|
||||||
|
runButtonPanel.setLayout(new FlowLayout());
|
||||||
|
JButton runTestsButton = new JButton("Run Precondition Checks");
|
||||||
|
runTestsButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
conditionsTestPanel.runTests();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
runButtonPanel.add(runTestsButton);
|
||||||
|
|
||||||
|
JButton skipTestsButton = new JButton("Skip");
|
||||||
|
skipTestsButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
conditionsTestPanel.skipTests();
|
||||||
|
model.goNext();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
runButtonPanel.add(skipTestsButton);
|
||||||
|
|
||||||
|
add(runButtonPanel, BorderLayout.SOUTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
if (conditionsTestPanel != null) {
|
||||||
|
conditionsTestPanel.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConditionTestPanel buildConditionPanel(Program source, Program destination) {
|
||||||
|
List<ConditionTester> list = getConditionTests(source, destination);
|
||||||
|
Collections.sort(list, (t1, t2) -> t1.getName().compareTo(t2.getName()));
|
||||||
|
ConditionTestPanel panel = new ConditionTestPanel(list);
|
||||||
|
panel.addListener(new ConditionTestListener() {
|
||||||
|
@Override
|
||||||
|
public void testsCompleted() {
|
||||||
|
testsDone();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testsDone() {
|
||||||
|
testsDone = true;
|
||||||
|
statusChangedCallback.call();
|
||||||
|
if (hasAnyErrorStatus()) {
|
||||||
|
Msg.showError(getClass(), this, "Warning - Serious Precondition failures",
|
||||||
|
"The precondition checks discovered one or more serious problems. \n\n" +
|
||||||
|
"If you continue, your version tracking results may be invalid.\n" +
|
||||||
|
"You should review the errors, cancel this wizard, and correct the problems.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ConditionTester> getConditionTests(Program sourceProgram,
|
||||||
|
Program destinationProgram) throws SecurityException {
|
||||||
|
List<ConditionTester> list = new ArrayList<ConditionTester>();
|
||||||
|
|
||||||
|
List<Class<? extends VTPreconditionValidator>> vtValidatorClasses =
|
||||||
|
ClassSearcher.getClasses(VTPreconditionValidator.class);
|
||||||
|
for (Class<? extends VTPreconditionValidator> validatorClass : vtValidatorClasses) {
|
||||||
|
try {
|
||||||
|
Constructor<? extends VTPreconditionValidator> ctor =
|
||||||
|
validatorClass.getConstructor(Program.class, Program.class, VTSession.class);
|
||||||
|
VTPreconditionValidator validator =
|
||||||
|
ctor.newInstance(sourceProgram, destinationProgram, null);
|
||||||
|
list.add(validator);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
Msg.error(this, "error including VTPreconditionValidator " + validatorClass, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean hasAnyErrorStatus() {
|
||||||
|
return conditionsTestPanel.getErrorCount() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
// Overridden to account for the fact that we don't know our preferred size until later in
|
||||||
|
// the wizard flow. At that point, the initial size of the wizard is already too small.
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
Dimension superSize = super.getPreferredSize();
|
||||||
|
if (superSize.width > DEFAULT_SIZE.width && superSize.height > DEFAULT_SIZE.height) {
|
||||||
|
return superSize;
|
||||||
|
}
|
||||||
|
return DEFAULT_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initializeTests(Program sourceProgram, Program destinationProgram) {
|
||||||
|
testsDone = false;
|
||||||
|
if (conditionsTestPanel != null) {
|
||||||
|
remove(conditionsTestPanel);
|
||||||
|
}
|
||||||
|
conditionsTestPanel = buildConditionPanel(sourceProgram, destinationProgram);
|
||||||
|
add(conditionsTestPanel, BorderLayout.CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasRunTests() {
|
||||||
|
return testsDone;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.feature.vt.gui.wizard.session;
|
||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
|
import docking.wizard.WizardModel;
|
||||||
|
import docking.wizard.WizardStep;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wizard step for running version tracking precondition tests when creating a new version tracking
|
||||||
|
* session.
|
||||||
|
*/
|
||||||
|
public class PreconditionsStep extends WizardStep<NewSessionData> {
|
||||||
|
private PreconditionsPanel preconditionsPanel;
|
||||||
|
|
||||||
|
protected PreconditionsStep(WizardModel<NewSessionData> model) {
|
||||||
|
super(model, "Precondition Checklist",
|
||||||
|
new HelpLocation("VersionTrackingPlugin", "Preconditions_Panel"));
|
||||||
|
|
||||||
|
preconditionsPanel = new PreconditionsPanel(model, this::notifyStatusChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(NewSessionData data) {
|
||||||
|
if (!data.hasPerformedPreconditionChecks()) {
|
||||||
|
Program sourceProgram = data.getSourceProgram();
|
||||||
|
Program destinationProgram = data.getDestinationProgram();
|
||||||
|
preconditionsPanel.initializeTests(sourceProgram, destinationProgram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
boolean hasRunTests = preconditionsPanel.hasRunTests();
|
||||||
|
if (hasRunTests) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void populateData(NewSessionData data) {
|
||||||
|
data.setPerformedPreconditionChecks(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(NewSessionData data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canFinish(NewSessionData data) {
|
||||||
|
return data.hasPerformedPreconditionChecks();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JComponent getComponent() {
|
||||||
|
return preconditionsPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void dispose(NewSessionData data) {
|
||||||
|
preconditionsPanel.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|