modules/controls/src/main/java/com/sun/javafx/scene/control/ContextMenuContent.java
Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
*** 21,34 ****
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
! package com.sun.javafx.scene.control.skin;
- import com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler;
import com.sun.javafx.scene.control.behavior.TwoLevelFocusPopupBehavior;
import javafx.animation.Animation.Status;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.InvalidationListener;
import javafx.beans.WeakInvalidationListener;
--- 21,34 ----
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
! package com.sun.javafx.scene.control;
import com.sun.javafx.scene.control.behavior.TwoLevelFocusPopupBehavior;
+ import com.sun.javafx.scene.control.skin.Utils;
import javafx.animation.Animation.Status;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.InvalidationListener;
import javafx.beans.WeakInvalidationListener;
*** 47,56 ****
--- 47,57 ----
import javafx.scene.AccessibleAttribute;
import javafx.scene.AccessibleRole;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.*;
+ import javafx.scene.control.skin.MenuBarSkin;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
*** 515,525 ****
// menu - this will move focus up to the parent menu
// as required. In the case of the parent being a
// menubar button we special case in the conditional code
// beneath this switch statement. See RT-34429 for more context.
final Node ownerNode = contextMenu.getOwnerNode();
! if (! (ownerNode instanceof MenuBarSkin.MenuBarButton)) {
contextMenu.hide();
ke.consume();
}
break;
case DOWN:
--- 516,526 ----
// menu - this will move focus up to the parent menu
// as required. In the case of the parent being a
// menubar button we special case in the conditional code
// beneath this switch statement. See RT-34429 for more context.
final Node ownerNode = contextMenu.getOwnerNode();
! if (! (ownerNode instanceof MenuBarButton)) {
contextMenu.hide();
ke.consume();
}
break;
case DOWN:
*** 551,566 ****
parent = parent.getParent();
}
if (parent instanceof ContextMenuContent) {
parent.getOnKeyPressed().handle(ke);
}
! } else if (ownerNode instanceof MenuBarSkin.MenuBarButton) {
! // This is a top-level MenuBar Menu, so forward event to MenuBar
! MenuBarSkin mbs = ((MenuBarSkin.MenuBarButton)ownerNode).getMenuBarSkin();
! if (mbs != null && mbs.getKeyEventHandler() != null) {
! mbs.getKeyEventHandler().handle(ke);
! }
}
}
}
});
--- 552,569 ----
parent = parent.getParent();
}
if (parent instanceof ContextMenuContent) {
parent.getOnKeyPressed().handle(ke);
}
! } else if (ownerNode instanceof MenuBarButton) {
! // the following code no longer appears necessary, but
! // leaving in intact for now...
! // // This is a top-level MenuBar Menu, so forward event to MenuBar
! // MenuBarSkin mbs = ((MenuBarButton)ownerNode).getMenuBarSkin();
! // if (mbs != null && mbs.getKeyEventHandler() != null) {
! // mbs.getKeyEventHandler().handle(ke);
! // }
}
}
}
});
*** 759,769 ****
/*
* Get the Y offset from the top of the popup to the menu item whose index
* is given.
*/
! double getMenuYOffset(int menuIndex) {
double offset = 0;
if (itemsContainer.getChildren().size() > menuIndex) {
offset = snappedTopInset();
Node menuitem = itemsContainer.getChildren().get(menuIndex);
offset += menuitem.getLayoutY() + menuitem.prefHeight(-1);
--- 762,772 ----
/*
* Get the Y offset from the top of the popup to the menu item whose index
* is given.
*/
! public double getMenuYOffset(int menuIndex) {
double offset = 0;
if (itemsContainer.getChildren().size() > menuIndex) {
offset = snappedTopInset();
Node menuitem = itemsContainer.getChildren().get(menuIndex);
offset += menuitem.getLayoutY() + menuitem.prefHeight(-1);
*** 983,993 ****
@Override
public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
return getClassCssMetaData();
}
! protected Label getLabelAt(int index) {
return ((MenuItemContainer)itemsContainer.getChildren().get(index)).getLabel();
}
/**
* Custom VBox to enable scrolling of items. Scrolling effect is achieved by
--- 986,996 ----
@Override
public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
return getClassCssMetaData();
}
! public Label getLabelAt(int index) {
return ((MenuItemContainer)itemsContainer.getChildren().get(index)).getLabel();
}
/**
* Custom VBox to enable scrolling of items. Scrolling effect is achieved by
*** 1110,1124 ****
private Node left;
private Node graphic;
private Node label;
private Node right;
! private final MultiplePropertyChangeListenerHandler listener =
! new MultiplePropertyChangeListenerHandler(param -> {
! handlePropertyChanged(param);
! return null;
! });
private EventHandler<MouseEvent> mouseEnteredEventHandler;
private EventHandler<MouseEvent> mouseReleasedEventHandler;
private EventHandler<ActionEvent> actionEventHandler;
--- 1113,1124 ----
private Node left;
private Node graphic;
private Node label;
private Node right;
! private final LambdaMultiplePropertyChangeListenerHandler listener =
! new LambdaMultiplePropertyChangeListenerHandler();
private EventHandler<MouseEvent> mouseEnteredEventHandler;
private EventHandler<MouseEvent> mouseReleasedEventHandler;
private EventHandler<ActionEvent> actionEventHandler;
*** 1145,1179 ****
// listen to changes in the state of certain MenuItem types
ReadOnlyBooleanProperty pseudoProperty;
if (item instanceof Menu) {
pseudoProperty = ((Menu)item).showingProperty();
! listener.registerChangeListener(pseudoProperty, "MENU_SHOWING");
pseudoClassStateChanged(SELECTED_PSEUDOCLASS_STATE, pseudoProperty.get());
setAccessibleRole(AccessibleRole.MENU);
} else if (item instanceof RadioMenuItem) {
pseudoProperty = ((RadioMenuItem)item).selectedProperty();
! listener.registerChangeListener(pseudoProperty, "RADIO_ITEM_SELECTED");
pseudoClassStateChanged(CHECKED_PSEUDOCLASS_STATE, pseudoProperty.get());
setAccessibleRole(AccessibleRole.RADIO_MENU_ITEM);
} else if (item instanceof CheckMenuItem) {
pseudoProperty = ((CheckMenuItem)item).selectedProperty();
! listener.registerChangeListener(pseudoProperty, "CHECK_ITEM_SELECTED");
pseudoClassStateChanged(CHECKED_PSEUDOCLASS_STATE, pseudoProperty.get());
setAccessibleRole(AccessibleRole.CHECK_MENU_ITEM);
} else {
setAccessibleRole(AccessibleRole.MENU_ITEM);
}
pseudoClassStateChanged(DISABLED_PSEUDOCLASS_STATE, item.disableProperty().get());
! listener.registerChangeListener(item.disableProperty(), "DISABLE");
// Add the menu item to properties map of this node. Used by QA for testing
// This allows associating this container with corresponding MenuItem.
getProperties().put(MenuItem.class, item);
! listener.registerChangeListener(item.graphicProperty(), "GRAPHIC");
actionEventHandler = e -> {
if (item instanceof Menu) {
final Menu menu = (Menu) item;
if (openSubmenu == menu && submenu.isShowing()) return;
--- 1145,1186 ----
// listen to changes in the state of certain MenuItem types
ReadOnlyBooleanProperty pseudoProperty;
if (item instanceof Menu) {
pseudoProperty = ((Menu)item).showingProperty();
! listener.registerChangeListener(pseudoProperty,
! e -> pseudoClassStateChanged(SELECTED_PSEUDOCLASS_STATE, ((Menu) item).isShowing()));
pseudoClassStateChanged(SELECTED_PSEUDOCLASS_STATE, pseudoProperty.get());
setAccessibleRole(AccessibleRole.MENU);
} else if (item instanceof RadioMenuItem) {
pseudoProperty = ((RadioMenuItem)item).selectedProperty();
! listener.registerChangeListener(pseudoProperty,
! e -> pseudoClassStateChanged(CHECKED_PSEUDOCLASS_STATE, ((RadioMenuItem) item).isSelected()));
pseudoClassStateChanged(CHECKED_PSEUDOCLASS_STATE, pseudoProperty.get());
setAccessibleRole(AccessibleRole.RADIO_MENU_ITEM);
} else if (item instanceof CheckMenuItem) {
pseudoProperty = ((CheckMenuItem)item).selectedProperty();
! listener.registerChangeListener(pseudoProperty,
! e -> pseudoClassStateChanged(CHECKED_PSEUDOCLASS_STATE, ((CheckMenuItem) item).isSelected()));
pseudoClassStateChanged(CHECKED_PSEUDOCLASS_STATE, pseudoProperty.get());
setAccessibleRole(AccessibleRole.CHECK_MENU_ITEM);
} else {
setAccessibleRole(AccessibleRole.MENU_ITEM);
}
pseudoClassStateChanged(DISABLED_PSEUDOCLASS_STATE, item.disableProperty().get());
! listener.registerChangeListener(item.disableProperty(),
! e -> pseudoClassStateChanged(DISABLED_PSEUDOCLASS_STATE, item.isDisable()));
// Add the menu item to properties map of this node. Used by QA for testing
// This allows associating this container with corresponding MenuItem.
getProperties().put(MenuItem.class, item);
! listener.registerChangeListener(item.graphicProperty(), e -> {
! createChildren();
! computeVisualMetrics();
! });
actionEventHandler = e -> {
if (item instanceof Menu) {
final Menu menu = (Menu) item;
if (openSubmenu == menu && submenu.isShowing()) return;
*** 1209,1242 ****
graphic = null;
label = null;
right = null;
}
- private void handlePropertyChanged(String p) {
- if ("MENU_SHOWING".equals(p)) {
- Menu menu = (Menu) item;
- pseudoClassStateChanged(SELECTED_PSEUDOCLASS_STATE, menu.isShowing());
- } else if ("RADIO_ITEM_SELECTED".equals(p)) {
- RadioMenuItem radioItem = (RadioMenuItem) item;
- pseudoClassStateChanged(CHECKED_PSEUDOCLASS_STATE, radioItem.isSelected());
- } else if ("CHECK_ITEM_SELECTED".equals(p)) {
- CheckMenuItem checkItem = (CheckMenuItem) item;
- pseudoClassStateChanged(CHECKED_PSEUDOCLASS_STATE, checkItem.isSelected());
- } else if ("DISABLE".equals(p)) {
- pseudoClassStateChanged(DISABLED_PSEUDOCLASS_STATE, item.isDisable());
- } else if ("GRAPHIC".equals(p)) {
- createChildren();
- computeVisualMetrics();
- } else if ("ACCELERATOR".equals(p)) {
- updateAccelerator();
- } else if ("FOCUSED".equals(p)) {
- if (isFocused()) {
- currentFocusedIndex = itemsContainer.getChildren().indexOf(MenuItemContainer.this);
- }
- }
- }
-
private void createChildren() {
getChildren().clear();
// draw background region for hover effects. All content (other
// than Nodes from NodeMenuItems) are set to be mouseTransparent, so
--- 1216,1225 ----
*** 1285,1295 ****
listener.unregisterChangeListener(focusedProperty());
// RT-19546 update currentFocusedIndex when MenuItemContainer gets focused.
// e.g this happens when you press the Right key to open a submenu; the first
// menuitem is focused.
! listener.registerChangeListener(focusedProperty(), "FOCUSED");
// --- draw in right column - this depends on whether we are
// a Menu or not. A Menu gets an arrow, whereas other MenuItems
// get the ability to draw an accelerator
if (item instanceof Menu) {
--- 1268,1282 ----
listener.unregisterChangeListener(focusedProperty());
// RT-19546 update currentFocusedIndex when MenuItemContainer gets focused.
// e.g this happens when you press the Right key to open a submenu; the first
// menuitem is focused.
! listener.registerChangeListener(focusedProperty(), e -> {
! if (isFocused()) {
! currentFocusedIndex = itemsContainer.getChildren().indexOf(MenuItemContainer.this);
! }
! });
// --- draw in right column - this depends on whether we are
// a Menu or not. A Menu gets an arrow, whereas other MenuItems
// get the ability to draw an accelerator
if (item instanceof Menu) {
*** 1362,1372 ****
}
addEventHandler(MouseEvent.MOUSE_ENTERED, mouseEnteredEventHandler);
addEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleasedEventHandler);
! listener.registerChangeListener(item.acceleratorProperty(), "ACCELERATOR");
}
}
}
private void updateAccelerator() {
--- 1349,1359 ----
}
addEventHandler(MouseEvent.MOUSE_ENTERED, mouseEnteredEventHandler);
addEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleasedEventHandler);
! listener.registerChangeListener(item.acceleratorProperty(), e -> updateAccelerator());
}
}
}
private void updateAccelerator() {