mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
Merge remote-tracking branch 'origin/GP-5599-dragonmacher-shared-key-binding-fix--SQUASHED'
This commit is contained in:
commit
bf1659f11d
7 changed files with 146 additions and 80 deletions
|
@ -112,7 +112,7 @@ public class LocationReferencesPlugin extends Plugin
|
|||
// only so the user can bind a key binding to it if they wish.
|
||||
new ActionBuilder("Show Xrefs", getName())
|
||||
.description("Show the Xrefs to the code unit containing the cursor")
|
||||
.validContextWhen(context -> context instanceof ListingActionContext)
|
||||
.withContext(ListingActionContext.class)
|
||||
.helpLocation(new HelpLocation("CodeBrowserPlugin", "Show_Xrefs"))
|
||||
.onAction(context -> showXrefs(context))
|
||||
.buildAndInstall(tool);
|
||||
|
|
|
@ -394,7 +394,7 @@ public class ListingCodeComparisonPanel
|
|||
.toolBarIcon(NEXT_DIFF_ICON)
|
||||
.toolBarGroup(DIFF_NAVIGATE_GROUP)
|
||||
.keyBinding("ctrl alt N")
|
||||
.validContextWhen(c -> isValidPanelContext(c))
|
||||
.validWhen(c -> isValidPanelContext(c))
|
||||
.enabledWhen(c -> isShowing() && listingDiff.hasCorrelation())
|
||||
.onAction(c -> nextAreaDiff(true))
|
||||
.build();
|
||||
|
@ -409,7 +409,7 @@ public class ListingCodeComparisonPanel
|
|||
.toolBarIcon(PREVIOUS_DIFF_ICON)
|
||||
.toolBarGroup(DIFF_NAVIGATE_GROUP)
|
||||
.keyBinding("ctrl alt P")
|
||||
.validContextWhen(c -> isValidPanelContext(c))
|
||||
.validWhen(c -> isValidPanelContext(c))
|
||||
.enabledWhen(c -> isShowing() && listingDiff.hasCorrelation())
|
||||
.onAction(c -> nextAreaDiff(false))
|
||||
.build();
|
||||
|
|
|
@ -584,5 +584,10 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
|||
tool.setStatusInfo(message, true);
|
||||
Toolkit.getDefaultToolkit().beep();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + ": " + validActions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -570,6 +570,24 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
|
|||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param predicate the predicate
|
||||
* @return this builder (for chaining)
|
||||
* @deprecated use {@link #validWhen(Predicate)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "11.4")
|
||||
public B validContextWhen(Predicate<C> predicate) {
|
||||
validContextPredicate = Objects.requireNonNull(predicate);
|
||||
|
||||
// automatic enablement management triggered, make sure there is a existing enablement
|
||||
// predicate. The default behavior of manual management interferes with automatic management.
|
||||
if (enabledPredicate == null) {
|
||||
enabledPredicate = ALWAYS_TRUE;
|
||||
}
|
||||
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a predicate for dynamically determining if this action is valid for the current
|
||||
* {@link ActionContext}. See {@link DockingActionIf#isValidContext(ActionContext)}.
|
||||
|
@ -584,7 +602,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends
|
|||
* validity for a given {@link ActionContext}
|
||||
* @return this builder (for chaining)
|
||||
*/
|
||||
public B validContextWhen(Predicate<C> predicate) {
|
||||
public B validWhen(Predicate<C> predicate) {
|
||||
validContextPredicate = Objects.requireNonNull(predicate);
|
||||
|
||||
// automatic enablement management triggered, make sure there is a existing enablement
|
||||
|
|
|
@ -211,14 +211,20 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
|
|||
}
|
||||
|
||||
private void setKeyBindingData(DockingActionIf action, ActionTrigger actionTrigger) {
|
||||
KeyBindingData kbData = null;
|
||||
|
||||
KeyBindingData newKbData = null;
|
||||
if (actionTrigger != null) {
|
||||
kbData = new KeyBindingData(actionTrigger);
|
||||
newKbData = new KeyBindingData(actionTrigger);
|
||||
}
|
||||
|
||||
KeyBindingData currentKbData = action.getKeyBindingData();
|
||||
if (Objects.equals(currentKbData, newKbData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we use the 'unvalidated' call since this value is provided by the user--we assume
|
||||
// that user input is correct; we only validate programmer input
|
||||
action.setUnvalidatedKeyBindingData(kbData);
|
||||
action.setUnvalidatedKeyBindingData(newKbData);
|
||||
}
|
||||
|
||||
private ActionTrigger getActionTriggerFromOptions(ActionTrigger validatedTrigger) {
|
||||
|
@ -232,6 +238,27 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
|
|||
return data.getActionTrigger();
|
||||
}
|
||||
|
||||
/*
|
||||
* This can be called from ToolActions.optionsRebuilt(). In that case, the code only
|
||||
* loops over KeyBindingType.INDIVIDAL actions types (which this class is), but not
|
||||
* KeyBindingType.SHARED actions, which the contained actions are. In the case of options
|
||||
* getting restored, 1) only this action gets updated, and 2), there is no options changed
|
||||
* event fired. Thus, to handle options being restored, we have to override this method to make
|
||||
* sure we update out internal client actions.
|
||||
*/
|
||||
@Override
|
||||
public void setUnvalidatedKeyBindingData(KeyBindingData newKeyBindingData) {
|
||||
|
||||
// update this shared key binding
|
||||
super.setUnvalidatedKeyBindingData(newKeyBindingData);
|
||||
|
||||
// update the client keybindings
|
||||
ActionTrigger newTrigger = getActionTrigger(newKeyBindingData);
|
||||
for (DockingActionIf action : clientActions.keySet()) {
|
||||
setKeyBindingData(action, newTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
||||
Object newValue) {
|
||||
|
@ -240,9 +267,11 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
|
|||
return; // not my binding
|
||||
}
|
||||
|
||||
// update this shared key binding
|
||||
ActionTrigger newTrigger = (ActionTrigger) newValue;
|
||||
setKeyBindingData(this, newTrigger);
|
||||
|
||||
// update the client keybindings
|
||||
for (DockingActionIf action : clientActions.keySet()) {
|
||||
setKeyBindingData(action, newTrigger);
|
||||
}
|
||||
|
@ -275,6 +304,11 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
|
|||
keyBindingOptions.removeOptionsChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Shared Stub Action: " + super.toString();
|
||||
}
|
||||
|
||||
private static void logDifferentKeyBindingsWarnigMessage(DockingActionIf newAction,
|
||||
DockingActionIf existingAction, ActionTrigger existingDefaultTrigger) {
|
||||
|
||||
|
|
|
@ -206,7 +206,7 @@ public class ActionBuilderTest {
|
|||
@Test
|
||||
public void testValidContextWhen() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.validContextWhen(c -> c.getContextObject() == this)
|
||||
.validWhen(c -> c.getContextObject() == this)
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.framework.main.datatree;
|
|||
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.KeyBindingData;
|
||||
import ghidra.framework.main.datatable.ProjectTreeAction;
|
||||
|
||||
|
@ -30,10 +31,18 @@ public class ClearCutAction extends ProjectTreeAction {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(FrontEndProjectTreeContext context) {
|
||||
public boolean isValidContext(ActionContext context) {
|
||||
return DataTreeClipboardUtils.isCuttablePresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(FrontEndProjectTreeContext context) {
|
||||
// If we are valid, then we are enabled (see isValidContext()). Most actions are always
|
||||
// valid, but only sometimes enabled. We use the valid check to remove ourselves completely
|
||||
// from the workflow. But, if we are valid, then we are also enabled.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(FrontEndProjectTreeContext context) {
|
||||
DataTreeClipboardUtils.clearCuttables();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue