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 com.sun.javafx.scene.control.skin;
27
28 import java.time.LocalDate;
29 import java.time.YearMonth;
30 import java.time.chrono.HijrahChronology;
31 import java.time.format.DateTimeParseException;
32
33 import javafx.beans.InvalidationListener;
34 import javafx.beans.Observable;
35 import javafx.event.ActionEvent;
36 import javafx.geometry.Insets;
37 import javafx.scene.Node;
38 import javafx.scene.control.DatePicker;
39 import javafx.scene.control.TextField;
40 import javafx.util.StringConverter;
41
42 import com.sun.javafx.scene.control.behavior.DatePickerBehavior;
43
44 public class DatePickerSkin extends ComboBoxPopupControl<LocalDate> {
45
46 private DatePicker datePicker;
47 private TextField displayNode;
48 private DatePickerContent datePickerContent;
49
50 public DatePickerSkin(final DatePicker datePicker) {
51 super(datePicker, new DatePickerBehavior(datePicker));
52
53 this.datePicker = datePicker;
54
55 // The "arrow" is actually a rectangular svg icon resembling a calendar.
56 // Round the size of the icon to whole integers to get sharp edges.
57 arrow.paddingProperty().addListener(new InvalidationListener() {
58 // This boolean protects against unwanted recursion.
59 private boolean rounding = false;
60 @Override public void invalidated(Observable observable) {
61 if (!rounding) {
62 Insets padding = arrow.getPadding();
63 Insets rounded = new Insets(Math.round(padding.getTop()), Math.round(padding.getRight()),
64 Math.round(padding.getBottom()), Math.round(padding.getLeft()));
65 if (!rounded.equals(padding)) {
66 rounding = true;
67 arrow.setPadding(rounded);
68 rounding = false;
69 }
70 }
71 }
72 });
73
74 registerChangeListener(datePicker.chronologyProperty(), "CHRONOLOGY");
75 registerChangeListener(datePicker.converterProperty(), "CONVERTER");
76 registerChangeListener(datePicker.dayCellFactoryProperty(), "DAY_CELL_FACTORY");
77 registerChangeListener(datePicker.showWeekNumbersProperty(), "SHOW_WEEK_NUMBERS");
78 registerChangeListener(datePicker.valueProperty(), "VALUE");
79 }
80
81 @Override public Node getPopupContent() {
82 if (datePickerContent == null) {
83 if (datePicker.getChronology() instanceof HijrahChronology) {
84 datePickerContent = new DatePickerHijrahContent(datePicker);
85 } else {
86 datePickerContent = new DatePickerContent(datePicker);
87 }
88 }
89
90 return datePickerContent;
91 }
92
93 @Override protected double computeMinWidth(double height,
94 double topInset, double rightInset,
95 double bottomInset, double leftInset) {
96 return 50;
97 }
98
99 @Override protected void focusLost() {
100 // do nothing
101 }
102
103
104 @Override public void show() {
105 super.show();
106 datePickerContent.clearFocus();
107 }
108
109 @Override protected void handleControlPropertyChanged(String p) {
110
111 if ("CHRONOLOGY".equals(p) ||
112 "DAY_CELL_FACTORY".equals(p)) {
113
114 updateDisplayNode();
115 // if (datePickerContent != null) {
116 // datePickerContent.refresh();
117 // }
118 datePickerContent = null;
119 popup = null;
120 } else if ("CONVERTER".equals(p)) {
121 updateDisplayNode();
122 } else if ("EDITOR".equals(p)) {
123 getEditableInputNode();
124 } else if ("SHOWING".equals(p)) {
125 if (datePicker.isShowing()) {
126 if (datePickerContent != null) {
127 LocalDate date = datePicker.getValue();
128 datePickerContent.displayedYearMonthProperty().set((date != null) ? YearMonth.from(date) : YearMonth.now());
129 datePickerContent.updateValues();
130 }
131 show();
132 } else {
133 hide();
134 }
135 } else if ("SHOW_WEEK_NUMBERS".equals(p)) {
136 if (datePickerContent != null) {
137 datePickerContent.updateGrid();
138 datePickerContent.updateWeeknumberDateCells();
139 }
140 } else if ("VALUE".equals(p)) {
141 updateDisplayNode();
142 if (datePickerContent != null) {
143 LocalDate date = datePicker.getValue();
144 datePickerContent.displayedYearMonthProperty().set((date != null) ? YearMonth.from(date) : YearMonth.now());
145 datePickerContent.updateValues();
146 }
147 datePicker.fireEvent(new ActionEvent());
148 } else {
149 super.handleControlPropertyChanged(p);
150 }
151 }
152
153 @Override protected TextField getEditor() {
154 // Use getSkinnable() here because this method is called from
155 // the super constructor before datePicker is initialized.
156 return ((DatePicker)getSkinnable()).getEditor();
157 }
158
159 @Override protected StringConverter<LocalDate> getConverter() {
160 return ((DatePicker)getSkinnable()).getConverter();
161 }
162
163 @Override public Node getDisplayNode() {
164 if (displayNode == null) {
165 displayNode = getEditableInputNode();
166 displayNode.getStyleClass().add("date-picker-display-node");
167 updateDisplayNode();
168 }
169 displayNode.setEditable(datePicker.isEditable());
170
171 return displayNode;
172 }
173
174 public void syncWithAutoUpdate() {
175 if (!getPopup().isShowing() && datePicker.isShowing()) {
176 // Popup was dismissed. Maybe user clicked outside or typed ESCAPE.
177 // Make sure DatePicker button is in sync.
178 datePicker.hide();
179 }
180 }
181 }
|
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.control.skin;
27
28 import java.time.LocalDate;
29 import java.time.YearMonth;
30 import java.time.chrono.HijrahChronology;
31
32 import com.sun.javafx.scene.control.DatePickerContent;
33 import com.sun.javafx.scene.control.DatePickerHijrahContent;
34 import com.sun.javafx.scene.control.behavior.BehaviorBase;
35 import com.sun.javafx.scene.control.behavior.ComboBoxBaseBehavior;
36 import javafx.beans.InvalidationListener;
37 import javafx.beans.Observable;
38 import javafx.event.ActionEvent;
39 import javafx.geometry.Insets;
40 import javafx.scene.Node;
41 import javafx.scene.control.Button;
42 import javafx.scene.control.Control;
43 import javafx.scene.control.DatePicker;
44 import javafx.scene.control.TextField;
45 import javafx.util.StringConverter;
46
47 import com.sun.javafx.scene.control.behavior.DatePickerBehavior;
48
49 /**
50 * Default skin implementation for the {@link DatePicker} control.
51 *
52 * @see DatePicker
53 * @since 9
54 */
55 public class DatePickerSkin extends ComboBoxPopupControl<LocalDate> {
56
57 /***************************************************************************
58 * *
59 * Private fields *
60 * *
61 **************************************************************************/
62
63 private final DatePicker datePicker;
64 private TextField displayNode;
65 private DatePickerContent datePickerContent;
66
67 private final DatePickerBehavior behavior;
68
69
70
71 /***************************************************************************
72 * *
73 * Constructors *
74 * *
75 **************************************************************************/
76
77 /**
78 * Creates a new DatePickerSkin instance, installing the necessary child
79 * nodes into the Control {@link Control#getChildren() children} list, as
80 * well as the necessary input mappings for handling key, mouse, etc events.
81 *
82 * @param control The control that this skin should be installed onto.
83 */
84 public DatePickerSkin(final DatePicker control) {
85 super(control);
86
87 this.datePicker = control;
88
89 // install default input map for the control
90 this.behavior = new DatePickerBehavior(control);
91 // control.setInputMap(behavior.getInputMap());
92
93 // The "arrow" is actually a rectangular svg icon resembling a calendar.
94 // Round the size of the icon to whole integers to get sharp edges.
95 arrow.paddingProperty().addListener(new InvalidationListener() {
96 // This boolean protects against unwanted recursion.
97 private boolean rounding = false;
98 @Override public void invalidated(Observable observable) {
99 if (!rounding) {
100 Insets padding = arrow.getPadding();
101 Insets rounded = new Insets(Math.round(padding.getTop()), Math.round(padding.getRight()),
102 Math.round(padding.getBottom()), Math.round(padding.getLeft()));
103 if (!rounded.equals(padding)) {
104 rounding = true;
105 arrow.setPadding(rounded);
106 rounding = false;
107 }
108 }
109 }
110 });
111
112 registerChangeListener(control.chronologyProperty(), e -> {
113 updateDisplayNode();
114 datePickerContent = null;
115 popup = null;
116 });
117 registerChangeListener(control.converterProperty(), e -> updateDisplayNode());
118 registerChangeListener(control.dayCellFactoryProperty(), e -> {
119 updateDisplayNode();
120 datePickerContent = null;
121 popup = null;
122 });
123 registerChangeListener(control.showWeekNumbersProperty(), e -> {
124 if (datePickerContent != null) {
125 datePickerContent.updateGrid();
126 datePickerContent.updateWeeknumberDateCells();
127 }
128 });
129 registerChangeListener(control.valueProperty(), e -> {
130 updateDisplayNode();
131 if (datePickerContent != null) {
132 LocalDate date = control.getValue();
133 datePickerContent.displayedYearMonthProperty().set((date != null) ? YearMonth.from(date) : YearMonth.now());
134 datePickerContent.updateValues();
135 }
136 control.fireEvent(new ActionEvent());
137 });
138 registerChangeListener(control.showingProperty(), e -> {
139 if (control.isShowing()) {
140 if (datePickerContent != null) {
141 LocalDate date = control.getValue();
142 datePickerContent.displayedYearMonthProperty().set((date != null) ? YearMonth.from(date) : YearMonth.now());
143 datePickerContent.updateValues();
144 }
145 show();
146 } else {
147 hide();
148 }
149 });
150 }
151
152
153
154 /***************************************************************************
155 * *
156 * Public API *
157 * *
158 **************************************************************************/
159
160 /** {@inheritDoc} */
161 @Override public void dispose() {
162 super.dispose();
163
164 if (behavior != null) {
165 behavior.dispose();
166 }
167 }
168
169 /** {@inheritDoc} */
170 @Override public Node getPopupContent() {
171 if (datePickerContent == null) {
172 if (datePicker.getChronology() instanceof HijrahChronology) {
173 datePickerContent = new DatePickerHijrahContent(datePicker);
174 } else {
175 datePickerContent = new DatePickerContent(datePicker);
176 }
177 }
178
179 return datePickerContent;
180 }
181
182 /** {@inheritDoc} */
183 @Override protected double computeMinWidth(double height,
184 double topInset, double rightInset,
185 double bottomInset, double leftInset) {
186 return 50;
187 }
188
189 /** {@inheritDoc} */
190 @Override public void show() {
191 super.show();
192 datePickerContent.clearFocus();
193 }
194
195 /** {@inheritDoc} */
196 @Override protected TextField getEditor() {
197 // Use getSkinnable() here because this method is called from
198 // the super constructor before datePicker is initialized.
199 return ((DatePicker)getSkinnable()).getEditor();
200 }
201
202 /** {@inheritDoc} */
203 @Override protected StringConverter<LocalDate> getConverter() {
204 return ((DatePicker)getSkinnable()).getConverter();
205 }
206
207 /** {@inheritDoc} */
208 @Override public Node getDisplayNode() {
209 if (displayNode == null) {
210 displayNode = getEditableInputNode();
211 displayNode.getStyleClass().add("date-picker-display-node");
212 updateDisplayNode();
213 }
214 displayNode.setEditable(datePicker.isEditable());
215
216 return displayNode;
217 }
218
219
220
221 /***************************************************************************
222 * *
223 * Private implementation *
224 * *
225 **************************************************************************/
226
227 /** {@inheritDoc} */
228 @Override void focusLost() {
229 // do nothing
230 }
231
232 /** {@inheritDoc} */
233 @Override ComboBoxBaseBehavior getBehavior() {
234 return behavior;
235 }
236 }
|