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);
|