modules/controls/src/main/java/javafx/scene/control/skin/MenuButtonSkinBase.java
Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
*** 1,7 ****
/*
! * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 21,88 ****
* 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.ControlAcceleratorSupport;
import javafx.collections.ListChangeListener;
import javafx.event.ActionEvent;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import com.sun.javafx.scene.control.behavior.MenuButtonBehaviorBase;
/**
* Base class for MenuButtonSkin and SplitMenuButtonSkin. It consists of the
* label, the arrowButton with its arrow shape, and the popup.
*/
! public abstract class MenuButtonSkinBase<C extends MenuButton, B extends MenuButtonBehaviorBase<C>> extends BehaviorSkinBase<C, B> {
/***************************************************************************
* *
! * UI Subcomponents *
* *
**************************************************************************/
! protected final LabeledImpl label;
! protected final StackPane arrow;
! protected final StackPane arrowButton;
! protected ContextMenu popup;
/**
* If true, the control should behave like a button for mouse button events.
*/
! protected boolean behaveLikeButton = false;
private ListChangeListener<MenuItem> itemsChangedListener;
-
-
/***************************************************************************
* *
* Constructors *
* *
**************************************************************************/
! public MenuButtonSkinBase(final C control, final B behavior) {
! super(control, behavior);
if (control.getOnMousePressed() == null) {
control.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
! getBehavior().mousePressed(e, behaveLikeButton);
});
}
if (control.getOnMouseReleased() == null) {
control.addEventHandler(MouseEvent.MOUSE_RELEASED, e -> {
! getBehavior().mouseReleased(e, behaveLikeButton);
});
}
/*
* Create the objects we will be displaying.
--- 21,103 ----
* 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 com.sun.javafx.scene.control.ContextMenuContent;
import com.sun.javafx.scene.control.ControlAcceleratorSupport;
+ import com.sun.javafx.scene.control.LabeledImpl;
+ import com.sun.javafx.scene.control.skin.Utils;
import javafx.collections.ListChangeListener;
import javafx.event.ActionEvent;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
+ import javafx.scene.control.SkinBase;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import com.sun.javafx.scene.control.behavior.MenuButtonBehaviorBase;
/**
* Base class for MenuButtonSkin and SplitMenuButtonSkin. It consists of the
* label, the arrowButton with its arrow shape, and the popup.
*/
! public class MenuButtonSkinBase<C extends MenuButton> extends SkinBase<C> {
/***************************************************************************
* *
! * Private fields *
* *
**************************************************************************/
! final LabeledImpl label;
! final StackPane arrow;
! final StackPane arrowButton;
! ContextMenu popup;
/**
* If true, the control should behave like a button for mouse button events.
*/
! boolean behaveLikeButton = false;
private ListChangeListener<MenuItem> itemsChangedListener;
/***************************************************************************
* *
* Constructors *
* *
**************************************************************************/
! /**
! * Creates a new instance of MenuButtonSkinBase, although note that this
! * instance does not handle any behavior / input mappings - this needs to be
! * handled appropriately by subclasses.
! *
! * @param control The control that this skin should be installed onto.
! */
! public MenuButtonSkinBase(final C control) {
! super(control);
if (control.getOnMousePressed() == null) {
control.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
! MenuButtonBehaviorBase behavior = getBehavior();
! if (behavior != null) {
! behavior.mousePressed(e, behaveLikeButton);
! }
});
}
if (control.getOnMouseReleased() == null) {
control.addEventHandler(MouseEvent.MOUSE_RELEASED, e -> {
! MenuButtonBehaviorBase behavior = getBehavior();
! if (behavior != null) {
! behavior.mouseReleased(e, behaveLikeButton);
! }
});
}
/*
* Create the objects we will be displaying.
*** 138,216 ****
//
// }
// });
// Register listeners
! registerChangeListener(control.showingProperty(), "SHOWING");
! registerChangeListener(control.focusedProperty(), "FOCUSED");
! registerChangeListener(control.mnemonicParsingProperty(), "MNEMONIC_PARSING");
! registerChangeListener(popup.showingProperty(), "POPUP_VISIBLE");
! }
!
! /** {@inheritDoc} */
! @Override public void dispose() {
! getSkinnable().getItems().removeListener(itemsChangedListener);
! super.dispose();
! if (popup != null ) {
! if (popup.getSkin() != null && popup.getSkin().getNode() != null) {
! ContextMenuContent cmContent = (ContextMenuContent)popup.getSkin().getNode();
! cmContent.dispose();
! cmContent = null;
! }
! popup.setSkin(null);
! popup = null;
! }
! }
! /***************************************************************************
! * *
! * Control change handlers *
! * *
! **************************************************************************/
!
! private void show() {
! if (!popup.isShowing()) {
! popup.show(getSkinnable(), getSkinnable().getPopupSide(), 0, 0);
!
! // if (getSkinnable().isOpenVertically()) {
! // // FIXME ugly hack - need to work out why we need '12' for
! // // MenuButton/SplitMenuButton, but not for Menus
! // double indent = getSkinnable().getStyleClass().contains("menu") ? 0 : 12;
! // popup.show(getSkinnable(), Side.BOTTOM, indent, 0);
! // } else {
! // popup.show(getSkinnable(), Side.RIGHT, 0, 12);
! // }
! }
! }
!
! private void hide() {
! if (popup.isShowing()) {
! popup.hide();
! // popup.getAnchor().requestFocus();
! }
! }
!
! /**
! * Handles changes to properties of the MenuButton.
! */
! @Override protected void handleControlPropertyChanged(String p) {
! super.handleControlPropertyChanged(p);
!
! if ("SHOWING".equals(p)) {
if (getSkinnable().isShowing()) {
show();
} else {
hide();
}
! } else if ("FOCUSED".equals(p)) {
// Handle tabbing away from an open MenuButton
if (!getSkinnable().isFocused() && getSkinnable().isShowing()) {
hide();
}
if (!getSkinnable().isFocused() && popup.isShowing()) {
hide();
}
! } else if ("POPUP_VISIBLE".equals(p)) {
if (!popup.isShowing() && getSkinnable().isShowing()) {
// Popup was dismissed. Maybe user clicked outside or typed ESCAPE.
// Make sure button is in sync.
getSkinnable().hide();
}
--- 153,183 ----
//
// }
// });
// Register listeners
! registerChangeListener(control.showingProperty(), e -> {
if (getSkinnable().isShowing()) {
show();
} else {
hide();
}
! });
! registerChangeListener(control.focusedProperty(), e -> {
// Handle tabbing away from an open MenuButton
if (!getSkinnable().isFocused() && getSkinnable().isShowing()) {
hide();
}
if (!getSkinnable().isFocused() && popup.isShowing()) {
hide();
}
! });
! registerChangeListener(control.mnemonicParsingProperty(), e -> {
! label.setMnemonicParsing(getSkinnable().isMnemonicParsing());
! getSkinnable().requestLayout();
! });
! registerChangeListener(popup.showingProperty(), e -> {
if (!popup.isShowing() && getSkinnable().isShowing()) {
// Popup was dismissed. Maybe user clicked outside or typed ESCAPE.
// Make sure button is in sync.
getSkinnable().hide();
}
*** 219,284 ****
Utils.addMnemonics(popup, getSkinnable().getScene(), getSkinnable().impl_isShowMnemonics());
}
else {
Utils.removeMnemonics(popup, getSkinnable().getScene());
}
- } else if ("MNEMONIC_PARSING".equals(p)) {
- label.setMnemonicParsing(getSkinnable().isMnemonicParsing());
- getSkinnable().requestLayout();
- }
- }
/***************************************************************************
* *
! * Layout *
* *
**************************************************************************/
@Override protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
return leftInset
+ label.minWidth(height)
+ snapSize(arrowButton.minWidth(height))
+ rightInset;
}
@Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
return topInset
+ Math.max(label.minHeight(width), snapSize(arrowButton.minHeight(-1)))
+ bottomInset;
}
@Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
return leftInset
+ label.prefWidth(height)
+ snapSize(arrowButton.prefWidth(height))
+ rightInset;
}
@Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
return topInset
+ Math.max(label.prefHeight(width), snapSize(arrowButton.prefHeight(-1)))
+ bottomInset;
}
@Override protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
return getSkinnable().prefWidth(height);
}
@Override protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
return getSkinnable().prefHeight(width);
}
@Override protected void layoutChildren(final double x, final double y,
final double w, final double h) {
final double arrowButtonWidth = snapSize(arrowButton.prefWidth(-1));
label.resizeRelocate(x, y, w - arrowButtonWidth, h);
! arrowButton.resizeRelocate(x+(w-arrowButtonWidth), y, arrowButtonWidth, h);
}
! private class MenuLabeledImpl extends LabeledImpl {
MenuButton button;
public MenuLabeledImpl(MenuButton b) {
super(b);
button = b;
addEventHandler(ActionEvent.ACTION, e -> {
--- 186,311 ----
Utils.addMnemonics(popup, getSkinnable().getScene(), getSkinnable().impl_isShowMnemonics());
}
else {
Utils.removeMnemonics(popup, getSkinnable().getScene());
}
+ });
+ }
/***************************************************************************
* *
! * Private implementation *
* *
**************************************************************************/
+ /** {@inheritDoc} */
+ @Override public void dispose() {
+ getSkinnable().getItems().removeListener(itemsChangedListener);
+ super.dispose();
+ if (popup != null ) {
+ if (popup.getSkin() != null && popup.getSkin().getNode() != null) {
+ ContextMenuContent cmContent = (ContextMenuContent)popup.getSkin().getNode();
+ cmContent.dispose();
+ }
+ popup.setSkin(null);
+ popup = null;
+ }
+ }
+
+ /** {@inheritDoc} */
@Override protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
return leftInset
+ label.minWidth(height)
+ snapSize(arrowButton.minWidth(height))
+ rightInset;
}
+ /** {@inheritDoc} */
@Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
return topInset
+ Math.max(label.minHeight(width), snapSize(arrowButton.minHeight(-1)))
+ bottomInset;
}
+ /** {@inheritDoc} */
@Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
return leftInset
+ label.prefWidth(height)
+ snapSize(arrowButton.prefWidth(height))
+ rightInset;
}
+ /** {@inheritDoc} */
@Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
return topInset
+ Math.max(label.prefHeight(width), snapSize(arrowButton.prefHeight(-1)))
+ bottomInset;
}
+ /** {@inheritDoc} */
@Override protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
return getSkinnable().prefWidth(height);
}
+ /** {@inheritDoc} */
@Override protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
return getSkinnable().prefHeight(width);
}
+ /** {@inheritDoc} */
@Override protected void layoutChildren(final double x, final double y,
final double w, final double h) {
final double arrowButtonWidth = snapSize(arrowButton.prefWidth(-1));
label.resizeRelocate(x, y, w - arrowButtonWidth, h);
! arrowButton.resizeRelocate(x + (w - arrowButtonWidth), y, arrowButtonWidth, h);
}
!
!
! /***************************************************************************
! * *
! * Private implementation *
! * *
! **************************************************************************/
!
! MenuButtonBehaviorBase<C> getBehavior() {
! return null;
! }
!
! private void show() {
! if (!popup.isShowing()) {
! popup.show(getSkinnable(), getSkinnable().getPopupSide(), 0, 0);
!
! // if (getSkinnable().isOpenVertically()) {
! // // FIXME ugly hack - need to work out why we need '12' for
! // // MenuButton/SplitMenuButton, but not for Menus
! // double indent = getSkinnable().getStyleClass().contains("menu") ? 0 : 12;
! // popup.show(getSkinnable(), Side.BOTTOM, indent, 0);
! // } else {
! // popup.show(getSkinnable(), Side.RIGHT, 0, 12);
! // }
! }
! }
!
! private void hide() {
! if (popup.isShowing()) {
! popup.hide();
! // popup.getAnchor().requestFocus();
! }
! }
!
!
!
! /***************************************************************************
! * *
! * Support classes *
! * *
! **************************************************************************/
!
! private static class MenuLabeledImpl extends LabeledImpl {
MenuButton button;
public MenuLabeledImpl(MenuButton b) {
super(b);
button = b;
addEventHandler(ActionEvent.ACTION, e -> {