GT-3179 - Help - addressed missing help for tool options; fixed bug that

caused help find dialog to be stuck behind Tool Options dialog; fixed
bug that caused the Help Find Dialog keybinding to trigger an exception
This commit is contained in:
dragonmacher 2019-10-04 15:43:13 -04:00
parent ea953ce924
commit 66198876e5
28 changed files with 296 additions and 151 deletions

View file

@ -16,6 +16,7 @@
<P>Often, users need to navigate to specific locations in a program.&nbsp; Ghidra provides <P>Often, users need to navigate to specific locations in a program.&nbsp; Ghidra provides
several different ways to do this:&nbsp;</P> several different ways to do this:&nbsp;</P>
<BLOCKQUOTE>
<UL> <UL>
<LI>&nbsp;&nbsp;&nbsp;Enter a particular address or label (<A href="#Go_To_Address_Label">Go <LI>&nbsp;&nbsp;&nbsp;Enter a particular address or label (<A href="#Go_To_Address_Label">Go
To</A>)</LI> To</A>)</LI>
@ -29,11 +30,12 @@
<LI>&nbsp;&nbsp; Use the <A href="#Navigation_History">Navigation History</A> to return to a <LI>&nbsp;&nbsp; Use the <A href="#Navigation_History">Navigation History</A> to return to a
previously visited location</LI> previously visited location</LI>
</UL> </UL>
</BLOCKQUOTE>
<H2><A name="Go_To_Address_Label"></A>Go To Address, Label, or Expression</H2> <H2><A name="Go_To_Address_Label"></A>Go To Address, Label, or Expression</H2>
<BLOCKQUOTE> <BLOCKQUOTE>
<H3>To perform a Go To:&nbsp;</H3> <H3>To Perform a Go To:&nbsp;</H3>
<OL> <OL>
<LI>In the menu-bar of a tool, select <B>Navigation <IMG src="../../shared/arrow.gif" <LI>In the menu-bar of a tool, select <B>Navigation <IMG src="../../shared/arrow.gif"
@ -228,25 +230,40 @@
expresion evaluation.<BR> expresion evaluation.<BR>
For example:<BR> For example:<BR>
</P> </P>
<TABLE BORDER="1">
<TR>
<TD WIDTH="35%">
<B>ENTRY+10</B>
</TD>
<TD>Positions
the cursor at the address 0x10 addresses past the symbol ENTRY
</TD>
</TR>
<TR>
<TD><B>0x100000+30</B>
</TD>
<TD>Positions the cursor at address 0x100030
</TD>
</TR>
<TR>
<TD><B>0x100000+(2*10)</B>
</TD>
<TD>Posiitons the cursor at address 0x100020
</TD>
</TR>
<TR>
<TD><B>+20</B>
</TD>
<TD>Positions the cursor at an address that is 0x20 past the current location
</TD>
</TR>
</TABLE>
</BLOCKQUOTE> </BLOCKQUOTE>
</BLOCKQUOTE> </BLOCKQUOTE>
<DIV style="margin-left: 4em">
<UL>
<LI>ENTRY+10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Positions
the cursor at the address 0x10 addresses past the symbol ENTRY.</LI>
<LI>0x100000+30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Positions the cursor
at address 0x100030.</LI>
<LI>0x100000+(2*10)&nbsp;&nbsp;&nbsp; Posiitons the cursor at address 0x100020.</LI>
<LI>
+20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Positions the cursor at an address that is 0x20 past the current location.<BR>
</LI>
</UL>
</DIV>
<BLOCKQUOTE> <BLOCKQUOTE>
<H3>Executing a Query</H3> <H3>Executing a Query</H3>
@ -626,6 +643,79 @@
<BR> <BR>
<HR WIDTH="80%">
<H2><A NAME="Navigation_Options"></A>Navigation Options</H2>
<BLOCKQUOTE>
<P>
<B>'Go To' in Current Program Only</B> -
'Go To' service will only search for and navigate to labels in the current program.
If this option is off and the search label is not found in the current program, the
'Go To' action will search other open programs,
possibly resulting in the listing view switching to a different open program tab.
By default, this option is on, thereby guaranteeing that the listing view will not
change to a different program when performing a <A HREF="#Go_To_Address_Label">
'Go To' action</A>.
</P>
<P>
<B>External Navigation</B> -
Determines the behavior for navigation to external symbols and references.
By default, navigating to an external will attempt to navigate within the
current program to the first linkage reference (pointer or thunk).
Alternatively, if an external program has been associated with an
import Library, then that program will be opened and positioned to the selected
external location if found.
</P>
<P>
<B>Follow Indirection</B> -
Determines the behavior for navigation on indirect flow references.
By default, this option is disabled providing navigation to the
referenced pointer data. If enabled, the pointer will be followed
to its referenced destination if contained within the program's memory.
</P>
<P>
<B>Prefer Current Address Space</B> -
Determines if the 'Go To' action prefers the current address space when entering address offsets.
For example, if your program has multiple address spaces such as 'RAM' or 'DATA' and you
enter 1000 into the 'Go To' field, you could mean RAM:1000 or DATA:1000. If this option
is on, then it will go to the address with the address space that matches the current
cursor location. Otherwise, it will show a list of possible addresses for the given offset.
The default is on for this option.
</P>
<P>
<B>Range Navigation</B> -
Determines how <A HREF="help/topics/Selection/Selecting.htm#NavigateOverSelection">
navigation of ranges</A>
(i.e., selection ranges and highlight ranges) takes place. By default, navigating
to ranges will place the cursor at the top of the
next range. You may use this option to navigate to both the top and the bottom of each
range being navigated.
</P>
</BLOCKQUOTE>
<!--
This file is different than most, since it has multiple plugins contributing to the
content. Add some space at the bottom of the file to separate this contribution.
-->
<BR>
<BR>
<BR>
<BR>
<BR>
<BR>
<P class="relatedtopic">Related Topics:</P> <P class="relatedtopic">Related Topics:</P>

View file

@ -24,12 +24,10 @@
types of selections that are available from the tool <B>Select</B> menu. Each predefined type types of selections that are available from the tool <B>Select</B> menu. Each predefined type
of selection exposes different characteristics of the program.</P> of selection exposes different characteristics of the program.</P>
<P>To create a selection using one of the predefined methods:</P> <P>To create a selection using one of the predefined methods via the menu item
<B>Select</B><I><B><IMG src=
<UL type="disc"> "../../shared/arrow.gif">SelectionType</B>.</I>
<LI>From the Code Browser, select the menu option <B>Select</B><I><B><IMG src= </P>
"../../shared/arrow.gif">SelectionType</B>.</I></LI>
</UL>
<P>The <I><B>SelectionTypes</B></I> and their descriptions are as follows:</P> <P>The <I><B>SelectionTypes</B></I> and their descriptions are as follows:</P>

View file

