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
several different ways to do this:&nbsp;</P>
<BLOCKQUOTE>
<UL>
<LI>&nbsp;&nbsp;&nbsp;Enter a particular address or label (<A href="#Go_To_Address_Label">Go
To</A>)</LI>
@ -29,11 +30,12 @@
<LI>&nbsp;&nbsp; Use the <A href="#Navigation_History">Navigation History</A> to return to a
previously visited location</LI>
</UL>
</BLOCKQUOTE>
<H2><A name="Go_To_Address_Label"></A>Go To Address, Label, or Expression</H2>
<BLOCKQUOTE>
<H3>To perform a Go To:&nbsp;</H3>
<H3>To Perform a Go To:&nbsp;</H3>
<OL>
<LI>In the menu-bar of a tool, select <B>Navigation <IMG src="../../shared/arrow.gif"
@ -228,25 +230,40 @@
expresion evaluation.<BR>
For example:<BR>
</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>
<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>
<H3>Executing a Query</H3>
@ -626,6 +643,79 @@
<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>

View File

@ -24,12 +24,10 @@
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>
<P>To create a selection using one of the predefined methods:</P>
<UL type="disc">
<LI>From the Code Browser, select the menu option <B>Select</B><I><B><IMG src=
"../../shared/arrow.gif">SelectionType</B>.</I></LI>
</UL>
<P>To create a selection using one of the predefined methods via the menu item
<B>Select</B><I><B><IMG src=
"../../shared/arrow.gif">SelectionType</B>.</I>
</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);
ToolOptions displayOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
displayOptions.registerOptionsEditor(new ListingDisplayOptionsEditor(this, displayOptions));
displayOptions.registerOptionsEditor(new ListingDisplayOptionsEditor(displayOptions));
displayOptions.setOptionsHelpLocation(
new HelpLocation(getName(), GhidraOptions.CATEGORY_BROWSER_DISPLAY));
fieldOptions.setOptionsHelpLocation(

View File

@ -267,12 +267,12 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
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) {
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) {
return endAddressToPixel.get(addr);
}
@ -294,7 +294,7 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
return flowArrows.iterator();
}
/** Those arrows starting at the current address */
/* Those arrows starting at the current address */
Iterator<FlowArrow> getActiveArrows() {
return activeArrows.iterator();
}
@ -584,8 +584,8 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
for (int layout = 0; layout < n; layout++) {
Address addr = layoutToPixel.getLayoutAddress(layout);
if (addr != null) {
startAddressToPixel.put(addr, new Integer(layoutToPixel.getBeginPosition(layout)));
endAddressToPixel.put(addr, new Integer(layoutToPixel.getEndPosition(layout)));
startAddressToPixel.put(addr, layoutToPixel.getBeginPosition(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);
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(),
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(),
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(),
OptionsGui.BACKGROUND.getDefaultColor());

View File

@ -20,9 +20,12 @@ import ghidra.framework.options.OptionsChangeListener;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.OptionsService;
import ghidra.util.HelpLocation;
public class NavigationOptions implements OptionsChangeListener {
static final String NAVIGATION_TOPIC = "Navigation";
static final String NAVIGATION_OPTIONS = GhidraOptions.NAVIGATION_OPTIONS;
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_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 " +
"current program to the first linkage reference (pointer or thunk). " +
"Alternatively, if an external program has been associated with an " +
@ -78,12 +81,12 @@ public class NavigationOptions implements OptionsChangeListener {
GhidraOptions.FOLLOW_INDIRECTION_NAVIGATION_OPTION;
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 " +
"referenced pointer data. If enabled, the pointer will be followed " +
"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 =
"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 " +
@ -92,7 +95,7 @@ public class NavigationOptions implements OptionsChangeListener {
"cursor location. Otherwise, it will show a list of possible addresses for the given offset. " +
"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 " +
"'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 " +
@ -120,32 +123,33 @@ public class NavigationOptions implements OptionsChangeListener {
this.options = options;
HelpLocation help = new HelpLocation(NAVIGATION_TOPIC, "Navigation_Options");
options.registerOption(NavigationOptions.NAVIGATION_RANGE_OPTION,
RangeNavigationEnum.TopOfRangeOnly, null,
RangeNavigationEnum.TopOfRangeOnly, help,
NavigationOptions.NAVIGATION_RANGE_DESCRIPTION);
RangeNavigationEnum rangeNavigationOption = options.getEnum(
NavigationOptions.NAVIGATION_RANGE_OPTION, RangeNavigationEnum.TopOfRangeOnly);
gotoTopAndBottom = (rangeNavigationOption == RangeNavigationEnum.TopAndBottomOfRange);
options.registerOption(NavigationOptions.EXTERNAL_NAVIGATION_OPTION,
ExternalNavigationEnum.NavigateToLinkage, null,
ExternalNavigationEnum.NavigateToLinkage, help,
NavigationOptions.EXTERNAL_NAVIGATION_DESCRIPTION);
ExternalNavigationEnum externalNavigationOption = options.getEnum(
NavigationOptions.EXTERNAL_NAVIGATION_OPTION, ExternalNavigationEnum.NavigateToLinkage);
gotoExternalProgram =
(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);
followIndirectReferences =
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);
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);
restrictGotoToCurrentProgram = options.getBoolean(RESTRICT_GOTO_CURRENT_TAB, true);
@ -158,7 +162,7 @@ public class NavigationOptions implements OptionsChangeListener {
}
@Override
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
public void optionsChanged(ToolOptions toolOptions, String optionName, Object oldValue,
Object newValue) {
if (NavigationOptions.NAVIGATION_RANGE_OPTION.equals(optionName)) {
RangeNavigationEnum rangeNavigationOption = (RangeNavigationEnum) newValue;

View File

@ -401,9 +401,10 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener,
"Toggles highlight search results");
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,
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);

View File

@ -61,7 +61,7 @@ public class AddressFieldFactory extends FieldFactory {
/**
* Constructor
* @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 fieldOptions the Options for field specific properties.
*/
@ -75,7 +75,8 @@ public class AddressFieldFactory extends FieldFactory {
HelpLocation helpLoc = new HelpLocation("CodeBrowserPlugin", "Address_Field");
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 =
fieldOptions.getCustomOption(ADDRESS_DISPLAY_OPTIONS_NAME, null);
@ -204,9 +205,9 @@ public class AddressFieldFactory extends FieldFactory {
@Override
public FieldFactory newInstance(FieldFormatModel newModel,
HighlightProvider highlightStringProvider, ToolOptions displayOptions,
HighlightProvider highlightStringProvider, ToolOptions toolOptions,
ToolOptions fieldOptions) {
return new AddressFieldFactory(newModel, highlightStringProvider, displayOptions,
return new AddressFieldFactory(newModel, highlightStringProvider, toolOptions,
fieldOptions);
}
}

View File

@ -43,16 +43,16 @@ public class ArrayValuesFieldFactory extends FieldFactory {
@Override
public FieldFactory newInstance(FieldFormatModel formatModel,
HighlightProvider highlightProvider, ToolOptions displayOptions,
HighlightProvider highlightProvider, ToolOptions toolOptions,
ToolOptions fieldOptions) {
return new ArrayValuesFieldFactory(formatModel, highlightProvider, displayOptions,
return new ArrayValuesFieldFactory(formatModel, highlightProvider, toolOptions,
fieldOptions);
}
/**
* Constructor
* @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 fieldOptions the Options for field specific properties.
*/
@ -65,7 +65,8 @@ public class ArrayValuesFieldFactory extends FieldFactory {
private void setupOptions(Options fieldOptions) {
// 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,
new ArrayElementWrappedOption(), null, null, arrayOptionsEditor);
new ArrayElementWrappedOption(), null, FormatManager.ARRAY_DISPLAY_DESCRIPTION,
arrayOptionsEditor);
CustomOption wrappedOption = fieldOptions.getCustomOption(
FormatManager.ARRAY_DISPLAY_OPTIONS, new ArrayElementWrappedOption());
@ -162,9 +163,6 @@ public class ArrayValuesFieldFactory extends FieldFactory {
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
public void fieldOptionsChanged(Options options, String optionName, Object oldValue,
Object newValue) {

View File

@ -76,6 +76,8 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
*/
private final static String NAMESPACE_OPTIONS =
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
@ -106,7 +108,8 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
if (!exists) {
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");
fieldOptions.getOptions(GhidraOptions.OPERAND_GROUP_TITLE).setOptionsHelpLocation(hl);
@ -157,7 +160,8 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
private void updateFormat() {
fieldOptions.registerOption(NAMESPACE_OPTIONS, OptionType.CUSTOM_TYPE,
new NamespaceWrappedOption(), null, null, new NamespacePropertyEditor());
new NamespaceWrappedOption(), null, NAMESPACE_OPTIONS_DESCRIPTIONS,
new NamespacePropertyEditor());
CustomOption customOption =
fieldOptions.getCustomOption(NAMESPACE_OPTIONS, new NamespaceWrappedOption());
if (!(customOption instanceof NamespaceWrappedOption)) {
@ -208,7 +212,7 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
/**
* Add format change listener.
* Listeners will only be notified if autoUpdate was true when instantiated.
* @param listener
* @param listener the listener
*/
public void addChangeListener(ChangeListener listener) {
listeners.add(listener);
@ -216,7 +220,7 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
/**
* Remove format change listener
* @param listener
* @param listener the listener
*/
public void removeChangeListener(ChangeListener listener) {
listeners.remove(listener);

View File

@ -89,8 +89,9 @@ public abstract class FieldFactory implements ExtensionPoint {
// 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
displayOptions.registerOption(colorOptionName, Color.BLACK, null, null);
displayOptions.registerOption(styleOptionName, -1, null, null);
displayOptions.registerOption(colorOptionName, Color.BLACK, null,
"Sets the " + colorOptionName);
displayOptions.registerOption(styleOptionName, -1, null, "Sets the " + style);
color = displayOptions.getColor(colorOptionName, getDefaultColor());
style = displayOptions.getInt(styleOptionName, -1);

View File

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

View File

@ -654,11 +654,11 @@ public class PlateFieldFactory extends FieldFactory {
"Number of lines to displayed before a plate comment." +
" 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,
help, null);
help, "Shows/hides function header format for pointers to external functions");
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
* @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 fieldOptions the Options for field specific properties.
*/
@ -93,9 +93,12 @@ public class PostCommentFieldFactory extends FieldFactory {
Options displayOptions, Options fieldOptions) {
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
fieldOptions.registerOption(FLAG_FUNCTION_EXIT_OPTION, false, null, null);
fieldOptions.registerOption(FLAG_TERMINATOR_OPTION, false, null, null);
fieldOptions.registerOption(LINES_AFTER_BLOCKS_OPTION, 0, null, null);
fieldOptions.registerOption(FLAG_FUNCTION_EXIT_OPTION, false, null,
"Toggles the display of a post-comment for a function exit");
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);
flagJMPsRETs = fieldOptions.getBoolean(FLAG_TERMINATOR_OPTION, false);
@ -226,9 +229,8 @@ public class PostCommentFieldFactory extends FieldFactory {
comments.addFirst(callOtherCallOverrideComment);
}
else {
overrideData =
getOverrideCommentData(instr, RefType.CALLOTHER_OVERRIDE_JUMP, pcodeOps,
pCodeOverride);
overrideData = getOverrideCommentData(instr, RefType.CALLOTHER_OVERRIDE_JUMP,
pcodeOps, pCodeOverride);
if (overrideData != null) {
String callOtherJumpOverrideComment =
"-- CALLOTHER(" + overrideData.getOverriddenCallOther() +
@ -313,8 +315,8 @@ public class PostCommentFieldFactory extends FieldFactory {
@Override
public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider,
ToolOptions displayOptions, ToolOptions fieldOptions) {
return new PostCommentFieldFactory(formatModel, provider, displayOptions, fieldOptions);
ToolOptions toolOptions, ToolOptions fieldOptions) {
return new PostCommentFieldFactory(formatModel, provider, toolOptions, fieldOptions);
}
@Override
@ -525,7 +527,8 @@ public class PostCommentFieldFactory extends FieldFactory {
"at a jump or a return instruction.");
options.registerOption(LINES_AFTER_BLOCKS_OPTION, 0, null,
"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);
alwaysShowAutomatic = options.getBoolean(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, true);
@ -557,6 +560,7 @@ public class PostCommentFieldFactory extends FieldFactory {
return next;
}
catch (AddressOverflowException e) {
// don't care
}
return null;
}

View File

@ -77,17 +77,18 @@ public class PreCommentFieldFactory extends FieldFactory {
/**
* Constructor
* @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 fieldOptions the Options for field specific properties.
* @param serviceProvider the provider for services.
*/
private PreCommentFieldFactory(FieldFormatModel model, HighlightProvider hlProvider,
Options displayOptions, Options fieldOptions) {
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
fieldOptions.registerOption(FLAG_FUNCTION_ENTRY_OPTION, false, null, null);
fieldOptions.registerOption(FLAG_SUBROUTINE_ENTRY_OPTION, false, null, null);
fieldOptions.registerOption(FLAG_FUNCTION_ENTRY_OPTION, false, 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);
flagSubroutineEntry = fieldOptions.getBoolean(FLAG_SUBROUTINE_ENTRY_OPTION, false);
@ -183,8 +184,8 @@ public class PreCommentFieldFactory extends FieldFactory {
@Override
public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider,
ToolOptions displayOptions, ToolOptions fieldOptions) {
return new PreCommentFieldFactory(formatModel, provider, displayOptions, fieldOptions);
ToolOptions toolOptions, ToolOptions fieldOptions) {
return new PreCommentFieldFactory(formatModel, provider, toolOptions, fieldOptions);
}
@Override
@ -379,7 +380,8 @@ public class PreCommentFieldFactory extends FieldFactory {
"wrapping is off, comments are displayed in line format " +
"however the user entered them. Lines that are too long " +
"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);
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,
"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 =
displayOptions.getColor(OptionsGui.REGISTERS.getColorOptionName(), getDefaultColor());
@ -74,10 +75,9 @@ public class RegisterFieldFactory extends FieldFactory {
@Override
public FieldFactory newInstance(FieldFormatModel formatModel,
HighlightProvider highlightProvider, ToolOptions displayOptions,
HighlightProvider highlightProvider, ToolOptions toolOptions,
ToolOptions fieldOptions) {
return new RegisterFieldFactory(formatModel, highlightProvider, displayOptions,
fieldOptions);
return new RegisterFieldFactory(formatModel, highlightProvider, toolOptions, fieldOptions);
}
@Override

View File

@ -173,7 +173,8 @@ public class XRefFieldFactory extends FieldFactory {
private void setupNamespaceOptions(Options fieldOptions) {
// we need to install a custom editor that allows us to edit a group of related options
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);
fieldOptions.getOptions(NAMESPACE_OPTIONS).setOptionsHelpLocation(
new HelpLocation("CodeBrowserPlugin", "XREFs_Field"));
@ -529,6 +530,7 @@ public class XRefFieldFactory extends FieldFactory {
* Get an address location for this object.
*
* @param obj object to get location from
* @return the address
*/
protected Address getXRefLocation(Object obj) {
if (obj == null || !(obj instanceof CodeUnit)) {
@ -556,7 +558,7 @@ public class XRefFieldFactory extends FieldFactory {
@Override
public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider,
ToolOptions displayOptions, ToolOptions fieldOptions) {
return new XRefFieldFactory(formatModel, provider, displayOptions, fieldOptions);
ToolOptions toolOptions, ToolOptions 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";
public final static String 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;
@ -94,7 +95,8 @@ public class FormatManager implements OptionsChangeListener {
private void getArrayDisplayOptions(Options options) {
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);
if (option instanceof ArrayElementWrappedOption) {
ArrayElementWrappedOption arrayOption = (ArrayElementWrappedOption) option;

View File

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

View File

@ -69,11 +69,6 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
}
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 =
fieldOptions.getBoolean(DISPLAY_EXTERNAL_FUNCTION_POINTER_OPTION_NAME, true);
showNonExternalFunctionPointerFormat =

View File

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

View File

@ -15,11 +15,11 @@
*/
package ghidra.app.plugin.core.codebrowser;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import org.junit.*;
@ -45,6 +45,8 @@ import ghidra.program.model.symbol.SourceType;
import ghidra.program.util.BytesFieldLocation;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.HelpLocation;
import util.CollectionUtils;
public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env;
@ -969,6 +971,38 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
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 {
// nothing; just a dummy
}

View File

@ -149,7 +149,7 @@ public class VTPlugin extends Plugin {
private void initializeOptions() {
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(),
GhidraOptions.CATEGORY_BROWSER_DISPLAY));

View File

@ -1780,12 +1780,14 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
2) A component provider's code
3) A dialog provider's code
4) A background thread
5) The help window
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 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
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
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;
while (c != null) {
if (c instanceof Frame) {
if (c instanceof Window) {
return (Window) c;
}
c = c.getParent();

View File

@ -175,7 +175,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
for (ActionData actionData : actions) {
if (actionData.isMyProvider(localContext)) {
hasLocalActionsForKeyBinding = true;
if (actionData.action.isEnabledForContext(localContext)) {
if (isValidAndEnabled(actionData, localContext)) {
list.add(new ExecutableKeyActionAdapter(actionData.action, localContext));
}
}
@ -199,7 +199,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
(ComponentBasedDockingAction) actionData.action;
if (componentAction.isValidComponentContext(localContext)) {
hasLocalActionsForKeyBinding = true;
if (actionData.action.isEnabledForContext(localContext)) {
if (isValidAndEnabled(actionData, 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
// is a 'global' action. This allows more specific context to be used when
// available
if (actionData.action.isValidContext(localContext)) {
if (actionData.action.isEnabledForContext(localContext)) {
if (isValidAndEnabled(actionData, localContext)) {
list.add(new ExecutableKeyActionAdapter(actionData.action, localContext));
}
}
else if (actionData.action.isValidGlobalContext(globalContext)) {
if (actionData.action.isEnabledForContext(globalContext)) {
else if (isValidAndEnabled(actionData, globalContext)) {
list.add(new ExecutableKeyActionAdapter(actionData.action, globalContext));
}
}
}
}
return list;
}
private boolean isValidAndEnabled(ActionData actionData, ActionContext localContext) {
DockingActionIf a = actionData.action;
return a.isValidContext(localContext) && a.isEnabledForContext(localContext);
}
@Override
public boolean isReservedKeybindingPrecedence() {
return false; // MultipleKeyActions can never be reserved

View File

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

View File

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

View File

@ -26,8 +26,10 @@ import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import ghidra.util.datastruct.WeakDataStructureFactory;
import ghidra.util.datastruct.WeakSet;
import utilities.util.reflection.ReflectionUtilities;
public abstract class AbstractOptions implements Options {
public static final Set<Class<?>> SUPPORTED_CLASSES = buildSupportedClassSet();
@ -136,6 +138,10 @@ public abstract class AbstractOptions implements Options {
throw new IllegalStateException(
"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);
if (currentOption == null) {

View File

@ -116,6 +116,9 @@ public class ToolOptions extends AbstractOptions {
* Return an XML element for the option names and values.
* Note: only those options which have been explicitly set
* 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) {
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.
* @param newOptions
* @param newOptions the new options into which the current options values will be placed
*/
public void copyOptions(Options newOptions) {
List<String> optionNames = newOptions.getOptionNames();