mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
GT-2925 - Key Bindings - Support Window Menu Provider Key Bindings -
Step - Added 'snapshot' concept to base Component Provider to fix how actions are added to the toolbar and menu; fixed bugs and tests
This commit is contained in:
@@ -70,9 +70,13 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
||||
public ProgramByteViewerComponentProvider(PluginTool tool, ByteViewerPlugin plugin,
|
||||
boolean isConnected) {
|
||||
super(tool, plugin, "Bytes", ByteViewerActionContext.class);
|
||||
this.isConnected = isConnected;
|
||||
|
||||
setIcon(ResourceManager.loadImage("images/binaryData.gif"), true);
|
||||
this.isConnected = isConnected;
|
||||
if (!isConnected) {
|
||||
setTransient();
|
||||
}
|
||||
|
||||
setIcon(ResourceManager.loadImage("images/binaryData.gif"), isConnected);
|
||||
|
||||
decorationComponent = new DecoratorPanel(panel, isConnected);
|
||||
clipboardProvider = new ByteViewerClipboardProvider(this, tool);
|
||||
@@ -88,6 +92,12 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
||||
tool.addLocalAction(this, cloneByteViewerAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSnapshot() {
|
||||
// we are a snapshot when we are 'disconnected'
|
||||
return !isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
return decorationComponent;
|
||||
@@ -132,11 +142,6 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
||||
plugin.closeProvider(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransient() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelection(ProgramSelection selection) {
|
||||
setSelection(selection, true);
|
||||
|
||||
@@ -28,8 +28,10 @@ import javax.swing.event.TableColumnModelEvent;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.*;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.menu.ToolBarItemManager;
|
||||
import docking.menu.ToolBarManager;
|
||||
import docking.widgets.EventTrigger;
|
||||
import docking.widgets.fieldpanel.FieldPanel;
|
||||
import docking.widgets.fieldpanel.field.Field;
|
||||
@@ -168,7 +170,7 @@ public class ByteViewerPlugin1Test extends AbstractGhidraHeadedIntegrationTest {
|
||||
DataModelInfo info = panel.getDataModelInfo();
|
||||
String[] names = info.getNames();
|
||||
assertEquals(3, names.length);
|
||||
Set<String> viewNames = new HashSet<String>(Arrays.asList(names));
|
||||
Set<String> viewNames = new HashSet<>(Arrays.asList(names));
|
||||
assertTrue(viewNames.contains("Hex"));
|
||||
assertTrue(viewNames.contains("Octal"));
|
||||
assertTrue(viewNames.contains("Ascii"));
|
||||
@@ -668,6 +670,64 @@ public class ByteViewerPlugin1Test extends AbstractGhidraHeadedIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowingSnapshotDoesNotAddMultipleToolbarActions() {
|
||||
|
||||
DockingActionIf cloneAction = getAction(plugin, "ByteViewer Clone");
|
||||
performAction(cloneAction);
|
||||
waitForSwing();
|
||||
assertOnlyOneProviderToolbarAction();
|
||||
|
||||
performAction(cloneAction);
|
||||
waitForSwing();
|
||||
assertOnlyOneProviderToolbarAction();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Private Methods
|
||||
//==================================================================================================
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void assertOnlyOneProviderToolbarAction() {
|
||||
|
||||
DockingWindowManager dwm = tool.getWindowManager();
|
||||
ActionToGuiMapper guiActions =
|
||||
(ActionToGuiMapper) getInstanceField("actionToGuiMapper", dwm);
|
||||
GlobalMenuAndToolBarManager menuManager =
|
||||
(GlobalMenuAndToolBarManager) getInstanceField("menuAndToolBarManager", guiActions);
|
||||
|
||||
Map<WindowNode, WindowActionManager> windowToActionManagerMap =
|
||||
(Map<WindowNode, WindowActionManager>) getInstanceField("windowToActionManagerMap",
|
||||
menuManager);
|
||||
|
||||
ProgramByteViewerComponentProvider provider = plugin.getProvider();
|
||||
DockingActionIf showAction =
|
||||
(DockingActionIf) getInstanceField("showProviderAction", provider);
|
||||
String actionName = showAction.getName();
|
||||
List<DockingActionIf> matches = new ArrayList<>();
|
||||
for (WindowActionManager actionManager : windowToActionManagerMap.values()) {
|
||||
|
||||
ToolBarManager toolbarManager =
|
||||
(ToolBarManager) getInstanceField("toolBarMgr", actionManager);
|
||||
Map<String, List<ToolBarItemManager>> groupToItems =
|
||||
(Map<String, List<ToolBarItemManager>>) getInstanceField("groupToItemsMap",
|
||||
toolbarManager);
|
||||
|
||||
Collection<List<ToolBarItemManager>> values = groupToItems.values();
|
||||
for (List<ToolBarItemManager> list : values) {
|
||||
for (ToolBarItemManager manager : list) {
|
||||
DockingActionIf action = manager.getAction();
|
||||
if (actionName.equals(action.getName())) {
|
||||
matches.add(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Should only have 1 action on toolbar to show the provider", 1,
|
||||
matches.size());
|
||||
}
|
||||
|
||||
private void goToOperand(String addr) {
|
||||
goTo(addr(addr), OperandFieldFactory.FIELD_NAME);
|
||||
}
|
||||
@@ -731,11 +791,6 @@ public class ByteViewerPlugin1Test extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertEquals(expectedColumn, location.getCol());
|
||||
}
|
||||
|
||||
private void goTo(String addr) {
|
||||
GoToService goToService = tool.getService(GoToService.class);
|
||||
goToService.goTo(addr(addr));
|
||||
}
|
||||
|
||||
private void goToByte(String addr) {
|
||||
goToByte(addr(addr));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user