GP-1359 - Updated the Listing and Byte Viewer to show selection size as the user drags

This commit is contained in:
dragonmacher 2024-08-12 12:04:38 -04:00
parent 5047c00359
commit 4cda642e9c
9 changed files with 175 additions and 117 deletions

View File

@ -4,9 +4,9 @@
* 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.
@ -105,7 +105,10 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
private CoordinatedListingPanelListener coordinatedListingPanelListener;
private FormatManager formatMgr;
private FieldPanelCoordinator coordinator;
private ProgramSelectionListener liveProgramSelectionListener = (selection, trigger) -> {
liveSelection = selection;
updateSubTitle();
};
private FocusingMouseListener focusingMouseListener;
private CodeBrowserClipboardProvider codeViewerClipboardProvider;
@ -116,6 +119,7 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
private CloneCodeViewerAction cloneCodeViewerAction;
private ProgramSelection currentSelection;
private ProgramSelection liveSelection;
private ProgramSelection currentHighlight;
private String currentStringSelection;
@ -163,6 +167,7 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
createActions();
listingPanel.setProgramLocationListener(this);
listingPanel.setProgramSelectionListener(this);
listingPanel.setLiveProgramSelectionListener(liveProgramSelectionListener);
listingPanel.setStringSelectionListener(this);
listingPanel.addIndexMapChangeListener(this);
@ -542,11 +547,18 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
private void doSetSelection(ProgramSelection selection) {
liveSelection = null;
currentSelection = selection;
codeViewerClipboardProvider.setSelection(currentSelection);
listingPanel.setSelection(currentSelection);
plugin.selectionChanged(this, currentSelection);
contextChanged();
updateSubTitle();
}
private void updateSubTitle() {
ProgramSelection selection = liveSelection != null ? liveSelection : currentSelection;
String selectionInfo = null;
if (!selection.isEmpty()) {
long n = selection.getNumAddresses();

View File

@ -4,9 +4,9 @@
* 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.
@ -345,10 +345,8 @@ public class ListingModelAdapter implements LayoutModel, ListingModelListener {
return ps;
}
}
Program program = model.getProgram();
addrSet = model.adjustAddressSetToCodeUnitBoundaries(addrSet);
AddressFactory factory = program == null ? null : program.getAddressFactory();
return new ProgramSelection(factory, addrSet);
return new ProgramSelection(null, addrSet);
}
// this methods does NOT work for structures inside of unions, but handles structures

View File

@ -4,9 +4,9 @@
* 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.
@ -63,7 +63,19 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
private ProgramLocationListener programLocationListener;
private ProgramSelectionListener programSelectionListener;
private ProgramSelectionListener liveProgramSelectionListener;
private StringSelectionListener stringSelectionListener;
private FieldSelectionListener fieldPanelLiveSelectionListener = (selection, trigger) -> {
if (liveProgramSelectionListener == null) {
return;
}
ProgramSelection ps = layoutModel.getProgramSelection(selection);
if (ps != null) {
liveProgramSelectionListener.programSelectionChanged(ps, trigger);
}
};
private ListingModel listingModel;
private FieldHeader headerPanel;
@ -106,6 +118,7 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
fieldPanel.addFieldMouseListener(this);
fieldPanel.addFieldLocationListener(this);
fieldPanel.addFieldSelectionListener(this);
fieldPanel.addLiveFieldSelectionListener(fieldPanelLiveSelectionListener);
fieldPanel.addLayoutListener(this);
propertyBasedColorModel = new PropertyBasedBackgroundColorModel();
fieldPanel.setBackgroundColorModel(propertyBasedColorModel);
@ -207,6 +220,16 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
programSelectionListener = listener;
}
/**
* Sets the ProgramSelectionListener for selection changes while dragging. Only one listener is
* supported
*
* @param listener the ProgramSelectionListener to use.
*/
public void setLiveProgramSelectionListener(ProgramSelectionListener listener) {
liveProgramSelectionListener = listener;
}
public void setStringSelectionListener(StringSelectionListener listener) {
stringSelectionListener = listener;
}

View File

