1
1
package org .codefx .libfx .nesting ;
2
2
3
+ import javafx .beans .Observable ;
3
4
import javafx .beans .property .DoubleProperty ;
4
5
import javafx .beans .property .Property ;
5
6
import javafx .beans .property .SimpleObjectProperty ;
6
7
import javafx .beans .property .StringProperty ;
8
+ import javafx .beans .value .ObservableValue ;
7
9
8
10
import org .codefx .libfx .nesting .property .NestedDoubleProperty ;
9
11
import org .codefx .libfx .nesting .property .NestedProperty ;
12
14
/**
13
15
* Demonstrates some features of the nesting API.
14
16
*/
15
- public class NestedPropertyDemo {
17
+ public class NestedDemo {
16
18
17
19
// #region ATTRIBUTES
18
20
@@ -28,7 +30,7 @@ public class NestedPropertyDemo {
28
30
/**
29
31
* Creates a new demo.
30
32
*/
31
- private NestedPropertyDemo () {
33
+ private NestedDemo () {
32
34
this .currentEmployee = new SimpleObjectProperty <>(new Employee (54000 , "Some Street" ));
33
35
}
34
36
@@ -39,8 +41,10 @@ private NestedPropertyDemo() {
39
41
* command line arguments (will not be used)
40
42
*/
41
43
public static void main (String [] args ) {
42
- NestedPropertyDemo demo = new NestedPropertyDemo ();
44
+ NestedDemo demo = new NestedDemo ();
43
45
46
+ demo .nestingCreation ();
47
+ demo .nestedListenerCreation ();
44
48
demo .nestedPropertyCreation ();
45
49
demo .nestedPropertyCreationWithBuilder ();
46
50
demo .nestedPropertyBinding ();
@@ -52,43 +56,133 @@ public static void main(String[] args) {
52
56
53
57
// #region DEMOS
54
58
59
+ /**
60
+ * Demonstrates how to create a {@link Nesting}.
61
+ */
62
+ private void nestingCreation () {
63
+ print ("NESTING CREATION" );
64
+
65
+ /*
66
+ * A 'Nesting' is the basic building block of this API. Its Javadoc explains the terminology which is used in
67
+ * these demos as well as in the rest of the documentation.
68
+ */
69
+
70
+ /*
71
+ * A 'Nesting'-instance is created in several steps, which are shown here. It can then be used to create other
72
+ * nested objects like nested properties or nested listeners. Very often the nesting itself is not needed and
73
+ * the goal is the creation of those other objects based in it. In those cases the builder methods for those
74
+ * objects (e.g. 'buildProperty') can and should be called directly. What is important in this demo method is
75
+ * that all possibilities before calling a builder method apply to all kinds of nested functionality like nested
76
+ * properties and nested listeners.
77
+ */
78
+
79
+ // all created nestings wrap an observable which contains the current employee's street name (which is a String)
80
+
81
+ // create a 'Nesting<Property<String>>' by starting on the 'currentEmployee' property,
82
+ // nest to the employee's address and then to the address' street name;
83
+ Nesting <Property <String >> withObjectProperty = Nestings .on (currentEmployee )
84
+ .nestProperty (employee -> employee .addressProperty ())
85
+ .nestProperty (address -> address .streetNameProperty ())
86
+ .buildNesting ();
87
+ print ("The 'Nesting<Property<String>>' has the value: \" " + getValueFromNesting (withObjectProperty ) + "\" " );
88
+
89
+ // now, create a 'Nesting<StringProperty>' instead; note the second nesting step which is different from above
90
+ Nesting <StringProperty > withStringProperty = Nestings .on (currentEmployee )
91
+ .nestProperty (employee -> employee .addressProperty ())
92
+ .nestStringProperty (address -> address .streetNameProperty ())
93
+ .buildNesting ();
94
+ print ("The 'Nesting<StringProperty>' has the value: \" " + getValueFromNesting (withStringProperty ) + "\" " );
95
+
96
+ // calls to 'nestProperty' can be cut short; note the first nesting step which is different from above
97
+ Nesting <StringProperty > withShortcut = Nestings .on (currentEmployee )
98
+ .nest (employee -> employee .addressProperty ())
99
+ .nestStringProperty (address -> address .streetNameProperty ())
100
+ .buildNesting ();
101
+ print ("The 'Nesting<StringProperty>' (with shortcut) has the value: \" "
102
+ + getValueFromNesting (withShortcut ) + "\" " );
103
+
104
+ // if 'employee.addressProperty' were no property but an 'ObservableValue', a 'Nesting<ObservableValue<String>'
105
+ // could also be created; note the second nesting call which differs from those above
106
+ Nesting <ObservableValue <String >> withObservableValue = Nestings .on (currentEmployee )
107
+ .nestProperty (employee -> employee .addressProperty ())
108
+ .nestObservableValue (address -> address .streetNameProperty ())
109
+ .buildNesting ();
110
+ print ("The 'Nesting<ObservableValue<String>' has the value: \" "
111
+ + getValueFromNesting (withObservableValue ) + "\" " );
112
+
113
+ // the same is true, if it were only an 'Observable'
114
+ Nesting <Observable > withObservable = Nestings .on (currentEmployee )
115
+ .nestProperty (employee -> employee .addressProperty ())
116
+ .nestObservable (address -> address .streetNameProperty ())
117
+ .buildNesting ();
118
+ print ("The 'Nesting<Observable's value can not be accessed, so let's call 'toString': \" "
119
+ + withObservable .innerObservableProperty ().getValue ().get ().toString () + "\" " );
120
+
121
+ print ();
122
+ }
123
+
124
+ /**
125
+ * Demonstrates how to create nested listener.
126
+ */
127
+ private void nestedListenerCreation () {
128
+ print ("LISTENER CREATION" );
129
+
130
+ /*
131
+ * The listener creation is similar to the nesting creation (see above) and only differs in the final call to
132
+ * 'build...'. Note that a listener can only be added if the type of the Nesting's inner observable allows it.
133
+ * This means that a 'InvalidationListener' can always be added, but a 'ChangeListener' only to an
134
+ * 'ObservableValue'.
135
+ */
136
+
137
+ // nest as above and then add a change listener
138
+ Nestings .on (currentEmployee )
139
+ .nestProperty (employee -> employee .addressProperty ())
140
+ .nestProperty (address -> address .streetNameProperty ())
141
+ .addListener ((observable , oldValue , newValue ) -> {/* do something here */ });
142
+
143
+ // an invalidation listener could even be added if 'employee.addressProperty' were only an observable
144
+ Nestings .on (currentEmployee )
145
+ .nestProperty (employee -> employee .addressProperty ())
146
+ .nestObservable (address -> address .streetNameProperty ())
147
+ .addListener (observable -> {/* do something here */ });
148
+
149
+ print ();
150
+ }
151
+
55
152
/**
56
153
* Demonstrates how to create some nested properties.
57
154
*/
58
155
private void nestedPropertyCreation () {
59
- print ("CREATION" );
156
+ print ("PROPERTY CREATION" );
60
157
61
- // all created properties wrap the current employee's street name (which is a String)
158
+ /*
159
+ * The property creation is similar to the nesting creation (see above) and only differs in the final call to
160
+ * 'build...'. Note that a property can only be created if the type of the Nesting's inner observable is also a
161
+ * 'Property'. The reason for this is that only properties allow reading and writing their value.
162
+ */
62
163
63
- // create a Property<String> by starting on the 'currentEmployee' property,
64
- // nest to the employee's address and then to the address' street name;
164
+ // nest as above but instead of creating a 'Nesting<Property<String>>', create a 'Property<String>'
65
165
Property <String > asObjectProperty = Nestings .on (currentEmployee )
66
166
.nestProperty (employee -> employee .addressProperty ())
67
167
.nestProperty (address -> address .streetNameProperty ())
68
168
.buildProperty ();
69
169
print ("The nested 'Property<String>' has the value: \" " + asObjectProperty .getValue () + "\" " );
70
170
71
- // now, create a StringProperty instead; note the second nesting step which is different from above
171
+ // now, create a ' StringProperty instead'
72
172
StringProperty asStringProperty = Nestings .on (currentEmployee )
73
173
.nestProperty (employee -> employee .addressProperty ())
74
174
.nestStringProperty (address -> address .streetNameProperty ())
75
175
.buildProperty ();
76
176
print ("The nested 'StringProperty' has the value: \" " + asStringProperty .getValue () + "\" " );
77
177
78
178
// 'buildProperty' actually returns a 'Nested...Property', which also implements the interface 'Nested'
179
+ // (its additional functionality is demonstrated further below)
79
180
NestedStringProperty asNestedStringProperty = Nestings .on (currentEmployee )
80
- .nest (employee -> employee .addressProperty ())
181
+ .nestProperty (employee -> employee .addressProperty ())
81
182
.nestStringProperty (address -> address .streetNameProperty ())
82
183
.buildProperty ();
83
184
print ("The 'NestedStringProperty' has the value: \" " + asNestedStringProperty .getValue () + "\" " );
84
185
85
- // calls to 'nestProperty' can be cut short; note the first nesting step which is different from above
86
- NestedStringProperty withShortcut = Nestings .on (currentEmployee )
87
- .nest (employee -> employee .addressProperty ())
88
- .nestStringProperty (address -> address .streetNameProperty ())
89
- .buildProperty ();
90
- print ("The 'NestedStringProperty' (with shortcut) has the value: \" " + withShortcut .getValue () + "\" " );
91
-
92
186
print ();
93
187
}
94
188
@@ -163,7 +257,7 @@ private void nestedPropertyBinding() {
163
257
}
164
258
165
259
/**
166
- * Demonstrates how a {@link NestedProperty} behaves when the inner
260
+ * Demonstrates how a {@link NestedProperty} behaves when the inner observable is missing.
167
261
*/
168
262
private void nestedPropertyBindingWithMissingInnerObservable () {
169
263
print ("NESTED PROPERTY BINDING WHEN INNER OBSERVABLE IS MISSING" );
@@ -206,10 +300,9 @@ private void additionalNestedFeatures() {
206
300
// the interface 'Nested' has a property which indicates whether the inner observable is present;
207
301
// one use would be to automatically disable a UI element which displays the property's value;
208
302
// in this case, a change listener is added which simply prints the new state
209
- currentEmployeesStreetName .innerObservablePresentProperty ()
210
- .addListener (
211
- (observable , oldValue , newValue ) -> print ("\t Inner observable present changed to \" " + newValue
212
- + "\" ." ));
303
+ currentEmployeesStreetName .innerObservablePresentProperty ().addListener (
304
+ (observable , oldValue , newValue )
305
+ -> print ("\t Inner observable present changed to \" " + newValue + "\" ." ));
213
306
214
307
print ("Set the 'currentEmployee' to null, which means that no inner observable will be present." );
215
308
Employee notNullEmployee = currentEmployee .getValue ();
@@ -251,6 +344,19 @@ private static void print(String text) {
251
344
System .out .println (text );
252
345
}
253
346
347
+ /**
348
+ * Returns the value held by the specified nesting's inner observable.
349
+ *
350
+ * @param <T>
351
+ * the type of value contained in the observable
352
+ * @param nesting
353
+ * the {@link Nesting} whose value will be returned
354
+ * @return 'nesting.innerObservableProperty().getValue().get().getValue()'
355
+ */
356
+ private static <T > T getValueFromNesting (Nesting <? extends ObservableValue <T >> nesting ) {
357
+ return nesting .innerObservableProperty ().getValue ().get ().getValue ();
358
+ }
359
+
254
360
/**
255
361
* Outputs the salary of both specified properties.
256
362
*
0 commit comments