@ -135,7 +135,7 @@ public class CodeBrowserPlugin extends Plugin
GhidraOptions.CATEGORY_BROWSER_POPUPS); GhidraOptions.CATEGORY_BROWSER_POPUPS);
ToolOptions displayOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY); ToolOptions displayOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS); ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
displayOptions.registerOptionsEditor(new ListingDisplayOptionsEditor(this, displayOptions)); displayOptions.registerOptionsEditor(new ListingDisplayOptionsEditor(displayOptions));
displayOptions.setOptionsHelpLocation( displayOptions.setOptionsHelpLocation(
new HelpLocation(getName(), GhidraOptions.CATEGORY_BROWSER_DISPLAY)); new HelpLocation(getName(), GhidraOptions.CATEGORY_BROWSER_DISPLAY));
fieldOptions.setOptionsHelpLocation( fieldOptions.setOptionsHelpLocation(

View file

@ -267,12 +267,12 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
return address.compareTo(screenBottom) > 0; return address.compareTo(screenBottom) > 0;
} }
/** The y value of the start of the layout at the given address. */ /* The y value of the start of the layout at the given address. */
Integer getStartPos(Address addr) { Integer getStartPos(Address addr) {
return startAddressToPixel.get(addr); return startAddressToPixel.get(addr);
} }
/** The y value of the end of the layout at the given address. */ /* The y value of the end of the layout at the given address. */
Integer getEndPos(Address addr) { Integer getEndPos(Address addr) {
return endAddressToPixel.get(addr); return endAddressToPixel.get(addr);
} }
@ -294,7 +294,7 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
return flowArrows.iterator(); return flowArrows.iterator();
} }
/** Those arrows starting at the current address */ /* Those arrows starting at the current address */
Iterator<FlowArrow> getActiveArrows() { Iterator<FlowArrow> getActiveArrows() {
return activeArrows.iterator(); return activeArrows.iterator();
} }
@ -584,8 +584,8 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
for (int layout = 0; layout < n; layout++) { for (int layout = 0; layout < n; layout++) {
Address addr = layoutToPixel.getLayoutAddress(layout); Address addr = layoutToPixel.getLayoutAddress(layout);
if (addr != null) { if (addr != null) {
startAddressToPixel.put(addr, new Integer(layoutToPixel.getBeginPosition(layout))); startAddressToPixel.put(addr, layoutToPixel.getBeginPosition(layout));
endAddressToPixel.put(addr, new Integer(layoutToPixel.getEndPosition(layout))); endAddressToPixel.put(addr, layoutToPixel.getEndPosition(layout));
} }
} }
@ -640,11 +640,14 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
ToolOptions opt = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY); ToolOptions opt = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
opt.registerOption(OptionsGui.FLOW_ARROW_NON_ACTIVE.getColorOptionName(), opt.registerOption(OptionsGui.FLOW_ARROW_NON_ACTIVE.getColorOptionName(),
OptionsGui.FLOW_ARROW_NON_ACTIVE.getDefaultColor(), null, null); OptionsGui.FLOW_ARROW_NON_ACTIVE.getDefaultColor(), null,
"The color for an arrow with no endpoint at the current address");
opt.registerOption(OptionsGui.FLOW_ARROW_ACTIVE.getColorOptionName(), opt.registerOption(OptionsGui.FLOW_ARROW_ACTIVE.getColorOptionName(),
OptionsGui.FLOW_ARROW_ACTIVE.getDefaultColor(), null, null); OptionsGui.FLOW_ARROW_ACTIVE.getDefaultColor(), null,
"The color for an arrow with an endpoint at the current address");
opt.registerOption(OptionsGui.FLOW_ARROW_SELECTED.getColorOptionName(), opt.registerOption(OptionsGui.FLOW_ARROW_SELECTED.getColorOptionName(),
OptionsGui.FLOW_ARROW_SELECTED.getDefaultColor(), null, null); OptionsGui.FLOW_ARROW_SELECTED.getDefaultColor(), null,
"The color for an arrow that has been selected by the user");
Color c = opt.getColor(OptionsGui.BACKGROUND.getColorOptionName(), Color c = opt.getColor(OptionsGui.BACKGROUND.getColorOptionName(),
OptionsGui.BACKGROUND.getDefaultColor()); OptionsGui.BACKGROUND.getDefaultColor());

View file

