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);
}
}