1 /* 2 * Copyright (c) 2010, 2017, 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 26 package javafx.scene; 27 28 import com.sun.javafx.scene.GroupHelper; 29 import javafx.beans.DefaultProperty; 30 import javafx.beans.property.BooleanProperty; 31 import javafx.beans.property.BooleanPropertyBase; 32 import javafx.collections.ObservableList; 33 import javafx.geometry.Bounds; 34 import java.util.Collection; 35 36 37 38 /** 39 * A {@code Group} node contains an ObservableList of children that 40 * are rendered in order whenever this node is rendered. 41 * <p> 42 * A {@code Group} will take on the collective bounds of its children and is 43 * not directly resizable. 44 * <p> 45 * Any transform, effect, or state applied to a {@code Group} will be applied 46 * to all children of that group. Such transforms and effects will NOT be included 47 * in this Group's layout bounds, however if transforms and effects are set 48 * directly on children of this Group, those will be included in this Group's layout bounds. 49 * <p> 50 * By default, a {@code Group} will "auto-size" its managed resizable 51 * children to their preferred sizes during the layout pass to ensure that Regions 52 * and Controls are sized properly as their state changes. If an application 53 * needs to disable this auto-sizing behavior, then it should set {@link #autoSizeChildren} 54 * to {@code false} and understand that if the preferred size of the children 55 * change, they will not automatically resize (so buyer beware!). 56 * 57 * <p>Group Example:</p> 58 * 59 <PRE> 60 import javafx.scene.*; 61 import javafx.scene.paint.*; 62 import javafx.scene.shape.*; 63 import java.lang.Math; 64 65 Group g = new Group(); 66 for (int i = 0; i < 5; i++) { 67 Rectangle r = new Rectangle(); 68 r.setY(i * 20); 69 r.setWidth(100); 70 r.setHeight(10); 71 r.setFill(Color.RED); 72 g.getChildren().add(r); 73 } 74 </PRE> 75 * @since JavaFX 2.0 76 */ 77 @DefaultProperty("children") 78 public class Group extends Parent { 79 static { 80 // This is used by classes in different packages to get access to 81 // private and package private methods. 82 GroupHelper.setGroupAccessor(new GroupHelper.GroupAccessor() { 83 @Override 84 public Bounds doComputeLayoutBounds(Node node) { 85 return ((Group) node).doComputeLayoutBounds(); 86 } 87 }); 88 } 89 90 { 91 // To initialize the class helper at the begining each constructor of this class 92 GroupHelper.initHelper(this); 93 } 94 95 /** 96 * Constructs a group. 97 */ 98 public Group() { } 99 100 /** 101 * Constructs a group consisting of children. 102 * 103 * @param children children. 104 */ 105 public Group(Node... children) { 106 getChildren().addAll(children); 107 } 108 109 /** 110 * Constructs a group consisting of the given children. 111 * 112 * @param children children of the group 113 * @throws NullPointerException if the specified collection is null 114 * @since JavaFX 8.0 115 */ 116 public Group(Collection<Node> children) { 117 getChildren().addAll(children); 118 } 119 120 /** 121 * Controls whether or not this {@code Group} will automatically resize any 122 * managed resizable children to their preferred sizes 123 * during the layout pass. If set to {@code false}, then the application is 124 * responsible for setting the size of this Group's resizable children, otherwise 125 * such nodes may end up with a zero width/height and will not be visible. 126 * This variable has no effect on content nodes which are not resizable (Shape, Text, etc). 127 * 128 * @defaultValue true 129 */ 130 private BooleanProperty autoSizeChildren; 131 132 133 public final void setAutoSizeChildren(boolean value){ 134 autoSizeChildrenProperty().set(value); 135 } 136 137 public final boolean isAutoSizeChildren() { 138 return autoSizeChildren == null ? true : autoSizeChildren.get(); 139 } 140 141 public final BooleanProperty autoSizeChildrenProperty() { 142 if (autoSizeChildren == null) { 143 autoSizeChildren = new BooleanPropertyBase(true) { 144 145 @Override 146 protected void invalidated() { 147 requestLayout(); 148 } 149 150 @Override 151 public Object getBean() { 152 return Group.this; 153 } 154 155 @Override 156 public String getName() { 157 return "autoSizeChildren"; 158 } 159 }; 160 } 161 return autoSizeChildren; 162 } 163 164 /** 165 * Gets the list of children of this {@code Group}. 166 * @return the list of children of this {@code Group}. 167 */ 168 @Override public ObservableList<Node> getChildren() { 169 return super.getChildren(); 170 } 171 172 /* 173 * Note: This method MUST only be called via its accessor method. 174 */ 175 private Bounds doComputeLayoutBounds() { 176 layout(); // Needs to done prematurely, as we otherwise don't know the bounds of the children 177 return null; // helper only requires this node to call layout(). 178 } 179 180 /** 181 * Group defines the preferred width as simply being the width of its layout bounds, which 182 * in turn is simply the sum of the positions and widths of all of its children. That is, 183 * the preferred width is the one that it is at, because a Group cannot be resized. 184 * 185 * Note: as the layout bounds in autosize Group depend on the Group to be already laid-out, 186 * this call will do the layout of the Group if necessary. 187 * 188 * @param height This parameter is ignored by Group 189 * @return The layout bounds width 190 */ 191 @Override 192 public double prefWidth(double height) { 193 if (isAutoSizeChildren()) { 194 layout(); 195 } 196 final double result = getLayoutBounds().getWidth(); 197 return Double.isNaN(result) || result < 0 ? 0 : result; 198 } 199 200 /** 201 * Group defines the preferred height as simply being the height of its layout bounds, which 202 * in turn is simply the sum of the positions and heights of all of its children. That is, 203 * the preferred height is the one that it is at, because a Group cannot be resized. 204 * 205 * Note: as the layout bounds in autosize Group depend on the Group to be already laid-out, 206 * this call will do the layout of the Group if necessary. 207 * 208 * @param width This parameter is ignored by Group 209 * @return The layout bounds height 210 */ 211 @Override 212 public double prefHeight(double width) { 213 if (isAutoSizeChildren()) { 214 layout(); 215 } 216 final double result = getLayoutBounds().getHeight(); 217 return Double.isNaN(result) || result < 0 ? 0 : result; 218 } 219 220 221 @Override 222 public double minHeight(double width) { 223 return prefHeight(width); 224 } 225 226 @Override 227 public double minWidth(double height) { 228 return prefWidth(height); 229 } 230 231 /** 232 * Group implements layoutChildren such that each child is resized to its preferred 233 * size, if the child is resizable. Non-resizable children are simply left alone. 234 * If {@link #autoSizeChildren} is false, then Group does nothing in this method. 235 */ 236 @Override protected void layoutChildren() { 237 if (isAutoSizeChildren()) { 238 super.layoutChildren(); 239 } 240 } 241 }