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