mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-04 21:30:22 +08:00
Merge remote-tracking branch
'origin/GP-6336-dragonmacher-filters-hide-action--SQUASHED' (#8771)
This commit is contained in:
@@ -63,10 +63,10 @@
|
|||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
<H3><A name="Toggle_Filter"></A>Toggle Filter</H3>
|
<H3><A name="Hide_Filter"></A>Hide Filter</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P>
|
<P>
|
||||||
The <B>Toggle Filter</B> action will hide and show the filter field of the tree or table.
|
The <B>Hide Filter</B> action will hide the filter field of the tree or table.
|
||||||
To use this action you must first assign it a key binding from the tool options.
|
To use this action you must first assign it a key binding from the tool options.
|
||||||
</P>
|
</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|||||||
+19
@@ -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.*;
|
||||||
import docking.actions.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.menu.keys.MenuKeyProcessor;
|
import docking.menu.keys.MenuKeyProcessor;
|
||||||
import ghidra.util.bean.GGlassPane;
|
import ghidra.util.bean.GGlassPane;
|
||||||
@@ -36,6 +37,24 @@ import ghidra.util.exception.AssertException;
|
|||||||
* <p>
|
* <p>
|
||||||
* {@link #install()} must be called in order to install this <code>Singleton</code> into Java's
|
* {@link #install()} must be called in order to install this <code>Singleton</code> into Java's
|
||||||
* key event processing system.
|
* key event processing system.
|
||||||
|
* <P>
|
||||||
|
* Keybindings are processed here to manage how {@link DockingAction}s will get executed. The basic
|
||||||
|
* action processing flow is:
|
||||||
|
* <OL>
|
||||||
|
* <LI>System actions (e.g., F1 for help)</LI>
|
||||||
|
* <LI>Java text components</LI>
|
||||||
|
* <LI>Java widget key listeners</LI>
|
||||||
|
* <LI>Java action map bindings</LI>
|
||||||
|
* <LI>{@link ComponentBasedDockingAction}s</LI>
|
||||||
|
* <LI>{@link ComponentProvider} local actions</LI>
|
||||||
|
* <LI>Tool global actions</LI>
|
||||||
|
* </OL>
|
||||||
|
* When a key event is processed, if that event has a binding at one of these levels, then that
|
||||||
|
* binding will be processed, either by our framework or the default Java processing framework.
|
||||||
|
* Our framework allows for multiple actions to share a key bindings. When that happens, the
|
||||||
|
* {@link MultipleKeyAction} class is responsible for determining the correct priority for the
|
||||||
|
* action to be processed. If there is more than one action that maps to a binding, then the user
|
||||||
|
* will be shown a dialog to choose which action to execute.
|
||||||
*/
|
*/
|
||||||
public class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher {
|
public class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher {
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,11 @@ import generic.util.WindowUtilities;
|
|||||||
import ghidra.util.Swing;
|
import ghidra.util.Swing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action that manages multiple {@link DockingAction}s mapped to a given key binding
|
* Action that manages multiple {@link DockingAction}s mapped to a given key binding.
|
||||||
|
* <P>
|
||||||
|
* Actions are ordered in a way that mimics how the {@link KeyBindingOverrideKeyEventDispatcher}
|
||||||
|
* orders its event processing, lowest level components get precedence over higher-level actions,
|
||||||
|
* such as global actions. See the javadoc of the dispatcher for more info.
|
||||||
*/
|
*/
|
||||||
public class MultipleKeyAction extends DockingKeyBindingAction {
|
public class MultipleKeyAction extends DockingKeyBindingAction {
|
||||||
private List<ActionData> actions = new ArrayList<>();
|
private List<ActionData> actions = new ArrayList<>();
|
||||||
@@ -134,19 +138,24 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
|||||||
|
|
||||||
MultiExecutableAction multiAction = new MultiExecutableAction();
|
MultiExecutableAction multiAction = new MultiExecutableAction();
|
||||||
|
|
||||||
//
|
/*
|
||||||
// 1) Prefer local actions for the active provider
|
Note on action ordering: order matters, as any action found first may prevent actions
|
||||||
//
|
found later from being executed, *even if the lower-level action is not enabled. Having
|
||||||
getLocalContextActions(localContext, multiAction);
|
disabled actions prevent higher-level actions from being executed helps us maintain
|
||||||
if (multiAction.isValid()) {
|
consistent action execution behavior. The downside of this is that if the user assigns
|
||||||
// At this point, we have local docking actions that may or may not be enabled. Exit
|
the same key binding to actions at 2 different levels, the lower priority action will
|
||||||
// so that any component specific actions or global found below will not interfere with
|
never get executed. We currently have no way of supporting both actions in this
|
||||||
// the provider's local actions
|
scenario. It is currently up to the user to avoid this. The one exception we have to
|
||||||
return multiAction;
|
this rule is for ComponentBasedDockingActions. These actions can optionally mark
|
||||||
}
|
themselves as invalid for a given context, which then allows the action processing to
|
||||||
|
go higher up the chain of actions. This is currently done by hard-coding the action
|
||||||
|
behavior, with no means for the user to change it. This solution seemed good enough
|
||||||
|
for now.
|
||||||
|
*/
|
||||||
|
|
||||||
//
|
//
|
||||||
// 2) Check for actions local to the source component (e.g., GTable and GTree)
|
// 1) Check for actions local to the source component (e.g., GTable and GTree). These are
|
||||||
|
// considered lower level actions that can be processed before the component provider.
|
||||||
//
|
//
|
||||||
getLocalComponentActions(localContext, multiAction);
|
getLocalComponentActions(localContext, multiAction);
|
||||||
if (multiAction.isValid()) {
|
if (multiAction.isValid()) {
|
||||||
@@ -156,6 +165,17 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
|||||||
return multiAction;
|
return multiAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 2) Check for local actions for the active provider
|
||||||
|
//
|
||||||
|
getLocalContextActions(localContext, multiAction);
|
||||||
|
if (multiAction.isValid()) {
|
||||||
|
// At this point, we have local docking actions that may or may not be enabled. Exit
|
||||||
|
// so that any component specific actions or global found below will not interfere with
|
||||||
|
// the provider's local actions
|
||||||
|
return multiAction;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// 3) Check for global actions using the current context
|
// 3) Check for global actions using the current context
|
||||||
//
|
//
|
||||||
@@ -332,14 +352,13 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
|||||||
return multiAction;
|
return multiAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
/*
|
||||||
// 1) Check for local actions
|
See the note in createNonDialogExecutableAction().
|
||||||
//
|
*/
|
||||||
// Note: dialog key binding actions are proxy actions that get added to the tool as global
|
|
||||||
// actions. Thus, there are no 'local' actions for the dialog.
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 2) Check for actions local to the source component (e.g., GTable and GTree)
|
// 1) Check for actions local to the source component (e.g., GTable and GTree). These are
|
||||||
|
// considered lower level actions that can be processed before the component provider.
|
||||||
//
|
//
|
||||||
getLocalComponentActions(context, multiAction);
|
getLocalComponentActions(context, multiAction);
|
||||||
if (multiAction.isValid()) {
|
if (multiAction.isValid()) {
|
||||||
@@ -349,6 +368,12 @@ public class MultipleKeyAction extends DockingKeyBindingAction {
|
|||||||
return multiAction;
|
return multiAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 2) Check for dialog local actions
|
||||||
|
//
|
||||||
|
// Note: dialog key binding actions are proxy actions that get added to the tool as global
|
||||||
|
// actions. Thus, there are no 'local' actions for the dialog.
|
||||||
|
|
||||||
//
|
//
|
||||||
// 3) Check for global actions using the current context. As noted above, at the time of
|
// 3) Check for global actions using the current context. As noted above, at the time of
|
||||||
// writing, dialog actions are all registered at the global level.
|
// writing, dialog actions are all registered at the global level.
|
||||||
|
|||||||
@@ -1532,7 +1532,7 @@ public class GTable extends JTable {
|
|||||||
activateFilterAction.setHelpLocation(new HelpLocation("Trees", "Activate_Filter"));
|
activateFilterAction.setHelpLocation(new HelpLocation("Trees", "Activate_Filter"));
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
GTableAction toggleFilterAction = new GTableAction("Table/Tree Toggle Filter", owner) {
|
GTableAction hideFilterAction = new GTableAction("Table/Tree Hide Filter", owner) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabledForContext(ActionContext context) {
|
public boolean isEnabledForContext(ActionContext context) {
|
||||||
@@ -1546,22 +1546,43 @@ public class GTable extends JTable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
|
GTable gTable = (GTable) context.getSourceComponent();
|
||||||
|
GTableFilterPanel<?> filterPanel = gTable.getTableFilterPanel();
|
||||||
|
filterPanel.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidComponentContext(ActionContext context) {
|
||||||
|
/*
|
||||||
|
Subtle Code Alert!
|
||||||
|
We use this method to signal that this action is only to be included in the key
|
||||||
|
binding processing when the filter is showing. This is different than normal
|
||||||
|
docking actions in that normal actions are always valid, just enabled/disabled.
|
||||||
|
Returning false here prevents this action from interfering with key bindings
|
||||||
|
further up the processing chain when the filter is not showing.
|
||||||
|
*/
|
||||||
|
if (!super.isValidComponentContext(context)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
GTable gTable = (GTable) context.getSourceComponent();
|
GTable gTable = (GTable) context.getSourceComponent();
|
||||||
GTableFilterPanel<?> filterPanel = gTable.getTableFilterPanel();
|
GTableFilterPanel<?> filterPanel = gTable.getTableFilterPanel();
|
||||||
filterPanel.toggleVisibility();
|
if (filterPanel == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return filterPanel.isShowing();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
toggleFilterAction.setPopupMenuData(new MenuData(
|
hideFilterAction.setPopupMenuData(new MenuData(
|
||||||
new String[] { "Toggle Filter" },
|
new String[] { "Hide Filter" },
|
||||||
null /*icon*/,
|
null /*icon*/,
|
||||||
actionMenuGroup,
|
actionMenuGroup,
|
||||||
NO_MNEMONIC,
|
NO_MNEMONIC,
|
||||||
Integer.toString(subGroupIndex++)
|
Integer.toString(subGroupIndex++)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
toggleFilterAction.setHelpLocation(new HelpLocation("Trees", "Toggle_Filter"));
|
hideFilterAction.setHelpLocation(new HelpLocation("Trees", "Hide_Filter"));
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
toolActions.addGlobalAction(copyAction);
|
toolActions.addGlobalAction(copyAction);
|
||||||
@@ -1571,7 +1592,7 @@ public class GTable extends JTable {
|
|||||||
toolActions.addGlobalAction(exportColumnsAction);
|
toolActions.addGlobalAction(exportColumnsAction);
|
||||||
toolActions.addGlobalAction(selectAllAction);
|
toolActions.addGlobalAction(selectAllAction);
|
||||||
toolActions.addGlobalAction(activateFilterAction);
|
toolActions.addGlobalAction(activateFilterAction);
|
||||||
toolActions.addGlobalAction(toggleFilterAction);
|
toolActions.addGlobalAction(hideFilterAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|||||||
+11
-1
@@ -402,10 +402,20 @@ public class GTableFilterPanel<ROW_OBJECT> extends JPanel {
|
|||||||
setVisible(true);
|
setVisible(true);
|
||||||
isFilterDisplayed = true;
|
isFilterDisplayed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
requestFocus();
|
requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides this filter if showing.
|
||||||
|
*/
|
||||||
|
public void close() {
|
||||||
|
if (isFilterDisplayed) {
|
||||||
|
setVisible(false);
|
||||||
|
isFilterDisplayed = false;
|
||||||
|
table.requestFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the visibility of this filter panel, make it not visible it if showing, showing it if
|
* Changes the visibility of this filter panel, make it not visible it if showing, showing it if
|
||||||
* not visible.
|
* not visible.
|
||||||
|
|||||||
+11
@@ -198,6 +198,17 @@ public class DefaultGTreeFilterProvider implements GTreeFilterProvider {
|
|||||||
if (isFilterDisplayed) {
|
if (isFilterDisplayed) {
|
||||||
filterPanel.requestFocus();
|
filterPanel.requestFocus();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
gTree.requestFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (isFilterDisplayed) {
|
||||||
|
doToggleVisibility();
|
||||||
|
gTree.requestFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doToggleVisibility() {
|
private void doToggleVisibility() {
|
||||||
|
|||||||
@@ -1978,22 +1978,43 @@ public class GTree extends JPanel implements BusyListener {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
activateFilterAction.setKeyBindingData(new KeyBindingData("Control F"));
|
activateFilterAction.setKeyBindingData(new KeyBindingData("Control F"));
|
||||||
activateFilterAction.setHelpLocation(new HelpLocation("Trees", "Toggle_Filter"));
|
activateFilterAction.setHelpLocation(new HelpLocation("Trees", "Activate_Filter"));
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
GTreeAction toggleFilterAction = new GTreeAction("Table/Tree Toggle Filter", owner) {
|
GTreeAction hideFilterAction = new GTreeAction("Table/Tree Hide Filter", owner) {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
GTree gTree = getTree(context);
|
GTree gTree = getTree(context);
|
||||||
gTree.filterProvider.toggleVisibility();
|
gTree.filterProvider.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidComponentContext(ActionContext context) {
|
||||||
|
/*
|
||||||
|
Subtle Code Alert!
|
||||||
|
We use this method to signal that this action is only to be included in the key
|
||||||
|
binding processing when the filter is showing. This is different than normal
|
||||||
|
docking actions in that normal actions are always valid, just enabled/disabled.
|
||||||
|
Returning false here prevents this action from interfering with key bindings
|
||||||
|
further up the processing chain when the filter is not showing.
|
||||||
|
*/
|
||||||
|
if (!super.isValidComponentContext(context)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GTree gTree = getTree(context);
|
||||||
|
return gTree.filterProvider.isShowing();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//@formatter:on
|
|
||||||
toggleFilterAction.setPopupMenuData(new MenuData(
|
//@formatter:off
|
||||||
new String[] { "Toggle Filter" },
|
hideFilterAction.setPopupMenuData(new MenuData(
|
||||||
|
new String[] { "Hide Filter" },
|
||||||
null,
|
null,
|
||||||
actionMenuGroup, NO_MNEMONIC,
|
actionMenuGroup, NO_MNEMONIC,
|
||||||
Integer.toString(subGroupIndex++)));
|
Integer.toString(subGroupIndex++)));
|
||||||
toggleFilterAction.setHelpLocation(new HelpLocation("Trees", "Toggle_Filter"));
|
hideFilterAction.setHelpLocation(new HelpLocation("Trees", "Hide_Filter"));
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
// these actions are self-explanatory and do need help
|
// these actions are self-explanatory and do need help
|
||||||
collapseAction.markHelpUnnecessary();
|
collapseAction.markHelpUnnecessary();
|
||||||
@@ -2007,7 +2028,7 @@ public class GTree extends JPanel implements BusyListener {
|
|||||||
toolActions.addGlobalAction(expandTreeAction);
|
toolActions.addGlobalAction(expandTreeAction);
|
||||||
toolActions.addGlobalAction(copyFormattedAction);
|
toolActions.addGlobalAction(copyFormattedAction);
|
||||||
toolActions.addGlobalAction(activateFilterAction);
|
toolActions.addGlobalAction(activateFilterAction);
|
||||||
toolActions.addGlobalAction(toggleFilterAction);
|
toolActions.addGlobalAction(hideFilterAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String generateFilterPreferenceKey() {
|
private static String generateFilterPreferenceKey() {
|
||||||
|
|||||||
@@ -126,6 +126,28 @@ public interface GTreeFilterProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides this filter if showing.
|
||||||
|
*/
|
||||||
|
public default void close() {
|
||||||
|
JComponent c = getFilterComponent();
|
||||||
|
if (c.isShowing()) {
|
||||||
|
c.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the filter is showing.
|
||||||
|
* @return true if the filter is showing.
|
||||||
|
* @see #activate()
|
||||||
|
* @see #toggleVisibility()
|
||||||
|
* @see #close()
|
||||||
|
*/
|
||||||
|
public default boolean isShowing() {
|
||||||
|
JComponent c = getFilterComponent();
|
||||||
|
return c.isShowing();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A method for subclasses to do any optional cleanup
|
* A method for subclasses to do any optional cleanup
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user