mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-23 04:35:53 +08:00
Merge remote-tracking branch 'origin/GP-3531-dragonmacher-update-auto-comments--SQUASHED'
This commit is contained in:
+38
-16
@@ -518,24 +518,46 @@
|
||||
<H3><A name="EOL_Comments_Field"></A>EOL Comments Field</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The EOL Comments field displays the end-of-line comment at this address. If there is no
|
||||
EOL comment, it displays the repeatable comment. If there is no repeatable comment, it
|
||||
displays the repeatable comments from all referenced addresses. If there aren't any
|
||||
referenced repeatable comments, it displays an automatic comment if it can.</P>
|
||||
<P>The EOL Comments field displays the end-of-line comment at this address. By default,
|
||||
if there is no EOL comment, then other comment types may be displayed.
|
||||
</P>
|
||||
|
||||
<P><B>Always Show the Automatic Comment -</B> Normally automatic comments are not shown if
|
||||
there is an EOL comment, repeatable comment, or referenced repeatable comment. By selecting
|
||||
this option, the automatic comment will be shown even if there is an EOL comment,
|
||||
repeatable comment, or referenced repeatable comment.</P>
|
||||
<P><B>Additional Comment Types -</B> The following comment types may be optionally displayed
|
||||
in the EOL Comments field. For each type below, the following setting may be applied:
|
||||
<UL>
|
||||
<LI><B>ALWAYS -</B> Always show the comment type, regardless of other comment types
|
||||
that are showing. The appearance of any comment will be limited by the maximum
|
||||
number of lines currently set on the EOL Comments field.
|
||||
</LI>
|
||||
<LI><B>DEFAULT -</B> Show the comment type only when there is no other comment type
|
||||
of a higher precedence. When all fields are set to this option, then the EOL
|
||||
Comments field will only display one comment type at a time.
|
||||
</LI>
|
||||
<LI><B>NEVER -</B> Do not show this comment type.
|
||||
</LI>
|
||||
</UL>
|
||||
</P>
|
||||
|
||||
<P>
|
||||
Each of the comments below is listed in order of precedence. The default behavior is to
|
||||
show one comment in the EOL Comments field at a time, based on this precedence, with the EOL
|
||||
Comment being the highest.
|
||||
</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Repeatable -</B> The Repeatable Comment defined <I>at the current
|
||||
code unit address</I>.</P>
|
||||
|
||||
<P><B>Referenced Repeatable -</B> The Repeatable Comment that is defined at the
|
||||
target reference address that the code unit at this address refers to.</P>
|
||||
|
||||
<P><B>Automatic Function -</B> A preview of the referenced function.</P>
|
||||
|
||||
<P><B>Automatic Data -</B> A preview of the referenced data. For example, a String
|
||||
reference will show a preview of the target String.</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><B>Always Show the Referenced Repeatable Comment -</B> Normally referenced repeatable
|
||||
comments are not shown if there is an EOL comment or repeatable comment. By selecting this
|
||||
option, the referenced repeatable comment will be shown even if there is an EOL comment or
|
||||
repeatable comment.</P>
|
||||
|
||||
<P><B>Always Show the Repeatable Comment -</B> Normally repeatable comments are not shown
|
||||
if there is an EOL comment. By selecting this option, the repeatable comment will be shown
|
||||
even if there is an EOL comment.</P>
|
||||
|
||||
<P><B>Enable Word Wrapping -</B> If this option is not set, each comment line is displayed
|
||||
on a line by itself. By turning on word-wrapping, comment lines are displayed in paragraph
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+33
-28
@@ -17,10 +17,12 @@ package ghidra.app.util.exporter;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import generic.theme.GThemeDefaults.Colors.Messages;
|
||||
import ghidra.app.util.DisplayableEol;
|
||||
import ghidra.app.util.EolComments;
|
||||
import ghidra.app.util.template.TemplateSimplifier;
|
||||
import ghidra.app.util.viewer.field.EolExtraCommentsOption;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
@@ -56,10 +58,6 @@ class ProgramTextWriter {
|
||||
ProgramTextOptions options, ServiceProvider provider) throws FileNotFoundException {
|
||||
|
||||
this.options = options;
|
||||
// Exit if options are INVALID
|
||||
int len = options.getAddrWidth() + options.getBytesWidth() + options.getPreMnemonicWidth() +
|
||||
options.getMnemonicWidth() + options.getOperandWidth() + options.getEolWidth();
|
||||
|
||||
this.program = program;
|
||||
this.listing = program.getListing();
|
||||
this.memory = program.getMemory();
|
||||
@@ -293,29 +291,7 @@ class ProgramTextWriter {
|
||||
//// End of Line Area //////////////////////////////////////////
|
||||
|
||||
if (options.isShowComments()) {
|
||||
DisplayableEol displayableEol = new DisplayableEol(currentCodeUnit, false, false,
|
||||
false, true, 6 /* arbitrary! */, true, true);
|
||||
String[] eol = displayableEol.getComments();
|
||||
if (eol != null && eol.length > 0) {
|
||||
len = options.getAddrWidth() + options.getBytesWidth() +
|
||||
options.getPreMnemonicWidth() + options.getMnemonicWidth() +
|
||||
options.getOperandWidth();
|
||||
|
||||
String fill = genFill(len);
|
||||
|
||||
for (int i = 0; i < eol.length; ++i) {
|
||||
if (i > 0) {
|
||||
buffy.append(fill);
|
||||
}
|
||||
String eolcmt = options.getCommentPrefix() + eol[i];
|
||||
if (eolcmt.length() > options.getEolWidth()) {
|
||||
eolcmt = clip(eolcmt, options.getEolWidth(), true, true);
|
||||
}
|
||||
buffy.append(eolcmt);
|
||||
writer.println(buffy.toString());
|
||||
buffy = new StringBuilder();
|
||||
}
|
||||
}
|
||||
addComments(currentCodeUnit);
|
||||
}
|
||||
|
||||
if (buffy.length() > 0) {
|
||||
@@ -369,6 +345,35 @@ class ProgramTextWriter {
|
||||
writer.close();
|
||||
}
|
||||
|
||||
private void addComments(CodeUnit currentCodeUnit) {
|
||||
|
||||
EolExtraCommentsOption eolOption = new EolExtraCommentsOption();
|
||||
EolComments eolComments =
|
||||
new EolComments(currentCodeUnit, true, 6 /* arbitrary */, eolOption);
|
||||
List<String> comments = eolComments.getComments();
|
||||
if (comments.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int len = options.getAddrWidth() + options.getBytesWidth() +
|
||||
options.getPreMnemonicWidth() + options.getMnemonicWidth() +
|
||||
options.getOperandWidth();
|
||||
|
||||
String fill = genFill(len);
|
||||
for (int i = 0; i < comments.size(); ++i) {
|
||||
if (i > 0) {
|
||||
buffy.append(fill);
|
||||
}
|
||||
String text = options.getCommentPrefix() + comments.get(i);
|
||||
if (text.length() > options.getEolWidth()) {
|
||||
text = clip(text, options.getEolWidth(), true, true);
|
||||
}
|
||||
buffy.append(text);
|
||||
writer.println(buffy.toString());
|
||||
buffy = new StringBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
private void insertUndefinedBytesRemovedMarker(Address bytesRemovedRangeStart,
|
||||
Address bytesRemovedRangeEnd) {
|
||||
|
||||
|
||||
+124
-142
@@ -16,6 +16,7 @@
|
||||
package ghidra.app.util.viewer.field;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.beans.PropertyEditor;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -28,57 +29,49 @@ import ghidra.app.util.viewer.field.ListingColors.CommentColors;
|
||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||
import ghidra.app.util.viewer.options.OptionsGui;
|
||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.options.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.bean.field.AnnotatedTextFieldElement;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
/**
|
||||
* Generates End of line comment Fields.
|
||||
*/
|
||||
* Generates End of line comment Fields.
|
||||
*/
|
||||
public class EolCommentFieldFactory extends FieldFactory {
|
||||
public static final String FIELD_NAME = "EOL Comment";
|
||||
private static final String GROUP_TITLE = "EOL Comments Field";
|
||||
private static final String SEMICOLON_PREFIX = "; ";
|
||||
public static final String ENABLE_WORD_WRAP_MSG =
|
||||
|
||||
public static final String ENABLE_WORD_WRAP_KEY =
|
||||
GROUP_TITLE + Options.DELIMITER + FieldUtils.WORD_WRAP_OPTION_NAME;
|
||||
public static final String MAX_DISPLAY_LINES_MSG =
|
||||
GROUP_TITLE + Options.DELIMITER + "Maximum Lines To Display";
|
||||
public static final String ENABLE_SHOW_SEMICOLON_MSG =
|
||||
GROUP_TITLE + Options.DELIMITER + "Show Semicolon at Start of Each Line";
|
||||
public static final String ENABLE_ALWAYS_SHOW_REPEATABLE_MSG =
|
||||
GROUP_TITLE + Options.DELIMITER + "Always Show the Repeatable Comment";
|
||||
public static final String ENABLE_ALWAYS_SHOW_REF_REPEATABLE_MSG =
|
||||
GROUP_TITLE + Options.DELIMITER + "Always Show the Referenced Repeatable Comments";
|
||||
public static final String ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG =
|
||||
GROUP_TITLE + Options.DELIMITER + "Always Show the Automatic Comment";
|
||||
public static final String USE_ABBREVIATED_AUTOMITIC_COMMENT_MSG =
|
||||
GROUP_TITLE + Options.DELIMITER + "Use Abbreviated Automatic Comments";
|
||||
public static final String SHOW_FUNCTION_AUTOMITIC_COMMENT_MSG =
|
||||
GROUP_TITLE + Options.DELIMITER + "Show Function Reference Automatic Comments";
|
||||
public static final String ENABLE_PREPEND_REF_ADDRESS_MSG =
|
||||
GROUP_TITLE + Options.DELIMITER + "Prepend the Address to Each Referenced Comment";
|
||||
public static final String MAX_DISPLAY_LINES_KEY =
|
||||
GROUP_TITLE + Options.DELIMITER + "Maximum Lines";
|
||||
public static final String ENABLE_SHOW_SEMICOLON_KEY =
|
||||
GROUP_TITLE + Options.DELIMITER + "Prepend Semicolon";
|
||||
public static final String ENABLE_PREPEND_REF_ADDRESS_KEY =
|
||||
GROUP_TITLE + Options.DELIMITER + "Prepend Address to References";
|
||||
public static final String EXTRA_COMMENT_KEY =
|
||||
GROUP_TITLE + Options.DELIMITER + "Auto Comments";
|
||||
|
||||
public static final Color DEFAULT_COLOR = Palette.BLUE;
|
||||
|
||||
private boolean isWordWrap;
|
||||
private int maxDisplayLines;
|
||||
private boolean showSemicolon;
|
||||
private boolean alwaysShowRepeatable;
|
||||
private boolean alwaysShowRefRepeatables;
|
||||
private boolean alwaysShowAutomatic;
|
||||
private boolean useAbbreviatedAutomatic;
|
||||
private boolean showAutomaticFunctions;
|
||||
private boolean prependRefAddress;
|
||||
private int repeatableCommentStyle;
|
||||
private int automaticCommentStyle;
|
||||
private int refRepeatableCommentStyle;
|
||||
|
||||
// The codeUnitFormatOptions is used to monitor "follow pointer..." option to avoid
|
||||
// duplication of data within auto-comment. We don't bother adding a listener
|
||||
// to kick the model since this is done by the operand field.
|
||||
private EolExtraCommentsOption extraCommentsOption = new EolExtraCommentsOption();
|
||||
private PropertyEditor extraCommmentsEditor = new EolExtraCommentsPropertyEditor();
|
||||
|
||||
// The codeUnitFormatOptions is used to monitor "follow pointer..." option to avoid duplication
|
||||
// of data within auto-comment. We don't bother adding a listener to kick the model since this
|
||||
// is done by the operand field.
|
||||
private BrowserCodeUnitFormatOptions codeUnitFormatOptions;
|
||||
|
||||
/**
|
||||
@@ -100,55 +93,49 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
|
||||
HelpLocation hl = new HelpLocation("CodeBrowserPlugin", "EOL_Comments_Field");
|
||||
|
||||
fieldOptions.registerOption(MAX_DISPLAY_LINES_MSG, 6, hl,
|
||||
fieldOptions.registerOption(MAX_DISPLAY_LINES_KEY, 6, hl,
|
||||
"The maximum number of lines used to display the end-of-line comment.");
|
||||
fieldOptions.registerOption(ENABLE_WORD_WRAP_MSG, false, hl,
|
||||
fieldOptions.registerOption(ENABLE_WORD_WRAP_KEY, false, hl,
|
||||
FieldUtils.WORD_WRAP_OPTION_DESCRIPTION);
|
||||
|
||||
fieldOptions.registerOption(ENABLE_SHOW_SEMICOLON_MSG, false, hl,
|
||||
fieldOptions.registerOption(ENABLE_SHOW_SEMICOLON_KEY, false, hl,
|
||||
"Displays a semi-colon before each line in the end-of-line comment. " +
|
||||
"This option is ignored if word wrapping is on.");
|
||||
|
||||
fieldOptions.registerOption(ENABLE_ALWAYS_SHOW_REPEATABLE_MSG, false, hl,
|
||||
"Displays all referenced repeatable comments even if there is an EOL " +
|
||||
"or repeatable comment at the code unit.");
|
||||
|
||||
fieldOptions.registerOption(ENABLE_ALWAYS_SHOW_REF_REPEATABLE_MSG, false, hl,
|
||||
"Displays all referenced repeatable comments even if there is an EOL " +
|
||||
"or repeatable comment at the code unit.");
|
||||
fieldOptions.registerOption(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, false, hl,
|
||||
"Displays an automatic comment whenever one exists instead of only if there " +
|
||||
"aren't any EOL or repeatable comments.");
|
||||
fieldOptions.registerOption(USE_ABBREVIATED_AUTOMITIC_COMMENT_MSG, true, hl,
|
||||
"When showing automatic comments, show the smallest amount of information possible");
|
||||
fieldOptions.registerOption(SHOW_FUNCTION_AUTOMITIC_COMMENT_MSG, true, hl,
|
||||
"When showing automatic comments, show direct function references");
|
||||
|
||||
fieldOptions.registerOption(ENABLE_PREPEND_REF_ADDRESS_MSG, false, hl,
|
||||
fieldOptions.registerOption(ENABLE_PREPEND_REF_ADDRESS_KEY, false, hl,
|
||||
"Displays the address before each referenced repeatable comment.");
|
||||
|
||||
maxDisplayLines = fieldOptions.getInt(MAX_DISPLAY_LINES_MSG, 6);
|
||||
isWordWrap = fieldOptions.getBoolean(ENABLE_WORD_WRAP_MSG, false);
|
||||
maxDisplayLines = fieldOptions.getInt(MAX_DISPLAY_LINES_KEY, 6);
|
||||
isWordWrap = fieldOptions.getBoolean(ENABLE_WORD_WRAP_KEY, false);
|
||||
repeatableCommentStyle =
|
||||
displayOptions.getInt(OptionsGui.COMMENT_REPEATABLE.getStyleOptionName(), -1);
|
||||
automaticCommentStyle =
|
||||
displayOptions.getInt(OptionsGui.COMMENT_AUTO.getStyleOptionName(), -1);
|
||||
refRepeatableCommentStyle =
|
||||
displayOptions.getInt(OptionsGui.COMMENT_REF_REPEAT.getStyleOptionName(), -1);
|
||||
showSemicolon = fieldOptions.getBoolean(ENABLE_SHOW_SEMICOLON_MSG, false);
|
||||
alwaysShowRepeatable = fieldOptions.getBoolean(ENABLE_ALWAYS_SHOW_REPEATABLE_MSG, false);
|
||||
alwaysShowRefRepeatables =
|
||||
fieldOptions.getBoolean(ENABLE_ALWAYS_SHOW_REF_REPEATABLE_MSG, false);
|
||||
alwaysShowAutomatic = fieldOptions.getBoolean(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, false);
|
||||
useAbbreviatedAutomatic =
|
||||
fieldOptions.getBoolean(USE_ABBREVIATED_AUTOMITIC_COMMENT_MSG, true);
|
||||
showAutomaticFunctions = fieldOptions.getBoolean(SHOW_FUNCTION_AUTOMITIC_COMMENT_MSG, true);
|
||||
|
||||
prependRefAddress = fieldOptions.getBoolean(ENABLE_PREPEND_REF_ADDRESS_MSG, false);
|
||||
showSemicolon = fieldOptions.getBoolean(ENABLE_SHOW_SEMICOLON_KEY, false);
|
||||
prependRefAddress = fieldOptions.getBoolean(ENABLE_PREPEND_REF_ADDRESS_KEY, false);
|
||||
|
||||
fieldOptions.getOptions(GROUP_TITLE).setOptionsHelpLocation(hl);
|
||||
|
||||
codeUnitFormatOptions = new BrowserCodeUnitFormatOptions(fieldOptions, true);
|
||||
|
||||
setupAutoCommentOptions(fieldOptions, hl);
|
||||
}
|
||||
|
||||
private void setupAutoCommentOptions(Options fieldOptions, HelpLocation hl) {
|
||||
fieldOptions.registerOption(EXTRA_COMMENT_KEY, OptionType.CUSTOM_TYPE,
|
||||
new EolExtraCommentsOption(), hl, "The group of auto comment options",
|
||||
extraCommmentsEditor);
|
||||
CustomOption customOption = fieldOptions.getCustomOption(EXTRA_COMMENT_KEY, null);
|
||||
|
||||
if (!(customOption instanceof EolExtraCommentsOption)) {
|
||||
throw new AssertException("Someone set an option for " + EXTRA_COMMENT_KEY +
|
||||
" that is not the expected " +
|
||||
EolExtraCommentsOption.class.getName() + " type.");
|
||||
}
|
||||
|
||||
extraCommentsOption = (EolExtraCommentsOption) customOption;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,28 +148,19 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
@Override
|
||||
public void fieldOptionsChanged(Options options, String optionName, Object oldValue,
|
||||
Object newValue) {
|
||||
if (optionName.equals(MAX_DISPLAY_LINES_MSG)) {
|
||||
if (optionName.equals(MAX_DISPLAY_LINES_KEY)) {
|
||||
setMaximumLinesToDisplay(((Integer) newValue).intValue(), options);
|
||||
}
|
||||
else if (optionName.equals(ENABLE_WORD_WRAP_MSG)) {
|
||||
else if (optionName.equals(ENABLE_WORD_WRAP_KEY)) {
|
||||
isWordWrap = ((Boolean) newValue).booleanValue();
|
||||
}
|
||||
else if (optionName.equals(ENABLE_SHOW_SEMICOLON_MSG)) {
|
||||
else if (optionName.equals(ENABLE_SHOW_SEMICOLON_KEY)) {
|
||||
showSemicolon = ((Boolean) newValue).booleanValue();
|
||||
}
|
||||
else if (optionName.equals(ENABLE_ALWAYS_SHOW_REPEATABLE_MSG)) {
|
||||
alwaysShowRepeatable = ((Boolean) newValue).booleanValue();
|
||||
else if (optionName.equals(EXTRA_COMMENT_KEY)) {
|
||||
extraCommentsOption = (EolExtraCommentsOption) newValue;
|
||||
}
|
||||
else if (optionName.equals(ENABLE_ALWAYS_SHOW_REF_REPEATABLE_MSG)) {
|
||||
alwaysShowRefRepeatables = ((Boolean) newValue).booleanValue();
|
||||
}
|
||||
else if (optionName.equals(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG)) {
|
||||
alwaysShowAutomatic = ((Boolean) newValue).booleanValue();
|
||||
}
|
||||
else if (optionName.equals(USE_ABBREVIATED_AUTOMITIC_COMMENT_MSG)) {
|
||||
useAbbreviatedAutomatic = ((Boolean) newValue).booleanValue();
|
||||
}
|
||||
else if (optionName.equals(ENABLE_PREPEND_REF_ADDRESS_MSG)) {
|
||||
else if (optionName.equals(ENABLE_PREPEND_REF_ADDRESS_KEY)) {
|
||||
prependRefAddress = ((Boolean) newValue).booleanValue();
|
||||
}
|
||||
}
|
||||
@@ -249,7 +227,7 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
private void setMaximumLinesToDisplay(int maxLines, Options options) {
|
||||
if (maxLines < 1) {
|
||||
maxLines = 1;
|
||||
options.setInt(MAX_DISPLAY_LINES_MSG, maxLines);
|
||||
options.setInt(MAX_DISPLAY_LINES_KEY, maxLines);
|
||||
}
|
||||
maxDisplayLines = maxLines;
|
||||
}
|
||||
@@ -279,57 +257,44 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
}
|
||||
}
|
||||
|
||||
DisplayableEol displayableEol =
|
||||
new DisplayableEol(cu, alwaysShowRepeatable, alwaysShowRefRepeatables,
|
||||
alwaysShowAutomatic, codeUnitFormatOptions.followReferencedPointers(),
|
||||
maxDisplayLines, useAbbreviatedAutomatic, showAutomaticFunctions);
|
||||
|
||||
List<FieldElement> elementList = new ArrayList<>();
|
||||
EolComments comments =
|
||||
new EolComments(cu, codeUnitFormatOptions.followReferencedPointers(),
|
||||
maxDisplayLines, extraCommentsOption);
|
||||
|
||||
// This Code Unit's End of Line Comment
|
||||
AttributedString myEolPrefixString = new AttributedString(SEMICOLON_PREFIX,
|
||||
CommentColors.EOL, getMetrics(style), false, null);
|
||||
String[] eolComments = displayableEol.getEOLComments();
|
||||
List<FieldElement> eolFieldElements = convertToFieldElements(program, eolComments,
|
||||
myEolPrefixString, showSemicolon, isWordWrap, getNextRow(elementList));
|
||||
elementList.addAll(eolFieldElements);
|
||||
List<FieldElement> elementList = new ArrayList<>();
|
||||
AttributedString prefix = createPrefix(style);
|
||||
List<String> eols = comments.getEOLComments();
|
||||
List<FieldElement> eolElements = convertToFieldElements(program, eols, prefix, 0);
|
||||
elementList.addAll(eolElements);
|
||||
|
||||
// This Code Unit's Repeatable Comment
|
||||
if (alwaysShowRepeatable || elementList.isEmpty()) {
|
||||
AttributedString myRepeatablePrefixString = new AttributedString(SEMICOLON_PREFIX,
|
||||
CommentColors.REPEATABLE, getMetrics(repeatableCommentStyle), false, null);
|
||||
String[] repeatableComments = displayableEol.getRepeatableComments();
|
||||
List<FieldElement> repeatableFieldElements =
|
||||
convertToFieldElements(program, repeatableComments, myRepeatablePrefixString,
|
||||
showSemicolon, isWordWrap, getNextRow(elementList));
|
||||
elementList.addAll(repeatableFieldElements);
|
||||
if (comments.isShowingRepeatables()) {
|
||||
prefix = createPrefix(repeatableCommentStyle);
|
||||
int row = getNextRow(elementList);
|
||||
List<String> repeatables = comments.getRepeatableComments();
|
||||
List<FieldElement> elements = convertToFieldElements(program, repeatables, prefix, row);
|
||||
elementList.addAll(elements);
|
||||
}
|
||||
|
||||
// Referenced Repeatable Comments
|
||||
if (alwaysShowRefRepeatables || elementList.isEmpty()) {
|
||||
AttributedString refRepeatPrefixString = new AttributedString(SEMICOLON_PREFIX,
|
||||
CommentColors.REF_REPEATABLE, getMetrics(refRepeatableCommentStyle), false, null);
|
||||
int refRepeatCount = displayableEol.getReferencedRepeatableCommentsCount();
|
||||
for (int subTypeIndex = 0; subTypeIndex < refRepeatCount; subTypeIndex++) {
|
||||
RefRepeatComment refRepeatComment =
|
||||
displayableEol.getReferencedRepeatableComments(subTypeIndex);
|
||||
String[] refRepeatComments = refRepeatComment.getCommentLines();
|
||||
List<FieldElement> refRepeatFieldElements = convertToRefFieldElements(
|
||||
refRepeatComments, program, refRepeatPrefixString, showSemicolon, isWordWrap,
|
||||
prependRefAddress, refRepeatComment.getAddress(), getNextRow(elementList));
|
||||
elementList.addAll(refRepeatFieldElements);
|
||||
if (comments.isShowingRefRepeatables()) {
|
||||
prefix = createPrefix(refRepeatableCommentStyle);
|
||||
List<RefRepeatComment> refRepeatables =
|
||||
comments.getReferencedRepeatableComments();
|
||||
for (RefRepeatComment comment : refRepeatables) {
|
||||
int row = getNextRow(elementList);
|
||||
String[] lines = comment.getCommentLines();
|
||||
List<FieldElement> elements = convertToRefFieldElements(
|
||||
lines, program, prefix, comment.getAddress(), row);
|
||||
elementList.addAll(elements);
|
||||
}
|
||||
}
|
||||
|
||||
// Automatic Comment
|
||||
if (alwaysShowAutomatic || elementList.isEmpty()) {
|
||||
AttributedString autoCommentPrefixString = new AttributedString(SEMICOLON_PREFIX,
|
||||
CommentColors.AUTO, getMetrics(automaticCommentStyle), false, null);
|
||||
String[] autoComment = displayableEol.getAutomaticComment();
|
||||
List<FieldElement> autoCommentFieldElements =
|
||||
convertToFieldElements(program, autoComment, autoCommentPrefixString, showSemicolon,
|
||||
isWordWrap, getNextRow(elementList));
|
||||
elementList.addAll(autoCommentFieldElements);
|
||||
if (comments.isShowingAutoComments()) {
|
||||
prefix = createPrefix(automaticCommentStyle);
|
||||
int row = getNextRow(elementList);
|
||||
List<String> autos = comments.getAutomaticComment();
|
||||
List<FieldElement> elements = convertToFieldElements(program, autos, prefix, row);
|
||||
elementList.addAll(elements);
|
||||
}
|
||||
|
||||
FieldElement[] fieldElements = elementList.toArray(new FieldElement[elementList.size()]);
|
||||
@@ -340,6 +305,27 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
maxDisplayLines, hlProvider);
|
||||
}
|
||||
|
||||
private AttributedString createPrefix(int commentStyle) {
|
||||
if (commentStyle == style) {
|
||||
return new AttributedString(SEMICOLON_PREFIX, CommentColors.EOL, getMetrics(style),
|
||||
false,
|
||||
null);
|
||||
}
|
||||
if (commentStyle == repeatableCommentStyle) {
|
||||
return new AttributedString(SEMICOLON_PREFIX,
|
||||
CommentColors.REPEATABLE, getMetrics(repeatableCommentStyle), false, null);
|
||||
}
|
||||
if (commentStyle == refRepeatableCommentStyle) {
|
||||
return new AttributedString(SEMICOLON_PREFIX,
|
||||
CommentColors.REF_REPEATABLE, getMetrics(refRepeatableCommentStyle), false, null);
|
||||
}
|
||||
if (commentStyle == automaticCommentStyle) {
|
||||
return new AttributedString(SEMICOLON_PREFIX,
|
||||
CommentColors.AUTO, getMetrics(automaticCommentStyle), false, null);
|
||||
}
|
||||
throw new AssertException("Unexected comment style: " + commentStyle);
|
||||
}
|
||||
|
||||
private int getNextRow(List<FieldElement> elementList) {
|
||||
int elementIndex = elementList.size() - 1;
|
||||
if (elementIndex >= 0) {
|
||||
@@ -352,26 +338,25 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private List<FieldElement> convertToFieldElements(Program program, String[] comments,
|
||||
AttributedString currentPrefixString, boolean showPrefix, boolean wordWrap,
|
||||
int nextRow) {
|
||||
private List<FieldElement> convertToFieldElements(Program program, List<String> comments,
|
||||
AttributedString currentPrefixString, int nextRow) {
|
||||
|
||||
List<FieldElement> fieldElements = new ArrayList<>();
|
||||
if (comments.length == 0) {
|
||||
if (comments.isEmpty()) {
|
||||
return fieldElements;
|
||||
}
|
||||
for (int rowIndex = 0; rowIndex < comments.length; rowIndex++) {
|
||||
for (int rowIndex = 0; rowIndex < comments.size(); rowIndex++) {
|
||||
int encodedRow = nextRow + rowIndex;
|
||||
fieldElements.add(CommentUtils.parseTextForAnnotations(comments[rowIndex], program,
|
||||
fieldElements.add(CommentUtils.parseTextForAnnotations(comments.get(rowIndex), program,
|
||||
currentPrefixString, encodedRow));
|
||||
}
|
||||
|
||||
if (wordWrap) {
|
||||
int lineWidth = showPrefix ? width - currentPrefixString.getStringWidth() : width;
|
||||
if (isWordWrap) {
|
||||
int lineWidth = showSemicolon ? width - currentPrefixString.getStringWidth() : width;
|
||||
fieldElements = FieldUtils.wrap(fieldElements, lineWidth);
|
||||
}
|
||||
|
||||
if (showPrefix) {
|
||||
if (showSemicolon) {
|
||||
for (int i = 0; i < fieldElements.size(); i++) {
|
||||
RowColLocation startRowCol =
|
||||
fieldElements.get(i).getDataLocationForCharacterIndex(0);
|
||||
@@ -387,8 +372,7 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
}
|
||||
|
||||
private List<FieldElement> convertToRefFieldElements(String[] comments, Program program,
|
||||
AttributedString currentPrefixString, boolean showPrefix, boolean wordWrap,
|
||||
boolean showRefAddress, Address refAddress, int nextRow) {
|
||||
AttributedString currentPrefixString, Address refAddress, int nextRow) {
|
||||
|
||||
int numCommentLines = comments.length;
|
||||
List<FieldElement> fieldElements = new ArrayList<>();
|
||||
@@ -400,7 +384,7 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
fieldElements.add(CommentUtils.parseTextForAnnotations(comments[rowIndex], program,
|
||||
currentPrefixString, encodedRow));
|
||||
}
|
||||
if (showRefAddress) {
|
||||
if (prependRefAddress) {
|
||||
FieldElement commentElement = fieldElements.get(0);
|
||||
// Address
|
||||
String refAddrComment = "{@address " + refAddress.toString() + "}";
|
||||
@@ -418,12 +402,12 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
new FieldElement[] { addressElement, spacerElement, commentElement }));
|
||||
}
|
||||
|
||||
if (wordWrap) {
|
||||
int lineWidth = showPrefix ? width - currentPrefixString.getStringWidth() : width;
|
||||
if (isWordWrap) {
|
||||
int lineWidth = showSemicolon ? width - currentPrefixString.getStringWidth() : width;
|
||||
fieldElements = FieldUtils.wrap(fieldElements, lineWidth);
|
||||
}
|
||||
|
||||
if (showPrefix) {
|
||||
if (showSemicolon) {
|
||||
for (int i = 0; i < fieldElements.size(); i++) {
|
||||
RowColLocation startRowCol =
|
||||
fieldElements.get(i).getDataLocationForCharacterIndex(0);
|
||||
@@ -451,10 +435,9 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
return null;
|
||||
}
|
||||
CodeUnit cu = (CodeUnit) obj;
|
||||
DisplayableEol displayableEol =
|
||||
new DisplayableEol(cu, alwaysShowRepeatable, alwaysShowRefRepeatables,
|
||||
alwaysShowAutomatic, codeUnitFormatOptions.followReferencedPointers(),
|
||||
maxDisplayLines, useAbbreviatedAutomatic, showAutomaticFunctions);
|
||||
EolComments displayableEol =
|
||||
new EolComments(cu, codeUnitFormatOptions.followReferencedPointers(),
|
||||
maxDisplayLines, extraCommentsOption);
|
||||
|
||||
// Hold position in connected tool if navigating within semicolon.
|
||||
int numLeadColumns = 0;
|
||||
@@ -489,10 +472,9 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
return null;
|
||||
}
|
||||
|
||||
DisplayableEol displayableEol =
|
||||
new DisplayableEol((CodeUnit) obj, alwaysShowRepeatable, alwaysShowRefRepeatables,
|
||||
alwaysShowAutomatic, codeUnitFormatOptions.followReferencedPointers(),
|
||||
maxDisplayLines, useAbbreviatedAutomatic, showAutomaticFunctions);
|
||||
EolComments displayableEol =
|
||||
new EolComments((CodeUnit) obj, codeUnitFormatOptions.followReferencedPointers(),
|
||||
maxDisplayLines, extraCommentsOption);
|
||||
|
||||
ListingTextField btf = (ListingTextField) bf;
|
||||
RowColLocation eolRowCol = displayableEol.getRowCol((CommentFieldLocation) loc);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.viewer.field;
|
||||
|
||||
public enum EolEnablement {
|
||||
ALWAYS,
|
||||
DEFAULT,
|
||||
NEVER;
|
||||
}
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.viewer.field;
|
||||
|
||||
import ghidra.framework.options.CustomOption;
|
||||
import ghidra.framework.options.GProperties;
|
||||
|
||||
/**
|
||||
* An option class that is used by the {@link EolExtraCommentsPropertyEditor} to load and save
|
||||
* option settings.
|
||||
*/
|
||||
public class EolExtraCommentsOption implements CustomOption {
|
||||
|
||||
private static final String BASE_KEY = "extraComment";
|
||||
private static final String KEY_REPETABLE = BASE_KEY + "Repeatable";
|
||||
private static final String KEY_REF_REPETABLE = BASE_KEY + "RefRepeatable";
|
||||
private static final String KEY_AUTO_DATA = BASE_KEY + "AutoData";
|
||||
private static final String KEY_AUTO_FUNCTION = BASE_KEY + "AutoFunction";
|
||||
private static final String KEY_USE_ABBRAVIATED = BASE_KEY + "UseAbbreviated";
|
||||
|
||||
private EolEnablement repeatable = EolEnablement.DEFAULT;
|
||||
private EolEnablement refRepeatable = EolEnablement.DEFAULT;
|
||||
private EolEnablement autoFunction = EolEnablement.DEFAULT;
|
||||
private EolEnablement autoData = EolEnablement.DEFAULT;
|
||||
|
||||
private boolean useAbbreviatedComments = true;
|
||||
|
||||
public EolExtraCommentsOption() {
|
||||
// required for persistence
|
||||
}
|
||||
|
||||
public EolEnablement getRepeatable() {
|
||||
return repeatable;
|
||||
}
|
||||
|
||||
public void setRepeatable(EolEnablement priority) {
|
||||
repeatable = priority;
|
||||
}
|
||||
|
||||
public EolEnablement getRefRepeatable() {
|
||||
return refRepeatable;
|
||||
}
|
||||
|
||||
public void setRefRepeatable(EolEnablement priority) {
|
||||
refRepeatable = priority;
|
||||
}
|
||||
|
||||
public EolEnablement getAutoData() {
|
||||
return autoData;
|
||||
}
|
||||
|
||||
public void setAutoData(EolEnablement priority) {
|
||||
autoData = priority;
|
||||
}
|
||||
|
||||
public EolEnablement getAutoFunction() {
|
||||
return autoFunction;
|
||||
}
|
||||
|
||||
public void setAutoFunction(EolEnablement priority) {
|
||||
autoFunction = priority;
|
||||
}
|
||||
|
||||
public boolean useAbbreviatedComments() {
|
||||
return useAbbreviatedComments;
|
||||
}
|
||||
|
||||
public void setUseAbbreviatedComments(boolean b) {
|
||||
useAbbreviatedComments = b;
|
||||
}
|
||||
|
||||
public boolean alwaysShowAutoComments() {
|
||||
return autoData == EolEnablement.ALWAYS || autoFunction == EolEnablement.ALWAYS;
|
||||
}
|
||||
|
||||
public boolean isShowingRefRepeatables(boolean hasOtherComments) {
|
||||
return isShowing(refRepeatable, hasOtherComments);
|
||||
}
|
||||
|
||||
public boolean isShowingRepeatables(boolean hasOtherComments) {
|
||||
return isShowing(repeatable, hasOtherComments);
|
||||
}
|
||||
|
||||
public boolean isShowingAutoComments(boolean hasOtherComments) {
|
||||
|
||||
if (alwaysShowAutoComments()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isShowing(autoData, hasOtherComments)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isShowing(autoFunction, hasOtherComments);
|
||||
}
|
||||
|
||||
private boolean isShowing(EolEnablement enablement, boolean hasExistingComments) {
|
||||
return enablement == EolEnablement.ALWAYS ||
|
||||
(enablement == EolEnablement.DEFAULT && !hasExistingComments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readState(GProperties properties) {
|
||||
repeatable = properties.getEnum(KEY_REPETABLE, EolEnablement.DEFAULT);
|
||||
refRepeatable = properties.getEnum(KEY_REF_REPETABLE, EolEnablement.DEFAULT);
|
||||
autoData = properties.getEnum(KEY_AUTO_DATA, EolEnablement.DEFAULT);
|
||||
autoFunction = properties.getEnum(KEY_AUTO_FUNCTION, EolEnablement.DEFAULT);
|
||||
useAbbreviatedComments = properties.getBoolean(KEY_USE_ABBRAVIATED, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeState(GProperties properties) {
|
||||
properties.putEnum(KEY_REPETABLE, repeatable);
|
||||
properties.putEnum(KEY_REF_REPETABLE, refRepeatable);
|
||||
properties.putEnum(KEY_AUTO_DATA, autoData);
|
||||
properties.putEnum(KEY_AUTO_FUNCTION, autoFunction);
|
||||
properties.putBoolean(KEY_USE_ABBRAVIATED, useAbbreviatedComments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((autoData == null) ? 0 : autoData.hashCode());
|
||||
result = prime * result + ((autoFunction == null) ? 0 : autoFunction.hashCode());
|
||||
result = prime * result + ((refRepeatable == null) ? 0 : refRepeatable.hashCode());
|
||||
result = prime * result + ((repeatable == null) ? 0 : repeatable.hashCode());
|
||||
result = prime * result + (useAbbreviatedComments ? 1231 : 1237);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
EolExtraCommentsOption other = (EolExtraCommentsOption) obj;
|
||||
if (autoData != other.autoData) {
|
||||
return false;
|
||||
}
|
||||
if (autoFunction != other.autoFunction) {
|
||||
return false;
|
||||
}
|
||||
if (refRepeatable != other.refRepeatable) {
|
||||
return false;
|
||||
}
|
||||
if (repeatable != other.repeatable) {
|
||||
return false;
|
||||
}
|
||||
if (useAbbreviatedComments != other.useAbbreviatedComments) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.viewer.field;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.TitledBorder;
|
||||
|
||||
import docking.widgets.checkbox.GCheckBox;
|
||||
import docking.widgets.combobox.GComboBox;
|
||||
import ghidra.framework.options.CustomOptionsEditor;
|
||||
import ghidra.util.layout.PairLayout;
|
||||
|
||||
public class EolExtraCommentsPropertyEditor extends PropertyEditorSupport
|
||||
implements CustomOptionsEditor {
|
||||
|
||||
private static final String REPEATABLE_LABEL = "Repeatable Comment";
|
||||
private static final String REF_REPEATABLE_LABEL = "Referenced Repeatable Comments";
|
||||
private static final String AUTO_DATA_LABEL = "Auto Data Comment";
|
||||
private static final String AUTO_FUNCTION_LABEL = "Auto Function Comment";
|
||||
private static final String ABBREVIATED_LABEL = "Use Abbreviated Comments";
|
||||
|
||||
private static final String REPEATABLE_TOOLTIP =
|
||||
"<HTML>For repeatable comments:" +
|
||||
"<UL>" +
|
||||
" <LI>ALWAYS - show even if an EOL comment exists</LI>" +
|
||||
" <LI>DEFAULT - show only when no EOL comment exists</LI>" +
|
||||
" <LI>NEVER - do not show</LI>" +
|
||||
"</UL>";
|
||||
|
||||
private static final String REF_REPEATABLE_TOOLTIP =
|
||||
"<HTML>For referenced repeatable comments:" +
|
||||
"<UL>" +
|
||||
" <LI>ALWAYS - show even if a higher priority comment exists</LI>" +
|
||||
" <LI>DEFAULT - show only when no higher priority comment exists</LI>" +
|
||||
" <LI>NEVER - do not show</LI>" +
|
||||
"</UL>";
|
||||
|
||||
private static final String AUTO_TOOLTIP =
|
||||
"<HTML>For automatic comments:" +
|
||||
"<UL>" +
|
||||
" <LI>ALWAYS - show even if a higher priority comment exists</LI>" +
|
||||
" <LI>DEFAULT - show only when no higher priority comment exists</LI>" +
|
||||
" <LI>NEVER - do not show</LI>" +
|
||||
"</UL>";
|
||||
|
||||
private static final String ABBREVIATED_TOOLTIP =
|
||||
"When showing automatic comments, show the smallest amount of information possible";
|
||||
|
||||
private static final String[] NAMES =
|
||||
{ REPEATABLE_LABEL, REF_REPEATABLE_LABEL, AUTO_DATA_LABEL, AUTO_FUNCTION_LABEL,
|
||||
ABBREVIATED_LABEL };
|
||||
|
||||
private static final String[] DESCRIPTIONS = {
|
||||
REPEATABLE_TOOLTIP, REF_REPEATABLE_TOOLTIP, AUTO_TOOLTIP, AUTO_TOOLTIP,
|
||||
ABBREVIATED_TOOLTIP
|
||||
};
|
||||
|
||||
private Component editorComponent;
|
||||
|
||||
private GComboBox<EolEnablement> repeatableCombo;
|
||||
private GComboBox<EolEnablement> refRepeatableCombo;
|
||||
private GComboBox<EolEnablement> autoDataCombo;
|
||||
private GComboBox<EolEnablement> autoFunctionCombo;
|
||||
private JCheckBox abbreviatedCheckbox;
|
||||
|
||||
private EolExtraCommentsOption commentsOption;
|
||||
|
||||
public EolExtraCommentsPropertyEditor() {
|
||||
editorComponent = buildEditor();
|
||||
}
|
||||
|
||||
private Component buildEditor() {
|
||||
|
||||
// values picked through trial-and-error
|
||||
int vgap = 3;
|
||||
int hgap = 5;
|
||||
int minRightSize = 150; // big enough to match other items in the external options panel
|
||||
JPanel panel = new JPanel(new PairLayout(vgap, hgap, minRightSize));
|
||||
|
||||
JLabel label = new JLabel(REPEATABLE_LABEL);
|
||||
label.setToolTipText(REPEATABLE_TOOLTIP);
|
||||
repeatableCombo = new GComboBox<>(EolEnablement.values());
|
||||
repeatableCombo.setSelectedItem(EolEnablement.DEFAULT);
|
||||
repeatableCombo.addItemListener(e -> firePropertyChange());
|
||||
|
||||
panel.add(label);
|
||||
panel.add(repeatableCombo);
|
||||
|
||||
label = new JLabel(REF_REPEATABLE_LABEL);
|
||||
label.setToolTipText(REF_REPEATABLE_TOOLTIP);
|
||||
refRepeatableCombo = new GComboBox<>(EolEnablement.values());
|
||||
refRepeatableCombo.setSelectedItem(EolEnablement.DEFAULT);
|
||||
refRepeatableCombo.addItemListener(e -> firePropertyChange());
|
||||
|
||||
panel.add(label);
|
||||
panel.add(refRepeatableCombo);
|
||||
|
||||
label = new JLabel(AUTO_DATA_LABEL);
|
||||
label.setToolTipText(AUTO_TOOLTIP);
|
||||
autoDataCombo = new GComboBox<>(EolEnablement.values());
|
||||
autoDataCombo.setSelectedItem(EolEnablement.DEFAULT);
|
||||
autoDataCombo.addItemListener(e -> firePropertyChange());
|
||||
|
||||
panel.add(label);
|
||||
panel.add(autoDataCombo);
|
||||
|
||||
label = new JLabel(AUTO_FUNCTION_LABEL);
|
||||
label.setToolTipText(AUTO_TOOLTIP);
|
||||
autoFunctionCombo = new GComboBox<>(EolEnablement.values());
|
||||
autoFunctionCombo.setSelectedItem(EolEnablement.DEFAULT);
|
||||
autoFunctionCombo.addItemListener(e -> firePropertyChange());
|
||||
|
||||
panel.add(label);
|
||||
panel.add(autoFunctionCombo);
|
||||
|
||||
abbreviatedCheckbox = new GCheckBox(ABBREVIATED_LABEL);
|
||||
abbreviatedCheckbox.setSelected(true);
|
||||
abbreviatedCheckbox.setToolTipText(ABBREVIATED_TOOLTIP);
|
||||
|
||||
ItemListener listener = e -> firePropertyChange();
|
||||
repeatableCombo.addItemListener(listener);
|
||||
refRepeatableCombo.addItemListener(listener);
|
||||
autoDataCombo.addItemListener(listener);
|
||||
autoFunctionCombo.addItemListener(listener);
|
||||
abbreviatedCheckbox.addItemListener(listener);
|
||||
|
||||
panel.setBorder(BorderFactory.createCompoundBorder(
|
||||
new TitledBorder("Additional Comment Types"),
|
||||
BorderFactory.createEmptyBorder(10, 10, 10, 10)));
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
private Object cloneOptionValues() {
|
||||
EolExtraCommentsOption newOption = new EolExtraCommentsOption();
|
||||
newOption.setRepeatable((EolEnablement) repeatableCombo.getSelectedItem());
|
||||
newOption.setRefRepeatable((EolEnablement) refRepeatableCombo.getSelectedItem());
|
||||
newOption.setAutoData((EolEnablement) autoDataCombo.getSelectedItem());
|
||||
newOption.setAutoFunction((EolEnablement) autoFunctionCombo.getSelectedItem());
|
||||
return newOption;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getOptionNames() {
|
||||
return NAMES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getOptionDescriptions() {
|
||||
return DESCRIPTIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return cloneOptionValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getCustomEditor() {
|
||||
return editorComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCustomEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object value) {
|
||||
if (!(value instanceof EolExtraCommentsOption)) {
|
||||
return;
|
||||
}
|
||||
|
||||
commentsOption = (EolExtraCommentsOption) value;
|
||||
setLocalValues(commentsOption);
|
||||
firePropertyChange();
|
||||
}
|
||||
|
||||
private void setLocalValues(EolExtraCommentsOption sourceOption) {
|
||||
|
||||
EolEnablement currentPriority = (EolEnablement) repeatableCombo.getSelectedItem();
|
||||
EolEnablement newPriority = sourceOption.getRepeatable();
|
||||
if (currentPriority != newPriority) {
|
||||
repeatableCombo.setSelectedItem(newPriority);
|
||||
}
|
||||
|
||||
currentPriority = (EolEnablement) refRepeatableCombo.getSelectedItem();
|
||||
newPriority = sourceOption.getRefRepeatable();
|
||||
if (currentPriority != newPriority) {
|
||||
refRepeatableCombo.setSelectedItem(newPriority);
|
||||
}
|
||||
|
||||
currentPriority = (EolEnablement) autoDataCombo.getSelectedItem();
|
||||
newPriority = sourceOption.getAutoData();
|
||||
if (currentPriority != newPriority) {
|
||||
autoDataCombo.setSelectedItem(newPriority);
|
||||
}
|
||||
|
||||
currentPriority = (EolEnablement) autoFunctionCombo.getSelectedItem();
|
||||
newPriority = sourceOption.getAutoFunction();
|
||||
if (currentPriority != newPriority) {
|
||||
autoFunctionCombo.setSelectedItem(newPriority);
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-5
@@ -167,15 +167,14 @@ 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_KEY, OptionType.CUSTOM_TYPE,
|
||||
new NamespaceWrappedOption(), null, "Adjusts the XREFs Field namespace display",
|
||||
namespaceOptionsEditor);
|
||||
new NamespaceWrappedOption(), new HelpLocation("CodeBrowserPlugin", "XREFs_Field"),
|
||||
"Adjusts the XREFs Field namespace display", namespaceOptionsEditor);
|
||||
CustomOption customOption = fieldOptions.getCustomOption(NAMESPACE_OPTIONS_KEY, null);
|
||||
fieldOptions.getOptions(NAMESPACE_OPTIONS_KEY)
|
||||
.setOptionsHelpLocation(new HelpLocation("CodeBrowserPlugin", "XREFs_Field"));
|
||||
|
||||
if (!(customOption instanceof NamespaceWrappedOption)) {
|
||||
throw new AssertException("Someone set an option for " + NAMESPACE_OPTIONS_KEY +
|
||||
" that is not the expected " +
|
||||
"ghidra.app.util.viewer.field.NamespaceWrappedOption type.");
|
||||
NamespaceWrappedOption.class.getName() + " type.");
|
||||
}
|
||||
|
||||
NamespaceWrappedOption namespaceOption = (NamespaceWrappedOption) customOption;
|
||||
|
||||
+35
-37
@@ -578,29 +578,16 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
|
||||
@Test
|
||||
public void testEOLCommentsOptions() throws Exception {
|
||||
|
||||
final int SHOW_AUTO = 0;
|
||||
final int SHOW_REF_REPEAT = 1;
|
||||
final int SHOW_REPEATABLE = 2;
|
||||
final int WORD_WRAP = 3;
|
||||
final int MAX_LINES = 4;
|
||||
final int SHOW_REF_ADDR = 5;
|
||||
//final int SHOW_FUNCTION_AUTO = 6;
|
||||
final int SHOW_SEMICOLON = 7;
|
||||
// for readability
|
||||
String EXTRA_COMMENTS = EolCommentFieldFactory.EXTRA_COMMENT_KEY;
|
||||
String WORD_WRAP = EolCommentFieldFactory.ENABLE_WORD_WRAP_KEY;
|
||||
String MAX_LINES = EolCommentFieldFactory.MAX_DISPLAY_LINES_KEY;
|
||||
String SHOW_REF_ADDR = EolCommentFieldFactory.ENABLE_PREPEND_REF_ADDRESS_KEY;
|
||||
String SHOW_SEMICOLON = EolCommentFieldFactory.ENABLE_SHOW_SEMICOLON_KEY;
|
||||
|
||||
showTool(tool);
|
||||
loadProgram();
|
||||
Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||
List<String> names = getOptionNames(options, "EOL Comments Field");
|
||||
assertEquals(9, names.size());
|
||||
assertEquals(EolCommentFieldFactory.ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, names.get(0));
|
||||
assertEquals(EolCommentFieldFactory.ENABLE_ALWAYS_SHOW_REF_REPEATABLE_MSG, names.get(1));
|
||||
assertEquals(EolCommentFieldFactory.ENABLE_ALWAYS_SHOW_REPEATABLE_MSG, names.get(2));
|
||||
assertEquals(EolCommentFieldFactory.ENABLE_WORD_WRAP_MSG, names.get(3));
|
||||
assertEquals(EolCommentFieldFactory.MAX_DISPLAY_LINES_MSG, names.get(4));
|
||||
assertEquals(EolCommentFieldFactory.ENABLE_PREPEND_REF_ADDRESS_MSG, names.get(5));
|
||||
assertEquals(EolCommentFieldFactory.SHOW_FUNCTION_AUTOMITIC_COMMENT_MSG, names.get(6));
|
||||
assertEquals(EolCommentFieldFactory.ENABLE_SHOW_SEMICOLON_MSG, names.get(7));
|
||||
assertEquals(EolCommentFieldFactory.USE_ABBREVIATED_AUTOMITIC_COMMENT_MSG, names.get(8));
|
||||
|
||||
Address callAddress = addr("0x1003fcc");
|
||||
Address callRefAddress = addr("0x1006642");
|
||||
Address otherRefAddress = addr("0x1003fa1");
|
||||
@@ -637,66 +624,77 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
|
||||
CodeUnit.REPEATABLE_COMMENT, "Mem ref line1.\n" + "");
|
||||
tool.execute(commentRefCmd, program);
|
||||
|
||||
options.setBoolean(names.get(SHOW_AUTO), false);
|
||||
options.setBoolean(names.get(SHOW_REF_REPEAT), false);
|
||||
options.setBoolean(names.get(SHOW_REPEATABLE), false);
|
||||
options.setBoolean(names.get(WORD_WRAP), false);
|
||||
options.setInt(names.get(MAX_LINES), 20);
|
||||
options.setBoolean(names.get(SHOW_REF_ADDR), false);
|
||||
options.setBoolean(names.get(SHOW_SEMICOLON), false);
|
||||
// these values are all DEFAULT, by default; set them in case that changes in the future
|
||||
EolExtraCommentsOption extraCommentsOption = new EolExtraCommentsOption();
|
||||
extraCommentsOption.setRepeatable(EolEnablement.DEFAULT);
|
||||
extraCommentsOption.setRefRepeatable(EolEnablement.DEFAULT);
|
||||
extraCommentsOption.setAutoData(EolEnablement.DEFAULT);
|
||||
extraCommentsOption.setAutoFunction(EolEnablement.DEFAULT);
|
||||
|
||||
options.setCustomOption(EXTRA_COMMENTS, extraCommentsOption);
|
||||
options.setBoolean(WORD_WRAP, false);
|
||||
options.setInt(MAX_LINES, 20);
|
||||
options.setBoolean(SHOW_REF_ADDR, false);
|
||||
options.setBoolean(SHOW_SEMICOLON, false);
|
||||
|
||||
cb.updateNow();
|
||||
cb.goToField(callAddress, "EOL Comment", 0, 0);
|
||||
ListingTextField btf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(9, getNumberOfLines(btf));
|
||||
|
||||
options.setBoolean(names.get(WORD_WRAP), true);
|
||||
options.setBoolean(WORD_WRAP, true);
|
||||
cb.updateNow();
|
||||
btf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(18, getNumberOfLines(btf));
|
||||
|
||||
options.setBoolean(names.get(SHOW_SEMICOLON), true);
|
||||
options.setBoolean(SHOW_SEMICOLON, true);
|
||||
cb.updateNow();
|
||||
btf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(20, getNumberOfLines(btf));
|
||||
assertEquals("; ", btf.getFieldElement(1, 0).getText());
|
||||
|
||||
options.setBoolean(names.get(SHOW_REPEATABLE), true);
|
||||
extraCommentsOption.setRepeatable(EolEnablement.ALWAYS);
|
||||
options.setCustomOption(EXTRA_COMMENTS, extraCommentsOption);
|
||||
cb.updateNow();
|
||||
btf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(20, getNumberOfLines(btf));
|
||||
assertEquals("; ", btf.getFieldElement(1, 0).getText());
|
||||
|
||||
options.setBoolean(names.get(SHOW_AUTO), true);
|
||||
extraCommentsOption.setAutoData(EolEnablement.ALWAYS);
|
||||
extraCommentsOption.setAutoFunction(EolEnablement.ALWAYS);
|
||||
options.setCustomOption(EXTRA_COMMENTS, extraCommentsOption);
|
||||
cb.updateNow();
|
||||
btf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(20, getNumberOfLines(btf));
|
||||
assertEquals("; ", btf.getFieldElement(1, 0).getText());
|
||||
|
||||
options.setBoolean(names.get(SHOW_REF_REPEAT), true);
|
||||
extraCommentsOption.setRefRepeatable(EolEnablement.ALWAYS);
|
||||
options.setCustomOption(EXTRA_COMMENTS, extraCommentsOption);
|
||||
cb.updateNow();
|
||||
btf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(20, getNumberOfLines(btf));
|
||||
assertEquals("; ", btf.getFieldElement(1, 0).getText());
|
||||
|
||||
options.setBoolean(names.get(SHOW_REF_ADDR), true);
|
||||
options.setBoolean(EolCommentFieldFactory.ENABLE_PREPEND_REF_ADDRESS_KEY, true);
|
||||
cb.updateNow();
|
||||
btf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(20, getNumberOfLines(btf));
|
||||
assertEquals("; ", btf.getFieldElement(1, 0).getText());
|
||||
|
||||
options.setBoolean(names.get(SHOW_REPEATABLE), false);
|
||||
extraCommentsOption.setRepeatable(EolEnablement.DEFAULT);
|
||||
options.setCustomOption(EXTRA_COMMENTS, extraCommentsOption);
|
||||
cb.updateNow();
|
||||
btf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(20, getNumberOfLines(btf));
|
||||
assertEquals("; ", btf.getFieldElement(1, 0).getText());
|
||||
|
||||
options.setBoolean(names.get(WORD_WRAP), false);
|
||||
options.setBoolean(WORD_WRAP, false);
|
||||
cb.updateNow();
|
||||
btf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(12, getNumberOfLines(btf));
|
||||
assertTrue("; ".equals(btf.getFieldElement(5, 0).getText()));
|
||||
|
||||
options.setBoolean(names.get(SHOW_SEMICOLON), false);
|
||||
options.setBoolean(SHOW_SEMICOLON, false);
|
||||
cb.updateNow();
|
||||
btf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(12, getNumberOfLines(btf));
|
||||
@@ -704,7 +702,7 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
|
||||
assertEquals("01003fa1", btf.getFieldElement(11, 4).getText());
|
||||
assertEquals("Mem ref line1.", btf.getFieldElement(11, 11).getText());
|
||||
|
||||
options.setBoolean(names.get(SHOW_REF_ADDR), false);
|
||||
options.setBoolean(SHOW_REF_ADDR, false);
|
||||
cb.updateNow();
|
||||
btf = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(11, getNumberOfLines(btf));
|
||||
|
||||
+2
-2
@@ -247,8 +247,8 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
setFieldWidth(browser, EolCommentFieldFactory.FIELD_NAME, 100);
|
||||
|
||||
Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||
options.setBoolean(EolCommentFieldFactory.ENABLE_WORD_WRAP_MSG, true);
|
||||
options.setInt(EolCommentFieldFactory.MAX_DISPLAY_LINES_MSG, 100);
|
||||
options.setBoolean(EolCommentFieldFactory.ENABLE_WORD_WRAP_KEY, true);
|
||||
options.setInt(EolCommentFieldFactory.MAX_DISPLAY_LINES_KEY, 100);
|
||||
|
||||
runSwing(() -> tool.getToolFrame().setSize(800, 800));
|
||||
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ public class EolCommentFieldFactoryTest extends AbstractGhidraHeadedIntegrationT
|
||||
ListingTextField tf = getFieldText(function);
|
||||
assertEquals(2, tf.getNumRows());
|
||||
|
||||
setBooleanOption(EolCommentFieldFactory.ENABLE_WORD_WRAP_MSG, true);
|
||||
setBooleanOption(EolCommentFieldFactory.ENABLE_WORD_WRAP_KEY, true);
|
||||
|
||||
tf = getFieldText(function);
|
||||
assertEquals(4, tf.getNumRows());
|
||||
|
||||
+2
-1
@@ -243,7 +243,8 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
// skip options that are "not simple", i.e. have custom editors
|
||||
if (simpleName.equals("Display Namespace") ||
|
||||
simpleName.equals("Array Display Options") ||
|
||||
simpleName.equals("Address Display Options")) {
|
||||
simpleName.equals("Address Display Options") ||
|
||||
simpleName.equals("Auto Comments")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
+64
-47
@@ -18,13 +18,16 @@ package ghidra.app.plugin.core.comments;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.app.cmd.refs.AddMemRefCmd;
|
||||
import ghidra.app.util.DisplayableEol;
|
||||
import ghidra.app.util.EolComments;
|
||||
import ghidra.app.util.viewer.field.EolEnablement;
|
||||
import ghidra.app.util.viewer.field.EolExtraCommentsOption;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
@@ -37,11 +40,11 @@ import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
import ghidra.util.exception.RollbackException;
|
||||
|
||||
public class DisplayableEolTest extends AbstractGenericTest {
|
||||
public class EolCommentsTest extends AbstractGenericTest {
|
||||
|
||||
private ProgramDB program;
|
||||
|
||||
public DisplayableEolTest() {
|
||||
public EolCommentsTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -72,12 +75,22 @@ public class DisplayableEolTest extends AbstractGenericTest {
|
||||
|
||||
Listing listing = program.getListing();
|
||||
CodeUnit cu = listing.getCodeUnitAt(addr("0x110"));
|
||||
DisplayableEol displayableEol =
|
||||
new DisplayableEol(cu, true, true, true, false, 5, true, true);
|
||||
|
||||
String[] comments = displayableEol.getAutomaticComment();
|
||||
assertEquals(1, comments.length);
|
||||
assertEquals("? -> 00000120", comments[0]);
|
||||
EolExtraCommentsOption eolOption = createShowAllOption();
|
||||
EolComments eolComments = new EolComments(cu, false, 5, eolOption);
|
||||
|
||||
List<String> comments = eolComments.getAutomaticComment();
|
||||
assertEquals(1, comments.size());
|
||||
assertEquals("? -> 00000120", comments.get(0));
|
||||
}
|
||||
|
||||
private EolExtraCommentsOption createShowAllOption() {
|
||||
EolExtraCommentsOption eolOption = new EolExtraCommentsOption();
|
||||
eolOption.setRepeatable(EolEnablement.ALWAYS);
|
||||
eolOption.setRefRepeatable(EolEnablement.ALWAYS);
|
||||
eolOption.setAutoData(EolEnablement.ALWAYS);
|
||||
eolOption.setAutoFunction(EolEnablement.ALWAYS);
|
||||
return eolOption;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -89,12 +102,12 @@ public class DisplayableEolTest extends AbstractGenericTest {
|
||||
|
||||
Listing listing = program.getListing();
|
||||
CodeUnit cu = listing.getCodeUnitAt(addr("0x1001000"));
|
||||
DisplayableEol displayableEol =
|
||||
new DisplayableEol(cu, true, true, true, false, 5, true, true);
|
||||
EolExtraCommentsOption eolOption = createShowAllOption();
|
||||
EolComments eolComments = new EolComments(cu, false, 5, eolOption);
|
||||
|
||||
String[] comments = displayableEol.getAutomaticComment();
|
||||
assertEquals(1, comments.length);
|
||||
assertEquals("= \"one.two\"", comments[0]);
|
||||
List<String> comments = eolComments.getAutomaticComment();
|
||||
assertEquals(1, comments.size());
|
||||
assertEquals("= \"one.two\"", comments.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -109,15 +122,15 @@ public class DisplayableEolTest extends AbstractGenericTest {
|
||||
Listing listing = program.getListing();
|
||||
CodeUnit cu = listing.getCodeUnitAt(addr("0x1001000"));
|
||||
|
||||
EolExtraCommentsOption eolOption = createShowAllOption();
|
||||
|
||||
// with this at false, all of the string will be rendered
|
||||
boolean useAbbreviatedComments = false;
|
||||
eolOption.setUseAbbreviatedComments(false);
|
||||
EolComments eolComments = new EolComments(cu, false, 5, eolOption);
|
||||
|
||||
DisplayableEol displayableEol =
|
||||
new DisplayableEol(cu, true, true, true, false, 5, useAbbreviatedComments, true);
|
||||
|
||||
String[] comments = displayableEol.getAutomaticComment();
|
||||
assertEquals(1, comments.length);
|
||||
assertEquals("= \"one.two\"", comments[0]);
|
||||
List<String> comments = eolComments.getAutomaticComment();
|
||||
assertEquals(1, comments.size());
|
||||
assertEquals("= \"one.two\"", comments.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -132,16 +145,16 @@ public class DisplayableEolTest extends AbstractGenericTest {
|
||||
Listing listing = program.getListing();
|
||||
CodeUnit cu = listing.getCodeUnitAt(addr("0x1001000"));
|
||||
|
||||
// with this at false, all of the string will be rendered
|
||||
boolean useAbbreviatedComments = false;
|
||||
boolean showAutoFunctions = false;
|
||||
DisplayableEol displayableEol =
|
||||
new DisplayableEol(cu, true, true, true, false, 5, useAbbreviatedComments,
|
||||
showAutoFunctions);
|
||||
EolExtraCommentsOption eolOption = createShowAllOption();
|
||||
|
||||
String[] comments = displayableEol.getAutomaticComment();
|
||||
assertEquals(1, comments.length);
|
||||
assertEquals("= \"one.two\"", comments[0]);
|
||||
// with this at false, all of the string will be rendered
|
||||
eolOption.setUseAbbreviatedComments(false);
|
||||
eolOption.setAutoFunction(EolEnablement.NEVER);
|
||||
EolComments eolComments = new EolComments(cu, false, 5, eolOption);
|
||||
|
||||
List<String> comments = eolComments.getAutomaticComment();
|
||||
assertEquals(1, comments.size());
|
||||
assertEquals("= \"one.two\"", comments.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -159,15 +172,15 @@ public class DisplayableEolTest extends AbstractGenericTest {
|
||||
Listing listing = program.getListing();
|
||||
CodeUnit cu = listing.getCodeUnitAt(addr("0x1001000"));
|
||||
|
||||
EolExtraCommentsOption eolOption = createShowAllOption();
|
||||
|
||||
// with this at true, only the used part of the string will be rendered
|
||||
boolean useAbbreviatedComments = true;
|
||||
eolOption.setUseAbbreviatedComments(true);
|
||||
EolComments eolComments = new EolComments(cu, false, 5, eolOption);
|
||||
|
||||
DisplayableEol displayableEol =
|
||||
new DisplayableEol(cu, true, true, true, false, 5, useAbbreviatedComments, true);
|
||||
|
||||
String[] comments = displayableEol.getAutomaticComment();
|
||||
assertEquals(1, comments.length);
|
||||
assertEquals("= \"two\"", comments[0]);// full string is one.two
|
||||
List<String> comments = eolComments.getAutomaticComment();
|
||||
assertEquals(1, comments.size());
|
||||
assertEquals("= \"two\"", comments.get(0));// full string is one.two
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -181,13 +194,13 @@ public class DisplayableEolTest extends AbstractGenericTest {
|
||||
|
||||
Listing listing = program.getListing();
|
||||
CodeUnit cu = listing.getCodeUnitAt(from);
|
||||
boolean showAutoFunctions = true;
|
||||
DisplayableEol displayableEol =
|
||||
new DisplayableEol(cu, true, true, true, false, 5, false, showAutoFunctions);
|
||||
|
||||
String[] comments = displayableEol.getAutomaticComment();
|
||||
assertEquals(1, comments.length);
|
||||
assertEquals("undefined FUN_01001050()", comments[0]);
|
||||
EolExtraCommentsOption eolOption = createShowAllOption();
|
||||
EolComments eolComments = new EolComments(cu, false, 5, eolOption);
|
||||
|
||||
List<String> comments = eolComments.getAutomaticComment();
|
||||
assertEquals(1, comments.size());
|
||||
assertEquals("undefined FUN_01001050()", comments.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -201,12 +214,16 @@ public class DisplayableEolTest extends AbstractGenericTest {
|
||||
|
||||
Listing listing = program.getListing();
|
||||
CodeUnit cu = listing.getCodeUnitAt(from);
|
||||
boolean showAutoFunctions = false;
|
||||
DisplayableEol displayableEol =
|
||||
new DisplayableEol(cu, true, true, true, false, 5, false, showAutoFunctions);
|
||||
|
||||
String[] comments = displayableEol.getAutomaticComment();
|
||||
assertEquals(0, comments.length);
|
||||
EolExtraCommentsOption eolOption = createShowAllOption();
|
||||
|
||||
// with this at false, all of the string will be rendered
|
||||
eolOption.setUseAbbreviatedComments(false);
|
||||
eolOption.setAutoFunction(EolEnablement.NEVER);
|
||||
EolComments eolComments = new EolComments(cu, false, 5, eolOption);
|
||||
|
||||
List<String> comments = eolComments.getAutomaticComment();
|
||||
assertEquals(0, comments.size());
|
||||
}
|
||||
|
||||
public boolean applyCmd(Command cmd) throws RollbackException {
|
||||
-1
@@ -27,7 +27,6 @@ import ghidra.util.layout.HorizontalLayout;
|
||||
public class CustomOptionComponent extends GenericOptionsComponent {
|
||||
|
||||
protected CustomOptionComponent(EditorState editorState) {
|
||||
super(editorState);
|
||||
|
||||
// this layout allows us to easily left-align the single component in this container
|
||||
setLayout(new HorizontalLayout(0));
|
||||
|
||||
+1
-2
@@ -32,7 +32,6 @@ public class DefaultOptionComponent extends GenericOptionsComponent {
|
||||
private Component component;
|
||||
|
||||
public DefaultOptionComponent(EditorState editorState) {
|
||||
super(editorState);
|
||||
setLayout(new PairLayout(0, 6, 40));
|
||||
this.component = editorState.getEditorComponent();
|
||||
|
||||
@@ -71,7 +70,7 @@ public class DefaultOptionComponent extends GenericOptionsComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setAlignmentPreferredSize(Dimension dimension) {
|
||||
protected void setPreferredAlignmentSize(Dimension dimension) {
|
||||
label.setPreferredSize(dimension);
|
||||
}
|
||||
|
||||
|
||||
+30
-30
@@ -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,56 +15,56 @@
|
||||
*/
|
||||
package docking.options.editor;
|
||||
|
||||
import ghidra.framework.options.EditorState;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import ghidra.framework.options.EditorState;
|
||||
|
||||
public abstract class GenericOptionsComponent extends JPanel {
|
||||
protected final EditorState editorState;
|
||||
|
||||
/**
|
||||
* Do not use this constructor directly. Instead, use the factory method:
|
||||
* {@link #createOptionComponent(EditorState)}
|
||||
*/
|
||||
protected GenericOptionsComponent(EditorState editorState) {
|
||||
this.editorState = editorState;
|
||||
protected GenericOptionsComponent() {
|
||||
// stub
|
||||
}
|
||||
|
||||
/**
|
||||
* A factory method to create new OptionComponents.
|
||||
* @param state The state that will be used to create the correct OptionComponent
|
||||
* @return the new OptionComponent.
|
||||
*/
|
||||
public static GenericOptionsComponent createOptionComponent( EditorState state ) {
|
||||
if ( state.supportsCustomOptionsEditor() ) {
|
||||
return new CustomOptionComponent( state );
|
||||
}
|
||||
return new DefaultOptionComponent( state );
|
||||
}
|
||||
/**
|
||||
* A factory method to create new OptionComponents.
|
||||
* @param state The state that will be used to create the correct OptionComponent
|
||||
* @return the new OptionComponent.
|
||||
*/
|
||||
public static GenericOptionsComponent createOptionComponent(EditorState state) {
|
||||
if (state.supportsCustomOptionsEditor()) {
|
||||
return new CustomOptionComponent(state);
|
||||
}
|
||||
return new DefaultOptionComponent(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and sets a preferred alignment based upon the given list of option components.
|
||||
* @param components the list of options components from which to determine the alignment.
|
||||
*/
|
||||
/**
|
||||
* Creates and sets a preferred alignment based upon the given list of option components.
|
||||
* @param components the list of options components from which to determine the alignment.
|
||||
*/
|
||||
public static void alignLabels(List<GenericOptionsComponent> components) {
|
||||
int maxWidth = 0;
|
||||
int maxHeight = 0;
|
||||
for (GenericOptionsComponent optionComponent : components) {
|
||||
Dimension dimension = optionComponent.getPreferredAlignmentSize();
|
||||
maxWidth = Math.max( dimension.width, maxWidth );
|
||||
maxHeight = Math.max( dimension.height, maxHeight );
|
||||
}
|
||||
Dimension dimension = optionComponent.getPreferredAlignmentSize();
|
||||
maxWidth = Math.max(dimension.width, maxWidth);
|
||||
maxHeight = Math.max(dimension.height, maxHeight);
|
||||
}
|
||||
|
||||
for (GenericOptionsComponent component : components) {
|
||||
component.setAlignmentPreferredSize( new Dimension(maxWidth, maxHeight));
|
||||
}
|
||||
component.setPreferredAlignmentSize(new Dimension(maxWidth, maxHeight));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
public void setEnabled(boolean enabled) {
|
||||
// stub
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +72,8 @@ public abstract class GenericOptionsComponent extends JPanel {
|
||||
* components.
|
||||
* @param dimension The alignment dimension.
|
||||
*/
|
||||
protected void setAlignmentPreferredSize( Dimension dimension ) {
|
||||
protected void setPreferredAlignmentSize(Dimension dimension) {
|
||||
// stub
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,6 +81,6 @@ public abstract class GenericOptionsComponent extends JPanel {
|
||||
* @return the alignment dimension.
|
||||
*/
|
||||
protected Dimension getPreferredAlignmentSize() {
|
||||
return getPreferredSize();
|
||||
return getPreferredSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,33 +18,28 @@ package ghidra.framework.options;
|
||||
public interface CustomOption {
|
||||
|
||||
/**
|
||||
* <code>SaveState</code> key which corresponds to custom option
|
||||
* implementation class. The use of this key/value within the stored
|
||||
* state information is reserved for use by the option storage
|
||||
* implementation and should be ignored by {@link #readState(SaveState)}
|
||||
* implementation
|
||||
* Key which corresponds to custom option implementation class. The use of this key/value
|
||||
* within the stored state information is reserved for use by the option storage implementation
|
||||
* and should be ignored by {@link #readState(GProperties)} implementation.
|
||||
*/
|
||||
public final String CUSTOM_OPTION_CLASS_NAME_KEY = "CUSTOM_OPTION_CLASS";
|
||||
|
||||
/**
|
||||
* Concrete subclass of WrappedOption should read all of its
|
||||
* state from the given saveState object.
|
||||
* Read state from the given properties
|
||||
* @param properties container of state information
|
||||
*/
|
||||
public void readState(GProperties properties);
|
||||
|
||||
/**
|
||||
* Concrete subclass of WrappedOption should write all of its
|
||||
* state to the given saveState object.
|
||||
* Write state into the given properties
|
||||
* @param properties container of state information
|
||||
*/
|
||||
public void writeState(GProperties properties);
|
||||
|
||||
/**
|
||||
* CustomOption should implement this method to provide a formatted
|
||||
* string value of this option value. The returned value will
|
||||
* be used in support of the {@link Options#getValueAsString(String)}
|
||||
* and {@link Options#getDefaultValueAsString(String)}.
|
||||
* Subclasses should implement this method to provide a formatted string value of this option
|
||||
* value. The returned value will be used in support of the
|
||||
* {@link Options#getValueAsString(String)} and {@link Options#getDefaultValueAsString(String)}.
|
||||
* @return option value as string
|
||||
*/
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user