Merge remote-tracking branch 'origin/GT-3269-CodeViewerVisibleAddresses'

This commit is contained in:
Ryan Kurtz
2019-11-04 13:41:45 -05:00
7 changed files with 141 additions and 23 deletions
@@ -937,8 +937,8 @@ public class CodeBrowserPlugin extends Plugin
tableFromSelectionAction.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_SELECTION, "Create Table From Selection" }, null,
"SelectUtils"));
tableFromSelectionAction.setHelpLocation(
new HelpLocation("CodeBrowserPlugin", "Selection_Table"));
tableFromSelectionAction
.setHelpLocation(new HelpLocation("CodeBrowserPlugin", "Selection_Table"));
}
private GhidraProgramTableModel<Address> createTableModel(CodeUnitIterator iterator,
@@ -1013,8 +1013,8 @@ public class CodeBrowserPlugin extends Plugin
public boolean goToField(Address a, String fieldName, int occurrence, int row, int col,
boolean scroll) {
boolean result = SystemUtilities.runSwingNow(
() -> doGoToField(a, fieldName, occurrence, row, col, scroll));
boolean result = SystemUtilities
.runSwingNow(() -> doGoToField(a, fieldName, occurrence, row, col, scroll));
return result;
}
@@ -1135,6 +1135,16 @@ public class CodeBrowserPlugin extends Plugin
return null;
}
@Override
public void addListingDisplayListener(ListingDisplayListener listener) {
connectedProvider.addListingDisplayListener(listener);
}
@Override
public void removeListingDisplayListener(ListingDisplayListener listener) {
connectedProvider.removeListingDisplayListener(listener);
}
public String getCurrentFieldText() {
ListingField lf = getCurrentField();
if (lf instanceof ListingTextField) {
@@ -889,8 +889,8 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
int index = saveState.getInt("INDEX", 0);
int yOffset = saveState.getInt("Y_OFFSET", 0);
ViewerPosition vp = new ViewerPosition(index, 0, yOffset);
listingPanel.getFieldPanel().setViewerPosition(vp.getIndex(), vp.getXOffset(),
vp.getYOffset());
listingPanel.getFieldPanel()
.setViewerPosition(vp.getIndex(), vp.getXOffset(), vp.getYOffset());
if (program != null) {
currentLocation = ProgramLocation.getLocation(program, saveState);
if (currentLocation != null) {
@@ -906,8 +906,8 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
// (its done in an invoke later)
Swing.runLater(() -> {
newProvider.doSetProgram(program);
newProvider.listingPanel.getFieldPanel().setViewerPosition(vp.getIndex(),
vp.getXOffset(), vp.getYOffset());
newProvider.listingPanel.getFieldPanel()
.setViewerPosition(vp.getIndex(), vp.getXOffset(), vp.getYOffset());
newProvider.setLocation(currentLocation);
});
}
@@ -975,8 +975,8 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
public void actionPerformed(ActionContext context) {
boolean show = !listingPanel.isHeaderShowing();
listingPanel.showHeader(show);
getToolBarData().setIcon(
show ? LISTING_FORMAT_COLLAPSE_ICON : LISTING_FORMAT_EXPAND_ICON);
getToolBarData()
.setIcon(show ? LISTING_FORMAT_COLLAPSE_ICON : LISTING_FORMAT_EXPAND_ICON);
}
}
@@ -1039,4 +1039,20 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
return list.toArray(new Highlight[list.size()]);
}
}
/**
* Add the ListingDisplayListener to the listing panel
* @param listener the listener to add
*/
public void addListingDisplayListener(ListingDisplayListener listener) {
listingPanel.addListingDisplayListener(listener);
}
/**
* Remove the ListingDisplayListener from the listing panel
* @param listener the listener to remove
*/
public void removeListingDisplayListener(ListingDisplayListener listener) {
listingPanel.removeListingDisplayListener(listener);
}
}
@@ -15,6 +15,12 @@
*/
package ghidra.app.services;
import javax.swing.JComponent;
import docking.action.DockingAction;
import docking.widgets.fieldpanel.FieldPanel;
import docking.widgets.fieldpanel.Layout;
import docking.widgets.fieldpanel.field.Field;
import ghidra.app.nav.Navigatable;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.util.HighlightProvider;
@@ -29,13 +35,6 @@ import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import javax.swing.JComponent;
import docking.action.DockingAction;
import docking.widgets.fieldpanel.FieldPanel;
import docking.widgets.fieldpanel.Layout;
import docking.widgets.fieldpanel.field.Field;
/**
* Service provided by a plugin that shows the listing from a Program, i.e., a
* Code Viewer. The service allows other plugins to add components and
@@ -224,4 +223,16 @@ public interface CodeViewerService {
* @return the current program selection.
*/
public ProgramSelection getCurrentSelection();
/**
* Adds a listener to be notified when the set of visible addresses change.
* @param listener the listener to be notified;
*/
public void addListingDisplayListener(ListingDisplayListener listener);
/**
* Removes listener from being notified when the set of visible addresses change.
* @param listener the listener to be notified;
*/
public void removeListingDisplayListener(ListingDisplayListener listener);
}
@@ -0,0 +1,30 @@
/* ###
* 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.listingpanel;
import ghidra.program.model.address.AddressSetView;
/**
* Interface for being notified whenever the set of visible addresses change in the listing.
*/
public interface ListingDisplayListener {
/**
* Callback whenever the set of visible addresses change in the listing.
* @param visibleAddresses the current set of visible addresses in the listing. If no
* visible addresses are in the listing view, then an empty AddressSetView will be passed.
*/
void visibleAddressesChanged(AddressSetView visibleAddresses);
}
@@ -45,6 +45,7 @@ import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*;
import ghidra.program.util.*;
import ghidra.util.Msg;
import ghidra.util.layout.HorizontalLayout;
public class ListingPanel extends JPanel implements FieldMouseListener, FieldLocationListener,
@@ -88,6 +89,7 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
// don't care
}
};
private List<ListingDisplayListener> displayListeners = new ArrayList<>();
/**
* Constructs a new ListingPanel using the given FormatManager and ServiceProvider.
@@ -461,6 +463,21 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
for (MarginProvider element : marginProviders) {
element.setPixelMap(pixmap);
}
for (ListingDisplayListener listener : displayListeners) {
notifyDisplayListener(listener);
}
}
private void notifyDisplayListener(ListingDisplayListener listener) {
AddressSetView displayAddresses = pixmap.getAddressSet();
try {
listener.visibleAddressesChanged(displayAddresses);
}
catch (Throwable t) {
Msg.showError(this, fieldPanel, "Error in Display Listener",
"Execption encountered when notifying listeners of change in display", t);
}
}
/**
@@ -843,8 +860,8 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
FieldLocation dropLoc = new FieldLocation();
ListingField field = (ListingField) fieldPanel.getFieldAt(point.x, point.y, dropLoc);
if (field != null) {
return field.getFieldFactory().getProgramLocation(dropLoc.getRow(), dropLoc.getCol(),
field);
return field.getFieldFactory()
.getProgramLocation(dropLoc.getRow(), dropLoc.getCol(), field);
}
return null;
}
@@ -1091,4 +1108,11 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
layoutModel.dataChanged(true);
}
public void addListingDisplayListener(ListingDisplayListener listener) {
displayListeners.add(listener);
}
public void removeListingDisplayListener(ListingDisplayListener listener) {
displayListeners.remove(listener);
}
}
@@ -128,6 +128,10 @@ public class VerticalPixelAddressMapImpl implements VerticalPixelAddressMap {
@Override
public AddressSetView getAddressSet() {
// If there are no visible layouts (no open data to display or listing component height = 0)
if (layouts.isEmpty()) {
return new AddressSet();
}
if (viewedAddresses == null) {
viewedAddresses =
map.getOriginalAddressSet().intersectRange(getStartAddress(), getEndAddress());
@@ -18,6 +18,7 @@ package ghidra.app.util.viewer.listingpanel;
import static org.junit.Assert.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.*;
@@ -51,10 +52,6 @@ public class ListingPanelTest extends AbstractGhidraHeadedIntegrationTest {
private AddressFactory addrFactory;
private AddressSpace space;
public ListingPanelTest() {
super();
}
@Before
public void setUp() throws Exception {
env = new TestEnv();
@@ -305,6 +302,32 @@ public class ListingPanelTest extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testListingDisplayListener() {
showTool(tool);
AtomicReference<AddressSetView> addresses = new AtomicReference<>();
CodeViewerService cvs = tool.getService(CodeViewerService.class);
cvs.addListingDisplayListener(new ListingDisplayListener() {
@Override
public void visibleAddressesChanged(AddressSetView visibleAddresses) {
addresses.set(visibleAddresses);
}
});
assertNull(addresses.get());
cvs.goTo(new ProgramLocation(program, addr(0x1008000)), false);
assertNotNull(addresses.get());
assertTrue(addresses.get().contains(addr(0x1008000)));
assertFalse(addresses.get().contains(addr(0x1001000)));
cvs.goTo(new ProgramLocation(program, addr(0x1001000)), false);
assertNotNull(addresses.get());
assertFalse(addresses.get().contains(addr(0x1008000)));
assertTrue(addresses.get().contains(addr(0x1001000)));
}
private void resetFormatOptions() {
Options fieldOptions = cb.getFormatManager().getFieldOptions();
List<String> names = fieldOptions.getOptionNames();