mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-26 06:02:29 +00:00
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:
parent
ea953ce924
commit
66198876e5
@ -16,6 +16,7 @@
|
||||
<P>Often, users need to navigate to specific locations in a program. Ghidra provides
|
||||
several different ways to do this: </P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<UL>
|
||||
<LI> Enter a particular address or label (<A href="#Go_To_Address_Label">Go
|
||||
To</A>)</LI>
|
||||
@ -29,11 +30,12 @@
|
||||
<LI> 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: </H3>
|
||||
<H3>To Perform a Go To: </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 Positions
|
||||
the cursor at the address 0x10 addresses past the symbol ENTRY.</LI>
|
||||
|
||||
<LI>0x100000+30 Positions the cursor
|
||||
at address 0x100030.</LI>
|
||||
|
||||
<LI>0x100000+(2*10) Posiitons the cursor at address 0x100020.</LI>
|
||||
|
||||
<LI>
|
||||
+20
|
||||
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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user