1010/**
1111 * A group of of Bindings that are disposed together.
1212 * <p>
13- * All methods of this class are thread-safe.
13+ * All methods of this class must be called on JavaFX Thread
1414 */
1515public final class CompositeBinding {
1616
1717 private Set <Binding > bindings ;
18+ private Set <CompositeBinding > compBindings ;
1819 private boolean disposedInd ;
1920
2021 public CompositeBinding () {}
@@ -24,16 +25,40 @@ public CompositeBinding(final Binding... bindings) {
2425 }
2526
2627 public void invalidate () {
27- bindings .forEach (Binding ::invalidate );
28+ if (bindings != null ) {
29+ bindings .forEach (Binding ::invalidate );
30+ }
31+ if (compBindings != null ) {
32+ compBindings .forEach (CompositeBinding ::invalidate );
33+ }
2834 }
2935 public boolean isDisposed () {
3036 return disposedInd ;
3137 }
3238
39+ /**
40+ * Adds a new {@link CompositeBinding} to this {@code CompositeBinding} if the
41+ * {@code CompositeBinding} is not yet disposed. If the {@code CompositeBinding} <em>is</em>
42+ * disposed, {@code add} will indicate this by explicitly disposing the new {@code CompositeBinding} as
43+ * well.
44+ *
45+ * @param b the {@link Subscription} to add
46+ */
47+ public void add (final CompositeBinding b ) {
48+ if (!disposedInd ) {
49+ if (compBindings == null ) {
50+ compBindings = new HashSet <>(4 );
51+ }
52+ compBindings .add (b );
53+ return ;
54+ }
55+ b .dispose ();
56+ }
57+
3358 /**
3459 * Adds a new {@link Binding} to this {@code CompositeBinding} if the
3560 * {@code CompositeBinding} is not yet disposedInd. If the {@code CompositeBinding} <em>is</em>
36- * disposed, {@code add} will indicate this by explicitly unsubscribing the new {@code Subscription } as
61+ * disposed, {@code add} will indicate this by explicitly disposing the new {@code Binding } as
3762 * well.
3863 *
3964 * @param b the {@link Subscription} to add
@@ -49,6 +74,26 @@ public void add(final Binding b) {
4974 b .dispose ();
5075 }
5176
77+ /**
78+ * Removes a {@link CompositeBinding} from this {@code CompositeBinding}, and disposes the
79+ * {@link CompositeBinding}.
80+ *
81+ * @param b the {@link CompositeBinding} to remove
82+ */
83+ public void remove (final CompositeBinding b ) {
84+ if (!disposedInd ) {
85+ boolean unsubscribe = false ;
86+ if (compBindings == null ) {
87+ return ;
88+ }
89+ unsubscribe = compBindings .remove (b );
90+ if (unsubscribe ) {
91+ // if we removed successfully we then need to call dispose on it
92+ b .dispose ();
93+ }
94+ }
95+ }
96+
5297 /**
5398 * Removes a {@link Binding} from this {@code CompositeBinding}, and disposes the
5499 * {@link Binding}.
@@ -69,21 +114,29 @@ public void remove(final Binding b) {
69114 }
70115 }
71116
117+
72118 /**
73119 * Disposes any bindings that are currently part of this {@code CompositeBinding} and remove
74120 * them from the {@code CompositeBinding} so that the {@code CompositeBinding} is empty and
75121 * able to manage new bindings.
76122 */
77123 public void clear () {
78124 if (!disposedInd ) {
79- Collection <Binding > unsubscribe = null ;
80- if (bindings == null ) {
125+ Collection <Binding > unsubscribe1 = null ;
126+ Collection <CompositeBinding > unsubscribe2 = null ;
127+ if (bindings == null && compBindings == null ) {
81128 return ;
82- } else {
83- unsubscribe = bindings ;
129+ }
130+ if (bindings != null ) {
131+ unsubscribe1 = bindings ;
84132 bindings = null ;
133+ unsubscribeFromAll (unsubscribe1 );
134+ }
135+ if (compBindings != null ) {
136+ unsubscribe2 = compBindings ;
137+ compBindings = null ;
138+ unsubscribeFromAllComposite (unsubscribe2 );
85139 }
86- unsubscribeFromAll (unsubscribe );
87140 }
88141 }
89142
@@ -95,15 +148,36 @@ public void clear() {
95148 */
96149 public void dispose () {
97150 if (!disposedInd ) {
98- Collection <Binding > unsubscribe = null ;
151+ Collection <Binding > unsubscribe1 = null ;
152+ Collection <CompositeBinding > unsubscribe2 = null ;
99153 disposedInd = true ;
100- unsubscribe = bindings ;
154+ unsubscribe1 = bindings ;
155+ unsubscribe2 = compBindings ;
101156 bindings = null ;
157+ compBindings = null ;
102158 // we will only get here once
103- unsubscribeFromAll (unsubscribe );
159+ unsubscribeFromAll (unsubscribe1 );
160+ unsubscribeFromAllComposite (unsubscribe2 );
104161 }
105162 }
106163
164+ private static void unsubscribeFromAllComposite (Collection <CompositeBinding > bindings ) {
165+ if (bindings == null ) {
166+ return ;
167+ }
168+ List <Throwable > es = null ;
169+ for (CompositeBinding b : bindings ) {
170+ try {
171+ b .dispose ();
172+ } catch (Throwable e ) {
173+ if (es == null ) {
174+ es = new ArrayList <>();
175+ }
176+ es .add (e );
177+ }
178+ }
179+ Exceptions .throwIfAny (es );
180+ }
107181 private static void unsubscribeFromAll (Collection <Binding > bindings ) {
108182 if (bindings == null ) {
109183 return ;
@@ -129,10 +203,7 @@ private static void unsubscribeFromAll(Collection<Binding> bindings) {
129203 * @since 1.0.7
130204 */
131205 public boolean hasSubscriptions () {
132- if (!disposedInd ) {
133- return bindings != null && !bindings .isEmpty ();
134- }
135- return false ;
206+ return !disposedInd && ((bindings != null && !bindings .isEmpty ()) || (compBindings != null && !compBindings .isEmpty ()));
136207 }
137208}
138209
0 commit comments