1
1
package org .codefx .libfx .nesting .property ;
2
2
3
3
import java .util .Objects ;
4
+ import java .util .Optional ;
5
+ import java .util .function .Supplier ;
4
6
5
7
import javafx .beans .property .Property ;
6
8
7
9
import org .codefx .libfx .nesting .Nesting ;
10
+ import org .codefx .libfx .nesting .property .InnerObservableMissingBehavior .WhenInnerObservableGoesMissing ;
11
+ import org .codefx .libfx .nesting .property .InnerObservableMissingBehavior .WhenInnerObservableMissingOnUpdate ;
8
12
9
13
/**
10
14
* Abstract superclass to nested property builders. Collects common builder settings; e.g. for the new property's
11
15
* {@link Property#getBean() bean} and {@link Property#getName() name}.
12
16
*
17
+ * @param <T>
18
+ * the most concrete type of the value wrapped by the property which will be built
13
19
* @param <O>
14
20
* the type of the nesting hierarchy's inner observable (which is a {@link Property})
15
21
* @param <P>
16
22
* the type of {@link Property} which will be built
23
+ * @param <B>
24
+ * the most concrete type of this builder (used for fluent API)
17
25
*/
18
- abstract class AbstractNestedPropertyBuilder <O extends Property <?>, P extends NestedProperty <?>> {
26
+ abstract class AbstractNestedPropertyBuilder <T , O extends Property <?>, P extends NestedProperty <?>, B extends AbstractNestedPropertyBuilder < T , O , P , B >> {
19
27
20
28
// #begin PROPERTIES
21
29
@@ -24,6 +32,11 @@ abstract class AbstractNestedPropertyBuilder<O extends Property<?>, P extends Ne
24
32
*/
25
33
private final Nesting <O > nesting ;
26
34
35
+ /**
36
+ * The behavior for the case that the inner observable is missing.
37
+ */
38
+ private final MutableInnerObservableMissingBehavior <T > innerObservableMissingBehavior ;
39
+
27
40
/**
28
41
* The property's future {@link Property#getBean() bean}.
29
42
*/
@@ -47,6 +60,7 @@ abstract class AbstractNestedPropertyBuilder<O extends Property<?>, P extends Ne
47
60
protected AbstractNestedPropertyBuilder (Nesting <O > nesting ) {
48
61
Objects .requireNonNull (nesting , "The argument 'nesting' must not be null." );
49
62
this .nesting = nesting ;
63
+ this .innerObservableMissingBehavior = new MutableInnerObservableMissingBehavior <>();
50
64
}
51
65
52
66
//#end CONSTRUCTOR
@@ -63,76 +77,236 @@ protected AbstractNestedPropertyBuilder(Nesting<O> nesting) {
63
77
64
78
//#end ABSTRACT METHODS
65
79
66
- // #begin ACCESSORS
80
+ // #begin MUTATORS
67
81
68
82
/**
69
- * @return the nesting which will be used for all nested properties
83
+ * Sets the property's {@link Property#getBean() bean}.
84
+ *
85
+ * @param bean
86
+ * the property's future bean
87
+ * @return this builder
70
88
*/
71
- protected final Nesting <O > getNesting () {
72
- return nesting ;
89
+ public final B setBean (Object bean ) {
90
+ Objects .requireNonNull (bean , "The argument 'bean' must not be null." );
91
+ this .bean = bean ;
92
+ return thisAsB ();
73
93
}
74
94
75
95
/**
76
- * @return the property's future {@link Property#getBean() bean}.
96
+ * Sets the property's {@link Property#getName() name}.
97
+ *
98
+ * @param name
99
+ * the property's future name
100
+ * @return this builder
77
101
*/
78
- protected final Object getBean () {
79
- return bean ;
102
+ public B setName (String name ) {
103
+ Objects .requireNonNull (name , "The argument 'name' must not be null." );
104
+ this .name = name ;
105
+ return thisAsB ();
80
106
}
81
107
82
108
/**
83
- * Sets the property's future {@link Property#getBean() bean}.
109
+ * The property will keep its value when the inner observable goes missing (see {@link NestedProperty} for details
110
+ * on this).
111
+ * <p>
112
+ * This is the default behavior.
84
113
*
85
- * @param bean
86
- * the property's future bean
114
+ * @return this builder
87
115
*/
88
- protected final void setTheBean ( Object bean ) {
89
- Objects . requireNonNull ( bean , "The argument 'bean' must not be null." );
90
- this . bean = bean ;
116
+ public B onInnerObservableMissingKeepValue ( ) {
117
+ innerObservableMissingBehavior . whenGoesMissing ( WhenInnerObservableGoesMissing . KEEP_VALUE );
118
+ return thisAsB () ;
91
119
}
92
120
93
121
/**
94
- * Sets the property's future {@link Property#getBean() bean}.
122
+ * The property will change to the default value for the wrapped type when the inner observable goes missing (see
123
+ * {@link NestedProperty} for details on this).
124
+ * <p>
125
+ * For primitive wrapping properties (e.g. {@link NestedIntegerProperty}), this will set the primitive default (e.g.
126
+ * 0); for reference wrapping properties this will be null.
95
127
*
96
- * @param bean
97
- * the property's future bean
98
128
* @return this builder
99
129
*/
100
- public AbstractNestedPropertyBuilder <O , P > setBean (Object bean ) {
101
- Objects .requireNonNull (bean , "The argument 'bean' must not be null." );
102
- this .bean = bean ;
103
- return this ;
130
+ public B onInnerObservableMissingSetDefaultValue () {
131
+ innerObservableMissingBehavior .whenGoesMissing (WhenInnerObservableGoesMissing .SET_DEFAULT_VALUE );
132
+ return thisAsB ();
104
133
}
105
134
106
135
/**
107
- * @return the property's future {@link Property#getBean() bean}.
136
+ * The property will change to the specified value when the inner observable goes missing (see
137
+ * {@link NestedProperty} for details on this).
138
+ * <p>
139
+ * This method does not accept null as a value. Call {@link #onInnerObservableMissingSetDefaultValue()} if the
140
+ * property should change to the default value for the wrapped type (e.g. 0 for {@link NestedIntegerProperty}).
141
+ *
142
+ * @param value
143
+ * the value to set
144
+ * @return this builder
108
145
*/
109
- protected final String getName () {
110
- return name ;
146
+ public B onInnerObservableMissingSetValue (T value ) {
147
+ Objects .requireNonNull (value , "The argument 'value' must not be null." );
148
+
149
+ innerObservableMissingBehavior .whenGoesMissing (WhenInnerObservableGoesMissing .SET_VALUE_FROM_SUPPLIER );
150
+ innerObservableMissingBehavior .valueForMissing (() -> value );
151
+ return thisAsB ();
111
152
}
112
153
113
154
/**
114
- * Sets the property's future {@link Property#getName() name}.
155
+ * The property will change to the value computed by the specified supplier when the inner observable goes missing
156
+ * (see {@link NestedProperty} for details on this).
157
+ * <p>
158
+ * The supplier may produce null in which case primitive wrapping properties will fall back to the type's default
159
+ * value (e.g. 0 for {@link NestedIntegerProperty}).
115
160
*
116
- * @param name
117
- * the property's future name
161
+ * @param valueSupplier
162
+ * the supplier which computes the value to set; may produce null
163
+ * @return this builder
118
164
*/
119
- protected final void setTheName (String name ) {
120
- Objects .requireNonNull (name , "The argument 'name' must not be null." );
121
- this .name = name ;
165
+ public B onInnerObservableMissingComputeValue (Supplier <T > valueSupplier ) {
166
+ Objects .requireNonNull (valueSupplier , "The argument 'valueSupplier' must not be null." );
167
+
168
+ innerObservableMissingBehavior .whenGoesMissing (WhenInnerObservableGoesMissing .SET_VALUE_FROM_SUPPLIER );
169
+ innerObservableMissingBehavior .valueForMissing (valueSupplier );
170
+ return thisAsB ();
122
171
}
123
172
124
173
/**
125
- * Sets the property's future {@link Property#getName() name}.
174
+ * The property will throw an {@link IllegalStateException} when it is updated (e.g. by calling
175
+ * {@link Property#setValue(Object) setValue} or via a binding) while the inner observable is missing (see
176
+ * {@link NestedProperty} for details on this).
177
+ * <p>
178
+ * This is the default behavior.
179
+ *
180
+ * @return this builder
181
+ */
182
+ public B onUpdateWhenInnerObservableMissingThrowException () {
183
+ innerObservableMissingBehavior .onUpdate (WhenInnerObservableMissingOnUpdate .THROW_EXCEPTION );
184
+ return thisAsB ();
185
+ }
186
+
187
+ /**
188
+ * The property will accept new values when it is updated (e.g. by calling {@link Property#setValue(Object)
189
+ * setValue} or via a binding) while the inner observable is missing (see {@link NestedProperty} for details on
190
+ * this).
191
+ * <p>
192
+ * Once the nesting changes to a new (non-missing) inner observable, the property will change to that observable's
193
+ * value.
126
194
*
127
- * @param name
128
- * the property's future name
129
195
* @return this builder
130
196
*/
131
- public AbstractNestedPropertyBuilder <O , P > setName (String name ) {
132
- setTheName (name );
133
- return this ;
197
+ public B onUpdateWhenInnerObservableMissingAcceptValues () {
198
+ innerObservableMissingBehavior
199
+ .onUpdate (WhenInnerObservableMissingOnUpdate .ACCEPT_VALUE_UNTIL_NEXT_INNER_OBSERVABLE );
200
+ return thisAsB ();
201
+ }
202
+
203
+ /**
204
+ * Performs an unchecked cast to {@code B} which
205
+ *
206
+ * @return this builder as an instance of {@code B}
207
+ */
208
+ @ SuppressWarnings ("unchecked" )
209
+ private B thisAsB () {
210
+ B thisAsB = (B ) this ;
211
+ return thisAsB ;
212
+ }
213
+
214
+ // #end MUTATORS
215
+
216
+ // #begin ACCESSORS FOR SUBCLASSES
217
+
218
+ /**
219
+ * @return the nesting which will be used for all nested properties
220
+ */
221
+ protected final Nesting <O > getNesting () {
222
+ return nesting ;
223
+ }
224
+
225
+ /**
226
+ * @return the property's {@link Property#getBean() bean}.
227
+ */
228
+ protected final Object getBean () {
229
+ return bean ;
230
+ }
231
+
232
+ /**
233
+ * @return the property's {@link Property#getBean() bean}.
234
+ */
235
+ protected final String getName () {
236
+ return name ;
237
+ }
238
+
239
+ /**
240
+ * @return the property's behavior for the case that the inner observable is missing
241
+ */
242
+ protected final InnerObservableMissingBehavior <T > getInnerObservableMissingBehavior () {
243
+ return new ImmutableInnerObservableMissingBehavior <>(innerObservableMissingBehavior );
244
+ }
245
+
246
+ //#end ACCESSORS FOR SUBCLASSES
247
+
248
+ // #begin NESTED CLASSES
249
+
250
+ private static class MutableInnerObservableMissingBehavior <T > {
251
+
252
+ private static final WhenInnerObservableGoesMissing DEFAULT_WHEN_GOES_MISSING = WhenInnerObservableGoesMissing .KEEP_VALUE ;
253
+ private static final WhenInnerObservableMissingOnUpdate DEFAULT_ON_UPDATE = WhenInnerObservableMissingOnUpdate .THROW_EXCEPTION ;
254
+
255
+ private WhenInnerObservableGoesMissing whenGoesMissing ;
256
+ private Optional <? extends Supplier <T >> valueForMissing ;
257
+ private WhenInnerObservableMissingOnUpdate onUpdate ;
258
+
259
+ public MutableInnerObservableMissingBehavior () {
260
+ this .whenGoesMissing = DEFAULT_WHEN_GOES_MISSING ;
261
+ this .valueForMissing = Optional .empty ();
262
+ this .onUpdate = DEFAULT_ON_UPDATE ;
263
+ }
264
+
265
+ public void whenGoesMissing (WhenInnerObservableGoesMissing whenGoesMissing ) {
266
+ assert whenGoesMissing != null : "The argument 'whenGoesMissing' must not be null." ;
267
+ this .whenGoesMissing = whenGoesMissing ;
268
+ }
269
+
270
+ public void valueForMissing (Supplier <T > valueForMissing ) {
271
+ this .valueForMissing = Optional .of (valueForMissing );
272
+ }
273
+
274
+ public void onUpdate (WhenInnerObservableMissingOnUpdate onUpdate ) {
275
+ assert onUpdate != null : "The argument 'onUpdate' must not be null." ;
276
+ this .onUpdate = onUpdate ;
277
+ }
278
+
279
+ }
280
+
281
+ private static class ImmutableInnerObservableMissingBehavior <T > implements InnerObservableMissingBehavior <T > {
282
+
283
+ private final WhenInnerObservableGoesMissing whenGoesMissing ;
284
+ private final Optional <? extends Supplier <T >> valueForMissing ;
285
+ private final WhenInnerObservableMissingOnUpdate onUpdate ;
286
+
287
+ public ImmutableInnerObservableMissingBehavior (MutableInnerObservableMissingBehavior <T > behavior ) {
288
+ this .whenGoesMissing = behavior .whenGoesMissing ;
289
+ this .valueForMissing = behavior .valueForMissing ;
290
+ this .onUpdate = behavior .onUpdate ;
291
+ }
292
+
293
+ @ Override
294
+ public WhenInnerObservableGoesMissing whenGoesMissing () {
295
+ return whenGoesMissing ;
296
+ }
297
+
298
+ @ Override
299
+ public Optional <? extends Supplier <T >> valueForMissing () {
300
+ return valueForMissing ;
301
+ }
302
+
303
+ @ Override
304
+ public WhenInnerObservableMissingOnUpdate onUpdate () {
305
+ return onUpdate ;
306
+ }
307
+
134
308
}
135
309
136
- //#end ACCESSORS
310
+ // #end NESTED CLASSES
137
311
138
312
}
0 commit comments