mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Fixed tests failing due to focus timing issues by allowing the test
framework to specify the source of key bindings
This commit is contained in:
parent
3418492a8c
commit
3f62f91a2e
5 changed files with 71 additions and 10 deletions
|
@ -337,7 +337,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
// Note: there may be a test focus issue here. If this test fails sporadically due to
|
// Note: there may be a test focus issue here. If this test fails sporadically due to
|
||||||
// how the action context is generated (it depends on focus). It is only useful to fail
|
// how the action context is generated (it depends on focus). It is only useful to fail
|
||||||
// here in development mode.
|
// here in development mode.
|
||||||
triggerKey(tool.getToolFrame(), controlEsc);
|
triggerKey(provider.getComponent(), controlEsc);
|
||||||
assertProviderIsHidden_InNonBatchMode();
|
assertProviderIsHidden_InNonBatchMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,6 +376,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
provider.addToTool();
|
provider.addToTool();
|
||||||
tool.showComponentProvider(provider, true);
|
tool.showComponentProvider(provider, true);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
waitForCondition(() -> provider.isVisible());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hideProvider() {
|
private void hideProvider() {
|
||||||
|
@ -546,6 +547,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
// simulate the user mousing over the toolbar button
|
// simulate the user mousing over the toolbar button
|
||||||
DockingActionIf closeAction = getAction(tool, provider.getOwner(), "Close Window");
|
DockingActionIf closeAction = getAction(tool, provider.getOwner(), "Close Window");
|
||||||
assertNotNull("Provider action not installed in toolbar", closeAction);
|
assertNotNull("Provider action not installed in toolbar", closeAction);
|
||||||
|
|
||||||
DockingWindowManager.setMouseOverAction(closeAction);
|
DockingWindowManager.setMouseOverAction(closeAction);
|
||||||
|
|
||||||
performLaunchKeyStrokeDialogAction();
|
performLaunchKeyStrokeDialogAction();
|
||||||
|
@ -554,6 +556,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
runSwing(() -> dialog.setKeyStroke(ks));
|
runSwing(() -> dialog.setKeyStroke(ks));
|
||||||
|
|
||||||
pressButtonByText(dialog, "OK");
|
pressButtonByText(dialog, "OK");
|
||||||
|
waitForSwing();
|
||||||
|
|
||||||
assertFalse("Invalid key stroke: " + ks, runSwing(() -> dialog.isVisible()));
|
assertFalse("Invalid key stroke: " + ks, runSwing(() -> dialog.isVisible()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,12 +77,13 @@ public class TableChooserDialogTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
tool.setVisible(true);
|
tool.setVisible(true);
|
||||||
Program program = new ToyProgramBuilder("Test", true).getProgram();
|
Program program = new ToyProgramBuilder("Test", true).getProgram();
|
||||||
Navigatable navigatable = null;
|
Navigatable navigatable = null;
|
||||||
dialog = new TableChooserDialog(tool, executor, program, "Title", navigatable);
|
dialog = new TableChooserDialog(tool, executor, program, "Dialog Title", navigatable);
|
||||||
|
|
||||||
testAction = new TestAction();
|
testAction = new TestAction();
|
||||||
dialog.addAction(testAction);
|
dialog.addAction(testAction);
|
||||||
|
|
||||||
dialog.show();
|
dialog.show();
|
||||||
|
waitForDialogComponent(TableChooserDialog.class);
|
||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +290,8 @@ public class TableChooserDialogTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
KeyStroke newKs = KeyStroke.getKeyStroke('A', 0, false);
|
KeyStroke newKs = KeyStroke.getKeyStroke('A', 0, false);
|
||||||
setKeyBindingViaF4Dialog(testAction, newKs);
|
setKeyBindingViaF4Dialog(testAction, newKs);
|
||||||
triggerKey(dialog.getComponent(), newKs);
|
triggerKey(dialog.getComponent(), newKs);
|
||||||
assertTrue(testAction.wasInvoked());
|
assertTrue("Action was not invoked from the new key binding: " + newKs,
|
||||||
|
testAction.wasInvoked());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -354,9 +354,9 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the window which contains the specified Provider's component.
|
* Get the window that contains the specified Provider's component
|
||||||
* @param provider component provider
|
* @param provider component provider
|
||||||
* @return window or null if component is not visible or not found.
|
* @return window or null if component is not visible or not found
|
||||||
*/
|
*/
|
||||||
public Window getProviderWindow(ComponentProvider provider) {
|
public Window getProviderWindow(ComponentProvider provider) {
|
||||||
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
|
ComponentPlaceholder placeholder = getActivePlaceholder(provider);
|
||||||
|
@ -366,6 +366,24 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the provider that contains the specified component
|
||||||
|
* @param c the component
|
||||||
|
* @return the provider; null if now containing provider is found
|
||||||
|
*/
|
||||||
|
public ComponentProvider getProvider(Component c) {
|
||||||
|
if (c != null) {
|
||||||
|
DockableComponent dc = getDockableComponent(c);
|
||||||
|
if (dc != null) {
|
||||||
|
ComponentPlaceholder placeholder = dc.getComponentWindowingPlaceholder();
|
||||||
|
if (placeholder != null) {
|
||||||
|
return placeholder.getProvider();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
ComponentPlaceholder getActivePlaceholder(ComponentProvider provider) {
|
ComponentPlaceholder getActivePlaceholder(ComponentProvider provider) {
|
||||||
return placeholderManager.getActivePlaceholder(provider);
|
return placeholderManager.getActivePlaceholder(provider);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.awt.event.KeyListener;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
|
|
||||||
|
import docking.action.MultipleKeyAction;
|
||||||
import docking.actions.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
import ghidra.util.bean.GGlassPane;
|
import ghidra.util.bean.GGlassPane;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
@ -136,7 +137,7 @@ public class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyBindingPrecedence keyBindingPrecedence = action.getKeyBindingPrecedence();
|
KeyBindingPrecedence keyBindingPrecedence = getValidKeyBindingPrecedence(action);
|
||||||
if (keyBindingPrecedence == null) {
|
if (keyBindingPrecedence == null) {
|
||||||
// Odd Code: we use the precedence as a signal to say that, when it is null, there
|
// Odd Code: we use the precedence as a signal to say that, when it is null, there
|
||||||
// are no valid bindings to be processed. We used to have a isValidContext()
|
// are no valid bindings to be processed. We used to have a isValidContext()
|
||||||
|
@ -158,6 +159,15 @@ public class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private KeyBindingPrecedence getValidKeyBindingPrecedence(DockingKeyBindingAction action) {
|
||||||
|
|
||||||
|
if (action instanceof MultipleKeyAction) {
|
||||||
|
MultipleKeyAction multiAction = (MultipleKeyAction) action;
|
||||||
|
return multiAction.geValidKeyBindingPrecedence(focusProvider.getFocusOwner());
|
||||||
|
}
|
||||||
|
return action.getKeyBindingPrecedence();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given key event should be blocked (i.e., not processed by us or Java).
|
* Returns true if the given key event should be blocked (i.e., not processed by us or Java).
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package docking.action;
|
package docking.action;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -23,10 +24,11 @@ import javax.swing.*;
|
||||||
|
|
||||||
import docking.*;
|
import docking.*;
|
||||||
import docking.actions.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
|
import generic.util.WindowUtilities;
|
||||||
import ghidra.util.Swing;
|
import ghidra.util.Swing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action that manages multiple PluginActions mapped to this action's key binding.
|
* Action that manages multiple {@link DockingAction}s mapped to a given key binding
|
||||||
*/
|
*/
|
||||||
public class MultipleKeyAction extends DockingKeyBindingAction {
|
public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||||
private List<ActionData> actions = new ArrayList<>();
|
private List<ActionData> actions = new ArrayList<>();
|
||||||
|
@ -228,7 +230,19 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyBindingPrecedence getKeyBindingPrecedence() {
|
public KeyBindingPrecedence getKeyBindingPrecedence() {
|
||||||
List<ExecutableKeyActionAdapter> validActions = getActionsForCurrentContext(null);
|
return geValidKeyBindingPrecedence(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a special version of {@link #getKeyBindingPrecedence()} that allows the internal
|
||||||
|
* key event processing to specify the source component when determining how precedence should
|
||||||
|
* be established for the actions contained herein.
|
||||||
|
* @param source the component; may be null
|
||||||
|
* @return the precedence; may be null
|
||||||
|
*/
|
||||||
|
public KeyBindingPrecedence geValidKeyBindingPrecedence(Component source) {
|
||||||
|
|
||||||
|
List<ExecutableKeyActionAdapter> validActions = getActionsForCurrentContext(source);
|
||||||
if (validActions.isEmpty()) {
|
if (validActions.isEmpty()) {
|
||||||
return null; // a signal that no actions are valid for the current context
|
return null; // a signal that no actions are valid for the current context
|
||||||
}
|
}
|
||||||
|
@ -245,7 +259,7 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||||
private List<ExecutableKeyActionAdapter> getActionsForCurrentContext(Object eventSource) {
|
private List<ExecutableKeyActionAdapter> getActionsForCurrentContext(Object eventSource) {
|
||||||
|
|
||||||
DockingWindowManager dwm = tool.getWindowManager();
|
DockingWindowManager dwm = tool.getWindowManager();
|
||||||
Window window = dwm.getActiveWindow();
|
Window window = getWindow(dwm, eventSource);
|
||||||
if (window instanceof DockingDialog) {
|
if (window instanceof DockingDialog) {
|
||||||
DockingDialog dockingDialog = (DockingDialog) window;
|
DockingDialog dockingDialog = (DockingDialog) window;
|
||||||
DialogComponentProvider provider = dockingDialog.getDialogComponent();
|
DialogComponentProvider provider = dockingDialog.getDialogComponent();
|
||||||
|
@ -258,13 +272,27 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||||
return validActions;
|
return validActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentProvider localProvider = dwm.getActiveComponentProvider();
|
ComponentProvider localProvider = getProvider(dwm, eventSource);
|
||||||
ActionContext localContext = getLocalContext(localProvider);
|
ActionContext localContext = getLocalContext(localProvider);
|
||||||
localContext.setSourceObject(eventSource);
|
localContext.setSourceObject(eventSource);
|
||||||
List<ExecutableKeyActionAdapter> validActions = getValidContextActions(localContext);
|
List<ExecutableKeyActionAdapter> validActions = getValidContextActions(localContext);
|
||||||
return validActions;
|
return validActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ComponentProvider getProvider(DockingWindowManager dwm, Object eventSource) {
|
||||||
|
if (eventSource instanceof Component) {
|
||||||
|
return dwm.getProvider((Component) eventSource);
|
||||||
|
}
|
||||||
|
return dwm.getActiveComponentProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Window getWindow(DockingWindowManager dwm, Object eventSource) {
|
||||||
|
if (eventSource instanceof Component) {
|
||||||
|
return WindowUtilities.windowForComponent((Component) eventSource);
|
||||||
|
}
|
||||||
|
return dwm.getActiveWindow();
|
||||||
|
}
|
||||||
|
|
||||||
public List<DockingActionIf> getActions() {
|
public List<DockingActionIf> getActions() {
|
||||||
List<DockingActionIf> list = new ArrayList<>(actions.size());
|
List<DockingActionIf> list = new ArrayList<>(actions.size());
|
||||||
for (ActionData actionData : actions) {
|
for (ActionData actionData : actions) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue