mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Merge remote-tracking branch 'origin/GP-1619-dragonmacher-multi-action-events--SQUASHED'
This commit is contained in:
commit
6d741ee445
25 changed files with 197 additions and 627 deletions
|
@ -31,10 +31,6 @@ public class MultiActionBuilder
|
|||
* List of actions for the the MultActionDockingAction
|
||||
*/
|
||||
private List<DockingActionIf> actionList = Collections.emptyList();
|
||||
/**
|
||||
* determines if the the main action is invokable
|
||||
*/
|
||||
private boolean performActionOnButtonClick = true;
|
||||
|
||||
/**
|
||||
* Builder constructor
|
||||
|
@ -61,7 +57,6 @@ public class MultiActionBuilder
|
|||
};
|
||||
decorateAction(action);
|
||||
action.setActions(actionList);
|
||||
action.setPerformActionOnButtonClick(performActionOnButtonClick);
|
||||
return action;
|
||||
}
|
||||
|
||||
|
@ -81,26 +76,8 @@ public class MultiActionBuilder
|
|||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure whether to perform actions on a button click.
|
||||
* See {@link MultiActionDockingAction#setPerformActionOnButtonClick(boolean)}
|
||||
*
|
||||
* @param b true if the main action is invokable
|
||||
* @return this MultiActionDockingActionBuilder (for chaining)
|
||||
*/
|
||||
public MultiActionBuilder performActionOnButtonClick(boolean b) {
|
||||
this.performActionOnButtonClick = b;
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validate() {
|
||||
// if the MultiAction performs an action when the main button is presseed, make sure that
|
||||
// an action callback has been defined in before building (which is what super validate
|
||||
// does). Otherwise, don't force the client to define an action callback if it won't be used.
|
||||
if (performActionOnButtonClick) {
|
||||
super.validate();
|
||||
}
|
||||
if (actionList == null) {
|
||||
throw new IllegalStateException("No ActionList has been set");
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@ import java.util.function.BiConsumer;
|
|||
import javax.swing.Icon;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.menu.*;
|
||||
import docking.menu.ActionState;
|
||||
import docking.menu.MultiStateDockingAction;
|
||||
import docking.widgets.EventTrigger;
|
||||
|
||||
/**
|
||||
|
@ -35,7 +36,6 @@ public class MultiStateActionBuilder<T> extends
|
|||
|
||||
private BiConsumer<ActionState<T>, EventTrigger> actionStateChangedCallback;
|
||||
private boolean useCheckboxForIcons;
|
||||
private boolean performActionOnButtonClick = false;
|
||||
|
||||
private List<ActionState<T>> states = new ArrayList<>();
|
||||
|
||||
|
@ -68,18 +68,6 @@ public class MultiStateActionBuilder<T> extends
|
|||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure whether to perform actions on a button click.
|
||||
* See {@link MultiActionDockingAction#setPerformActionOnButtonClick(boolean)}
|
||||
*
|
||||
* @param b true if the main action is invokable
|
||||
* @return this MultiActionDockingActionBuilder (for chaining)
|
||||
*/
|
||||
public MultiStateActionBuilder<T> performActionOnButtonClick(boolean b) {
|
||||
this.performActionOnButtonClick = b;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default icons for actions shown in popup menu of the multi-state action. By
|
||||
* default, the popup menu items will use the icons as provided by the {@link ActionState}.
|
||||
|
@ -103,7 +91,7 @@ public class MultiStateActionBuilder<T> extends
|
|||
* @return this MultiActionDockingActionBuilder (for chaining)
|
||||
*/
|
||||
public MultiStateActionBuilder<T> addState(String displayName, Icon icon, T userData) {
|
||||
states.add(new ActionState<T>(displayName, icon, userData));
|
||||
states.add(new ActionState<>(displayName, icon, userData));
|
||||
return self();
|
||||
}
|
||||
|
||||
|
@ -133,7 +121,7 @@ public class MultiStateActionBuilder<T> extends
|
|||
public MultiStateDockingAction<T> build() {
|
||||
validate();
|
||||
MultiStateDockingAction<T> action =
|
||||
new MultiStateDockingAction<>(name, owner, isToolbarAction()) {
|
||||
new MultiStateDockingAction<>(name, owner) {
|
||||
|
||||
@Override
|
||||
public void actionStateChanged(ActionState<T> newActionState,
|
||||
|
@ -142,10 +130,13 @@ public class MultiStateActionBuilder<T> extends
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void doActionPerformed(ActionContext context) {
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (actionCallback != null) {
|
||||
actionCallback.accept(context);
|
||||
}
|
||||
else {
|
||||
super.actionPerformed(context);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -154,16 +145,12 @@ public class MultiStateActionBuilder<T> extends
|
|||
}
|
||||
|
||||
decorateAction(action);
|
||||
action.setPerformActionOnPrimaryButtonClick(performActionOnButtonClick);
|
||||
action.setUseCheckboxForIcons(useCheckboxForIcons);
|
||||
return action;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validate() {
|
||||
if (performActionOnButtonClick) {
|
||||
super.validate(); // require an action callback has been defined
|
||||
}
|
||||
if (actionStateChangedCallback == null) {
|
||||
throw new IllegalStateException(
|
||||
"Can't build a MultiStateDockingAction without an action state changed callback");
|
||||
|
|
|
@ -22,13 +22,14 @@ import javax.swing.JButton;
|
|||
|
||||
import docking.ActionContext;
|
||||
import docking.action.*;
|
||||
import ghidra.util.Swing;
|
||||
|
||||
/**
|
||||
* A class that supports multiple sub-actions, as well as a primary action. This is useful for
|
||||
* actions that perform navigation operations.
|
||||
* <p>
|
||||
* Clients may add actions to this class with the intention that they will be accessible
|
||||
* to the user via a GUI; for example, from a popup menu.
|
||||
* Clients may add actions to this class with the intention that they will be accessible to the
|
||||
* user via a GUI; for example, from a popup menu.
|
||||
* <p>
|
||||
* Actions added must have menu bar data set.
|
||||
*
|
||||
|
@ -36,18 +37,20 @@ import docking.action.*;
|
|||
* the user to execute.
|
||||
*
|
||||
* <p>
|
||||
* If the user executes this action directly, then
|
||||
* {@link #actionPerformed(ActionContext)} will be called. Otherwise, the
|
||||
* {@link DockingAction#actionPerformed(ActionContext)} method of the sub-action
|
||||
* that was executed will be called.
|
||||
* If the user executes this action directly (by clicking the non-popup section of the button),
|
||||
* then {@link #actionPerformed(ActionContext)} will be called. By default, when the button is
|
||||
* clicked, the popup menu is shown. To change this behavior, override
|
||||
* {@link #actionPerformed(ActionContext)}. If an item of the popup menu is clicked, then the
|
||||
* {@link DockingAction#actionPerformed(ActionContext)} method of the sub-action that was executed
|
||||
* will be called.
|
||||
*
|
||||
* @see MultiStateDockingAction
|
||||
*/
|
||||
public abstract class MultiActionDockingAction extends DockingAction
|
||||
public class MultiActionDockingAction extends DockingAction
|
||||
implements MultiActionDockingActionIf {
|
||||
|
||||
private List<DockingActionIf> actionList = Collections.emptyList();
|
||||
private boolean performActionOnButtonClick = true;
|
||||
private MultipleActionDockingToolbarButton multipleButton;
|
||||
|
||||
public MultiActionDockingAction(String name, String owner) {
|
||||
super(name, owner);
|
||||
|
@ -67,24 +70,23 @@ public abstract class MultiActionDockingAction extends DockingAction
|
|||
return actionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when the user clicks the button <B>when this action is used as part of
|
||||
* the default {@link DockingAction} framework.</B>
|
||||
*
|
||||
* This is the callback to be overridden when the child wishes to respond to user button
|
||||
* presses that are on the button and not the drop-down. The default behavior is to show the
|
||||
* popup menu when the button is clicked.
|
||||
*/
|
||||
@Override
|
||||
public JButton doCreateButton() {
|
||||
MultipleActionDockingToolbarButton button = new MultipleActionDockingToolbarButton(this);
|
||||
button.setPerformActionOnButtonClick(performActionOnButtonClick);
|
||||
return button;
|
||||
public void actionPerformed(ActionContext context) {
|
||||
Swing.runLater(() -> multipleButton.showPopup());
|
||||
}
|
||||
|
||||
/**
|
||||
* By default a click on this action will trigger <code>actionPerformed()</code> to be called.
|
||||
* You can call this method to disable that feature. When called with <code>false</code>, this
|
||||
* method will effectively let the user click anywhere on the button or its drop-down arrow
|
||||
* to show the popup menu. During normal operation, the user can only show the popup by
|
||||
* clicking the drop-down arrow.
|
||||
* @param performActionOnButtonClick if true, pressing the button calls actionPerformed;
|
||||
* otherwise it pops up the menu.
|
||||
*/
|
||||
public void setPerformActionOnButtonClick(boolean performActionOnButtonClick) {
|
||||
this.performActionOnButtonClick = performActionOnButtonClick;
|
||||
@Override
|
||||
public JButton doCreateButton() {
|
||||
multipleButton = new MultipleActionDockingToolbarButton(this);
|
||||
return multipleButton;
|
||||
}
|
||||
|
||||
public static DockingActionIf createSeparator() {
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package docking.menu;
|
||||
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -23,25 +22,24 @@ import javax.swing.Icon;
|
|||
import javax.swing.JButton;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.action.*;
|
||||
import docking.widgets.EventTrigger;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import resources.icons.EmptyIcon;
|
||||
|
||||
/**
|
||||
* An action that can be in one of multiple states. The button of this action has a
|
||||
* drop-down icon that allows users to change the state of the button. Also, by default, as
|
||||
* the user presses the button, it will execute the action corresponding to the current
|
||||
* state.
|
||||
*
|
||||
* <p>Warning: if you use this action in a toolbar, then be sure to call the
|
||||
* {@link #MultiStateDockingAction(String, String, boolean) correct constructor}. If you call
|
||||
* another constructor, or pass false for this boolean above, your
|
||||
* {@link #doActionPerformed(ActionContext)} method will get called twice.
|
||||
* drop-down icon that allows users to change the state of the button. As the user changes the
|
||||
* state of this action, {@link #actionStateChanged(ActionState, EventTrigger)} will be called.
|
||||
* Clients may also use the button of this action to respond to button presses by overriding
|
||||
* {@link #actionPerformed(ActionContext)}.
|
||||
*
|
||||
* <p>This action is intended primarily for use as toolbar actions. Alternatively, some clients
|
||||
* use this action to add a button to custom widgets. In the custom usage case, clients should use
|
||||
* {@link NonToolbarMultiStateAction}.
|
||||
*
|
||||
* @param <T> the type of the user data
|
||||
* @see MultiActionDockingAction
|
||||
*/
|
||||
|
@ -54,16 +52,9 @@ public abstract class MultiStateDockingAction<T> extends DockingAction {
|
|||
private MultiActionDockingActionIf multiActionGenerator;
|
||||
private MultipleActionDockingToolbarButton multipleButton;
|
||||
|
||||
private boolean performActionOnPrimaryButtonClick = true;
|
||||
private Icon defaultIcon;
|
||||
private boolean useCheckboxForIcons;
|
||||
|
||||
// A listener that will get called when the button (not the popup) is clicked. Toolbar
|
||||
// actions do not use this listener.
|
||||
private ActionListener clickListener = e -> {
|
||||
// stub for toolbar actions
|
||||
};
|
||||
|
||||
/**
|
||||
* Call this constructor with this action will not be added to a toolbar
|
||||
*
|
||||
|
@ -72,7 +63,11 @@ public abstract class MultiStateDockingAction<T> extends DockingAction {
|
|||
* @see #MultiStateDockingAction(String, String, boolean)
|
||||
*/
|
||||
public MultiStateDockingAction(String name, String owner) {
|
||||
this(name, owner, false);
|
||||
super(name, owner);
|
||||
multiActionGenerator = context -> getStateActions();
|
||||
|
||||
// set this here so we don't have to check for null elsewhere
|
||||
super.setToolBarData(new ToolBarData(null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,50 +77,31 @@ public abstract class MultiStateDockingAction<T> extends DockingAction {
|
|||
* @param name the action name
|
||||
* @param owner the owner
|
||||
* @param isToolbarAction true if this action is a toolbar action
|
||||
* @deprecated use {@link #MultiStateDockingAction(String, String)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "10.2")
|
||||
protected MultiStateDockingAction(String name, String owner, boolean isToolbarAction) {
|
||||
super(name, owner);
|
||||
multiActionGenerator = context -> getStateActions();
|
||||
|
||||
// set this here so we don't have to check for null elsewhere
|
||||
super.setToolBarData(new ToolBarData(null));
|
||||
|
||||
if (!isToolbarAction) {
|
||||
// we need this listener to perform the action when the user click the button;
|
||||
// toolbar actions have their own listener
|
||||
clickListener = e -> {
|
||||
actionPerformed(getActionContext());
|
||||
};
|
||||
}
|
||||
this(name, owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called as the user changes the selected button state
|
||||
* @param newActionState the newly selected state
|
||||
* @param trigger the source of the event
|
||||
*/
|
||||
public abstract void actionStateChanged(ActionState<T> newActionState, EventTrigger trigger);
|
||||
|
||||
/**
|
||||
* If <code>doPerformAction</code> is <code>true</code>, then, when the user clicks the
|
||||
* button and not the drop-down arrow, the {@link #doActionPerformed(ActionContext)}
|
||||
* method will be called. If <code>doPerformAction</code> is <code>false</code>, then, when
|
||||
* the user clicks the button and not the drop-down arrow, the popup menu will be shown, just
|
||||
* as if the user had clicked the drop-down arrow.
|
||||
* <p>
|
||||
* Also, if the parameter is true, then the button will behave like a button in terms of
|
||||
* mouse feedback. If false, then the button will behave more like a label.
|
||||
*
|
||||
* @param doPerformAction true to call {@link #doActionPerformed(ActionContext)} when the
|
||||
* user presses the button for this action (not the drop-down menu; see above)
|
||||
* This method is called when the user clicks the button <B>when this action is used as part of
|
||||
* the default {@link DockingAction} framework.</B>
|
||||
*
|
||||
* This is the callback to be overridden when the child wishes to respond to user button
|
||||
* presses that are on the button and not the drop-down. The default behavior is to show the
|
||||
* popup menu when the button is clicked.
|
||||
*/
|
||||
public void setPerformActionOnPrimaryButtonClick(boolean doPerformAction) {
|
||||
performActionOnPrimaryButtonClick = doPerformAction;
|
||||
if (multipleButton == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
multipleButton.setPerformActionOnButtonClick(performActionOnPrimaryButtonClick);
|
||||
|
||||
multipleButton.removeActionListener(clickListener);
|
||||
if (performActionOnPrimaryButtonClick) {
|
||||
multipleButton.addActionListener(clickListener);
|
||||
}
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
Swing.runLater(() -> multipleButton.showPopup());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,38 +127,6 @@ public abstract class MultiStateDockingAction<T> extends DockingAction {
|
|||
this.defaultIcon = icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void actionPerformed(ActionContext context) {
|
||||
if (!performActionOnPrimaryButtonClick) {
|
||||
SystemUtilities.runSwingLater(() -> multipleButton.showPopup(null));
|
||||
return;
|
||||
}
|
||||
|
||||
doActionPerformed(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the callback to be overridden when the child wishes to respond to user button
|
||||
* presses that are on the button and not the drop-down. This will only be called if
|
||||
* {@link #performActionOnPrimaryButtonClick} is true.
|
||||
*
|
||||
* @param context the action context
|
||||
*/
|
||||
protected void doActionPerformed(ActionContext context) {
|
||||
// override me to do work
|
||||
}
|
||||
|
||||
private ActionContext getActionContext() {
|
||||
DockingWindowManager manager = DockingWindowManager.getActiveInstance();
|
||||
|
||||
ActionContext context = manager.getActionContext(this);
|
||||
|
||||
if (context == null) {
|
||||
context = new ActionContext();
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
protected List<DockingActionIf> getStateActions() {
|
||||
ActionState<T> selectedState = actionStates.get(currentStateIndex);
|
||||
List<DockingActionIf> actions = new ArrayList<>(actionStates.size());
|
||||
|
@ -295,15 +239,6 @@ public abstract class MultiStateDockingAction<T> extends DockingAction {
|
|||
@Override
|
||||
public JButton doCreateButton() {
|
||||
multipleButton = new MultipleActionDockingToolbarButton(multiActionGenerator);
|
||||
multipleButton.setPerformActionOnButtonClick(performActionOnPrimaryButtonClick);
|
||||
|
||||
if (performActionOnPrimaryButtonClick) {
|
||||
multipleButton.addActionListener(clickListener);
|
||||
}
|
||||
else {
|
||||
multipleButton.removeActionListener(clickListener);
|
||||
}
|
||||
|
||||
if (currentStateIndex >= 0) {
|
||||
ActionState<T> actionState = actionStates.get(currentStateIndex);
|
||||
setButtonState(actionState);
|
||||
|
@ -350,6 +285,10 @@ public abstract class MultiStateDockingAction<T> extends DockingAction {
|
|||
return getName() + ": " + getCurrentState().getName();
|
||||
}
|
||||
|
||||
protected void showPopup() {
|
||||
multipleButton.showPopup();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
|
|
|
@ -43,11 +43,11 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
private static int ARROW_PADDING = 4;
|
||||
|
||||
private PopupMouseListener popupListener;
|
||||
private JPopupMenu popupMenu;
|
||||
private Shape popupContext;
|
||||
private long popupLastClosedTime;
|
||||
|
||||
private final MultiActionDockingActionIf multipleAction;
|
||||
private boolean iconBorderEnabled = true;
|
||||
private boolean entireButtonShowsPopupMenu;
|
||||
|
||||
public MultipleActionDockingToolbarButton(MultiActionDockingActionIf action) {
|
||||
multipleAction = action;
|
||||
|
@ -74,21 +74,6 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
return disabledIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default a click on this button will trigger <code>actionPerformed()</code> to be called.
|
||||
* You can call this method to disable that feature. When called with <code>false</code>, this
|
||||
* method will effectively let the user click anywhere on the button or its drop-down arrow
|
||||
* to show the popup menu. During normal operation, the user can only show the popup by
|
||||
* clicking the drop-down arrow.
|
||||
*
|
||||
* @param performActionOnButtonClick true to perform the action when the button is clicked
|
||||
*/
|
||||
public void setPerformActionOnButtonClick(boolean performActionOnButtonClick) {
|
||||
entireButtonShowsPopupMenu = !performActionOnButtonClick;
|
||||
iconBorderEnabled = performActionOnButtonClick;
|
||||
popupContext = createPopupContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBorder(Graphics g) {
|
||||
Border buttonBorder = getBorder();
|
||||
|
@ -98,10 +83,7 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
|
||||
Insets borderInsets = buttonBorder.getBorderInsets(this);
|
||||
int leftIconWidth = primaryIcon.getIconWidth() + (borderInsets.left + borderInsets.right);
|
||||
if (iconBorderEnabled) {
|
||||
buttonBorder.paintBorder(this, g, 0, 0, leftIconWidth, getHeight());
|
||||
}
|
||||
|
||||
buttonBorder.paintBorder(this, g, 0, 0, leftIconWidth, getHeight());
|
||||
int rightButtonWidth =
|
||||
ARROW_WIDTH + ARROW_PADDING + (borderInsets.left + borderInsets.right);
|
||||
buttonBorder.paintBorder(this, g, leftIconWidth, 0, rightButtonWidth, getHeight());
|
||||
|
@ -132,10 +114,6 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
}
|
||||
|
||||
private Shape createPopupContext() {
|
||||
if (entireButtonShowsPopupMenu) {
|
||||
return new Rectangle(0, 0, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
Border buttonBorder = getBorder();
|
||||
Insets borderInsets =
|
||||
buttonBorder == null ? new Insets(0, 0, 0, 0) : buttonBorder.getBorderInsets(this);
|
||||
|
@ -163,10 +141,31 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
|
||||
/**
|
||||
* Show a popup containing all the actions below the button
|
||||
* @param listener for the created popup menu
|
||||
* @return the popup menu that was shown
|
||||
*/
|
||||
JPopupMenu showPopup(PopupMenuListener listener) {
|
||||
JPopupMenu showPopup() {
|
||||
|
||||
if (popupIsShowing()) {
|
||||
popupMenu.setVisible(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
// showPopup() will handled 2 cases when this action's button is clicked:
|
||||
// 1) show a popup if it was not showing
|
||||
// 2) hide the popup if it was showing
|
||||
//
|
||||
// Case 2 requires timestamps. Java will close the popup as the button is clicked. This
|
||||
// means that when we are told to show the popup as the result of a click, the popup will
|
||||
// never be showing. To work around this, we track the elapsed time since last click. If
|
||||
// the period is too short, then we assume Java closed the popup when the click happened
|
||||
//and thus we should ignore it.
|
||||
//
|
||||
long elapsedTime = System.currentTimeMillis() - popupLastClosedTime;
|
||||
if (elapsedTime < 500) { // somewhat arbitrary time window
|
||||
return null;
|
||||
}
|
||||
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
List<DockingActionIf> actionList = multipleAction.getActionList(getActionContext());
|
||||
for (DockingActionIf dockingAction : actionList) {
|
||||
|
@ -202,9 +201,7 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
menu.add(item);
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
menu.addPopupMenuListener(listener);
|
||||
}
|
||||
menu.addPopupMenuListener(popupListener);
|
||||
Point p = getPopupPoint();
|
||||
menu.show(this, p.x, p.y);
|
||||
return menu;
|
||||
|
@ -215,6 +212,10 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
return new Point(0, bounds.y + bounds.height);
|
||||
}
|
||||
|
||||
private boolean popupIsShowing() {
|
||||
return (popupMenu != null) && popupMenu.isVisible();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
|
@ -285,8 +286,6 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
|
||||
private class PopupMouseListener extends MouseAdapter implements PopupMenuListener {
|
||||
private final MouseListener[] parentListeners;
|
||||
private JPopupMenu popupMenu;
|
||||
private long actionID = 0; // used to determine when the popup was closed by clicking the button
|
||||
|
||||
public PopupMouseListener(MouseListener[] parentListeners) {
|
||||
this.parentListeners = parentListeners;
|
||||
|
@ -294,16 +293,6 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
// close the popup if the user clicks the button while the popup is visible
|
||||
if (popupIsShowing() && e.getClickCount() == 1) { // ignore double-click when the menu is up
|
||||
popupMenu.setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
long eventTime = System.currentTimeMillis();
|
||||
if (actionID == eventTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
Point clickPoint = e.getPoint();
|
||||
if (isEnabled() && popupContext.contains(clickPoint)) {
|
||||
|
@ -311,8 +300,8 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
// Unusual Code Alert: we need to put this call in an invoke later, since Java
|
||||
// will update the focused window after we click. We need the focus to be
|
||||
// correct before we show, since our menu is built with actions based upon the
|
||||
// focused dude.
|
||||
Swing.runLater(() -> popupMenu = showPopup(PopupMouseListener.this));
|
||||
// focused component.
|
||||
Swing.runLater(() -> popupMenu = showPopup());
|
||||
|
||||
e.consume();
|
||||
model.setPressed(false);
|
||||
|
@ -372,10 +361,6 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean popupIsShowing() {
|
||||
return (popupMenu != null) && popupMenu.isVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popupMenuCanceled(PopupMenuEvent e) {
|
||||
// no-op
|
||||
|
@ -383,7 +368,7 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
|
||||
@Override
|
||||
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
|
||||
actionID = System.currentTimeMillis(); // hacktastic!
|
||||
popupLastClosedTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,7 +15,13 @@
|
|||
*/
|
||||
package docking.menu;
|
||||
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JButton;
|
||||
|
||||
import docking.action.DockingAction;
|
||||
import docking.widgets.EventTrigger;
|
||||
import ghidra.util.Swing;
|
||||
|
||||
/**
|
||||
* A class for clients that wish to create a button that has multiple states, controlled by a
|
||||
|
@ -27,12 +33,39 @@ import docking.widgets.EventTrigger;
|
|||
* {@link #actionStateChanged(ActionState, EventTrigger)} callback. Call
|
||||
* {@link #createButton()} and add the return value to your UI.
|
||||
*
|
||||
* @param <T>
|
||||
* @param <T> the type
|
||||
* @see MultiStateDockingAction
|
||||
*/
|
||||
public abstract class NonToolbarMultiStateAction<T> extends MultiStateDockingAction<T> {
|
||||
|
||||
// A listener that will get called when the button (not the popup) is clicked. Toolbar
|
||||
// actions do not need this functionality, since the toolbar API will call actionPerfomred().
|
||||
private ActionListener clickListener = e -> {
|
||||
actionPerformed();
|
||||
};
|
||||
|
||||
public NonToolbarMultiStateAction(String name, String owner) {
|
||||
super(name, owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JButton doCreateButton() {
|
||||
JButton button = super.doCreateButton();
|
||||
button.addActionListener(clickListener);
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when the user clicks the button <B>when this action is used as a
|
||||
* custom button provider and not installed into the default {@link DockingAction} framework.
|
||||
* </B>
|
||||
*
|
||||
* This is the callback to be overridden when the child wishes to respond to user button
|
||||
* presses that are on the button and not the drop-down. The default behavior is to show the
|
||||
* popup menu when the button is clicked.
|
||||
*/
|
||||
protected void actionPerformed() {
|
||||
Swing.runLater(() -> showPopup());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ import javax.swing.table.TableModel;
|
|||
|
||||
import org.jdom.Element;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.help.HelpService;
|
||||
import docking.menu.*;
|
||||
|
@ -413,12 +412,12 @@ public class GTableFilterPanel<ROW_OBJECT> extends JPanel {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void doActionPerformed(ActionContext context) {
|
||||
protected void actionPerformed() {
|
||||
showFilterDialog(tableModel);
|
||||
}
|
||||
|
||||
};
|
||||
columnFilterAction.setPerformActionOnPrimaryButtonClick(true);
|
||||
|
||||
HelpLocation helpLocation = new HelpLocation("Trees", "Column_Filters");
|
||||
columnFilterAction.setHelpLocation(helpLocation);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue