Merge remote-tracking branch 'origin/patch' into

GP-0-dragonmacher-merge-conflict-resolution
This commit is contained in:
dragonmacher 2022-02-04 11:04:03 -05:00
commit 0e23fe8c23
11 changed files with 282 additions and 178 deletions

View File

@ -27,7 +27,7 @@ import ghidra.util.classfinder.ClassSearcher;
public class Annotation {
/**
* A pattern to match text between two quote characters and to capture that text. This
* A pattern to match text between two quote characters and to capture that text. This
* pattern does not match quote characters that are escaped with a '\' character.
*/
private static final Pattern QUOTATION_PATTERN =
@ -47,7 +47,7 @@ public class Annotation {
return ANNOTATED_STRING_MAP;
}
// locates AnnotatedStringHandler implementations to handle annotations
// locates AnnotatedStringHandler implementations to handle annotations
private static Map<String, AnnotatedStringHandler> createAnnotatedStringHandlerMap() {
Map<String, AnnotatedStringHandler> map = new HashMap<>();
@ -70,8 +70,9 @@ public class Annotation {
* <b>Note</b>: This constructor assumes that the string starts with "{<pre>@</pre>" and ends with '}'
*
* @param annotationText The complete annotation text.
* @param prototypeString An AttributedString that provides the attributes for the display
* @param prototypeString An AttributedString that provides the attributes for the display
* text this Annotation can create
* @param program the program
*/
public Annotation(String annotationText, AttributedString prototypeString, Program program) {
@ -126,7 +127,7 @@ public class Annotation {
* Called when a mouse click occurs on a FieldElement containing this Annotation.
*
* @param sourceNavigatable The source navigatable associated with the mouse click.
* @param serviceProvider The service provider to be used when creating
* @param serviceProvider The service provider to be used when creating
* {@link AnnotatedStringHandler} instances.
* @return true if the handler desires to handle the mouse click.
*/
@ -143,13 +144,13 @@ public class Annotation {
buffer.delete(0, 2); // remove '{' and '@'
buffer.deleteCharAt(buffer.length() - 1);
// first split out the tokens on '"' so that annotations can have groupings with
// first split out the tokens on '"' so that annotations can have groupings with
// whitespace
int unqouotedOffset = 0;
List<String> tokens = new ArrayList<>();
Matcher matcher = QUOTATION_PATTERN.matcher(buffer.toString());
while (matcher.find()) {
// put all text in the buffer,
// put all text in the buffer,
int quoteStart = matcher.start();
String contentBeforeQuote = buffer.substring(unqouotedOffset, quoteStart);
grabTokens(tokens, contentBeforeQuote);

View File

@ -23,9 +23,9 @@ import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.util.ProgramLocation;
/**
* A subclass of {@link FieldElement} that allows for mouse handling callbacks via the
* A subclass of {@link FieldElement} that allows for mouse handling callbacks via the
* {@link #handleMouseClicked(Navigatable, ServiceProvider)} method. This class
* is based upon {@link Annotation} objects, which are elements that perform actions when the
* is based upon {@link Annotation} objects, which are elements that perform actions when the
* use clicks an instance of this class in the display.
*/
final public class AnnotatedTextFieldElement extends AbstractTextFieldElement {
@ -56,13 +56,23 @@ final public class AnnotatedTextFieldElement extends AbstractTextFieldElement {
* Returns the original annotation text in the data model, which will differ from the display
* text.
* @return the original annotation text in the data model.
* @see #getDisplayString()
*/
public String getRawText() {
return annotation.getAnnotationText();
}
/**
* This method is designed to be called when a mouse click has occurred for a given
* Returns the display string of annotation
* @return the display string
* @see #getRawText()
*/
public String getDisplayString() {
return annotation.getDisplayString().getText();
}
/**
* This method is designed to be called when a mouse click has occurred for a given
* {@link ProgramLocation}.
*
* @param sourceNavigatable The source Navigatable

View File

@ -35,7 +35,7 @@ import util.CollectionUtils;
/**
* Class to handle highlights for a decompiled function.
*
* <p>This class does not painting directly. Rather, this class tracks the currently highlighted
* <p>This class does not paint directly. Rather, this class tracks the currently highlighted
* tokens and then sets the highlight color on the token when it is highlighted and clears the
* highlight color when the highlight is removed.
*
@ -206,7 +206,7 @@ public abstract class ClangHighlightController {
* Return the current highlighted token (if exists and unique)
* @return token or null
*/
private ClangToken getHighlightedToken() {
public ClangToken getHighlightedToken() {
if (primaryHighlightTokens.size() == 1) {
HighlightToken hlToken = CollectionUtils.any(primaryHighlightTokens);
return hlToken.getToken();

View File

@ -259,10 +259,6 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
highlightController.addPrimaryHighlights(root, ops, hlColor);
}
public String getHighlightedText() {
return highlightController.getPrimaryHighlightedText();
}
public void setHighlightController(ClangHighlightController highlightController) {
if (this.highlightController != null) {
this.highlightController.removeListener(this);
@ -698,6 +694,11 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
highlightersById.clear();
}
public FontMetrics getFontMetrics() {
Font font = options.getDefaultFont();
return super.getFontMetrics(font);
}
private FontMetrics getFontMetrics(DecompileOptions decompileOptions) {
Font font = decompileOptions.getDefaultFont();
return getFontMetrics(font);
@ -756,7 +757,7 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
tryGoToVarnode((ClangVariableToken) token, newWindow);
}
else if (token instanceof ClangCommentToken) {
tryGoToComment(location, event, textField, token, newWindow);
tryGoToComment(location, event, textField, newWindow);
}
else if (token instanceof ClangSyntaxToken) {
tryGoToSyntaxToken((ClangSyntaxToken) token);
@ -764,10 +765,9 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
}
private void tryGoToComment(FieldLocation location, MouseEvent event, ClangTextField textField,
ClangToken token, boolean newWindow) {
boolean newWindow) {
// special cases
// -comments: these no longer use tokens for each item, but are one composite field
// comments may use annotations; tell the annotation it was clicked
FieldElement clickedElement = textField.getClickedObject(location);
if (clickedElement instanceof AnnotatedTextFieldElement) {
AnnotatedTextFieldElement annotation = (AnnotatedTextFieldElement) clickedElement;
@ -775,7 +775,7 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
return;
}
String text = clickedElement.getText();
String text = textField.getText();
String word = StringUtilities.findWord(text, location.col);
tryGoToScalar(word, newWindow);
}
@ -879,7 +879,7 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
Address addr = space.getAddress(NumericUtilities.parseHexLong(offsetStr), true);
controller.goToAddress(addr, newWindow);
}
catch (Exception e) {
catch (AddressOutOfBoundsException e) {
// give-up
}
return;
@ -888,7 +888,7 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
long value = NumericUtilities.parseHexLong(text);
controller.goToScalar(value, newWindow);
}
catch (Exception e) {
catch (NumberFormatException e) {
return; // give up
}
}
@ -1017,6 +1017,49 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
return SPECIAL_COLOR_DEF;
}
public String getHighlightedText() {
ClangToken token = highlightController.getHighlightedToken();
if (token == null) {
return null;
}
if (token instanceof ClangCommentToken) {
return null; // comments are not single words that get highlighted
}
return token.getText();
}
public String getTextUnderCursor() {
FieldLocation location = fieldPanel.getCursorLocation();
ClangTextField textField = (ClangTextField) fieldPanel.getCurrentField();
if (textField == null) {
return null;
}
ClangToken token = textField.getToken(location);
if (!(token instanceof ClangCommentToken)) {
return token.getText(); // non-comment tokens are not multi-word; use the token's text
}
FieldElement clickedElement = textField.getClickedObject(location);
if (clickedElement instanceof AnnotatedTextFieldElement) {
AnnotatedTextFieldElement annotation = (AnnotatedTextFieldElement) clickedElement;
return annotation.getDisplayString();
}
String text = textField.getText();
return StringUtilities.findWord(text, location.col);
}
public String getSelectedText() {
FieldSelection selection = fieldPanel.getSelection();
if (selection.isEmpty()) {
return null;
}
return FieldSelectionHelper.getFieldSelectionText(selection, fieldPanel);
}
public FieldLocation getCursorPosition() {
return fieldPanel.getCursorLocation();
}
@ -1047,15 +1090,6 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
return null;
}
public String getTextSelection() {
FieldSelection selection = fieldPanel.getSelection();
if (selection.isEmpty()) {
return null;
}
return FieldSelectionHelper.getFieldSelectionText(selection, fieldPanel);
}
public ClangToken getTokenAtCursor() {
FieldLocation cursorPosition = fieldPanel.getCursorLocation();
Field field = fieldPanel.getCurrentField();

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.decompiler.component;
import org.apache.commons.lang3.StringUtils;
import docking.widgets.EventTrigger;
import docking.widgets.fieldpanel.field.Field;
import docking.widgets.fieldpanel.support.FieldLocation;
@ -40,6 +42,11 @@ public class LocationClangHighlightController extends ClangHighlightController {
return;
}
String text = tok.getText();
if (StringUtils.isBlank(text)) {
return; // do not highlight whitespace
}
addPrimaryHighlight(tok, defaultHighlightColor);
if (tok instanceof ClangSyntaxToken) {
addPrimaryHighlightToTokensForParenthesis((ClangSyntaxToken) tok, defaultParenColor);

View File

@ -462,7 +462,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
@Override
public String getTextSelection() {
DecompilerPanel decompilerPanel = controller.getDecompilerPanel();
return decompilerPanel.getTextSelection();
return decompilerPanel.getSelectedText();
}
boolean isBusy() {

View File

@ -19,6 +19,8 @@ import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.widgets.*;
@ -126,8 +128,15 @@ public class FindAction extends AbstractDecompilerAction {
protected void decompilerActionPerformed(DecompilerActionContext context) {
DecompilerPanel decompilerPanel = context.getDecompilerPanel();
FindDialog dialog = getFindDialog(decompilerPanel);
String text = decompilerPanel.getHighlightedText();
if (text != null) {
String text = decompilerPanel.getSelectedText();
if (text == null) {
text = decompilerPanel.getHighlightedText();
// note: if we decide to grab the text under the cursor, then use
// text = decompilerPanel.getTextUnderCursor();
}
if (!StringUtils.isBlank(text)) {
dialog.setSearchText(text);
}

View File

@ -392,6 +392,8 @@ public class FieldPanel extends JPanel
/**
* Returns the default background color.
* @return the default background color.
* @see #getBackground()
*/
public Color getBackgroundColor() {
return backgroundColorModel.getDefaultBackgroundColor();
@ -431,6 +433,7 @@ public class FieldPanel extends JPanel
/**
*
* Returns the foreground color.
* @return the foreground color.
*/
public Color getForegroundColor() {
return paintContext.getForeground();
@ -438,6 +441,7 @@ public class FieldPanel extends JPanel
/**
* Returns the color used as the background for selected items.
* @return the color used as the background for selected items.
*/
public Color getSelectionColor() {
return paintContext.getSelectionColor();
@ -445,18 +449,24 @@ public class FieldPanel extends JPanel
/**
* Returns the color color used as the background for highlighted items.
* @return the color color used as the background for highlighted items.
*/
public Color getHighlightColor() {
return paintContext.getHighlightColor();
}
/**
* Returns the current cursor color.
* Returns the cursor color when this field panel is focused.
* @return the cursor color when this field panel is focused.
*/
public Color getFocusedCursorColor() {
return paintContext.getFocusedCursorColor();
}
/**
* Returns the cursor color when this field panel is not focused.
* @return the cursor color when this field panel is not focused.
*/
public Color getNonFocusCursorColor() {
return paintContext.getNotFocusedCursorColor();
}
@ -485,6 +495,7 @@ public class FieldPanel extends JPanel
/**
* Returns the point in pixels of where the cursor is located.
* @return the point in pixels of where the cursor is located.
*/
public Point getCursorPoint() {
Rectangle bounds = getCursorBounds();
@ -529,7 +540,7 @@ public class FieldPanel extends JPanel
selectionListeners.remove(listener);
}
/**
/**
* Adds a selection listener that will be notified while the selection is being created
* @param listener the listener to be notified
*/
@ -537,7 +548,7 @@ public class FieldPanel extends JPanel
liveSelectionListeners.add(listener);
}
/**
/**
* Removes the selection listener from being notified when the selection is being created
* @param listener the listener to be removed from being notified
*/
@ -680,6 +691,7 @@ public class FieldPanel extends JPanel
/**
* Returns the current selection.
* @return the current selection.
*/
public FieldSelection getSelection() {
return new FieldSelection(selection);
@ -687,6 +699,7 @@ public class FieldPanel extends JPanel
/**
* Returns the current highlight (marked area).
* @return the current highlight (marked area).
*/
public FieldSelection getHighlight() {
return new FieldSelection(highlight);
@ -730,7 +743,6 @@ public class FieldPanel extends JPanel
return setCursorPosition(index, fieldNum, row, col, EventTrigger.API_CALL);
}
// for subclasses to control the event trigger
/**
* Sets the cursorPosition to the given location with the given trigger.
*
@ -762,6 +774,7 @@ public class FieldPanel extends JPanel
/**
* Returns the state of the cursor. True if on, false if off.
* @return the state of the cursor. True if on, false if off.
*/
public boolean isCursorOn() {
return cursorHandler.isCursorOn();
@ -858,6 +871,7 @@ public class FieldPanel extends JPanel
* that layout. For example, if the layout is completely displayed, yPos will be 0. If part of
* the layout is off the top off the screen, then yPos will have a negative value (indicating
* that it begins above the displayable part of the screen.
* @return the position
*/
public ViewerPosition getViewerPosition() {
if (layouts.size() > 0) {
@ -872,7 +886,8 @@ public class FieldPanel extends JPanel
* &lt;= 0, meaning the layout may be partially off the top of the screen.
*
* @param index the index of the layout to show at the top of the screen.
* @param yPos the position to show the layout.
* @param xPos the x position to set.
* @param yPos the y position to set.
*/
public void setViewerPosition(BigInteger index, int xPos, int yPos) {
if (index.compareTo(BigInteger.ZERO) >= 0 && index.compareTo(model.getNumIndexes()) < 0) {
@ -909,7 +924,6 @@ public class FieldPanel extends JPanel
}
@Override
// BigLayoutModelListener
public void dataChanged(BigInteger start, BigInteger end) {
if (layouts.isEmpty()) {
notifyScrollListenerDataChanged(start, end);
@ -961,7 +975,6 @@ public class FieldPanel extends JPanel
}
@Override
// BigLayoutModelListener
public void modelSizeChanged(IndexMapper indexMapper) {
BigInteger anchorIndex =
layouts.isEmpty() ? BigInteger.ZERO : indexMapper.map(layouts.get(0).getIndex());
@ -1044,6 +1057,7 @@ public class FieldPanel extends JPanel
/**
* Returns the offset of the cursor from the top of the screen
* @return the offset of the cursor from the top of the screen
*/
public int getCursorOffset() {
return getOffset(cursorPosition);
@ -1238,7 +1252,9 @@ public class FieldPanel extends JPanel
}
/**
* Finds the layout containing the given point.
* Finds the layout containing the given y position.
* @param y the y position.
* @return the layout.
*/
AnchoredLayout findLayoutAt(int y) {
for (AnchoredLayout layout : layouts) {
@ -1304,10 +1320,11 @@ public class FieldPanel extends JPanel
}
}
// ==================================================================================================
//==================================================================================================
// Inner Classes
// ==================================================================================================
public class FieldPanelMouseAdapter extends MouseAdapter {
//==================================================================================================
private class FieldPanelMouseAdapter extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
@ -1329,12 +1346,12 @@ public class FieldPanel extends JPanel
hoverHandler.hoverExited();
}
public boolean isButton3(MouseEvent e) {
private boolean isButton3(MouseEvent e) {
return e.getButton() == MouseEvent.BUTTON3;
}
}
public class FieldPanelMouseMotionAdapter extends MouseMotionAdapter {
private class FieldPanelMouseMotionAdapter extends MouseMotionAdapter {
@Override
public void mouseDragged(MouseEvent e) {
hoverHandler.stopHover();
@ -1347,74 +1364,74 @@ public class FieldPanel extends JPanel
}
}
interface KeyAction {
public interface KeyAction {
public void handleKeyEvent(KeyEvent event);
}
class UpKeyAction implements KeyAction {
private class UpKeyAction implements KeyAction {
@Override
public void handleKeyEvent(KeyEvent e) {
keyHandler.vkUp(e);
}
}
class DownKeyAction implements KeyAction {
private class DownKeyAction implements KeyAction {
@Override
public void handleKeyEvent(KeyEvent e) {
keyHandler.vkDown(e);
}
}
class LeftKeyAction implements KeyAction {
private class LeftKeyAction implements KeyAction {
@Override
public void handleKeyEvent(KeyEvent e) {
keyHandler.vkLeft(e);
}
}
class RightKeyAction implements KeyAction {
private class RightKeyAction implements KeyAction {
@Override
public void handleKeyEvent(KeyEvent e) {
keyHandler.vkRight(e);
}
}
class HomeKeyAction implements KeyAction {
private class HomeKeyAction implements KeyAction {
@Override
public void handleKeyEvent(KeyEvent e) {
keyHandler.vkHome(e);
}
}
class EndKeyAction implements KeyAction {
private class EndKeyAction implements KeyAction {
@Override
public void handleKeyEvent(KeyEvent e) {
keyHandler.vkEnd(e);
}
}
class PageUpKeyAction implements KeyAction {
private class PageUpKeyAction implements KeyAction {
@Override
public void handleKeyEvent(KeyEvent e) {
keyHandler.vkPageUp(e);
}
}
class PageDownKeyAction implements KeyAction {
private class PageDownKeyAction implements KeyAction {
@Override
public void handleKeyEvent(KeyEvent e) {
keyHandler.vkPageDown(e);
}
}
class EnterKeyAction implements KeyAction {
private class EnterKeyAction implements KeyAction {
@Override
public void handleKeyEvent(KeyEvent e) {
keyHandler.vkEnter(e);
}
}
class FieldPanelKeyAdapter extends KeyAdapter {
private class FieldPanelKeyAdapter extends KeyAdapter {
private Map<KeyStroke, KeyAction> actionMap;
FieldPanelKeyAdapter() {
@ -1460,8 +1477,7 @@ public class FieldPanel extends JPanel
// Shift is handled special, so mask it off in the event before getting the action.
// If the shift is being held, the selection is extended while moving the cursor.
int keyCode = e.getKeyCode();
int modifiers =
e.getModifiers() & ~(InputEvent.SHIFT_DOWN_MASK | InputEvent.SHIFT_MASK);
int modifiers = e.getModifiersEx() & ~InputEvent.SHIFT_DOWN_MASK;
KeyEvent maskedEvent = new KeyEvent(e.getComponent(), e.getID(), e.getWhen(), modifiers,
keyCode, e.getKeyChar(), e.getKeyLocation());
@ -1490,7 +1506,7 @@ public class FieldPanel extends JPanel
}
}
public class FieldPanelFocusListener implements FocusListener {
private class FieldPanelFocusListener implements FocusListener {
@Override
public void focusGained(FocusEvent e) {
inFocus = true;
@ -1511,7 +1527,7 @@ public class FieldPanel extends JPanel
}
}
public class BigFieldPanelMouseWheelListener implements MouseWheelListener {
private class BigFieldPanelMouseWheelListener implements MouseWheelListener {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
double wheelRotation = e.getPreciseWheelRotation();
@ -1555,7 +1571,7 @@ public class FieldPanel extends JPanel
}
}
public class MouseHandler implements ActionListener {
private class MouseHandler implements ActionListener {
private Timer scrollTimer; // used to generate auto scroll
private int mouseDownX;
private int mouseDownY;
@ -1563,11 +1579,11 @@ public class FieldPanel extends JPanel
private int timerScrollAmount;
private FieldLocation timerPoint;
public MouseHandler() {
MouseHandler() {
scrollTimer = new Timer(100, this);
}
public void dispose() {
void dispose() {
scrollTimer.stop();
}
@ -1588,7 +1604,7 @@ public class FieldPanel extends JPanel
}
}
public void mousePressed(MouseEvent e) {
void mousePressed(MouseEvent e) {
requestFocus();
didDrag = false;
if (e.getButton() != MouseEvent.BUTTON1) {
@ -1624,11 +1640,11 @@ public class FieldPanel extends JPanel
}
}
public boolean didDrag() {
boolean didDrag() {
return didDrag;
}
public void mouseDragged(MouseEvent e) {
void mouseDragged(MouseEvent e) {
if ((e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) == 0) {
return;
}
@ -1652,7 +1668,7 @@ public class FieldPanel extends JPanel
}
}
public void mouseReleased(MouseEvent e) {
void mouseReleased(MouseEvent e) {
scrollTimer.stop();
if (e.getButton() != MouseEvent.BUTTON1) {
return;
@ -1661,7 +1677,7 @@ public class FieldPanel extends JPanel
cursorHandler.setCursorPos(e.getX(), e.getY(), EventTrigger.GUI_ACTION);
if (didDrag) {
// Send an event after the drag is finished. Event are suppressed while dragging,
// meaning that the above call to setCursorPos() will not have fired an event
// meaning that the above call to setCursorPos() will not have fired an event
// because the internal cursor position did not change during the mouse release.
cursorHandler.notifyCursorChanged(EventTrigger.GUI_ACTION);
}
@ -1672,55 +1688,51 @@ public class FieldPanel extends JPanel
}
/**
* Basically checks if the the "shift" modifier is on and the "control" modifier is not.
* Note that "control" is operating system dependent. It is <control> on windows, and
* <command> on mac.
* Checks if the the "shift" modifier is on and the "control" modifier is not.
*/
private boolean isAddToContiguousSelectionActivator(MouseEvent e) {
return (e.isShiftDown() && !DockingUtils.isControlModifier(e));
}
/**
* Basically checks if the the "control" modifier is on and the shift modifier is not. Note
* that "control" is operating system dependent. It is <control> on windows, and <command>
* on mac.
* Checks if the the "control" modifier is on and the shift modifier is not.
*/
private boolean isAddRemoveDisjointSelectionActivator(MouseEvent e) {
return DockingUtils.isControlModifier(e) && !e.isShiftDown();
}
}
class KeyHandler {
private class KeyHandler {
public void shiftKeyPressed() {
void shiftKeyPressed() {
selectionHandler.beginSelectionSequence(cursorPosition);
}
public void shiftKeyReleased() {
void shiftKeyReleased() {
selectionHandler.endSelectionSequence();
}
public void vkUp(KeyEvent e) {
void vkUp(KeyEvent e) {
cursorHandler.doCursorUp(EventTrigger.GUI_ACTION);
selectionHandler.updateSelectionSequence(cursorPosition);
}
public void vkDown(KeyEvent e) {
void vkDown(KeyEvent e) {
cursorHandler.doCursorDown(EventTrigger.GUI_ACTION);
selectionHandler.updateSelectionSequence(cursorPosition);
}
public void vkLeft(KeyEvent e) {
void vkLeft(KeyEvent e) {
cursorHandler.doCursorLeft(EventTrigger.GUI_ACTION);
selectionHandler.updateSelectionSequence(cursorPosition);
}
public void vkRight(KeyEvent e) {
void vkRight(KeyEvent e) {
cursorHandler.doCursorRight(EventTrigger.GUI_ACTION);
selectionHandler.updateSelectionSequence(cursorPosition);
}
public void vkEnd(KeyEvent e) {
void vkEnd(KeyEvent e) {
if (DockingUtils.isControlModifier(e)) {
doEndOfFile(EventTrigger.GUI_ACTION);
}
@ -1730,7 +1742,7 @@ public class FieldPanel extends JPanel
selectionHandler.updateSelectionSequence(cursorPosition);
}
public void vkHome(KeyEvent e) {
void vkHome(KeyEvent e) {
if (DockingUtils.isControlModifier(e)) {
doTopOfFile(EventTrigger.GUI_ACTION);
}
@ -1740,27 +1752,26 @@ public class FieldPanel extends JPanel
selectionHandler.updateSelectionSequence(cursorPosition);
}
public void vkPageUp(KeyEvent e) {
void vkPageUp(KeyEvent e) {
doPageUp(EventTrigger.GUI_ACTION);
selectionHandler.updateSelectionSequence(cursorPosition);
}
public void vkPageDown(KeyEvent e) {
void vkPageDown(KeyEvent e) {
doPageDown(EventTrigger.GUI_ACTION);
selectionHandler.updateSelectionSequence(cursorPosition);
}
public void vkEnter(KeyEvent e) {
void vkEnter(KeyEvent e) {
Point pt = getCursorPoint();
if (pt != null) {
notifyFieldMouseListeners(new MouseEvent(e.getComponent(), e.getID(), e.getWhen(),
0, pt.x, pt.y, 2, false, MouseEvent.BUTTON1));
}
}
}
class SelectionHandler {
private class SelectionHandler {
private boolean selectionOn = true;
private boolean selectionChanged;
private boolean removeFromSelection;
@ -1828,7 +1839,7 @@ public class FieldPanel extends JPanel
selectionChanged = true;
}
public void enableSelection(boolean b) {
void enableSelection(boolean b) {
selectionOn = b;
if (!selectionOn) {
selection.clear();
@ -1836,7 +1847,7 @@ public class FieldPanel extends JPanel
}
}
public class CursorHandler {
private class CursorHandler {
private int lastX = 0;
private boolean cursorOn = true;
private Field currentField;
@ -1846,7 +1857,7 @@ public class FieldPanel extends JPanel
cursorBlinker = new CursorBlinker(FieldPanel.this);
}
public void setBlinkCursor(Boolean blinkCursor) {
void setBlinkCursor(Boolean blinkCursor) {
if (blinkCursor && cursorBlinker == null) {
cursorBlinker = new CursorBlinker(FieldPanel.this);
}
@ -1856,28 +1867,28 @@ public class FieldPanel extends JPanel
}
}
public boolean isCursorOn() {
boolean isCursorOn() {
return cursorOn;
}
public void setCursorOn(boolean cursorOn) {
void setCursorOn(boolean cursorOn) {
this.cursorOn = cursorOn;
}
public void focusLost() {
void focusLost() {
if (cursorBlinker != null) {
cursorBlinker.stop();
}
}
public void focusGained() {
void focusGained() {
if (cursorBlinker != null) {
cursorBlinker.restart();
}
}
public Field getCurrentField() {
Field getCurrentField() {
if (currentField == null) {
AnchoredLayout layout = findLayoutOnScreen(cursorPosition.getIndex());
if (layout != null) {
@ -2135,7 +2146,7 @@ public class FieldPanel extends JPanel
}
public void scrollToCursor() {
void scrollToCursor() {
doScrollTo(cursorPosition);
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,8 +19,36 @@ import java.math.BigInteger;
import org.jdom.Element;
import docking.widgets.fieldpanel.Layout;
import docking.widgets.fieldpanel.field.Field;
/**
* Class to represent locations within the FieldViewer.
* Class to represent {@link Field} locations within the field viewer.
* <p>
* A field location represents a place within a Field. Fields live within a concept we call a
* layout. A layout represents an 'item', for example an address, along with a grouping of
* related information. Each layout will contain one or more Field objects. Further, each
* layout's fields may have varying shapes, such as single or multiple rows within the layout.
* Thusly, a layout could conceptually represent a single line of text or multiple groupings of
* text and images, similar to how a newspaper or web page is laid out.
* <p>
* A layout lives in a larger collection of layouts, which are laid out vertically. The index of a
* layout is its position within that larger list. This class contains the index of the layout
* within which it lives.
* <p>
* A {@link FieldSelection} may be within a single layout or may cross multiple layouts. To
* determine if a selection crosses multiple layouts, you can get the {@link FieldRange range} of
* the selection. You can then use the range's start and end locations to determine if the
* selection spans multiple layouts. If the start and end indexes of the range are the same, then
* the selection is within a single layout; otherwise, the selection spans multiple layouts.
* <p>
* This location also contains row and column values. These values refer to the row and column of
* text within a single Field. Lastly, this class contains a field number, which represents the
* relative field number inside of the over layout, which may contain multiple fields.
*
* @see FieldSelection
* @see FieldRange
* @see Layout
*/
public class FieldLocation implements Comparable<FieldLocation> {
public static final FieldLocation MAX =
@ -29,7 +56,7 @@ public class FieldLocation implements Comparable<FieldLocation> {
Integer.MAX_VALUE);
public int fieldNum; // the number of the field for this location
public int row; // the row position within the field .
public int row; // the row position within the field
public int col; // the col position within the field
private BigInteger index;
@ -94,12 +121,19 @@ public class FieldLocation implements Comparable<FieldLocation> {
this(loc.index, loc.fieldNum, loc.row, loc.col);
}
/**
* Returns the index for this location. The index corresponds to the layout that contains
* the field represented by this location. See the javadoc header for more details.
* @return the index for this location.
*/
public BigInteger getIndex() {
return index;
}
/**
* Returns the field index for this location.
* Returns the number of the field for this location. This is the number of the field within
* a given layout. See the javadoc header for more details.
* @return the number of the field for this location.
*/
public int getFieldNum() {
return fieldNum;
@ -107,6 +141,7 @@ public class FieldLocation implements Comparable<FieldLocation> {
/**
* Returns the row within the Field for this location.
* @return the row within the Field for this location.
*/
public int getRow() {
return row;
@ -114,15 +149,12 @@ public class FieldLocation implements Comparable<FieldLocation> {
/**
* Returns the column within the Field for this location.
* @return the column within the Field for this location.
*/
public int getCol() {
return col;
}
/**
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
@ -141,6 +173,7 @@ public class FieldLocation implements Comparable<FieldLocation> {
return false;
}
@Override
public int compareTo(FieldLocation o) {
int compareTo = index.compareTo(o.index);
if (compareTo != 0) {
@ -167,19 +200,11 @@ public class FieldLocation implements Comparable<FieldLocation> {
return 0;
}
/**
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return index.intValue() + fieldNum * 100 + row * 10 + col;
}
/**
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return index.toString() + ", " + fieldNum + ", " + row + ", " + col;
@ -200,7 +225,6 @@ public class FieldLocation implements Comparable<FieldLocation> {
fieldNum = loc.fieldNum;
row = loc.row;
col = loc.col;
}
public void setIndex(BigInteger index) {

View File

@ -15,20 +15,24 @@
*/
package docking.widgets.fieldpanel.support;
import ghidra.util.exception.AssertException;
import java.math.BigInteger;
import org.jdom.Element;
import docking.widgets.fieldpanel.Layout;
import ghidra.util.exception.AssertException;
/**
* Class to a range consisting of a start position within a start row to an end position within an
* end row (exclusive).
* A range consists of a start position within a start row to an end position within an end row
* (exclusive).
* <p>
* Conceptually, this class can be thought of as a range of rows (defined by
* <code>startIndex</code> and <code>endindex</code>) with sub-positions within those rows (defined by
* <code>startField</code> and <code>endField</code>). As an example, consider a text select that begins on
* some word in a row and ends on another word in a different row.
* Conceptually, this class can be thought of as a range of rows (defined by start and end
* indexes) with sub-positions within those rows. As an example, consider a text selection that
* begins on some word in a row and ends on another word in a different row.
*
* @see FieldSelection
* @see FieldLocation
* @see Layout
*/
public class FieldRange implements Comparable<FieldRange> {
FieldLocation start;
@ -71,9 +75,6 @@ public class FieldRange implements Comparable<FieldRange> {
return end;
}
/**
* Return string representation for debugging purposes.
*/
@Override
public String toString() {
return "FieldRange: (" + start + " :: " + end + ")";
@ -108,6 +109,7 @@ public class FieldRange implements Comparable<FieldRange> {
return start.hashCode() << 16 + end.hashCode();
}
@Override
public int compareTo(FieldRange o) {
int result = start.compareTo(o.start);
if (result == 0) {
@ -190,7 +192,8 @@ public class FieldRange implements Comparable<FieldRange> {
public boolean containsEntirely(int index) {
if (start.getIndex().intValue() > index ||
((start.getIndex().intValue() == index) && (start.fieldNum != 0 || start.row != 0 || start.col != 0))) {
((start.getIndex().intValue() == index) &&
(start.fieldNum != 0 || start.row != 0 || start.col != 0))) {
return false;
}
if (end.getIndex().intValue() <= index) {

View File

@ -15,17 +15,26 @@
*/
package docking.widgets.fieldpanel.support;
import ghidra.framework.options.SaveState;
import ghidra.util.Msg;
import java.math.BigInteger;
import java.util.*;
import org.jdom.Element;
import docking.widgets.fieldpanel.Layout;
import ghidra.framework.options.SaveState;
/**
* Interface for reporting the FieldViewer selection. The selection consists of
* a sequence of ranges of indexes.
* This class represents a selection in a field viewer.
* <p>
* A {@link FieldSelection} may be within a single layout or may cross multiple layouts. To
* determine if a selection crosses multiple layouts, you can get the {@link FieldRange range} of
* the selection. You can then use the range's start and end locations to determine if the
* selection spans multiple layouts. If the start and end indexes of the range are the same, then
* the selection is within a single layout; otherwise, the selection spans multiple layouts.
*
* @see FieldRange
* @see FieldLocation
* @see Layout
*/
public class FieldSelection implements Iterable<FieldRange> {
@ -35,7 +44,7 @@ public class FieldSelection implements Iterable<FieldRange> {
* Construct a new empty FieldSelection.
*/
public FieldSelection() {
ranges = new ArrayList<FieldRange>(4);
ranges = new ArrayList<>(4);
}
/**
@ -43,7 +52,7 @@ public class FieldSelection implements Iterable<FieldRange> {
* @param selection the FieldSelection to copy.
*/
public FieldSelection(FieldSelection selection) {
ranges = new ArrayList<FieldRange>(selection.ranges.size());
ranges = new ArrayList<>(selection.ranges.size());
for (FieldRange range : selection.ranges) {
ranges.add(new FieldRange(range));
}
@ -53,7 +62,7 @@ public class FieldSelection implements Iterable<FieldRange> {
* Removes all indexes from the list.
*/
public void clear() {
ranges = new ArrayList<FieldRange>(4);
ranges = new ArrayList<>(4);
}
/**
@ -69,6 +78,7 @@ public class FieldSelection implements Iterable<FieldRange> {
* Returns the range if the given Field at the given index is in the selection.
* Otherwise returns null.
* @param loc location to find the range for.
* @return the range
*/
public FieldRange getRangeContaining(FieldLocation loc) {
int insertIndex = Collections.binarySearch(ranges, new FieldRange(loc, FieldLocation.MAX));
@ -95,9 +105,11 @@ public class FieldSelection implements Iterable<FieldRange> {
/**
* Returns true if the all the fields in the layout with the given index are
* included in this selection.
* included in this selection.
* @param index index of the layout to test.
* @return true if the all the fields in the layout with the given index are
* included in this selection.
*/
public boolean containsEntirely(BigInteger index) {
FieldLocation start = new FieldLocation(index, 0, 0, 0);
@ -229,12 +241,14 @@ public class FieldSelection implements Iterable<FieldRange> {
}
}
}
insertIndex++;
while (insertIndex < ranges.size()) {
FieldRange range = ranges.get(insertIndex);
if (!deleteRange.intersects(range)) {
return;
}
FieldRange leftOver = range.subtract(deleteRange);
if (range.isEmpty()) {
ranges.remove(insertIndex);
@ -264,6 +278,7 @@ public class FieldSelection implements Iterable<FieldRange> {
/**
* Returns the current number of ranges in the list.
* @return the current number of ranges in the list.
*/
public int getNumRanges() {
return ranges.size();
@ -272,6 +287,7 @@ public class FieldSelection implements Iterable<FieldRange> {
/**
* Returns the i'th Field Range in the selection.
* @param rangeNum the index of the range to retrieve.
* @return the range
*/
public FieldRange getFieldRange(int rangeNum) {
return ranges.get(rangeNum);
@ -279,8 +295,9 @@ public class FieldSelection implements Iterable<FieldRange> {
/**
* Compute the intersection of this field selection and another one.
* The intersection of two field selections is all fields existing in
* The intersection of two field selections is all fields existing in
* both selections.
*
* <P>Note: This field selection becomes the intersection.
*
* @param selection field selection to intersect.
@ -304,6 +321,7 @@ public class FieldSelection implements Iterable<FieldRange> {
/**
* Computes the intersection of this field selection and the given field selection.
* @param selection the selection to intersect with.
* @return the selection
*/
public final FieldSelection findIntersection(FieldSelection selection) {
if (selection == null || this.ranges.size() == 0 || selection.ranges.size() == 0) {
@ -323,16 +341,14 @@ public class FieldSelection implements Iterable<FieldRange> {
/**
* Delete all fields in the ranges in the given field selection from this one.
* @param selection the field selection fields to remove from this
* field selection.
* @param selection the field selection fields to remove from this field selection.
*/
public final void delete(FieldSelection selection) {
if (selection == null || this.ranges.size() == 0 || selection.ranges.size() == 0) {
return;
}
// process all ranges in the selection, delete each one's
// associated fields from this set.
// process all ranges in the selection, delete each associated fields from this set
for (FieldRange range : selection.ranges) {
removeRange(range.start, range.end);
}
@ -340,63 +356,50 @@ public class FieldSelection implements Iterable<FieldRange> {
/**
* Insert all fields in the ranges in the given field selection from this one.
* @param selection the field selection fields to add to this
* field selection.
* @param selection the field selection fields to add to this field selection.
*/
public final void insert(FieldSelection selection) {
if (selection == null || selection.getNumRanges() == 0) {
return;
}
// process all ranges in the selection, add each one's
// associated fields from this set.
// process all ranges in the selection, add each associated fields from this set
for (FieldRange range : selection.ranges) {
addRange(range.start, range.end);
}
}
/**
* Prints out the ranges for debugging.
*/
public void printRanges() {
Msg.debug(this, "*********");
for (FieldRange range : ranges) {
Msg.debug(this, range);
}
Msg.debug(this, "**********");
}
@Override
public String toString() {
StringBuffer buf = new StringBuffer();
StringBuilder buf = new StringBuilder();
for (FieldRange range : ranges) {
buf.append(range.toString());
}
return buf.toString();
}
/**
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((ranges == null) ? 0 : ranges.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof FieldSelection)) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FieldSelection other = (FieldSelection) obj;
if (ranges.size() != other.ranges.size()) {
return false;
}
int n = ranges.size();
for (int i = 0; i < n; i++) {
FieldRange thisRange = ranges.get(i);
FieldRange otherRange = other.ranges.get(i);
if (!thisRange.equals(otherRange)) {
return false;
}
}
return true;
return Objects.equals(ranges, other.ranges);
}
public void save(SaveState saveState) {
@ -424,7 +427,7 @@ public class FieldSelection implements Iterable<FieldRange> {
}
public boolean isEmpty() {
return ranges.size() == 0;
return ranges.isEmpty();
}
public FieldSelection intersect(int index) {
@ -448,15 +451,17 @@ public class FieldSelection implements Iterable<FieldRange> {
int insertIndex = Collections.binarySearch(ranges, range);
// if exact match, return it;
// if exact match, return it
if (insertIndex >= 0) {
intersection.addRange(range);
return intersection;
}
insertIndex = -insertIndex - 2;
if (insertIndex < 0) {
insertIndex++;
}
while (insertIndex < ranges.size()) {
FieldRange searchRange = ranges.get(insertIndex);
if (searchRange.start.compareTo(range.end) >= 0) {