@ -20,9 +20,12 @@ import ghidra.framework.options.OptionsChangeListener;
import ghidra.framework.options.ToolOptions; import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.OptionsService; import ghidra.framework.plugintool.util.OptionsService;
import ghidra.util.HelpLocation;
public class NavigationOptions implements OptionsChangeListener { public class NavigationOptions implements OptionsChangeListener {
static final String NAVIGATION_TOPIC = "Navigation";
static final String NAVIGATION_OPTIONS = GhidraOptions.NAVIGATION_OPTIONS; static final String NAVIGATION_OPTIONS = GhidraOptions.NAVIGATION_OPTIONS;
static final String NAVIGATION_RANGE_OPTION = GhidraOptions.NAVIGATION_RANGE_OPTION; static final String NAVIGATION_RANGE_OPTION = GhidraOptions.NAVIGATION_RANGE_OPTION;
@ -51,7 +54,7 @@ public class NavigationOptions implements OptionsChangeListener {
static final String EXTERNAL_NAVIGATION_OPTION = GhidraOptions.EXTERNAL_NAVIGATION_OPTION; static final String EXTERNAL_NAVIGATION_OPTION = GhidraOptions.EXTERNAL_NAVIGATION_OPTION;
static final String EXTERNAL_NAVIGATION_DESCRIPTION = static final String EXTERNAL_NAVIGATION_DESCRIPTION =
"Determines the bahavior for navigation to external symbols and references. " + "Determines the behavior for navigation to external symbols and references. " +
"By default, navigating to an external will attempt to navigate within the " + "By default, navigating to an external will attempt to navigate within the " +
"current program to the first linkage reference (pointer or thunk). " + "current program to the first linkage reference (pointer or thunk). " +
"Alternatively, if an external program has been associated with an " + "Alternatively, if an external program has been associated with an " +
@ -78,12 +81,12 @@ public class NavigationOptions implements OptionsChangeListener {
GhidraOptions.FOLLOW_INDIRECTION_NAVIGATION_OPTION; GhidraOptions.FOLLOW_INDIRECTION_NAVIGATION_OPTION;
static final String FOLLOW_INDIRECTION_NAVIGATION_DESCRIPTION = static final String FOLLOW_INDIRECTION_NAVIGATION_DESCRIPTION =
"Determines the bahavior for navigation on indirect flow references. " + "Determines the behavior for navigation on indirect flow references. " +
"By default, this option is disabled providing navigation to the " + "By default, this option is disabled providing navigation to the " +
"referenced pointer data. If enabled, the pointer will be followed " + "referenced pointer data. If enabled, the pointer will be followed " +
"to its referenced destination if contained within the program's memory."; "to its referenced destination if contained within the program's memory.";
static final String ASSUME_CURRENT_ADDRESS_SPACE = "Prefer current Address Space"; static final String ASSUME_CURRENT_ADDRESS_SPACE = "Prefer Current Address Space";
private static final String ASSUME_CURRENT_ADDRESS_SPACE_DESCRIPTION = private static final String ASSUME_CURRENT_ADDRESS_SPACE_DESCRIPTION =
"Determines if the 'Go To' action prefers the current address space when entering address offsets. " + "Determines if the 'Go To' action prefers the current address space when entering address offsets. " +
"For example, if your program has multiple address spaces such as 'RAM' or 'DATA' and you " + "For example, if your program has multiple address spaces such as 'RAM' or 'DATA' and you " +
@ -92,7 +95,7 @@ public class NavigationOptions implements OptionsChangeListener {
"cursor location. Otherwise, it will show a list of possible addresses for the given offset. " + "cursor location. Otherwise, it will show a list of possible addresses for the given offset. " +
"The default is on for this option."; "The default is on for this option.";
private final String RESTRICT_GOTO_CURRENT_TAB = "'Go To' in current program only"; private final String RESTRICT_GOTO_CURRENT_TAB = "'Go To' in Current Program Only";
private static final String RESTRICT_GOTO_CURRENT_TAB_DESCRIPTION = "Determines if the " + private static final String RESTRICT_GOTO_CURRENT_TAB_DESCRIPTION = "Determines if the " +
"'Go To' service will only search for and navigate to labels in the current program. " + "'Go To' service will only search for and navigate to labels in the current program. " +
"If this option is off and the search label is not found in the current program, the " + "If this option is off and the search label is not found in the current program, the " +
@ -120,32 +123,33 @@ public class NavigationOptions implements OptionsChangeListener {
this.options = options; this.options = options;
HelpLocation help = new HelpLocation(NAVIGATION_TOPIC, "Navigation_Options");
options.registerOption(NavigationOptions.NAVIGATION_RANGE_OPTION, options.registerOption(NavigationOptions.NAVIGATION_RANGE_OPTION,
RangeNavigationEnum.TopOfRangeOnly, null, RangeNavigationEnum.TopOfRangeOnly, help,
NavigationOptions.NAVIGATION_RANGE_DESCRIPTION); NavigationOptions.NAVIGATION_RANGE_DESCRIPTION);
RangeNavigationEnum rangeNavigationOption = options.getEnum( RangeNavigationEnum rangeNavigationOption = options.getEnum(
NavigationOptions.NAVIGATION_RANGE_OPTION, RangeNavigationEnum.TopOfRangeOnly); NavigationOptions.NAVIGATION_RANGE_OPTION, RangeNavigationEnum.TopOfRangeOnly);
gotoTopAndBottom = (rangeNavigationOption == RangeNavigationEnum.TopAndBottomOfRange); gotoTopAndBottom = (rangeNavigationOption == RangeNavigationEnum.TopAndBottomOfRange);
options.registerOption(NavigationOptions.EXTERNAL_NAVIGATION_OPTION, options.registerOption(NavigationOptions.EXTERNAL_NAVIGATION_OPTION,
ExternalNavigationEnum.NavigateToLinkage, null, ExternalNavigationEnum.NavigateToLinkage, help,
NavigationOptions.EXTERNAL_NAVIGATION_DESCRIPTION); NavigationOptions.EXTERNAL_NAVIGATION_DESCRIPTION);
ExternalNavigationEnum externalNavigationOption = options.getEnum( ExternalNavigationEnum externalNavigationOption = options.getEnum(
NavigationOptions.EXTERNAL_NAVIGATION_OPTION, ExternalNavigationEnum.NavigateToLinkage); NavigationOptions.EXTERNAL_NAVIGATION_OPTION, ExternalNavigationEnum.NavigateToLinkage);
gotoExternalProgram = gotoExternalProgram =
(externalNavigationOption == ExternalNavigationEnum.NavigateToExternalProgram); (externalNavigationOption == ExternalNavigationEnum.NavigateToExternalProgram);
options.registerOption(NavigationOptions.FOLLOW_INDIRECTION_NAVIGATION_OPTION, false, null, options.registerOption(NavigationOptions.FOLLOW_INDIRECTION_NAVIGATION_OPTION, false, help,
NavigationOptions.FOLLOW_INDIRECTION_NAVIGATION_DESCRIPTION); NavigationOptions.FOLLOW_INDIRECTION_NAVIGATION_DESCRIPTION);
followIndirectReferences = followIndirectReferences =
options.getBoolean(NavigationOptions.FOLLOW_INDIRECTION_NAVIGATION_OPTION, false); options.getBoolean(NavigationOptions.FOLLOW_INDIRECTION_NAVIGATION_OPTION, false);
options.registerOption(ASSUME_CURRENT_ADDRESS_SPACE, true, null, options.registerOption(ASSUME_CURRENT_ADDRESS_SPACE, true, help,
ASSUME_CURRENT_ADDRESS_SPACE_DESCRIPTION); ASSUME_CURRENT_ADDRESS_SPACE_DESCRIPTION);
preferCurrentAddressSpace = options.getBoolean(ASSUME_CURRENT_ADDRESS_SPACE, true); preferCurrentAddressSpace = options.getBoolean(ASSUME_CURRENT_ADDRESS_SPACE, true);
options.registerOption(RESTRICT_GOTO_CURRENT_TAB, true, null, options.registerOption(RESTRICT_GOTO_CURRENT_TAB, true, help,
RESTRICT_GOTO_CURRENT_TAB_DESCRIPTION); RESTRICT_GOTO_CURRENT_TAB_DESCRIPTION);
restrictGotoToCurrentProgram = options.getBoolean(RESTRICT_GOTO_CURRENT_TAB, true); restrictGotoToCurrentProgram = options.getBoolean(RESTRICT_GOTO_CURRENT_TAB, true);
@ -158,7 +162,7 @@ public class NavigationOptions implements OptionsChangeListener {
} }
@Override @Override
public void optionsChanged(ToolOptions options, String optionName, Object oldValue, public void optionsChanged(ToolOptions toolOptions, String optionName, Object oldValue,
Object newValue) { Object newValue) {
if (NavigationOptions.NAVIGATION_RANGE_OPTION.equals(optionName)) { if (NavigationOptions.NAVIGATION_RANGE_OPTION.equals(optionName)) {
RangeNavigationEnum rangeNavigationOption = (RangeNavigationEnum) newValue; RangeNavigationEnum rangeNavigationOption = (RangeNavigationEnum) newValue;

View file

@ -401,9 +401,10 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener,
"Toggles highlight search results"); "Toggles highlight search results");
opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_COLOR_NAME, opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_COLOR_NAME,
PluginConstants.SEARCH_HIGHLIGHT_COLOR, null, null); PluginConstants.SEARCH_HIGHLIGHT_COLOR, null, "The search result highlight color");
opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_CURRENT_COLOR_NAME, opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_CURRENT_COLOR_NAME,
PluginConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR, null, null); PluginConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR, null,
"The search result highlight color for the currently selected match");
opt.addOptionsChangeListener(this); opt.addOptionsChangeListener(this);

View file

@ -61,7 +61,7 @@ public class AddressFieldFactory extends FieldFactory {
/** /**
* Constructor * Constructor
* @param model the model that the field belongs to. * @param model the model that the field belongs to.
* @param hsProvider the HightLightStringProvider. * @param hlProvider the HightLightStringProvider.
* @param displayOptions the Options for display properties. * @param displayOptions the Options for display properties.
* @param fieldOptions the Options for field specific properties. * @param fieldOptions the Options for field specific properties.
*/ */
@ -75,7 +75,8 @@ public class AddressFieldFactory extends FieldFactory {
HelpLocation helpLoc = new HelpLocation("CodeBrowserPlugin", "Address_Field"); HelpLocation helpLoc = new HelpLocation("CodeBrowserPlugin", "Address_Field");
fieldOptions.registerOption(ADDRESS_DISPLAY_OPTIONS_NAME, OptionType.CUSTOM_TYPE, fieldOptions.registerOption(ADDRESS_DISPLAY_OPTIONS_NAME, OptionType.CUSTOM_TYPE,
new AddressFieldOptionsWrappedOption(), helpLoc, null, addressFieldOptionsEditor); new AddressFieldOptionsWrappedOption(), helpLoc, "Adjusts the Address Field display",
addressFieldOptionsEditor);
CustomOption customOption = CustomOption customOption =
fieldOptions.getCustomOption(ADDRESS_DISPLAY_OPTIONS_NAME, null); fieldOptions.getCustomOption(ADDRESS_DISPLAY_OPTIONS_NAME, null);
@ -204,9 +205,9 @@ public class AddressFieldFactory extends FieldFactory {
@Override @Override
public FieldFactory newInstance(FieldFormatModel newModel, public FieldFactory newInstance(FieldFormatModel newModel,
HighlightProvider highlightStringProvider, ToolOptions displayOptions, HighlightProvider highlightStringProvider, ToolOptions toolOptions,
ToolOptions fieldOptions) { ToolOptions fieldOptions) {
return new AddressFieldFactory(newModel, highlightStringProvider, displayOptions, return new AddressFieldFactory(newModel, highlightStringProvider, toolOptions,
fieldOptions); fieldOptions);
} }
} }

View file

@ -43,16 +43,16 @@ public class ArrayValuesFieldFactory extends FieldFactory {
@Override @Override
public FieldFactory newInstance(FieldFormatModel formatModel, public FieldFactory newInstance(FieldFormatModel formatModel,
HighlightProvider highlightProvider, ToolOptions displayOptions, HighlightProvider highlightProvider, ToolOptions toolOptions,
ToolOptions fieldOptions) { ToolOptions fieldOptions) {
return new ArrayValuesFieldFactory(formatModel, highlightProvider, displayOptions, return new ArrayValuesFieldFactory(formatModel, highlightProvider, toolOptions,
fieldOptions); fieldOptions);
} }
/** /**
* Constructor * Constructor
* @param model the model that the field belongs to. * @param model the model that the field belongs to.
* @param hsProvider the HightLightStringProvider. * @param hlProvider the HightLightStringProvider.
* @param displayOptions the Options for display properties. * @param displayOptions the Options for display properties.
* @param fieldOptions the Options for field specific properties. * @param fieldOptions the Options for field specific properties.
*/ */
@ -65,7 +65,8 @@ public class ArrayValuesFieldFactory extends FieldFactory {
private void setupOptions(Options fieldOptions) { private void setupOptions(Options fieldOptions) {
// we need to install a custom editor that allows us to edit a group of related options // we need to install a custom editor that allows us to edit a group of related options
fieldOptions.registerOption(FormatManager.ARRAY_DISPLAY_OPTIONS, OptionType.CUSTOM_TYPE, fieldOptions.registerOption(FormatManager.ARRAY_DISPLAY_OPTIONS, OptionType.CUSTOM_TYPE,
new ArrayElementWrappedOption(), null, null, arrayOptionsEditor); new ArrayElementWrappedOption(), null, FormatManager.ARRAY_DISPLAY_DESCRIPTION,
arrayOptionsEditor);
CustomOption wrappedOption = fieldOptions.getCustomOption( CustomOption wrappedOption = fieldOptions.getCustomOption(
FormatManager.ARRAY_DISPLAY_OPTIONS, new ArrayElementWrappedOption()); FormatManager.ARRAY_DISPLAY_OPTIONS, new ArrayElementWrappedOption());
@ -162,9 +163,6 @@ public class ArrayValuesFieldFactory extends FieldFactory {
return (category == FieldFormatModel.ARRAY); return (category == FieldFormatModel.ARRAY);
} }
/**
* @see ghidra.app.util.viewer.field.FieldFactory#fieldOptionsChanged(ghidra.framework.options.ToolOptions, java.lang.String, java.lang.Object, java.lang.Object)
*/
@Override @Override
public void fieldOptionsChanged(Options options, String optionName, Object oldValue, public void fieldOptionsChanged(Options options, String optionName, Object oldValue,
Object newValue) { Object newValue) {

View file

@ -76,6 +76,8 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
*/ */
private final static String NAMESPACE_OPTIONS = private final static String NAMESPACE_OPTIONS =
GhidraOptions.OPERAND_GROUP_TITLE + Options.DELIMITER + "Display Namespace"; GhidraOptions.OPERAND_GROUP_TITLE + Options.DELIMITER + "Display Namespace";
private static final String NAMESPACE_OPTIONS_DESCRIPTIONS =
"Adjusts the Operands Field namespace display";
/** /**
* Option which controls the display of data mutability in the mnemonic representation * Option which controls the display of data mutability in the mnemonic representation
@ -106,7 +108,8 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
if (!exists) { if (!exists) {
fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE, fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE,
new NamespaceWrappedOption(), null, null, new NamespacePropertyEditor()); new NamespaceWrappedOption(), null, NAMESPACE_OPTIONS_DESCRIPTIONS,
new NamespacePropertyEditor());
HelpLocation hl = new HelpLocation("CodeBrowserPlugin", "Operands_Field"); HelpLocation hl = new HelpLocation("CodeBrowserPlugin", "Operands_Field");
fieldOptions.getOptions(GhidraOptions.OPERAND_GROUP_TITLE).setOptionsHelpLocation(hl); fieldOptions.getOptions(GhidraOptions.OPERAND_GROUP_TITLE).setOptionsHelpLocation(hl);
@ -157,7 +160,8 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
private void updateFormat() { private void updateFormat() {
fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE, fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE,
new NamespaceWrappedOption(), null, null, new NamespacePropertyEditor()); new NamespaceWrappedOption(), null, NAMESPACE_OPTIONS_DESCRIPTIONS,
new NamespacePropertyEditor());
CustomOption customOption = CustomOption customOption =
fieldOptions.getCustomOption(NAMESPACE_OPTIONS, new NamespaceWrappedOption()); fieldOptions.getCustomOption(NAMESPACE_OPTIONS, new NamespaceWrappedOption());
if (!(customOption instanceof NamespaceWrappedOption)) { if (!(customOption instanceof NamespaceWrappedOption)) {
@ -208,7 +212,7 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
/** /**
* Add format change listener. * Add format change listener.
* Listeners will only be notified if autoUpdate was true when instantiated. * Listeners will only be notified if autoUpdate was true when instantiated.
* @param listener * @param listener the listener
*/ */
public void addChangeListener(ChangeListener listener) { public void addChangeListener(ChangeListener listener) {
listeners.add(listener); listeners.add(listener);
@ -216,7 +220,7 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
/** /**
* Remove format change listener * Remove format change listener
* @param listener * @param listener the listener
*/ */
public void removeChangeListener(ChangeListener listener) { public void removeChangeListener(ChangeListener listener) {
listeners.remove(listener); listeners.remove(listener);

View file

@ -87,10 +87,11 @@ public abstract class FieldFactory implements ExtensionPoint {
baseFont = SystemUtilities.adjustForFontSizeOverride( baseFont = SystemUtilities.adjustForFontSizeOverride(
displayOptions.getFont(FONT_OPTION_NAME, DEFAULT_FIELD_FONT)); displayOptions.getFont(FONT_OPTION_NAME, DEFAULT_FIELD_FONT));
// For most fields (defined in optionsGui) these will be set. But "ad hoc" fields won't, // For most fields (defined in optionsGui) these will be set. But "ad hoc" fields won't,
//so register something. A second registration won't change the original // so register something. A second registration won't change the original
displayOptions.registerOption(colorOptionName, Color.BLACK, null, null); displayOptions.registerOption(colorOptionName, Color.BLACK, null,
displayOptions.registerOption(styleOptionName, -1, null, null); "Sets the " + colorOptionName);
displayOptions.registerOption(styleOptionName, -1, null, "Sets the " + style);
color = displayOptions.getColor(colorOptionName, getDefaultColor()); color = displayOptions.getColor(colorOptionName, getDefaultColor());
style = displayOptions.getInt(styleOptionName, -1); style = displayOptions.getInt(styleOptionName, -1);

View file

@ -81,7 +81,7 @@ public class LabelFieldFactory extends FieldFactory {
/** /**
* Constructor * Constructor
* @param model the model that the field belongs to. * @param model the model that the field belongs to.
* @param hsProvider the HightLightStringProvider. * @param hlProvider the HightLightStringProvider.
* @param displayOptions the Options for display properties. * @param displayOptions the Options for display properties.
* @param fieldOptions the Options for field specific properties. * @param fieldOptions the Options for field specific properties.
*/ */
@ -116,7 +116,8 @@ public class LabelFieldFactory extends FieldFactory {
private void setupNamespaceOptions(Options fieldOptions) { private void setupNamespaceOptions(Options fieldOptions) {
// we need to install a custom editor that allows us to edit a group of related options // we need to install a custom editor that allows us to edit a group of related options
fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE, fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE,
new NamespaceWrappedOption(), null, null, namespaceOptionsEditor); new NamespaceWrappedOption(), null, "Adjusts the Label Field namespace display",
namespaceOptionsEditor);
CustomOption wrappedOption = CustomOption wrappedOption =
fieldOptions.getCustomOption(NAMESPACE_OPTIONS, new NamespaceWrappedOption()); fieldOptions.getCustomOption(NAMESPACE_OPTIONS, new NamespaceWrappedOption());
if (!(wrappedOption instanceof NamespaceWrappedOption)) { if (!(wrappedOption instanceof NamespaceWrappedOption)) {
@ -406,8 +407,7 @@ public class LabelFieldFactory extends FieldFactory {
text = SymbolUtilities.getDynamicOffcutName(addr); text = SymbolUtilities.getDynamicOffcutName(addr);
} }
// since these labels are fictitious, they don't have a namespace. // since these labels are fictitious, they don't have a namespace.
return new LabelFieldLocation(cu.getProgram(), addr, cpath, text, null, row, return new LabelFieldLocation(cu.getProgram(), addr, cpath, text, null, row, col);
col);
} }
@Override @Override

View file

@ -654,11 +654,11 @@ public class PlateFieldFactory extends FieldFactory {
"Number of lines to displayed before a plate comment." + "Number of lines to displayed before a plate comment." +
" This setting has precedence over Lines Before Labels."); " This setting has precedence over Lines Before Labels.");
help = new HelpLocation(HelpTopics.CODE_BROWSER, "Function_Pointers");
options.registerOption(ListingModel.DISPLAY_EXTERNAL_FUNCTION_POINTER_OPTION_NAME, true, options.registerOption(ListingModel.DISPLAY_EXTERNAL_FUNCTION_POINTER_OPTION_NAME, true,
help, null); help, "Shows/hides function header format for pointers to external functions");
options.registerOption(ListingModel.DISPLAY_NONEXTERNAL_FUNCTION_POINTER_OPTION_NAME, false, options.registerOption(ListingModel.DISPLAY_NONEXTERNAL_FUNCTION_POINTER_OPTION_NAME, false,
help, null); help, "Shows/hides function header format for pointers to non-external functions");
} }
//================================================================================================== //==================================================================================================

View file

@ -85,7 +85,7 @@ public class PostCommentFieldFactory extends FieldFactory {
/** /**
* Constructor * Constructor
* @param model the model that the field belongs to. * @param model the model that the field belongs to.
* @param hsProvider the HightLightStringProvider. * @param hlProvider the HightLightStringProvider.
* @param displayOptions the Options for display properties. * @param displayOptions the Options for display properties.
* @param fieldOptions the Options for field specific properties. * @param fieldOptions the Options for field specific properties.
*/ */
@ -93,9 +93,12 @@ public class PostCommentFieldFactory extends FieldFactory {
Options displayOptions, Options fieldOptions) { Options displayOptions, Options fieldOptions) {
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions); super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
fieldOptions.registerOption(FLAG_FUNCTION_EXIT_OPTION, false, null, null); fieldOptions.registerOption(FLAG_FUNCTION_EXIT_OPTION, false, null,
fieldOptions.registerOption(FLAG_TERMINATOR_OPTION, false, null, null); "Toggles the display of a post-comment for a function exit");
fieldOptions.registerOption(LINES_AFTER_BLOCKS_OPTION, 0, null, null); fieldOptions.registerOption(FLAG_TERMINATOR_OPTION, false, null,
"Toggles the display of a jump/return post-comments");
fieldOptions.registerOption(LINES_AFTER_BLOCKS_OPTION, 0, null,
"The number of lines to display after basic blocks");
flagFunctionExits = fieldOptions.getBoolean(FLAG_FUNCTION_EXIT_OPTION, false); flagFunctionExits = fieldOptions.getBoolean(FLAG_FUNCTION_EXIT_OPTION, false);
flagJMPsRETs = fieldOptions.getBoolean(FLAG_TERMINATOR_OPTION, false); flagJMPsRETs = fieldOptions.getBoolean(FLAG_TERMINATOR_OPTION, false);
@ -226,9 +229,8 @@ public class PostCommentFieldFactory extends FieldFactory {
comments.addFirst(callOtherCallOverrideComment); comments.addFirst(callOtherCallOverrideComment);
} }
else { else {
overrideData = overrideData = getOverrideCommentData(instr, RefType.CALLOTHER_OVERRIDE_JUMP,
getOverrideCommentData(instr, RefType.CALLOTHER_OVERRIDE_JUMP, pcodeOps, pcodeOps, pCodeOverride);
pCodeOverride);
if (overrideData != null) { if (overrideData != null) {
String callOtherJumpOverrideComment = String callOtherJumpOverrideComment =
"-- CALLOTHER(" + overrideData.getOverriddenCallOther() + "-- CALLOTHER(" + overrideData.getOverriddenCallOther() +
@ -313,8 +315,8 @@ public class PostCommentFieldFactory extends FieldFactory {
@Override @Override
public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider, public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider,
ToolOptions displayOptions, ToolOptions fieldOptions) { ToolOptions toolOptions, ToolOptions fieldOptions) {
return new PostCommentFieldFactory(formatModel, provider, displayOptions, fieldOptions); return new PostCommentFieldFactory(formatModel, provider, toolOptions, fieldOptions);
} }
@Override @Override
@ -525,7 +527,8 @@ public class PostCommentFieldFactory extends FieldFactory {
"at a jump or a return instruction."); "at a jump or a return instruction.");
options.registerOption(LINES_AFTER_BLOCKS_OPTION, 0, null, options.registerOption(LINES_AFTER_BLOCKS_OPTION, 0, null,
"Number of lines to display in the post comment after a code block."); "Number of lines to display in the post comment after a code block.");
options.registerOption(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, true, null, null); options.registerOption(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, true, null,
"Toggles the display of the automatic post-comment");
isWordWrap = options.getBoolean(ENABLE_WORD_WRAP_MSG, false); isWordWrap = options.getBoolean(ENABLE_WORD_WRAP_MSG, false);
alwaysShowAutomatic = options.getBoolean(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, true); alwaysShowAutomatic = options.getBoolean(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, true);
@ -557,6 +560,7 @@ public class PostCommentFieldFactory extends FieldFactory {
return next; return next;
} }
catch (AddressOverflowException e) { catch (AddressOverflowException e) {
// don't care
} }
return null; return null;
} }

View file

@ -77,17 +77,18 @@ public class PreCommentFieldFactory extends FieldFactory {
/** /**
* Constructor * Constructor
* @param model the model that the field belongs to. * @param model the model that the field belongs to.
* @param hsProvider the HightLightStringProvider. * @param hlProvider the HightLightStringProvider.
* @param displayOptions the Options for display properties. * @param displayOptions the Options for display properties.
* @param fieldOptions the Options for field specific properties. * @param fieldOptions the Options for field specific properties.
* @param serviceProvider the provider for services.
*/ */
private PreCommentFieldFactory(FieldFormatModel model, HighlightProvider hlProvider, private PreCommentFieldFactory(FieldFormatModel model, HighlightProvider hlProvider,
Options displayOptions, Options fieldOptions) { Options displayOptions, Options fieldOptions) {
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions); super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
fieldOptions.registerOption(FLAG_FUNCTION_ENTRY_OPTION, false, null, null); fieldOptions.registerOption(FLAG_FUNCTION_ENTRY_OPTION, false, null,
fieldOptions.registerOption(FLAG_SUBROUTINE_ENTRY_OPTION, false, null, null); "Toggles the display of a pre-comment for a function entry");
fieldOptions.registerOption(FLAG_SUBROUTINE_ENTRY_OPTION, false, null,
"Toggles the display of a pre-comment for a sub-routine entry");
flagFunctionEntry = fieldOptions.getBoolean(FLAG_FUNCTION_ENTRY_OPTION, false); flagFunctionEntry = fieldOptions.getBoolean(FLAG_FUNCTION_ENTRY_OPTION, false);
flagSubroutineEntry = fieldOptions.getBoolean(FLAG_SUBROUTINE_ENTRY_OPTION, false); flagSubroutineEntry = fieldOptions.getBoolean(FLAG_SUBROUTINE_ENTRY_OPTION, false);
@ -183,8 +184,8 @@ public class PreCommentFieldFactory extends FieldFactory {
@Override @Override
public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider, public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider,
ToolOptions displayOptions, ToolOptions fieldOptions) { ToolOptions toolOptions, ToolOptions fieldOptions) {
return new PreCommentFieldFactory(formatModel, provider, displayOptions, fieldOptions); return new PreCommentFieldFactory(formatModel, provider, toolOptions, fieldOptions);
} }
@Override @Override
@ -379,7 +380,8 @@ public class PreCommentFieldFactory extends FieldFactory {
"wrapping is off, comments are displayed in line format " + "wrapping is off, comments are displayed in line format " +
"however the user entered them. Lines that are too long " + "however the user entered them. Lines that are too long " +
"for the field, are truncated."); "for the field, are truncated.");
options.registerOption(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, true, null, null); options.registerOption(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, true, null,
"Toggles the display of the automatic pre-comment");
isWordWrap = options.getBoolean(ENABLE_WORD_WRAP_MSG, false); isWordWrap = options.getBoolean(ENABLE_WORD_WRAP_MSG, false);
alwaysShowAutomatic = options.getBoolean(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, true); alwaysShowAutomatic = options.getBoolean(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, true);

View file

@ -63,7 +63,8 @@ public class RegisterFieldFactory extends FieldFactory {
fieldOptions.registerOption(DISPLAY_HIDDEN_REGISTERS_OPTION_NAME, false, null, fieldOptions.registerOption(DISPLAY_HIDDEN_REGISTERS_OPTION_NAME, false, null,
"Shows/hides context registers"); "Shows/hides context registers");
fieldOptions.registerOption(DISPLAY_DEFAULT_REGISTER_VALUES_OPTION_NAME, false, null, null); fieldOptions.registerOption(DISPLAY_DEFAULT_REGISTER_VALUES_OPTION_NAME, false, null,
"Shows/hides default register values");
regColor = regColor =
displayOptions.getColor(OptionsGui.REGISTERS.getColorOptionName(), getDefaultColor()); displayOptions.getColor(OptionsGui.REGISTERS.getColorOptionName(), getDefaultColor());
@ -74,10 +75,9 @@ public class RegisterFieldFactory extends FieldFactory {
@Override @Override
public FieldFactory newInstance(FieldFormatModel formatModel, public FieldFactory newInstance(FieldFormatModel formatModel,
HighlightProvider highlightProvider, ToolOptions displayOptions, HighlightProvider highlightProvider, ToolOptions toolOptions,
ToolOptions fieldOptions) { ToolOptions fieldOptions) {
return new RegisterFieldFactory(formatModel, highlightProvider, displayOptions, return new RegisterFieldFactory(formatModel, highlightProvider, toolOptions, fieldOptions);
fieldOptions);
} }
@Override @Override

View file

@ -173,7 +173,8 @@ public class XRefFieldFactory extends FieldFactory {
private void setupNamespaceOptions(Options fieldOptions) { private void setupNamespaceOptions(Options fieldOptions) {
// we need to install a custom editor that allows us to edit a group of related options // we need to install a custom editor that allows us to edit a group of related options
fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE, fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE,
new NamespaceWrappedOption(), null, null, namespaceOptionsEditor); new NamespaceWrappedOption(), null, "Adjusts the XREFs Field namespace display",
namespaceOptionsEditor);
CustomOption customOption = fieldOptions.getCustomOption(NAMESPACE_OPTIONS, null); CustomOption customOption = fieldOptions.getCustomOption(NAMESPACE_OPTIONS, null);
fieldOptions.getOptions(NAMESPACE_OPTIONS).setOptionsHelpLocation( fieldOptions.getOptions(NAMESPACE_OPTIONS).setOptionsHelpLocation(
new HelpLocation("CodeBrowserPlugin", "XREFs_Field")); new HelpLocation("CodeBrowserPlugin", "XREFs_Field"));
@ -529,6 +530,7 @@ public class XRefFieldFactory extends FieldFactory {
* Get an address location for this object. * Get an address location for this object.
* *
* @param obj object to get location from * @param obj object to get location from
* @return the address
*/ */
protected Address getXRefLocation(Object obj) { protected Address getXRefLocation(Object obj) {
if (obj == null || !(obj instanceof CodeUnit)) { if (obj == null || !(obj instanceof CodeUnit)) {
@ -556,7 +558,7 @@ public class XRefFieldFactory extends FieldFactory {
@Override @Override
public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider, public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider,
ToolOptions displayOptions, ToolOptions fieldOptions) { ToolOptions toolOptions, ToolOptions fieldOptions) {
return new XRefFieldFactory(formatModel, provider, displayOptions, fieldOptions); return new XRefFieldFactory(formatModel, provider, toolOptions, fieldOptions);
} }
} }

View file

@ -45,6 +45,7 @@ public class FormatManager implements OptionsChangeListener {
HIGHLIGHT_GROUP + Options.DELIMITER + "Alternate Highlight Color"; HIGHLIGHT_GROUP + Options.DELIMITER + "Alternate Highlight Color";
public final static String ARRAY_DISPLAY_OPTIONS = public final static String ARRAY_DISPLAY_OPTIONS =
OPTIONS_GROUP + Options.DELIMITER + "Array Display Options"; OPTIONS_GROUP + Options.DELIMITER + "Array Display Options";
public final static String ARRAY_DISPLAY_DESCRIPTION = "Adjusts the Array Field display";
private static final int NUM_MODELS = 7; private static final int NUM_MODELS = 7;
@ -94,7 +95,8 @@ public class FormatManager implements OptionsChangeListener {
private void getArrayDisplayOptions(Options options) { private void getArrayDisplayOptions(Options options) {
options.registerOption(ARRAY_DISPLAY_OPTIONS, OptionType.CUSTOM_TYPE, options.registerOption(ARRAY_DISPLAY_OPTIONS, OptionType.CUSTOM_TYPE,
new ArrayElementWrappedOption(), null, null, new ArrayElementPropertyEditor()); new ArrayElementWrappedOption(), null, ARRAY_DISPLAY_DESCRIPTION,
new ArrayElementPropertyEditor());
CustomOption option = options.getCustomOption(ARRAY_DISPLAY_OPTIONS, null); CustomOption option = options.getCustomOption(ARRAY_DISPLAY_OPTIONS, null);
if (option instanceof ArrayElementWrappedOption) { if (option instanceof ArrayElementWrappedOption) {
ArrayElementWrappedOption arrayOption = (ArrayElementWrappedOption) option; ArrayElementWrappedOption arrayOption = (ArrayElementWrappedOption) option;

View file

@ -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,13 +15,13 @@
*/ */
package ghidra.app.util.viewer.listingpanel; package ghidra.app.util.viewer.listingpanel;
import docking.widgets.fieldpanel.Layout;
import ghidra.app.util.viewer.format.FormatManager; import ghidra.app.util.viewer.format.FormatManager;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import docking.widgets.fieldpanel.Layout;
public interface ListingModel { public interface ListingModel {
@ -30,10 +29,10 @@ public interface ListingModel {
public static final String DISPLAY_EXTERNAL_FUNCTION_POINTER_OPTION_NAME = public static final String DISPLAY_EXTERNAL_FUNCTION_POINTER_OPTION_NAME =
FUNCTION_POINTER_OPTION_GROUP_NAME + Options.DELIMITER + FUNCTION_POINTER_OPTION_GROUP_NAME + Options.DELIMITER +
"Display Function Header for External Function Pointers"; "Display External Function Pointer Header";
public static final String DISPLAY_NONEXTERNAL_FUNCTION_POINTER_OPTION_NAME = public static final String DISPLAY_NONEXTERNAL_FUNCTION_POINTER_OPTION_NAME =
FUNCTION_POINTER_OPTION_GROUP_NAME + Options.DELIMITER + FUNCTION_POINTER_OPTION_GROUP_NAME + Options.DELIMITER +
"Display Function Header for Non-External Function Pointers"; "Display Non-External Function Pointer Header";
public AddressSetView getAddressSet(); public AddressSetView getAddressSet();

View file

@ -69,11 +69,6 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
} }
private void initOptions() { private void initOptions() {
fieldOptions.registerOption(DISPLAY_EXTERNAL_FUNCTION_POINTER_OPTION_NAME, true, null,
"Shows/hides function header format for pointers to external functions");
fieldOptions.registerOption(DISPLAY_NONEXTERNAL_FUNCTION_POINTER_OPTION_NAME, false, null,
"Shows/hides function header format for pointers to non-external functions");
showExternalFunctionPointerFormat = showExternalFunctionPointerFormat =
fieldOptions.getBoolean(DISPLAY_EXTERNAL_FUNCTION_POINTER_OPTION_NAME, true); fieldOptions.getBoolean(DISPLAY_EXTERNAL_FUNCTION_POINTER_OPTION_NAME, true);
showNonExternalFunctionPointerFormat = showNonExternalFunctionPointerFormat =

View file

@ -23,7 +23,6 @@ import javax.swing.JComponent;
import ghidra.GhidraOptions; import ghidra.GhidraOptions;
import ghidra.framework.options.*; import ghidra.framework.options.*;
import ghidra.framework.plugintool.Plugin;
/** /**
* Class for editing Listing display properties. * Class for editing Listing display properties.
@ -35,14 +34,11 @@ public class ListingDisplayOptionsEditor implements OptionsEditor {
private Options options; private Options options;
private PropertyChangeListener propertyChangeListener; private PropertyChangeListener propertyChangeListener;
private final Plugin ownerPlugin;
/** /**
* Constructs a new ListingDisplayOptionsEditor. * Constructs a new ListingDisplayOptionsEditor.
* @param options the options object to edit * @param options the options object to edit
*/ */
public ListingDisplayOptionsEditor(Plugin ownerPlugin, Options options) { public ListingDisplayOptionsEditor(Options options) {
this.ownerPlugin = ownerPlugin;
this.options = options; this.options = options;
registerOptions(); registerOptions();
} }
@ -56,17 +52,18 @@ public class ListingDisplayOptionsEditor implements OptionsEditor {
} }
private void registerOptions() { private void registerOptions() {
options.registerOption(GhidraOptions.OPTION_BASE_FONT, DEFAULT_FONT, null, null); String prefix = "Sets the ";
options.registerOption(GhidraOptions.OPTION_BASE_FONT, DEFAULT_FONT, null,
prefix + GhidraOptions.OPTION_BASE_FONT);
for (ScreenElement element : OptionsGui.elements) { for (ScreenElement element : OptionsGui.elements) {
options.registerOption(element.getColorOptionName(), element.getDefaultColor(), null, String colorOptionName = element.getColorOptionName();
null); options.registerOption(colorOptionName, element.getDefaultColor(), null,
options.registerOption(element.getStyleOptionName(), -1, null, null); prefix + colorOptionName);
String styleOptionName = element.getStyleOptionName();
options.registerOption(styleOptionName, -1, null, prefix + styleOptionName);
} }
} }
/**
* Apply the changes.
*/
@Override @Override
public void apply() { public void apply() {
if (optionsGui != null) { if (optionsGui != null) {
@ -105,9 +102,6 @@ public class ListingDisplayOptionsEditor implements OptionsEditor {
// nothing to do, as this component is reloaded when options are changed // nothing to do, as this component is reloaded when options are changed
} }
/**
* @see ghidra.framework.options.OptionsEditor#setOptionsPropertyChangeListener(java.beans.PropertyChangeListener)
*/
@Override @Override
public void setOptionsPropertyChangeListener(PropertyChangeListener listener) { public void setOptionsPropertyChangeListener(PropertyChangeListener listener) {
this.propertyChangeListener = listener; this.propertyChangeListener = listener;
@ -120,14 +114,12 @@ public class ListingDisplayOptionsEditor implements OptionsEditor {
/** /**
* Returns true if this component has "good" resizing behavior. Components * Returns true if this component has "good" resizing behavior. Components
* that do not have this property will be placed in a scrolled pane. * that do not have this property will be placed in a scrolled pane.
* @return true if resizable
*/ */
public boolean isResizable() { public boolean isResizable() {
return true; return true;
} }
/**
* Get the editor component.
*/
@Override @Override
public JComponent getEditorComponent(Options editableOptions, public JComponent getEditorComponent(Options editableOptions,
EditorStateFactory editorStateFactory) { EditorStateFactory editorStateFactory) {

View file

@ -15,11 +15,11 @@
*/ */
package ghidra.app.plugin.core.codebrowser; package ghidra.app.plugin.core.codebrowser;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import org.junit.*; import org.junit.*;
@ -45,6 +45,8 @@ import ghidra.program.model.symbol.SourceType;
import ghidra.program.util.BytesFieldLocation; import ghidra.program.util.BytesFieldLocation;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv; import ghidra.test.TestEnv;
import ghidra.util.HelpLocation;
import util.CollectionUtils;
public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest { public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env; private TestEnv env;
@ -969,6 +971,38 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
assertTrue(btf.getText().endsWith("[more]")); assertTrue(btf.getText().endsWith("[more]"));
} }
@Test
public void testEveryOptionHasHelp() throws Exception {
showTool(tool);
List<String> missing = new ArrayList<>();
ToolOptions[] toolOptions = tool.getOptions();
for (ToolOptions options : toolOptions) {
HelpLocation helpLocation = options.getOptionsHelpLocation();
if (helpLocation != null) {
continue; // this is a top-level help location for all sub-options
}
if (CollectionUtils.isOneOf(options.getName(), "Key Bindings", "Listing Display")) {
continue;
}
List<String> optionNames = options.getOptionNames();
for (String name : optionNames) {
HelpLocation hl = options.getHelpLocation(name);
if (hl == null) {
missing.add(options.getName() + "." + name);
}
}
}
if (!missing.isEmpty()) {
fail(missing.size() + " Tool Options is missing help\n" +
missing.stream().collect(Collectors.joining("\n")));
}
}
enum DUMMY { enum DUMMY {
// nothing; just a dummy // nothing; just a dummy
} }

View file

@ -149,7 +149,7 @@ public class VTPlugin extends Plugin {
private void initializeOptions() { private void initializeOptions() {
Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY); Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
options.registerOptionsEditor(new ListingDisplayOptionsEditor(this, options)); options.registerOptionsEditor(new ListingDisplayOptionsEditor(options));
options.setOptionsHelpLocation(new HelpLocation(CodeBrowserPlugin.class.getSimpleName(), options.setOptionsHelpLocation(new HelpLocation(CodeBrowserPlugin.class.getSimpleName(),
GhidraOptions.CATEGORY_BROWSER_DISPLAY)); GhidraOptions.CATEGORY_BROWSER_DISPLAY));

View file

@ -1780,12 +1780,14 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
2) A component provider's code 2) A component provider's code
3) A dialog provider's code 3) A dialog provider's code
4) A background thread 4) A background thread
5) The help window
It seems like the parent should be the active window for 1-2. It seems like the parent should be the active window for 1-2.
Case 3 should probably use the window of the dialog provider. Case 3 should probably use the window of the dialog provider.
Case 4 should probably use the main tool frame, since the user may be Case 4 should probably use the main tool frame, since the user may be
moving between windows while the thread is working. So, rather than using the moving between windows while the thread is working. So, rather than using the
active window, we can default to the tool's frame. active window, we can default to the tool's frame.
Case 5 should use the help window.
We have not yet solidified how we should parent. This documentation is meant to We have not yet solidified how we should parent. This documentation is meant to
move us towards clarity as we find Use Cases that don't make sense. (Once we move us towards clarity as we find Use Cases that don't make sense. (Once we
@ -1828,7 +1830,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
Component c = parent; Component c = parent;
while (c != null) { while (c != null) {
if (c instanceof Frame) { if (c instanceof Window) {
return (Window) c; return (Window) c;
} }
c = c.getParent(); c = c.getParent();

View file

@ -175,7 +175,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
for (ActionData actionData : actions) { for (ActionData actionData : actions) {
if (actionData.isMyProvider(localContext)) { if (actionData.isMyProvider(localContext)) {
hasLocalActionsForKeyBinding = true; hasLocalActionsForKeyBinding = true;
if (actionData.action.isEnabledForContext(localContext)) { if (isValidAndEnabled(actionData, localContext)) {
list.add(new ExecutableKeyActionAdapter(actionData.action, localContext)); list.add(new ExecutableKeyActionAdapter(actionData.action, localContext));
} }
} }
@ -199,7 +199,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
(ComponentBasedDockingAction) actionData.action; (ComponentBasedDockingAction) actionData.action;
if (componentAction.isValidComponentContext(localContext)) { if (componentAction.isValidComponentContext(localContext)) {
hasLocalActionsForKeyBinding = true; hasLocalActionsForKeyBinding = true;
if (actionData.action.isEnabledForContext(localContext)) { if (isValidAndEnabled(actionData, localContext)) {
list.add(new ExecutableKeyActionAdapter(actionData.action, localContext)); list.add(new ExecutableKeyActionAdapter(actionData.action, localContext));
} }
} }
@ -219,21 +219,22 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
// When looking for context matches, we prefer local context, even though this // When looking for context matches, we prefer local context, even though this
// is a 'global' action. This allows more specific context to be used when // is a 'global' action. This allows more specific context to be used when
// available // available
if (actionData.action.isValidContext(localContext)) { if (isValidAndEnabled(actionData, localContext)) {
if (actionData.action.isEnabledForContext(localContext)) {
list.add(new ExecutableKeyActionAdapter(actionData.action, localContext)); list.add(new ExecutableKeyActionAdapter(actionData.action, localContext));
} }
} else if (isValidAndEnabled(actionData, globalContext)) {
else if (actionData.action.isValidGlobalContext(globalContext)) {
if (actionData.action.isEnabledForContext(globalContext)) {
list.add(new ExecutableKeyActionAdapter(actionData.action, globalContext)); list.add(new ExecutableKeyActionAdapter(actionData.action, globalContext));
} }
} }
} }
}
return list; return list;
} }
private boolean isValidAndEnabled(ActionData actionData, ActionContext localContext) {
DockingActionIf a = actionData.action;
return a.isValidContext(localContext) && a.isEnabledForContext(localContext);
}
@Override @Override
public boolean isReservedKeybindingPrecedence() { public boolean isReservedKeybindingPrecedence() {
return false; // MultipleKeyActions can never be reserved return false; // MultipleKeyActions can never be reserved

View file

@ -142,8 +142,9 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
} }
KeyStroke ks = action.getKeyBinding(); KeyStroke ks = action.getKeyBinding();
String description = "Keybinding for " + action.getFullName();
keyBindingOptions.registerOption(action.getFullName(), OptionType.KEYSTROKE_TYPE, ks, null, keyBindingOptions.registerOption(action.getFullName(), OptionType.KEYSTROKE_TYPE, ks, null,
null); description);
KeyStroke newKs = keyBindingOptions.getKeyStroke(action.getFullName(), ks); KeyStroke newKs = keyBindingOptions.getKeyStroke(action.getFullName(), ks);
if (!Objects.equals(ks, newKs)) { if (!Objects.equals(ks, newKs)) {
action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs)); action.setUnvalidatedKeyBindingData(new KeyBindingData(newKs));
@ -175,8 +176,9 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
private void registerStub(SharedStubKeyBindingAction stub, KeyStroke defaultKeyStroke) { private void registerStub(SharedStubKeyBindingAction stub, KeyStroke defaultKeyStroke) {
stub.addPropertyChangeListener(this); stub.addPropertyChangeListener(this);
String description = "Keybinding for Stub action: " + stub.getFullName();
keyBindingOptions.registerOption(stub.getFullName(), OptionType.KEYSTROKE_TYPE, keyBindingOptions.registerOption(stub.getFullName(), OptionType.KEYSTROKE_TYPE,
defaultKeyStroke, null, null); defaultKeyStroke, null, description);
keyBindingsManager.addAction(null, stub); keyBindingsManager.addAction(null, stub);
} }

View file

@ -319,15 +319,16 @@ public class OptionsPanel extends JPanel {
return; // not sure this can happen return; // not sure this can happen
} }
HelpService help = Help.getHelpService();
HelpLocation location = options.getOptionsHelpLocation(); HelpLocation location = options.getOptionsHelpLocation();
if (location == null) { if (location == null) {
// The tree node may or may not have help. The leaf options should all have help. // The tree node may or may not have help. The leaf options should all have help.
return; help.clearHelp(this);
} }
else {
HelpService help = Help.getHelpService();
help.registerHelp(this, location); help.registerHelp(this, location);
} }
}
private OptionsEditor getOptionsEditor(OptionsTreeNode node) { private OptionsEditor getOptionsEditor(OptionsTreeNode node) {
OptionsEditor editor = editorMap.get(node); OptionsEditor editor = editorMap.get(node);

View file

@ -26,8 +26,10 @@ import javax.swing.KeyStroke;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakDataStructureFactory;
import ghidra.util.datastruct.WeakSet; import ghidra.util.datastruct.WeakSet;
import utilities.util.reflection.ReflectionUtilities;
public abstract class AbstractOptions implements Options { public abstract class AbstractOptions implements Options {
public static final Set<Class<?>> SUPPORTED_CLASSES = buildSupportedClassSet(); public static final Set<Class<?>> SUPPORTED_CLASSES = buildSupportedClassSet();
@ -136,6 +138,10 @@ public abstract class AbstractOptions implements Options {
throw new IllegalStateException( throw new IllegalStateException(
"Can't register a custom option without a property editor"); "Can't register a custom option without a property editor");
} }
if (description == null) {
Msg.error(this, "Registered an option without a description: " + optionName,
ReflectionUtilities.createJavaFilteredThrowable());
}
Option currentOption = valueMap.get(optionName); Option currentOption = valueMap.get(optionName);
if (currentOption == null) { if (currentOption == null) {

View file

@ -116,6 +116,9 @@ public class ToolOptions extends AbstractOptions {
* Return an XML element for the option names and values. * Return an XML element for the option names and values.
* Note: only those options which have been explicitly set * Note: only those options which have been explicitly set
* will be included. * will be included.
*
* @param includeDefaultBindings true to include default key binding values in the xml
* @return the xml root element
*/ */
public Element getXmlRoot(boolean includeDefaultBindings) { public Element getXmlRoot(boolean includeDefaultBindings) {
SaveState saveState = new SaveState(XML_ELEMENT_NAME); SaveState saveState = new SaveState(XML_ELEMENT_NAME);
@ -268,7 +271,7 @@ public class ToolOptions extends AbstractOptions {
/** /**
* Adds all the options name/value pairs to this Options. * Adds all the options name/value pairs to this Options.
* @param newOptions * @param newOptions the new options into which the current options values will be placed
*/ */
public void copyOptions(Options newOptions) { public void copyOptions(Options newOptions) {
List<String> optionNames = newOptions.getOptionNames(); List<String> optionNames = newOptions.getOptionNames();