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 +1,7 @@
/*
- * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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,68 +21,83 @@
* 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;
+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 abstract class MenuButtonSkinBase<C extends MenuButton, B extends MenuButtonBehaviorBase<C>> extends BehaviorSkinBase<C, B> {
+public class MenuButtonSkinBase<C extends MenuButton> extends SkinBase<C> {
/***************************************************************************
* *
- * UI Subcomponents *
+ * Private fields *
* *
**************************************************************************/
- protected final LabeledImpl label;
- protected final StackPane arrow;
- protected final StackPane arrowButton;
- protected ContextMenu popup;
+ final LabeledImpl label;
+ final StackPane arrow;
+ final StackPane arrowButton;
+ ContextMenu popup;
/**
* If true, the control should behave like a button for mouse button events.
*/
- protected boolean behaveLikeButton = false;
+ boolean behaveLikeButton = false;
private ListChangeListener<MenuItem> itemsChangedListener;
-
-
/***************************************************************************
* *
* Constructors *
* *
**************************************************************************/
- public MenuButtonSkinBase(final C control, final B behavior) {
- super(control, behavior);
+ /**
+ * 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 -> {
- getBehavior().mousePressed(e, behaveLikeButton);
+ MenuButtonBehaviorBase behavior = getBehavior();
+ if (behavior != null) {
+ behavior.mousePressed(e, behaveLikeButton);
+ }
});
}
if (control.getOnMouseReleased() == null) {
control.addEventHandler(MouseEvent.MOUSE_RELEASED, e -> {
- getBehavior().mouseReleased(e, behaveLikeButton);
+ MenuButtonBehaviorBase behavior = getBehavior();
+ if (behavior != null) {
+ behavior.mouseReleased(e, behaveLikeButton);
+ }
});
}
/*
* Create the objects we will be displaying.
@@ -138,79 +153,31 @@
//
// }
// });
// 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)) {
+ registerChangeListener(control.showingProperty(), e -> {
if (getSkinnable().isShowing()) {
show();
} else {
hide();
}
- } else if ("FOCUSED".equals(p)) {
+ });
+ registerChangeListener(control.focusedProperty(), e -> {
// 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)) {
+ });
+ 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,66 +186,126 @@
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 *
+ * 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);
+ arrowButton.resizeRelocate(x + (w - arrowButtonWidth), y, arrowButtonWidth, h);
}
- private class MenuLabeledImpl extends LabeledImpl {
+
+
+ /***************************************************************************
+ * *
+ * 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 -> {