@ -4,9 +4,9 @@
* 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.
@ -32,15 +32,6 @@ public class ProgramSelection implements AddressSetView {
* Construct a new empty ProgramSelection.
*/
public ProgramSelection() {
this((AddressFactory) null);
}
/**
* Construct a new empty ProgramSelection.
* @param addressFactory the address factory for the address set
* associated with this program selection.
*/
public ProgramSelection(AddressFactory addressFactory) {
addressSet = new AddressSet();
}
@ -50,18 +41,6 @@ public class ProgramSelection implements AddressSetView {
* @param to the end of the selection
*/
public ProgramSelection(Address from, Address to) {
this(null, from, to);
}
/**
* Constructor.
* @param addressFactory the address factory for the address set
* associated with this program selection.
* @param from the start of the selection
* @param to the end of the selection
*/
public ProgramSelection(AddressFactory addressFactory, Address from, Address to) {
this(addressFactory);
if (to.compareTo(from) < 0) {
Address temp = to;
to = from;
@ -75,36 +54,59 @@ public class ProgramSelection implements AddressSetView {
* @param setView address set for the selection
*/
public ProgramSelection(AddressSetView setView) {
this(null, setView);
}
/**
* Construct a new ProgramSelection
* @param addressFactory the address factory for the address set
* associated with this program selection.
* @param setView address set for the selection
*/
public ProgramSelection(AddressFactory addressFactory, AddressSetView setView) {
addressSet = new AddressSet(setView);
}
/**
* Construct a new ProgramSelection from the indicated interior selection.
* @param addressFactory the address factory for the address set
* associated with this program selection.
* @param sel the interior selection
*/
public ProgramSelection(AddressFactory addressFactory, InteriorSelection sel) {
this(addressFactory, sel.getStartAddress(), sel.getEndAddress());
interiorSelection = sel;
}
/**
* Construct a new ProgramSelection from the indicated interior selection.
* @param sel the interior selection
*/
public ProgramSelection(InteriorSelection sel) {
this(null, sel);
this(sel.getStartAddress(), sel.getEndAddress());
interiorSelection = sel;
}
/**
* Construct a new empty ProgramSelection.
* @param addressFactory NOT USED
* @deprecated use {@link #ProgramSelection()}
*/
@Deprecated(since = "11.2", forRemoval = true)
public ProgramSelection(AddressFactory addressFactory) {
this();
}
/**
* Constructor.
* @param addressFactory NOT USED
* @param from the start of the selection
* @param to the end of the selection
*/
@Deprecated(since = "11.2", forRemoval = true)
public ProgramSelection(AddressFactory addressFactory, Address from, Address to) {
this(from, to);
}
/**
* Construct a new ProgramSelection
* @param addressFactory NOT USED
* @param setView address set for the selection
* @deprecated use {@link #ProgramSelection(AddressSetView)}
*/
@Deprecated(since = "11.2", forRemoval = true)
public ProgramSelection(AddressFactory addressFactory, AddressSetView setView) {
this(setView);
}
/**
* Construct a new ProgramSelection from the indicated interior selection.
* @param addressFactory NOT USED
* @param sel the interior selection
* @deprecated use {@link #ProgramSelection(InteriorSelection)}s
*/
@Deprecated(since = "11.2", forRemoval = true)
public ProgramSelection(AddressFactory addressFactory, InteriorSelection sel) {
this(sel);
}
/**

View File

@ -4,9 +4,9 @@
* 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.
@ -68,6 +68,11 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
private ByteViewerHighlighter highlightProvider = new ByteViewerHighlighter();
private int highlightButton = MouseEvent.BUTTON2;
private FieldSelectionListener liveSelectionListener = (selection, trigger) -> {
ByteBlockSelection sel = processFieldSelection(selection);
panel.updateLiveSelection(ByteViewerComponent.this, sel);
};
/**
* Constructor
*
@ -206,12 +211,12 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
if (blockSet == null || doingRefresh) {
return;
}
ByteBlockSelection sel = processFieldSelection(selection);
// notify panel to update other components
panel.updateSelection(this, sel);
setViewerSelection(sel);
}
/**
@ -339,12 +344,10 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
return null;
}
/**
* Add listeners.
*/
void addListeners() {
addFieldLocationListener(this);
addFieldSelectionListener(this);
addLiveFieldSelectionListener(liveSelectionListener);
addFieldInputListener(this);
addFieldMouseListener(this);
}

View File

@ -4,9 +4,9 @@
* 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.
@ -429,6 +429,8 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
protected abstract void updateSelection(ByteBlockSelection selection);
protected abstract void updateLiveSelection(ByteBlockSelection selection);
void dispose() {
updateManager.dispose();
updateManager = null;

View File

@ -4,9 +4,9 @@
* 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.
@ -101,9 +101,8 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
height += dim.height;
}
boolean addHeight = true;
for (int i = 0; i < viewList.size(); i++) {
for (ByteViewerComponent c : viewList) {
ByteViewerComponent c = viewList.get(i);
Dimension d = c.getPreferredSize();
width += d.width;
width += 2; // for separator
@ -133,54 +132,47 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
//////////////////////////////////////////////////////////////////////////
void setCurrentCursorColor(Color c) {
currentCursorColor = c;
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent comp = viewList.get(i);
for (ByteViewerComponent comp : viewList) {
comp.setCurrentCursorColor(c);
}
}
void setCurrentCursorLineColor(Color c) {
currentCursorLineColor = c;
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent comp = viewList.get(i);
for (ByteViewerComponent comp : viewList) {
comp.setCurrentCursorLineColor(c);
}
}
void setHighlightButton(int highlightButton) {
this.highlightButton = highlightButton;
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent comp = viewList.get(i);
for (ByteViewerComponent comp : viewList) {
comp.setHighlightButton(highlightButton);
}
}
void setMouseButtonHighlightColor(Color color) {
this.highlightColor = color;
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent comp = viewList.get(i);
for (ByteViewerComponent comp : viewList) {
comp.setMouseButtonHighlightColor(color);
}
}
void setCursorColor(Color c) {
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent comp = viewList.get(i);
for (ByteViewerComponent comp : viewList) {
comp.setNonFocusCursorColor(c);
}
}
void setSeparatorColor(Color c) {
indexFactory.setMissingValueColor(c);
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent comp = viewList.get(i);
for (ByteViewerComponent comp : viewList) {
comp.setSeparatorColor(c);
}
}
void setNonFocusCursorColor(Color c) {
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent comp = viewList.get(i);
for (ByteViewerComponent comp : viewList) {
comp.setNonFocusCursorColor(c);
}
}
@ -217,13 +209,11 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
// Do the following loop twice - once with update off and then with update on.
// need to do this because all the byte view components must have their models
// updated before any one of them tells their dependents about the change.
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
c.enableIndexUpdate(false);
c.setIndexMap(indexMap);
}
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
c.enableIndexUpdate(true);
c.setIndexMap(indexMap);
}
@ -235,8 +225,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
}
void setViewerSelection(ByteBlockSelection selection) {
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
c.setViewerSelection(selection);
}
}
@ -249,8 +238,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
}
void setViewerHighlight(ByteBlockSelection highlight) {
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
c.setViewerHighlight(highlight);
}
}
@ -279,8 +267,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
void setCursorLocation(ByteBlock block, BigInteger index, int column) {
int modelIndex = -1;
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
modelIndex = c.setViewerCursorLocation(block, index, column);
}
if (modelIndex >= 0) {
@ -411,8 +398,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
}
void setEditMode(boolean editMode) {
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
c.setEditMode(editMode);
}
}
@ -428,8 +414,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
* Force the current view to be refreshed.
*/
void refreshView() {
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
c.refreshView();
}
}
@ -469,8 +454,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
* @throws InvalidInputException if a model cannot support the bytesPerLine value
*/
void checkBytesPerLine(int numBytesPerLine) throws InvalidInputException {
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
DataFormatModel model = c.getDataModel();
int groupSize = model.getGroupSize();
if (groupSize > 0) {
@ -531,8 +515,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
}
insertionField.setText(locRep);
}
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
if (source == c) {
continue;
}
@ -550,8 +533,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
void updateSelection(ByteViewerComponent source, ByteBlockSelection selection) {
provider.updateSelection(selection);
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
if (source == c) {
continue;
}
@ -559,6 +541,10 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
}
}
void updateLiveSelection(ByteViewerComponent source, ByteBlockSelection selection) {
provider.updateLiveSelection(selection);
}
FontMetrics getCurrentFontMetrics() {
return fontMetrics;
}
@ -589,8 +575,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
BigInteger offset = vp.getOffset();
ViewerPosition vpos = vp.getViewerPosition();
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
c.returnToView(block, offset, vpos);
}
indexPanel.setViewerPosition(vpos.getIndex(), vpos.getXOffset(), vpos.getYOffset());
@ -625,8 +610,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
void setFontMetrics(FontMetrics fm) {
this.fontMetrics = fm;
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
c.setFontMetrics(fm);
}
indexFactory = new IndexFieldFactory(fm);
@ -636,8 +620,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
void setEditColor(Color editColor) {
this.editColor = editColor;
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
c.setEditColor(editColor);
}
}
@ -761,8 +744,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
block = info.getBlock();
offset = info.getOffset();
}
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
c.setIndexMap(indexMap);
if (info != null) {
c.setViewerCursorLocation(block, offset, info.getColumn());
@ -775,8 +757,7 @@ public class ByteViewerPanel extends JPanel implements LayoutModel, LayoutListen
* Clear the selection.
*/
private void clearSelection() {
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent c = viewList.get(i);
for (ByteViewerComponent c : viewList) {
c.clearViewerSelection();
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -62,6 +62,7 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
protected Program program;
protected ProgramSelection currentSelection;
protected ProgramSelection liveSelection;
protected ProgramSelection currentHighlight;
protected ProgramLocation currentLocation;
@ -179,7 +180,9 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
}
protected void setSelection(ProgramSelection selection, boolean notify) {
liveSelection = null;
currentSelection = selection;
updateTitle();
if (selection == null) {
return;
}
@ -258,8 +261,26 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
if (!isConnected()) {
title = "[" + title + "]";
}
setTitle(title);
updateSubTitle();
}
private void updateSubTitle() {
// Note: the Listing has similar code
ProgramSelection selection = liveSelection != null ? liveSelection : currentSelection;
String selectionInfo = null;
if (selection != null && !selection.isEmpty()) {
long n = selection.getNumAddresses();
String nString = Long.toString(n);
if (n == 1) {
selectionInfo = "(1 byte selected)";
}
else {
selectionInfo = '(' + nString + " bytes selected)";
}
}
setSubTitle(selectionInfo);
}
//==================================================================================================
@ -366,7 +387,7 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
public boolean isVisible() {
return tool.isVisible(this);
}
//==================================================================================================
// End Navigatable interface methods */
//==================================================================================================
@ -583,12 +604,21 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
@Override
protected void updateSelection(ByteBlockSelection selection) {
ProgramSelectionPluginEvent event = blockSet.getPluginEvent(plugin.getName(), selection);
liveSelection = null;
currentSelection = event.getSelection();
plugin.updateSelection(this, event, program);
clipboardProvider.setSelection(currentSelection);
updateTitle();
contextChanged();
}
@Override
protected void updateLiveSelection(ByteBlockSelection selection) {
ProgramSelectionPluginEvent event = blockSet.getPluginEvent(plugin.getName(), selection);
liveSelection = event.getSelection();
updateTitle();
}
@Override
protected void updateLocation(ByteBlock block, BigInteger blockOffset, int column,
boolean export) {

View File

@ -4,9 +4,9 @@
* 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.
@ -346,6 +346,13 @@ public class AddressSet implements AddressSetView {
buffy.append(range);
buffy.append(" ");
}
// remove the last space maintain symmetry
char lastChar = buffy.charAt(buffy.length() - 1);
if (lastChar == ' ') {
buffy.deleteCharAt(buffy.length() - 1);
}
buffy.append("]");
return buffy.toString();
}