modules/controls/src/main/java/javafx/scene/control/skin/ButtonBarSkin.java

Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
   1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.javafx.scene.control.skin;
  26 
  27 import java.util.ArrayList;
  28 import java.util.Collections;
  29 import java.util.HashMap;
  30 import java.util.List;
  31 import java.util.Map;
  32 


  33 import javafx.beans.InvalidationListener;
  34 import javafx.beans.property.ObjectProperty;
  35 import javafx.collections.ListChangeListener;
  36 import javafx.geometry.Pos;
  37 import javafx.scene.Node;
  38 import javafx.scene.control.Button;
  39 import javafx.scene.control.ButtonBar;
  40 import javafx.scene.control.ButtonBar.ButtonData;


  41 import javafx.scene.layout.HBox;
  42 import javafx.scene.layout.Pane;
  43 import javafx.scene.layout.Priority;
  44 import javafx.scene.layout.Region;
  45 
  46 import com.sun.javafx.scene.control.behavior.BehaviorBase;
  47 import com.sun.javafx.scene.control.behavior.KeyBinding;
  48 
  49 public class ButtonBarSkin extends BehaviorSkinBase<ButtonBar, BehaviorBase<ButtonBar>> {



  50     
  51     /**************************************************************************
  52      * 
  53      * Static fields
  54      * 
  55      **************************************************************************/
  56 
  57     private static final double GAP_SIZE = 10; 
  58     
  59     private static final String CATEGORIZED_TYPES = "LRHEYNXBIACO"; //$NON-NLS-1$
  60     
  61     // represented as a ButtonData
  62     public static final String BUTTON_DATA_PROPERTY  = "javafx.scene.control.ButtonBar.ButtonData"; //$NON-NLS-1$
  63     
  64     // allows to exclude button from uniform resizing
  65     public static final String BUTTON_SIZE_INDEPENDENCE = "javafx.scene.control.ButtonBar.independentSize"; //$NON-NLS-1$
  66     
  67     // pick an arbitrary number
  68     private static final double DO_NOT_CHANGE_SIZE = Double.MAX_VALUE - 100;
  69     
  70     
  71     /**************************************************************************
  72      * 
  73      * fields
  74      * 
  75      **************************************************************************/
  76     
  77     private HBox layout;
  78 
  79     private InvalidationListener buttonDataListener = o -> layoutButtons();
  80     
  81     
  82     
  83     /**************************************************************************
  84      * 
  85      * Constructors
  86      * 
  87      **************************************************************************/
  88 








  89     public ButtonBarSkin(final ButtonBar control) {
  90         super(control, new BehaviorBase<>(control, Collections.<KeyBinding> emptyList()));
  91         
  92         this.layout = new HBox(GAP_SIZE) {
  93             @Override
  94             protected void layoutChildren() {
  95                 // has to be called first or layout is not correct sometimes
  96                 resizeButtons();
  97                 super.layoutChildren();
  98             }
  99         };
 100         this.layout.setAlignment(Pos.CENTER);
 101         this.layout.getStyleClass().add("container");
 102         getChildren().add(layout);
 103         
 104         layoutButtons();
 105 
 106         updateButtonListeners(control.getButtons(), true);
 107         control.getButtons().addListener((ListChangeListener<Node>) c -> {
 108             while (c.next()) {
 109                 updateButtonListeners(c.getRemoved(), false);
 110                 updateButtonListeners(c.getAddedSubList(), true);
 111             }
 112             layoutButtons();
 113         });
 114         
 115         registerChangeListener(control.buttonOrderProperty(), "BUTTON_ORDER"); //$NON-NLS-1$
 116         registerChangeListener(control.buttonMinWidthProperty(), "BUTTON_MIN_WIDTH"); //$NON-NLS-1$
 117     }
 118 








 119     private void updateButtonListeners(List<? extends Node> list, boolean buttonsAdded) {
 120         if (list != null) {
 121             for (Node n : list) {
 122                 final Map<Object, Object> properties = n.getProperties();
 123                 if (properties.containsKey(ButtonBarSkin.BUTTON_DATA_PROPERTY)) {
 124                     ObjectProperty<ButtonData> property = (ObjectProperty<ButtonData>) properties.get(ButtonBarSkin.BUTTON_DATA_PROPERTY);
 125                     if (property != null) {
 126                         if (buttonsAdded) {
 127                             property.addListener(buttonDataListener);
 128                         } else {
 129                             property.removeListener(buttonDataListener);
 130                         }
 131                     }
 132                 }
 133             }
 134         }
 135     }
 136 
 137 
 138     /**************************************************************************
 139      * 
 140      * Overriding public API
 141      * 
 142      **************************************************************************/
 143     
 144     @Override protected void handleControlPropertyChanged(String p) {
 145         super.handleControlPropertyChanged(p);
 146         
 147         if ("BUTTON_ORDER".equals(p)) { //$NON-NLS-1$
 148             layoutButtons();
 149         } else if ("BUTTON_MIN_WIDTH".equals(p)) { //$NON-NLS-1$
 150 //            layoutButtons();
 151             resizeButtons();
 152         }
 153     }
 154     
 155     
 156     
 157     /**************************************************************************
 158      * 
 159      * Implementation
 160      * 
 161      **************************************************************************/
 162     
 163     private void layoutButtons() {
 164         final ButtonBar buttonBar = getSkinnable();
 165         final List<? extends Node> buttons = buttonBar.getButtons();
 166         final double buttonMinWidth = buttonBar.getButtonMinWidth();
 167         
 168         String buttonOrder = getSkinnable().getButtonOrder();
 169 
 170         layout.getChildren().clear();
 171 
 172         // empty is valid, because it is BUTTON_ORDER_NONE
 173         if (buttonOrder == null) {
 174             throw new IllegalStateException("ButtonBar buttonOrder string can not be null"); //$NON-NLS-1$
 175         }
 176 
 177         if (buttonOrder == ButtonBar.BUTTON_ORDER_NONE) {
 178             // when using BUTTON_ORDER_NONE, we just lay out the buttons in the
 179             // order they are specified, but we do right-align the buttons by
 180             // inserting a dynamic spacer.
 181             Spacer.DYNAMIC.add(layout, true);


   1 /*
   2  * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javafx.scene.control.skin;
  26 
  27 import java.util.ArrayList;

  28 import java.util.HashMap;
  29 import java.util.List;
  30 import java.util.Map;
  31 
  32 import com.sun.javafx.scene.control.Properties;
  33 import com.sun.javafx.scene.control.behavior.BehaviorBase;
  34 import javafx.beans.InvalidationListener;
  35 import javafx.beans.property.ObjectProperty;
  36 import javafx.collections.ListChangeListener;
  37 import javafx.geometry.Pos;
  38 import javafx.scene.Node;
  39 import javafx.scene.control.Button;
  40 import javafx.scene.control.ButtonBar;
  41 import javafx.scene.control.ButtonBar.ButtonData;
  42 import javafx.scene.control.Control;
  43 import javafx.scene.control.SkinBase;
  44 import javafx.scene.layout.HBox;
  45 import javafx.scene.layout.Pane;
  46 import javafx.scene.layout.Priority;
  47 import javafx.scene.layout.Region;
  48 
  49 /**
  50  * Default skin implementation for the {@link ButtonBar} control.
  51  *
  52  * @see ButtonBar
  53  * @since 9
  54  */
  55 public class ButtonBarSkin extends SkinBase<ButtonBar> {
  56     
  57     /**************************************************************************
  58      * 
  59      * Static fields
  60      * 
  61      **************************************************************************/
  62 
  63     private static final double GAP_SIZE = 10; 
  64     
  65     private static final String CATEGORIZED_TYPES = "LRHEYNXBIACO"; //$NON-NLS-1$
  66     






  67     // pick an arbitrary number
  68     private static final double DO_NOT_CHANGE_SIZE = Double.MAX_VALUE - 100;
  69     
  70     
  71     /**************************************************************************
  72      * 
  73      * fields
  74      * 
  75      **************************************************************************/
  76     
  77     private HBox layout;

  78     private InvalidationListener buttonDataListener = o -> layoutButtons();
  79 
  80     
  81     
  82     /**************************************************************************
  83      * 
  84      * Constructors
  85      * 
  86      **************************************************************************/
  87 
  88     /**
  89      * Creates a new ButtonBarSkin instance, installing the necessary child
  90      * nodes into the Control {@link Control#getChildren() children} list, as
  91      * well as the necessary {@link Node#getInputMap() input mappings} for
  92      * handling key, mouse, etc events.
  93      *
  94      * @param control The control that this skin should be installed onto.
  95      */
  96     public ButtonBarSkin(final ButtonBar control) {
  97         super(control);
  98         
  99         this.layout = new HBox(GAP_SIZE) {
 100             @Override protected void layoutChildren() {

 101                 // has to be called first or layout is not correct sometimes
 102                 resizeButtons();
 103                 super.layoutChildren();
 104             }
 105         };
 106         this.layout.setAlignment(Pos.CENTER);
 107         this.layout.getStyleClass().add("container");
 108         getChildren().add(layout);
 109         
 110         layoutButtons();
 111 
 112         updateButtonListeners(control.getButtons(), true);
 113         control.getButtons().addListener((ListChangeListener<Node>) c -> {
 114             while (c.next()) {
 115                 updateButtonListeners(c.getRemoved(), false);
 116                 updateButtonListeners(c.getAddedSubList(), true);
 117             }
 118             layoutButtons();
 119         });
 120         
 121         registerChangeListener(control.buttonOrderProperty(), e -> layoutButtons());
 122         registerChangeListener(control.buttonMinWidthProperty(), e -> resizeButtons());
 123     }
 124 
 125 
 126 
 127     /**************************************************************************
 128      * 
 129      * Implementation
 130      * 
 131      **************************************************************************/
 132 
 133     private void updateButtonListeners(List<? extends Node> list, boolean buttonsAdded) {
 134         if (list != null) {
 135             for (Node n : list) {
 136                 final Map<Object, Object> properties = n.getProperties();
 137                 if (properties.containsKey(Properties.BUTTON_DATA_PROPERTY)) {
 138                     ObjectProperty<ButtonData> property = (ObjectProperty<ButtonData>) properties.get(Properties.BUTTON_DATA_PROPERTY);
 139                     if (property != null) {
 140                         if (buttonsAdded) {
 141                             property.addListener(buttonDataListener);
 142                         } else {
 143                             property.removeListener(buttonDataListener);
 144                         }
 145                     }
 146                 }
 147             }
 148         }
 149     }


























 150     
 151     private void layoutButtons() {
 152         final ButtonBar buttonBar = getSkinnable();
 153         final List<? extends Node> buttons = buttonBar.getButtons();
 154         final double buttonMinWidth = buttonBar.getButtonMinWidth();
 155         
 156         String buttonOrder = getSkinnable().getButtonOrder();
 157 
 158         layout.getChildren().clear();
 159 
 160         // empty is valid, because it is BUTTON_ORDER_NONE
 161         if (buttonOrder == null) {
 162             throw new IllegalStateException("ButtonBar buttonOrder string can not be null"); //$NON-NLS-1$
 163         }
 164 
 165         if (buttonOrder == ButtonBar.BUTTON_ORDER_NONE) {
 166             // when using BUTTON_ORDER_NONE, we just lay out the buttons in the
 167             // order they are specified, but we do right-align the buttons by
 168             // inserting a dynamic spacer.
 169             Spacer.DYNAMIC.add(layout, true);