modules/controls/src/main/java/javafx/scene/control/skin/MenuBarSkin.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.css.converters.EnumConverter; ! import com.sun.javafx.css.converters.SizeConverter; import com.sun.javafx.scene.traversal.ParentTraversalEngine; import javafx.beans.InvalidationListener; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyProperty; --- 21,36 ---- * 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 javafx.scene.control.skin; ! import javafx.css.converter.EnumConverter; ! import javafx.css.converter.SizeConverter; ! import com.sun.javafx.scene.control.MenuBarButton; ! import com.sun.javafx.scene.control.skin.Utils; import com.sun.javafx.scene.traversal.ParentTraversalEngine; import javafx.beans.InvalidationListener; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyProperty;
*** 44,60 **** import javafx.css.StyleableObjectProperty; import javafx.css.StyleableProperty; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.event.WeakEventHandler; - import javafx.geometry.Bounds; import javafx.geometry.NodeOrientation; import javafx.geometry.Pos; import javafx.scene.AccessibleAttribute; - import javafx.scene.AccessibleRole; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.CustomMenuItem; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; import javafx.scene.control.MenuButton; import javafx.scene.control.MenuItem; --- 46,61 ---- import javafx.css.StyleableObjectProperty; import javafx.css.StyleableProperty; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.event.WeakEventHandler; import javafx.geometry.NodeOrientation; import javafx.geometry.Pos; import javafx.scene.AccessibleAttribute; import javafx.scene.Node; import javafx.scene.Scene; + import javafx.scene.control.Control; import javafx.scene.control.CustomMenuItem; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; import javafx.scene.control.MenuButton; import javafx.scene.control.MenuItem;
*** 76,210 **** import java.util.WeakHashMap; import com.sun.javafx.menu.MenuBase; import com.sun.javafx.scene.SceneHelper; import com.sun.javafx.scene.control.GlobalMenuAdapter; - import com.sun.javafx.scene.control.behavior.BehaviorBase; - import com.sun.javafx.scene.traversal.TraverseListener; import com.sun.javafx.stage.StageHelper; import com.sun.javafx.tk.Toolkit; import javafx.stage.Window; - /** ! * The skin for the MenuBar. In essence it is a simple toolbar. For the time ! * being there is no overflow behavior and we just hide nodes which fall ! * outside the bounds. */ ! public class MenuBarSkin extends BehaviorSkinBase<MenuBar, BehaviorBase<MenuBar>> implements TraverseListener { private final HBox container; private Menu openMenu; private MenuBarButton openMenuButton; private int focusedMenuIndex = -1; private static WeakHashMap<Stage, Reference<MenuBarSkin>> systemMenuMap; ! private static List<MenuBase> wrappedDefaultMenus = new ArrayList<MenuBase>(); private static Stage currentMenuBarStage; private List<MenuBase> wrappedMenus; ! public static void setDefaultSystemMenuBar(final MenuBar menuBar) { ! if (Toolkit.getToolkit().getSystemMenu().isSupported()) { ! wrappedDefaultMenus.clear(); ! for (Menu menu : menuBar.getMenus()) { ! wrappedDefaultMenus.add(GlobalMenuAdapter.adapt(menu)); ! } ! menuBar.getMenus().addListener((ListChangeListener<Menu>) c -> { ! wrappedDefaultMenus.clear(); ! for (Menu menu : menuBar.getMenus()) { ! wrappedDefaultMenus.add(GlobalMenuAdapter.adapt(menu)); ! } ! }); ! } ! } ! private static MenuBarSkin getMenuBarSkin(Stage stage) { ! if (systemMenuMap == null) return null; ! Reference<MenuBarSkin> skinRef = systemMenuMap.get(stage); ! return skinRef == null ? null : skinRef.get(); ! } - private static void setSystemMenu(Stage stage) { - if (stage != null && stage.isFocused()) { - while (stage != null && stage.getOwner() instanceof Stage) { - MenuBarSkin skin = getMenuBarSkin(stage); - if (skin != null && skin.wrappedMenus != null) { - break; - } else { - // This is a secondary stage (dialog) that doesn't - // have own menu bar. - // - // Continue looking for a menu bar in the parent stage. - stage = (Stage)stage.getOwner(); - } - } - } else { - stage = null; - } ! if (stage != currentMenuBarStage) { ! List<MenuBase> menuList = null; ! if (stage != null) { ! MenuBarSkin skin = getMenuBarSkin(stage); ! if (skin != null) { ! menuList = skin.wrappedMenus; ! } } ! if (menuList == null) { ! menuList = wrappedDefaultMenus; } ! Toolkit.getToolkit().getSystemMenu().setMenus(menuList); ! currentMenuBarStage = stage; } } - - private static void initSystemMenuBar() { - systemMenuMap = new WeakHashMap<>(); - - final InvalidationListener focusedStageListener = ov -> { - setSystemMenu((Stage)((ReadOnlyProperty<?>)ov).getBean()); }; ! final ObservableList<Stage> stages = StageHelper.getStages(); ! for (Stage stage : stages) { ! stage.focusedProperty().addListener(focusedStageListener); } ! stages.addListener((ListChangeListener<Stage>) c -> { ! while (c.next()) { ! for (Stage stage : c.getRemoved()) { ! stage.focusedProperty().removeListener(focusedStageListener); } - for (Stage stage : c.getAddedSubList()) { - stage.focusedProperty().addListener(focusedStageListener); - setSystemMenu(stage); } } - }); } - private WeakEventHandler<KeyEvent> weakSceneKeyEventHandler; - private WeakEventHandler<MouseEvent> weakSceneMouseEventHandler; - private WeakChangeListener<Boolean> weakWindowFocusListener; - private WeakChangeListener<Window> weakWindowSceneListener; - private EventHandler<KeyEvent> keyEventHandler; - private EventHandler<MouseEvent> mouseEventHandler; - private ChangeListener<Boolean> menuBarFocusedPropertyListener; - private ChangeListener<Scene> sceneChangeListener; - EventHandler<KeyEvent> getKeyEventHandler() { - return keyEventHandler; - } /*************************************************************************** * * * Constructors * * * **************************************************************************/ public MenuBarSkin(final MenuBar control) { ! super(control, new BehaviorBase<>(control, Collections.emptyList())); container = new HBox(); container.getStyleClass().add("container"); getChildren().add(container); --- 77,200 ---- import java.util.WeakHashMap; import com.sun.javafx.menu.MenuBase; import com.sun.javafx.scene.SceneHelper; import com.sun.javafx.scene.control.GlobalMenuAdapter; import com.sun.javafx.stage.StageHelper; import com.sun.javafx.tk.Toolkit; import javafx.stage.Window; /** ! * Default skin implementation for the {@link MenuBar} control. In essence it is ! * a simple toolbar. For the time being there is no overflow behavior and we just ! * hide nodes which fall outside the bounds. ! * ! * @see MenuBar ! * @since 9 */ ! public class MenuBarSkin extends SkinBase<MenuBar> { ! ! /*************************************************************************** ! * * ! * Private fields * ! * * ! **************************************************************************/ private final HBox container; private Menu openMenu; private MenuBarButton openMenuButton; private int focusedMenuIndex = -1; private static WeakHashMap<Stage, Reference<MenuBarSkin>> systemMenuMap; ! private static List<MenuBase> wrappedDefaultMenus = new ArrayList<>(); private static Stage currentMenuBarStage; private List<MenuBase> wrappedMenus; ! private WeakEventHandler<KeyEvent> weakSceneKeyEventHandler; ! private WeakEventHandler<MouseEvent> weakSceneMouseEventHandler; ! private WeakChangeListener<Boolean> weakWindowFocusListener; ! private WeakChangeListener<Window> weakWindowSceneListener; ! private EventHandler<KeyEvent> keyEventHandler; ! private EventHandler<MouseEvent> mouseEventHandler; ! private ChangeListener<Boolean> menuBarFocusedPropertyListener; ! private ChangeListener<Scene> sceneChangeListener; ! private boolean pendingDismiss = false; ! ! /*************************************************************************** ! * * ! * Listeners / Callbacks * ! * * ! **************************************************************************/ ! ! // RT-20411 : reset menu selected/focused state ! private EventHandler<ActionEvent> menuActionEventHandler = t -> { ! if (t.getSource() instanceof CustomMenuItem) { ! // RT-29614 If CustomMenuItem hideOnClick is false, dont hide ! CustomMenuItem cmi = (CustomMenuItem)t.getSource(); ! if (!cmi.isHideOnClick()) return; } ! unSelectMenus(); ! }; ! ! private ListChangeListener<MenuItem> menuItemListener = (c) -> { ! while (c.next()) { ! for (MenuItem mi : c.getAddedSubList()) { ! mi.addEventHandler(ActionEvent.ACTION, menuActionEventHandler); } ! for (MenuItem mi: c.getRemoved()) { ! mi.removeEventHandler(ActionEvent.ACTION, menuActionEventHandler); } } }; ! Runnable firstMenuRunnable = new Runnable() { ! public void run() { ! /* ! ** check that this menubar's container has contents, ! ** and that the first item is a MenuButton.... ! ** otherwise the transfer is off! ! */ ! if (container.getChildren().size() > 0) { ! if (container.getChildren().get(0) instanceof MenuButton) { ! // container.getChildren().get(0).requestFocus(); ! if (focusedMenuIndex != 0) { ! unSelectMenus(); ! menuModeStart(0); ! openMenuButton = ((MenuBarButton)container.getChildren().get(0)); ! openMenu = getSkinnable().getMenus().get(0); ! openMenuButton.setHover(); } ! else { ! unSelectMenus(); } } } } + }; /*************************************************************************** * * * Constructors * * * **************************************************************************/ + /** + * Creates a new MenuBarSkin instance, installing the necessary child + * nodes into the Control {@link Control#getChildren() children} list, as + * well as the necessary {@link Node#getInputMap() input mappings} for + * handling key, mouse, etc events. + * + * @param control The control that this skin should be installed onto. + */ public MenuBarSkin(final MenuBar control) { ! super(control); container = new HBox(); container.getStyleClass().add("container"); getChildren().add(container);
*** 378,388 **** } }); }); ParentTraversalEngine engine = new ParentTraversalEngine(getSkinnable()); ! engine.addTraverseListener(this); getSkinnable().setImpl_traversalEngine(engine); control.sceneProperty().addListener((ov, t, t1) -> { if (weakSceneKeyEventHandler != null) { // remove event filter from the old scene (t) --- 368,381 ---- } }); }); ParentTraversalEngine engine = new ParentTraversalEngine(getSkinnable()); ! engine.addTraverseListener((node, bounds) -> { ! if (openMenu != null) openMenu.hide(); ! focusedMenuIndex = 0; ! }); getSkinnable().setImpl_traversalEngine(engine); control.sceneProperty().addListener((ov, t, t1) -> { if (weakSceneKeyEventHandler != null) { // remove event filter from the old scene (t)
*** 394,443 **** if (t != null) t.removeEventFilter(MouseEvent.MOUSE_CLICKED, weakSceneMouseEventHandler); } /** ! * remove the f10 accelerator from the old scene ! * add it to the new scene */ ! if (t != null) { ! t.getAccelerators().remove(acceleratorKeyCombo); ! } ! if (t1 != null ) { ! t1.getAccelerators().put(acceleratorKeyCombo, firstMenuRunnable); ! } ! }); } ! ! Runnable firstMenuRunnable = new Runnable() { ! public void run() { ! /* ! ** check that this menubar's container has contents, ! ** and that the first item is a MenuButton.... ! ** otherwise the transfer is off! ! */ ! if (container.getChildren().size() > 0) { ! if (container.getChildren().get(0) instanceof MenuButton) { ! // container.getChildren().get(0).requestFocus(); ! if (focusedMenuIndex != 0) { ! unSelectMenus(); ! menuModeStart(0); ! openMenuButton = ((MenuBarButton)container.getChildren().get(0)); ! openMenu = getSkinnable().getMenus().get(0); ! openMenuButton.setHover(); } ! else { ! unSelectMenus(); } } } } - }; ! private boolean pendingDismiss = false; // For testing purpose only. MenuButton getNodeForMenu(int i) { if (i < container.getChildren().size()) { return (MenuBarButton)container.getChildren().get(i); --- 387,670 ---- if (t != null) t.removeEventFilter(MouseEvent.MOUSE_CLICKED, weakSceneMouseEventHandler); } /** ! * remove the f10 accelerator from the old scene ! * add it to the new scene ! */ ! if (t != null) { ! t.getAccelerators().remove(acceleratorKeyCombo); ! } ! if (t1 != null ) { ! t1.getAccelerators().put(acceleratorKeyCombo, firstMenuRunnable); ! } ! }); ! } ! ! ! ! /*************************************************************************** ! * * ! * Static methods * ! * * ! **************************************************************************/ ! ! // RT-22480: This is intended as private API for SceneBuilder, ! // pending fix for RT-19857: Keeping menu in the Mac menu bar when ! // there is no more stage ! public static void setDefaultSystemMenuBar(final MenuBar menuBar) { ! if (Toolkit.getToolkit().getSystemMenu().isSupported()) { ! wrappedDefaultMenus.clear(); ! for (Menu menu : menuBar.getMenus()) { ! wrappedDefaultMenus.add(GlobalMenuAdapter.adapt(menu)); ! } ! menuBar.getMenus().addListener((ListChangeListener<Menu>) c -> { ! wrappedDefaultMenus.clear(); ! for (Menu menu : menuBar.getMenus()) { ! wrappedDefaultMenus.add(GlobalMenuAdapter.adapt(menu)); ! } ! }); ! } ! } ! ! private static MenuBarSkin getMenuBarSkin(Stage stage) { ! if (systemMenuMap == null) return null; ! Reference<MenuBarSkin> skinRef = systemMenuMap.get(stage); ! return skinRef == null ? null : skinRef.get(); ! } ! ! private static void setSystemMenu(Stage stage) { ! if (stage != null && stage.isFocused()) { ! while (stage != null && stage.getOwner() instanceof Stage) { ! MenuBarSkin skin = getMenuBarSkin(stage); ! if (skin != null && skin.wrappedMenus != null) { ! break; ! } else { ! // This is a secondary stage (dialog) that doesn't ! // have own menu bar. ! // ! // Continue looking for a menu bar in the parent stage. ! stage = (Stage)stage.getOwner(); ! } ! } ! } else { ! stage = null; ! } ! ! if (stage != currentMenuBarStage) { ! List<MenuBase> menuList = null; ! if (stage != null) { ! MenuBarSkin skin = getMenuBarSkin(stage); ! if (skin != null) { ! menuList = skin.wrappedMenus; ! } ! } ! if (menuList == null) { ! menuList = wrappedDefaultMenus; ! } ! Toolkit.getToolkit().getSystemMenu().setMenus(menuList); ! currentMenuBarStage = stage; ! } ! } ! ! private static void initSystemMenuBar() { ! systemMenuMap = new WeakHashMap<>(); ! ! final InvalidationListener focusedStageListener = ov -> { ! setSystemMenu((Stage)((ReadOnlyProperty<?>)ov).getBean()); ! }; ! ! final ObservableList<Stage> stages = StageHelper.getStages(); ! for (Stage stage : stages) { ! stage.focusedProperty().addListener(focusedStageListener); ! } ! stages.addListener((ListChangeListener<Stage>) c -> { ! while (c.next()) { ! for (Stage stage : c.getRemoved()) { ! stage.focusedProperty().removeListener(focusedStageListener); ! } ! for (Stage stage : c.getAddedSubList()) { ! stage.focusedProperty().addListener(focusedStageListener); ! setSystemMenu(stage); ! } ! } ! }); ! } ! ! ! ! /*************************************************************************** ! * * ! * Properties * ! * * ! **************************************************************************/ ! ! /** ! * Specifies the spacing between menu buttons on the MenuBar. ! */ ! // --- spacing ! private DoubleProperty spacing; ! public final void setSpacing(double value) { ! spacingProperty().set(snapSpace(value)); ! } ! ! public final double getSpacing() { ! return spacing == null ? 0.0 : snapSpace(spacing.get()); ! } ! ! public final DoubleProperty spacingProperty() { ! if (spacing == null) { ! spacing = new StyleableDoubleProperty() { ! ! @Override ! protected void invalidated() { ! final double value = get(); ! container.setSpacing(value); ! } ! ! @Override ! public Object getBean() { ! return MenuBarSkin.this; ! } ! ! @Override ! public String getName() { ! return "spacing"; ! } ! ! @Override ! public CssMetaData<MenuBar,Number> getCssMetaData() { ! return SPACING; ! } ! }; ! } ! return spacing; ! } ! ! /** ! * Specifies the alignment of the menu buttons inside the MenuBar (by default ! * it is Pos.TOP_LEFT). ! */ ! // --- container alignment ! private ObjectProperty<Pos> containerAlignment; ! public final void setContainerAlignment(Pos value) { ! containerAlignmentProperty().set(value); ! } ! ! public final Pos getContainerAlignment() { ! return containerAlignment == null ? Pos.TOP_LEFT : containerAlignment.get(); ! } ! ! public final ObjectProperty<Pos> containerAlignmentProperty() { ! if (containerAlignment == null) { ! containerAlignment = new StyleableObjectProperty<Pos>(Pos.TOP_LEFT) { ! ! @Override ! public void invalidated() { ! final Pos value = get(); ! container.setAlignment(value); ! } ! ! @Override ! public Object getBean() { ! return MenuBarSkin.this; ! } ! ! @Override ! public String getName() { ! return "containerAlignment"; ! } ! ! @Override ! public CssMetaData<MenuBar,Pos> getCssMetaData() { ! return ALIGNMENT; ! } ! }; ! } ! return containerAlignment; ! } ! ! ! ! /*************************************************************************** ! * * ! * Public API * ! * * ! **************************************************************************/ ! ! /** {@inheritDoc} */ ! @Override public void dispose() { ! cleanUpSystemMenu(); ! // call super.dispose last since it sets control to null ! super.dispose(); ! } ! ! // Return empty insets when "container" is empty, which happens ! // when using the system menu bar. ! ! /** {@inheritDoc} */ ! @Override protected double snappedTopInset() { ! return container.getChildren().isEmpty() ? 0 : super.snappedTopInset(); ! } ! /** {@inheritDoc} */ ! @Override protected double snappedBottomInset() { ! return container.getChildren().isEmpty() ? 0 : super.snappedBottomInset(); ! } ! /** {@inheritDoc} */ ! @Override protected double snappedLeftInset() { ! return container.getChildren().isEmpty() ? 0 : super.snappedLeftInset(); ! } ! /** {@inheritDoc} */ ! @Override protected double snappedRightInset() { ! return container.getChildren().isEmpty() ? 0 : super.snappedRightInset(); ! } ! ! /** ! * Layout the menu bar. This is a simple horizontal layout like an hbox. ! * Any menu items which don't fit into it will simply be made invisible. */ ! /** {@inheritDoc} */ ! @Override protected void layoutChildren(final double x, final double y, ! final double w, final double h) { ! // layout the menus one after another ! container.resizeRelocate(x, y, w, h); } ! /** {@inheritDoc} */ ! @Override protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { ! return container.minWidth(height) + snappedLeftInset() + snappedRightInset(); } ! ! /** {@inheritDoc} */ ! @Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { ! return container.prefWidth(height) + snappedLeftInset() + snappedRightInset(); } + + /** {@inheritDoc} */ + @Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { + return container.minHeight(width) + snappedTopInset() + snappedBottomInset(); } + + /** {@inheritDoc} */ + @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { + return container.prefHeight(width) + snappedTopInset() + snappedBottomInset(); } + + // grow horizontally, but not vertically + /** {@inheritDoc} */ + @Override protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { + return getSkinnable().prefHeight(-1); } ! ! /*************************************************************************** ! * * ! * Private implementation * ! * * ! **************************************************************************/ // For testing purpose only. MenuButton getNodeForMenu(int i) { if (i < container.getChildren().size()) { return (MenuBarButton)container.getChildren().get(i);
*** 480,510 **** } } return -1; } - // RT-20411 : reset menu selected/focused state - private EventHandler<ActionEvent> menuActionEventHandler = t -> { - if (t.getSource() instanceof CustomMenuItem) { - // RT-29614 If CustomMenuItem hideOnClick is false, dont hide - CustomMenuItem cmi = (CustomMenuItem)t.getSource(); - if (!cmi.isHideOnClick()) return; - } - unSelectMenus(); - }; - - private ListChangeListener<MenuItem> menuItemListener = (c) -> { - while (c.next()) { - for (MenuItem mi : c.getAddedSubList()) { - mi.addEventHandler(ActionEvent.ACTION, menuActionEventHandler); - } - for (MenuItem mi: c.getRemoved()) { - mi.removeEventHandler(ActionEvent.ACTION, menuActionEventHandler); - } - } - }; - private void updateActionListeners(Menu m, boolean add) { if (add) { m.getItems().addListener(menuItemListener); } else { m.getItems().removeListener(menuItemListener); --- 707,716 ----
*** 779,882 **** updateActionListeners(menu, true); } getSkinnable().requestLayout(); } - /* - * if (openMenu == null) return; - if ( !openMenu.isShowing()) { - selectPrevMenu(); // just move the selection bar - return; - } - showPrevMenu(); - } - */ - private DoubleProperty spacing; - public final void setSpacing(double value) { - spacingProperty().set(snapSpace(value)); - } - - public final double getSpacing() { - return spacing == null ? 0.0 : snapSpace(spacing.get()); - } - - public final DoubleProperty spacingProperty() { - if (spacing == null) { - spacing = new StyleableDoubleProperty() { - - @Override - protected void invalidated() { - final double value = get(); - container.setSpacing(value); - } - - @Override - public Object getBean() { - return MenuBarSkin.this; - } - - @Override - public String getName() { - return "spacing"; - } - - @Override - public CssMetaData<MenuBar,Number> getCssMetaData() { - return SPACING; - } - }; - } - return spacing; - } - - private ObjectProperty<Pos> containerAlignment; - public final void setContainerAlignment(Pos value) { - containerAlignmentProperty().set(value); - } - - public final Pos getContainerAlignment() { - return containerAlignment == null ? Pos.TOP_LEFT : containerAlignment.get(); - } - - public final ObjectProperty<Pos> containerAlignmentProperty() { - if (containerAlignment == null) { - containerAlignment = new StyleableObjectProperty<Pos>(Pos.TOP_LEFT) { - - @Override - public void invalidated() { - final Pos value = get(); - container.setAlignment(value); - } - - @Override - public Object getBean() { - return MenuBarSkin.this; - } - - @Override - public String getName() { - return "containerAlignment"; - } - - @Override - public CssMetaData<MenuBar,Pos> getCssMetaData() { - return ALIGNMENT; - } - }; - } - return containerAlignment; - } - - @Override - public void dispose() { - cleanUpSystemMenu(); - // call super.dispose last since it sets control to null - super.dispose(); - } - private void cleanUpSystemMenu() { - if (sceneChangeListener != null && getSkinnable() != null) { getSkinnable().sceneProperty().removeListener(sceneChangeListener); // rebuildUI creates sceneChangeListener and adds sceneChangeListener to sceneProperty, // so sceneChangeListener needs to be reset to null in the off chance that this // skin instance is reused. --- 985,995 ----
*** 1035,1165 **** return; } } } - @Override - public void onTraverse(Node node, Bounds bounds) { - if (openMenu != null) openMenu.hide(); - focusedMenuIndex = 0; - } - - static class MenuBarButton extends MenuButton { - private ChangeListener<Boolean> menuListener; - private MenuBarSkin menuBarSkin; - private Menu menu; - - private final ListChangeListener<MenuItem> itemsListener; - private final ListChangeListener<String> styleClassListener; - - public MenuBarButton(MenuBarSkin menuBarSkin, Menu menu) { - super(menu.getText(), menu.getGraphic()); - this.menuBarSkin = menuBarSkin; - setAccessibleRole(AccessibleRole.MENU); - - // listen to changes in menu items & update menuButton items - menu.getItems().addListener(itemsListener = c -> { - while (c.next()) { - getItems().removeAll(c.getRemoved()); - getItems().addAll(c.getFrom(), c.getAddedSubList()); - } - }); - menu.getStyleClass().addListener(styleClassListener = c -> { - while(c.next()) { - for(int i=c.getFrom(); i<c.getTo(); i++) { - getStyleClass().add(menu.getStyleClass().get(i)); - } - for (String str : c.getRemoved()) { - getStyleClass().remove(str); - } - } - }); - idProperty().bind(menu.idProperty()); - } - - public MenuBarSkin getMenuBarSkin() { - return menuBarSkin; - } - - private void clearHover() { - setHover(false); - } - - private void setHover() { - setHover(true); - - /* Transfer the a11y focus to an item in the menu bar. */ - menuBarSkin.getSkinnable().notifyAccessibleAttributeChanged(AccessibleAttribute.FOCUS_NODE); - } - - void dispose() { - menu.getItems().removeListener(itemsListener); - menu.getStyleClass().removeListener(styleClassListener); - idProperty().unbind(); - } - - @Override - public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) { - switch (attribute) { - case FOCUS_ITEM: return MenuBarButton.this; - default: return super.queryAccessibleAttribute(attribute, parameters); - } - } - } - - /*************************************************************************** - * * - * Layout * - * * - **************************************************************************/ - - // Return empty insets when "container" is empty, which happens - // when using the system menu bar. - - @Override protected double snappedTopInset() { - return container.getChildren().isEmpty() ? 0 : super.snappedTopInset(); - } - @Override protected double snappedBottomInset() { - return container.getChildren().isEmpty() ? 0 : super.snappedBottomInset(); - } - @Override protected double snappedLeftInset() { - return container.getChildren().isEmpty() ? 0 : super.snappedLeftInset(); - } - @Override protected double snappedRightInset() { - return container.getChildren().isEmpty() ? 0 : super.snappedRightInset(); - } - - /** - * Layout the menu bar. This is a simple horizontal layout like an hbox. - * Any menu items which don't fit into it will simply be made invisible. - */ - @Override protected void layoutChildren(final double x, final double y, - final double w, final double h) { - // layout the menus one after another - container.resizeRelocate(x, y, w, h); - } - - @Override protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return container.minWidth(height) + snappedLeftInset() + snappedRightInset(); - } - - @Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return container.prefWidth(height) + snappedLeftInset() + snappedRightInset(); - } - - @Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return container.minHeight(width) + snappedTopInset() + snappedBottomInset(); - } - - @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return container.prefHeight(width) + snappedTopInset() + snappedBottomInset(); - } - - // grow horizontally, but not vertically - @Override protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return getSkinnable().prefHeight(-1); - } /*************************************************************************** * * * CSS * --- 1148,1157 ----
*** 1221,1231 **** STYLEABLES = Collections.unmodifiableList(styleables); } /** ! * @return The CssMetaData associated with this class, which may include the * CssMetaData of its super classes. */ public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { return STYLEABLES; } --- 1213,1223 ---- STYLEABLES = Collections.unmodifiableList(styleables); } /** ! * Returns the CssMetaData associated with this class, which may include the * CssMetaData of its super classes. */ public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { return STYLEABLES; }
*** 1242,1253 **** * * * Accessibility handling * * * **************************************************************************/ ! @Override ! protected Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) { switch (attribute) { case FOCUS_NODE: return openMenuButton; default: return super.queryAccessibleAttribute(attribute, parameters); } } --- 1234,1245 ---- * * * Accessibility handling * * * **************************************************************************/ ! /** {@inheritDoc} */ ! @Override protected Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) { switch (attribute) { case FOCUS_NODE: return openMenuButton; default: return super.queryAccessibleAttribute(attribute, parameters); } }