modules/controls/src/main/java/javafx/scene/control/skin/ComboBoxBaseSkin.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,32 ****
* 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.behavior.ComboBoxBaseBehavior;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.control.ComboBoxBase;
--- 21,33 ----
* 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.scene.control.SkinBase;
import com.sun.javafx.scene.control.behavior.ComboBoxBaseBehavior;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.control.ComboBoxBase;
*** 34,59 ****
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import java.util.List;
! public abstract class ComboBoxBaseSkin<T> extends BehaviorSkinBase<ComboBoxBase<T>, ComboBoxBaseBehavior<T>> {
private Node displayNode; // this is normally either label or textField
! protected StackPane arrowButton;
! protected Region arrow;
/** The mode in which this control will be represented. */
private ComboBoxMode mode = ComboBoxMode.COMBOBOX;
! protected final ComboBoxMode getMode() { return mode; }
! protected final void setMode(ComboBoxMode value) { mode = value; }
! public ComboBoxBaseSkin(final ComboBoxBase<T> comboBox, final ComboBoxBaseBehavior<T> behavior) {
! // Call the super method with the ComboBox we were just given in the
! // constructor, as well as an instance of the behavior class.
! super(comboBox, behavior);
// open button / arrow
arrow = new Region();
arrow.setFocusTraversable(false);
arrow.getStyleClass().setAll("arrow");
--- 35,91 ----
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import java.util.List;
! /**
! * An abstract class intended to be used as the base skin for ComboBox-like
! * controls that are based on {@link ComboBoxBase}. Most users of this skin class
! * would be well-advised to also look at {@link ComboBoxPopupControl} for
! * additional useful API.
! *
! * @since 9
! * @param <T> The type of the ComboBox-like control.
! * @see ComboBoxBase
! * @see ComboBoxPopupControl
! */
! public abstract class ComboBoxBaseSkin<T> extends SkinBase<ComboBoxBase<T>> {
!
! /***************************************************************************
! * *
! * Private Fields *
! * *
! **************************************************************************/
private Node displayNode; // this is normally either label or textField
! StackPane arrowButton;
! Region arrow;
/** The mode in which this control will be represented. */
private ComboBoxMode mode = ComboBoxMode.COMBOBOX;
! final ComboBoxMode getMode() { return mode; }
! final void setMode(ComboBoxMode value) { mode = value; }
!
!
! /***************************************************************************
! * *
! * Constructors *
! * *
! **************************************************************************/
!
! /**
! * Creates a new instance of ComboBoxBaseSkin, 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 ComboBoxBaseSkin(final ComboBoxBase<T> control) {
! // Call the super method with the ComboBox we were just given in the constructor
! super(control);
// open button / arrow
arrow = new Region();
arrow.setFocusTraversable(false);
arrow.getStyleClass().setAll("arrow");
*** 66,76 ****
arrowButton.setFocusTraversable(false);
arrowButton.setId("arrow-button");
arrowButton.getStyleClass().setAll("arrow-button");
arrowButton.getChildren().add(arrow);
! if (comboBox.isEditable()) {
//
// arrowButton behaves like a button.
// This is strongly tied to the implementation in ComboBoxBaseBehavior.
//
arrowButton.addEventHandler(MouseEvent.MOUSE_ENTERED, (e) -> getBehavior().mouseEntered(e));
--- 98,108 ----
arrowButton.setFocusTraversable(false);
arrowButton.setId("arrow-button");
arrowButton.getStyleClass().setAll("arrow-button");
arrowButton.getChildren().add(arrow);
! if (control.isEditable()) {
//
// arrowButton behaves like a button.
// This is strongly tied to the implementation in ComboBoxBaseBehavior.
//
arrowButton.addEventHandler(MouseEvent.MOUSE_ENTERED, (e) -> getBehavior().mouseEntered(e));
*** 87,105 ****
focusLost();
}
});
// Register listeners
! registerChangeListener(comboBox.editableProperty(), "EDITABLE");
! registerChangeListener(comboBox.showingProperty(), "SHOWING");
! registerChangeListener(comboBox.focusedProperty(), "FOCUSED");
! registerChangeListener(comboBox.valueProperty(), "VALUE");
}
!
! protected void focusLost() {
! getSkinnable().hide();
}
/**
* This method should return a Node that will be positioned within the
* ComboBox 'button' area.
*/
public abstract Node getDisplayNode();
--- 119,147 ----
focusLost();
}
});
// Register listeners
! registerChangeListener(control.editableProperty(), e -> updateDisplayArea());
! registerChangeListener(control.showingProperty(), e -> {
! if (getSkinnable().isShowing()) {
! show();
! } else {
! hide();
}
! });
! registerChangeListener(control.valueProperty(), e -> updateDisplayArea());
}
+
+
+
+ /***************************************************************************
+ * *
+ * Public API *
+ * *
+ **************************************************************************/
+
/**
* This method should return a Node that will be positioned within the
* ComboBox 'button' area.
*/
public abstract Node getDisplayNode();
*** 114,162 ****
* This method will be called when the ComboBox popup should be hidden.
* It is up to specific skin implementations to determine how this is handled.
*/
public abstract void hide();
! /**
! * 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 ("EDITABLE".equals(p)) {
! updateDisplayArea();
! } else if ("VALUE".equals(p)) {
! updateDisplayArea();
! }
! }
!
! protected void updateDisplayArea() {
! final List<Node> children = getChildren();
! final Node oldDisplayNode = displayNode;
! displayNode = getDisplayNode();
!
! // don't remove displayNode if it hasn't changed.
! if (oldDisplayNode != null && oldDisplayNode != displayNode) {
! children.remove(oldDisplayNode);
! }
!
! if (displayNode != null && !children.contains(displayNode)) {
! children.add(displayNode);
! displayNode.applyCss();
! }
! }
!
! private boolean isButton() {
! return getMode() == ComboBoxMode.BUTTON;
! }
!
@Override protected void layoutChildren(final double x, final double y,
final double w, final double h) {
if (displayNode == null) {
updateDisplayArea();
}
--- 156,166 ----
* This method will be called when the ComboBox popup should be hidden.
* It is up to specific skin implementations to determine how this is handled.
*/
public abstract void hide();
! /** {@inheritDoc} */
@Override protected void layoutChildren(final double x, final double y,
final double w, final double h) {
if (displayNode == null) {
updateDisplayArea();
}
*** 176,185 ****
--- 180,190 ----
positionInArea(arrowButton, (x + w) - arrowButtonWidth, y,
arrowButtonWidth, h, 0, HPos.CENTER, VPos.CENTER);
}
}
+ /** {@inheritDoc} */
@Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
if (displayNode == null) {
updateDisplayArea();
}
*** 192,201 ****
--- 197,207 ----
final double totalWidth = displayNodeWidth + arrowButtonWidth;
return leftInset + totalWidth + rightInset;
}
+ /** {@inheritDoc} */
@Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
if (displayNode == null) {
updateDisplayArea();
}
*** 210,229 ****
--- 216,238 ----
}
return topInset+ ph + 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);
}
// Overridden so that we use the displayNode as the baseline, rather than the arrow.
// See RT-30754 for more information.
+ /** {@inheritDoc} */
@Override protected double computeBaselineOffset(double topInset, double rightInset, double bottomInset, double leftInset) {
if (displayNode == null) {
updateDisplayArea();
}
*** 231,236 ****
--- 240,281 ----
return displayNode.getLayoutBounds().getMinY() + displayNode.getLayoutY() + displayNode.getBaselineOffset();
}
return super.computeBaselineOffset(topInset, rightInset, bottomInset, leftInset);
}
+
+
+
+ /***************************************************************************
+ * *
+ * Private implementation *
+ * *
+ **************************************************************************/
+
+ ComboBoxBaseBehavior getBehavior() {
+ return null;
+ }
+
+ void focusLost() {
+ getSkinnable().hide();
+ }
+
+ private boolean isButton() {
+ return getMode() == ComboBoxMode.BUTTON;
+ }
+
+ void updateDisplayArea() {
+ final List<Node> children = getChildren();
+ final Node oldDisplayNode = displayNode;
+ displayNode = getDisplayNode();
+
+ // don't remove displayNode if it hasn't changed.
+ if (oldDisplayNode != null && oldDisplayNode != displayNode) {
+ children.remove(oldDisplayNode);
+ }
+
+ if (displayNode != null && !children.contains(displayNode)) {
+ children.add(displayNode);
+ displayNode.applyCss();
+ }
+ }
}