mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
GP-6207 - Byte Viewer - Fixed the option to toggle highlighting the current line; Fixed dragging behavior
This commit is contained in:
@@ -17,32 +17,40 @@ package ghidra.app.plugin.core.byteviewer;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.math.BigInteger;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import docking.widgets.fieldpanel.support.BackgroundColorModel;
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
|
||||
/**
|
||||
* {@link BackgroundColorModel} that changes the color for the currently focused byteviewer row
|
||||
* {@link BackgroundColorModel} that changes the color for the currently focused byte viewer row
|
||||
*/
|
||||
public class ByteViewerBGColorModel implements BackgroundColorModel {
|
||||
private Color bgColor = ByteViewerComponentProvider.BG_COLOR;
|
||||
private Supplier<BigInteger> cursorLocSupplier;
|
||||
private ByteViewerPanel panel;
|
||||
|
||||
/**
|
||||
* Creates new model.
|
||||
* Creates a new model.
|
||||
*
|
||||
* @param cursorLocSupplier provides the index of the byteviewer-global cursor
|
||||
* @param panel the byte viewer used to synchronize the current line across components
|
||||
*/
|
||||
public ByteViewerBGColorModel(Supplier<BigInteger> cursorLocSupplier) {
|
||||
this.cursorLocSupplier = cursorLocSupplier;
|
||||
public ByteViewerBGColorModel(ByteViewerPanel panel) {
|
||||
this.panel = panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getBackgroundColor(BigInteger index) {
|
||||
BigInteger cursorIndex = cursorLocSupplier.get();
|
||||
return cursorIndex.equals(index)
|
||||
? ByteViewerComponentProvider.CURRENT_LINE_COLOR
|
||||
: bgColor;
|
||||
|
||||
if (!panel.isHighlightCurrentLine()) {
|
||||
return bgColor;
|
||||
}
|
||||
|
||||
ByteViewerComponent c = panel.getCurrentComponent();
|
||||
FieldLocation loc = c.getCursorLocation();
|
||||
BigInteger cursorIndex = loc.getIndex();
|
||||
if (index.equals(cursorIndex)) {
|
||||
return ByteViewerComponentProvider.CURRENT_LINE_COLOR;
|
||||
}
|
||||
return bgColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -60,6 +60,7 @@ public class ByteViewerComponent extends FieldPanel
|
||||
private int charWidth;
|
||||
private IndexMap indexMap;
|
||||
private ProgramByteBlockSet blockSet;
|
||||
|
||||
private ByteViewerLayoutModel layoutModel;
|
||||
private boolean doingRefresh;
|
||||
private boolean doingEdit;
|
||||
@@ -71,24 +72,24 @@ public class ByteViewerComponent extends FieldPanel
|
||||
|
||||
private FieldSelectionListener liveSelectionListener = (selection, trigger) -> {
|
||||
ByteBlockSelection sel = processFieldSelection(selection);
|
||||
panel.updateLiveSelection(ByteViewerComponent.this, sel);
|
||||
panel.updateLiveSelection(this, sel);
|
||||
};
|
||||
private ByteViewerHoverProvider byteViewerHoverProvider;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param vpanel the byte viewer panel that this component lives in
|
||||
* @param panel the byte viewer panel that this component lives in
|
||||
* @param layoutModel the layout model for this component
|
||||
* @param model data format model that knows how the data should be displayed
|
||||
* @param bytesPerLine number of bytes displayed in a row
|
||||
*/
|
||||
protected ByteViewerComponent(ByteViewerPanel vpanel, ByteViewerLayoutModel layoutModel,
|
||||
protected ByteViewerComponent(ByteViewerPanel panel, ByteViewerLayoutModel layoutModel,
|
||||
DataFormatModel model, int bytesPerLine) {
|
||||
super(layoutModel, "Byte Viewer");
|
||||
setFieldDescriptionProvider((l, f) -> getFieldDescription(l, f));
|
||||
|
||||
this.panel = vpanel;
|
||||
this.panel = panel;
|
||||
this.model = model;
|
||||
this.bytesPerLine = bytesPerLine;
|
||||
this.layoutModel = layoutModel;
|
||||
@@ -693,8 +694,9 @@ public class ByteViewerComponent extends FieldPanel
|
||||
});
|
||||
|
||||
setBackgroundColor(ByteViewerComponentProvider.BG_COLOR);
|
||||
|
||||
// specialized line coloring
|
||||
setBackgroundColorModel(new ByteViewerBGColorModel(() -> getCursorLocation().getIndex()));
|
||||
setBackgroundColorModel(new ByteViewerBGColorModel(panel));
|
||||
|
||||
Gui.registerFont(this, ByteViewerComponentProvider.DEFAULT_FONT_ID);
|
||||
|
||||
@@ -707,6 +709,11 @@ public class ByteViewerComponent extends FieldPanel
|
||||
setHoverProvider(byteViewerHoverProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDragging() { // open access
|
||||
return super.isDragging();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable help for this component; used the model name as part of the help ID.
|
||||
*/
|
||||
@@ -950,7 +957,7 @@ public class ByteViewerComponent extends FieldPanel
|
||||
// WARNING: unusual situation. This method signature is the same between both
|
||||
// AbstractHoverProvider and the HoverService interface.
|
||||
// AbstractHoverProvider calls the scroll() on the service, but when
|
||||
// both calls end up at the same method, you will get a stackoverflow.
|
||||
// both calls end up at the same method, you will get a stack overflow.
|
||||
// We implement a do-nothing here that prevents that.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,8 +93,6 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
|
||||
static final String OPTION_FONT = "Font";
|
||||
|
||||
private static final String DEFAULT_VIEW = "Hex";
|
||||
private static final String CURRENT_LINE_COLOR_OPTION_NAME =
|
||||
GhidraOptions.HIGHLIGHT_CURSOR_LINE_COLOR_OPTION_NAME;
|
||||
private static final String OPTION_HIGHLIGHT_CURSOR_LINE =
|
||||
GhidraOptions.HIGHLIGHT_CURSOR_LINE_OPTION_NAME;
|
||||
private static final String OPTION_HIGHLIGHT_MIDDLE_MOUSE_NAME = "Middle Mouse Color";
|
||||
@@ -215,10 +213,10 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DockingActionIf> getPopupActions(Tool tool, ActionContext context) {
|
||||
public List<DockingActionIf> getPopupActions(Tool t, ActionContext context) {
|
||||
if (context instanceof ByteViewerActionContext bvContext &&
|
||||
bvContext.getComponentProvider() == this) {
|
||||
return bvContext.getActiveColumn().getPopupActions(tool, bvContext);
|
||||
return bvContext.getActiveColumn().getPopupActions(t, bvContext);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -248,12 +246,19 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
|
||||
@Override
|
||||
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
||||
Object newValue) {
|
||||
|
||||
if (options.getName().equals(CATEGORY_BROWSER_FIELDS)) {
|
||||
if (optionName.equals(CURSOR_HIGHLIGHT_BUTTON_NAME)) {
|
||||
CURSOR_MOUSE_BUTTON_NAMES mouseButton = (CURSOR_MOUSE_BUTTON_NAMES) newValue;
|
||||
panel.setHighlightButton(mouseButton.getMouseEventID());
|
||||
}
|
||||
}
|
||||
else if (options.getName().equals("ByteViewer")) {
|
||||
if (optionName.equals(OPTION_HIGHLIGHT_CURSOR_LINE)) {
|
||||
panel.setHighlightCurrentLineEnabled((Boolean) newValue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Options.getStringEnum() is deprecated
|
||||
@@ -285,16 +290,15 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
|
||||
CURSOR_COLOR_UNFOCUSED_EDIT.getId(), help,
|
||||
"Color of the cursor in the unfocused view when editing.");
|
||||
|
||||
opt.registerThemeColorBinding(CURRENT_LINE_COLOR_OPTION_NAME,
|
||||
GhidraOptions.DEFAULT_CURSOR_LINE_COLOR.getId(), help,
|
||||
"Color of the line containing the cursor.");
|
||||
|
||||
opt.registerThemeColorBinding(OPTION_HIGHLIGHT_MIDDLE_MOUSE_NAME,
|
||||
HIGHLIGHT_MIDDLE_MOUSE_COLOR.getId(), help, "The middle-mouse highlight color.");
|
||||
|
||||
opt.registerThemeFontBinding(OPTION_FONT, DEFAULT_FONT_ID, help, "Font used in the views.");
|
||||
opt.registerOption(OPTION_HIGHLIGHT_CURSOR_LINE, true, help,
|
||||
|
||||
boolean highlightCurrentLine = true;
|
||||
opt.registerOption(OPTION_HIGHLIGHT_CURSOR_LINE, highlightCurrentLine, help,
|
||||
"Toggles highlighting background color of line containing the cursor.");
|
||||
panel.setHighlightCurrentLineEnabled(highlightCurrentLine);
|
||||
|
||||
opt.addOptionsChangeListener(this);
|
||||
|
||||
@@ -332,14 +336,6 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
|
||||
return panel.getCursorLocation();
|
||||
}
|
||||
|
||||
ByteBlockSelection getBlockSelection() {
|
||||
return panel.getViewerSelection();
|
||||
}
|
||||
|
||||
void setBlockSelection(ByteBlockSelection selection) {
|
||||
panel.setViewerSelection(selection);
|
||||
}
|
||||
|
||||
ByteBlockSet getByteBlockSet() {
|
||||
return blockSet;
|
||||
}
|
||||
@@ -375,7 +371,6 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
|
||||
panel.repaint();
|
||||
}
|
||||
|
||||
|
||||
changed |= addNewViews(selectedViews);
|
||||
|
||||
if (changed) {
|
||||
@@ -513,8 +508,7 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
|
||||
model.setByteViewerConfigOptions(configOptions);
|
||||
|
||||
String viewName = model.getName();
|
||||
ByteViewerComponent bvc =
|
||||
panel.addView(viewName, model, editModeAction.isSelected(), updateViewPosition);
|
||||
ByteViewerComponent bvc = panel.addView(viewName, model, updateViewPosition);
|
||||
viewMap.put(viewName, bvc);
|
||||
if (configChanged) {
|
||||
tool.setConfigChanged(true);
|
||||
@@ -528,6 +522,7 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
|
||||
if (bvc == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
panel.removeView(bvc);
|
||||
|
||||
if (configChanged) {
|
||||
@@ -541,7 +536,8 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
|
||||
|
||||
protected abstract void updateSelection(ByteBlockSelection selection);
|
||||
|
||||
protected abstract void updateLiveSelection(ByteBlockSelection selection);
|
||||
protected abstract void updateLiveSelection(ByteViewerComponent bvc,
|
||||
ByteBlockSelection selection);
|
||||
|
||||
void dispose() {
|
||||
tool.removePopupActionProvider(this);
|
||||
|
||||
@@ -65,6 +65,9 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
|
||||
private IndexMap indexMap; // maps indexes to the correct block and offset
|
||||
private int blockOffset;
|
||||
private ByteViewerComponent currentView;
|
||||
|
||||
private boolean highlightCurrentLine;
|
||||
|
||||
private int highlightButton;
|
||||
private ListenerSet<LayoutModelListener> layoutListeners =
|
||||
new ListenerSet<>(LayoutModelListener.class, false);
|
||||
@@ -117,6 +120,15 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
|
||||
return highlightButton;
|
||||
}
|
||||
|
||||
void setHighlightCurrentLineEnabled(boolean b) {
|
||||
highlightCurrentLine = b;
|
||||
repaint();
|
||||
}
|
||||
|
||||
boolean isHighlightCurrentLine() {
|
||||
return highlightCurrentLine;
|
||||
}
|
||||
|
||||
void setHighlightButton(int highlightButton) {
|
||||
this.highlightButton = highlightButton;
|
||||
}
|
||||
@@ -269,11 +281,10 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
|
||||
*
|
||||
* @param viewName name of the format, e.g., Hex, Ascii, etc.
|
||||
* @param model model that understands the format
|
||||
* @param editMode true if edit mode is on
|
||||
* @param updateViewPosition true if the view position should be set
|
||||
* @return the new component
|
||||
*/
|
||||
ByteViewerComponent addView(String viewName, DataFormatModel model, boolean editMode,
|
||||
ByteViewerComponent addView(String viewName, DataFormatModel model,
|
||||
boolean updateViewPosition) {
|
||||
|
||||
if (viewList.size() != 0) {
|
||||
@@ -447,8 +458,17 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
|
||||
}
|
||||
}
|
||||
|
||||
void updateLiveSelection(ByteViewerComponent source, ByteBlockSelection selection) {
|
||||
provider.updateLiveSelection(selection);
|
||||
void updateLiveSelection(ByteViewerComponent bvc, ByteBlockSelection selection) {
|
||||
|
||||
provider.updateLiveSelection(bvc, selection);
|
||||
|
||||
for (ByteViewerComponent c : viewList) {
|
||||
if (c == bvc) {
|
||||
continue;
|
||||
}
|
||||
c.setViewerSelection(selection);
|
||||
}
|
||||
|
||||
updateIndexColumnCurrentLine();
|
||||
}
|
||||
|
||||
@@ -514,7 +534,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
|
||||
|
||||
setLayout(new BorderLayout(10, 0));
|
||||
setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
|
||||
|
||||
|
||||
setFont(ByteViewerComponentProvider.DEFAULT_FONT); // side-effect sets fontMetrics
|
||||
|
||||
// for the index/address column
|
||||
@@ -526,8 +546,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
|
||||
indexPanel.setFocusable(false);
|
||||
indexPanel.addLayoutListener(this);
|
||||
indexPanel.setBackgroundColor(ByteViewerComponentProvider.BG_COLOR);
|
||||
indexPanel.setBackgroundColorModel(
|
||||
new ByteViewerBGColorModel(() -> getCurrentComponent().getCursorLocation().getIndex()));
|
||||
indexPanel.setBackgroundColorModel(new ByteViewerBGColorModel(this));
|
||||
|
||||
indexedView = new ByteViewerIndexedView(indexPanel);
|
||||
IndexedScrollPane indexedScrollPane = new IndexedScrollPane(indexedView);
|
||||
|
||||
@@ -618,13 +618,17 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateLiveSelection(ByteBlockSelection selection) {
|
||||
if (blockSet != null) {
|
||||
AbstractSelectionPluginEvent event =
|
||||
blockSet.getPluginEvent(plugin.getName(), selection);
|
||||
liveSelection = event.getSelection();
|
||||
updateTitle();
|
||||
protected void updateLiveSelection(ByteViewerComponent sourceComponent,
|
||||
ByteBlockSelection blockSelection) {
|
||||
|
||||
if (blockSet == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractSelectionPluginEvent event =
|
||||
blockSet.getPluginEvent(plugin.getName(), blockSelection);
|
||||
liveSelection = event.getSelection();
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user