|
1 /* |
|
2 * CDDL HEADER START |
|
3 * |
|
4 * The contents of this file are subject to the terms of the |
|
5 * Common Development and Distribution License (the "License"). |
|
6 * You may not use this file except in compliance with the License. |
|
7 * |
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 * or http://www.opensolaris.org/os/licensing. |
|
10 * See the License for the specific language governing permissions |
|
11 * and limitations under the License. |
|
12 * |
|
13 * When distributing Covered Code, include this CDDL HEADER in each |
|
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 * If applicable, add the following below this CDDL HEADER, with the |
|
16 * fields enclosed by brackets "[]" replaced with your own identifying |
|
17 * information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 * |
|
19 * CDDL HEADER END |
|
20 */ |
|
21 |
|
22 /* |
|
23 * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. |
|
24 */ |
|
25 |
|
26 package com.oracle.solaris.vp.util.misc.property; |
|
27 |
|
28 import javax.swing.event.*; |
|
29 import com.oracle.solaris.vp.util.misc.ObjectUtil; |
|
30 |
|
31 /** |
|
32 * The {@code PropertySynchronizer} class provides a base class for |
|
33 * synchronization between a {@link MutableProperty} and some other {@link |
|
34 * #getObject object}, so that changes in one will automatically be reflected in |
|
35 * the other. Besides implementing the abstract methods, subclasses should call |
|
36 * {@link #objectChanged} whenever that object changes. |
|
37 */ |
|
38 public abstract class PropertySynchronizer<T, O> { |
|
39 // |
|
40 // Instance data |
|
41 // |
|
42 |
|
43 private MutableProperty<T> property; |
|
44 private O object; |
|
45 private boolean syncObjectChanges = true; |
|
46 private boolean syncPropertyChanges = true; |
|
47 |
|
48 private ChangeListener propListener = |
|
49 new ChangeListener() { |
|
50 @Override |
|
51 public void stateChanged(ChangeEvent e) { |
|
52 propertyChanged(); |
|
53 } |
|
54 }; |
|
55 |
|
56 // |
|
57 // Constructors |
|
58 // |
|
59 |
|
60 /** |
|
61 * Constructs a {@code PropertySynchronizer} and {@link #init initializes} |
|
62 * it. |
|
63 * |
|
64 * @param property |
|
65 * the property to synchronize with the secondary object |
|
66 * |
|
67 * @param object |
|
68 * the secondary object to synchronize with the property |
|
69 * |
|
70 * @param initFromProp |
|
71 * if {@code true}, initial synchronization will be from |
|
72 * the property to the secondary object; if {@code false}, |
|
73 * initial synchronization will go in the other direction |
|
74 */ |
|
75 public PropertySynchronizer(MutableProperty<T> property, O object, |
|
76 boolean initFromProp) { |
|
77 |
|
78 this.property = property; |
|
79 this.object = object; |
|
80 property.addChangeListener(propListener); |
|
81 |
|
82 init(initFromProp); |
|
83 } |
|
84 |
|
85 /** |
|
86 * Constructs a {@code PropertySynchronizer} with initial synchronization |
|
87 * from the property to the secondary object. |
|
88 */ |
|
89 public PropertySynchronizer(MutableProperty<T> property, O object) { |
|
90 this(property, object, true); |
|
91 } |
|
92 |
|
93 // |
|
94 // PropertySynchronizer methods |
|
95 // |
|
96 |
|
97 /** |
|
98 * Removes the {@code ChangeListener} that keeps the secondary object |
|
99 * up-to-date with changes in the {@link MutableProperty}. This method |
|
100 * should be overridden to additionally remove any listener that keeps the |
|
101 * {@link MutableProperty} up-to-date with changes in the secondary object. |
|
102 */ |
|
103 public void desynchronize() { |
|
104 property.removeChangeListener(propListener); |
|
105 } |
|
106 |
|
107 /** |
|
108 * Indicates whether the {@link #getProperty property} differs from the |
|
109 * {@link #getObject secondary object}. |
|
110 * <p/> |
|
111 * This default implementation compares the property's value with the |
|
112 * secondary object's {@link #getValue value}. Subclasses may wish to |
|
113 * compare other attributes. |
|
114 */ |
|
115 protected boolean differ() { |
|
116 return !ObjectUtil.equals(getValue(), property.getValue()); |
|
117 } |
|
118 |
|
119 /** |
|
120 * Initializes this {@code PropertySynchronizer}, calling {@link |
|
121 * #propertyChanged} if {@code initFromProp} is {@code true}, or {@link |
|
122 * #objectChanged} if {@code initFromProp} is {@code false}. |
|
123 */ |
|
124 public void init(boolean initFromProp) { |
|
125 if (initFromProp) { |
|
126 propertyChanged(); |
|
127 } else { |
|
128 objectChanged(); |
|
129 } |
|
130 } |
|
131 |
|
132 public O getObject() { |
|
133 return object; |
|
134 } |
|
135 |
|
136 public MutableProperty<T> getProperty() { |
|
137 return property; |
|
138 } |
|
139 |
|
140 /** |
|
141 * Gets whether changes in the {@link #getObject secondary object} |
|
142 * are propagated to the {@link #getProperty property}. |
|
143 */ |
|
144 protected boolean getSyncObjectChanges() { |
|
145 return syncObjectChanges; |
|
146 } |
|
147 |
|
148 /** |
|
149 * Gets whether changes in the {@link #getProperty property} are propagated |
|
150 * to the {@link #getObject secondary object}. |
|
151 */ |
|
152 protected boolean getSyncPropertyChanges() { |
|
153 return syncPropertyChanges; |
|
154 } |
|
155 |
|
156 /** |
|
157 * Gets the value of the {@link #getObject secondary object}. |
|
158 */ |
|
159 protected abstract T getValue(); |
|
160 |
|
161 /** |
|
162 * {@link #syncObjectChanges Updates} the {@link #getProperty property} with |
|
163 * the value of the {@link #getObject secondary object}, if they {@link |
|
164 * #differ differ}. This method should be called by subclasses when the |
|
165 * secondary object changes. |
|
166 */ |
|
167 protected void objectChanged() { |
|
168 if (syncObjectChanges) { |
|
169 if (differ()) { |
|
170 boolean saved = getSyncPropertyChanges(); |
|
171 // Disable property change syncs to avoid loops |
|
172 setSyncPropertyChanges(false); |
|
173 try { |
|
174 syncObjectChanges(); |
|
175 } finally { |
|
176 setSyncPropertyChanges(saved); |
|
177 } |
|
178 } |
|
179 } |
|
180 } |
|
181 |
|
182 /** |
|
183 * {@link #syncPropertyChanges Updates} the {@link #getObject secondary |
|
184 * object} with the value of the {@link #getProperty property}, if they |
|
185 * {@link #differ differ}. This method is called whenever the property |
|
186 * changes. |
|
187 */ |
|
188 protected void propertyChanged() { |
|
189 if (syncPropertyChanges) { |
|
190 if (differ()) { |
|
191 boolean saved = getSyncObjectChanges(); |
|
192 // Disable object change syncs to avoid loops |
|
193 setSyncObjectChanges(false); |
|
194 try { |
|
195 syncPropertyChanges(); |
|
196 } finally { |
|
197 setSyncObjectChanges(saved); |
|
198 } |
|
199 } |
|
200 } |
|
201 } |
|
202 |
|
203 /** |
|
204 * Sets whether changes in the {@link #getObject secondary object} |
|
205 * are propagated to the {@link #getProperty property}. |
|
206 */ |
|
207 protected void setSyncObjectChanges(boolean syncObjectChanges) { |
|
208 if (this.syncObjectChanges != syncObjectChanges) { |
|
209 this.syncObjectChanges = syncObjectChanges; |
|
210 } |
|
211 } |
|
212 |
|
213 /** |
|
214 * Sets whether changes in the {@link #getProperty property} |
|
215 * are propagated to the {@link #getObject secondary object}. |
|
216 */ |
|
217 protected void setSyncPropertyChanges(boolean syncPropertyChanges) { |
|
218 if (this.syncPropertyChanges != syncPropertyChanges) { |
|
219 this.syncPropertyChanges = syncPropertyChanges; |
|
220 } |
|
221 } |
|
222 |
|
223 /** |
|
224 * Sets the value in the {@link #getObject secondary object}. |
|
225 */ |
|
226 protected abstract void setValue(T value); |
|
227 |
|
228 /** |
|
229 * Does the actual work of propagating changes in the {@code #getObject |
|
230 * secondary object} to the {@link #getProperty property}. Called by {@link |
|
231 * #objectChanged} after verifing that the two {@link #differ differ} and |
|
232 * that such changes {@link #getSyncObjectChanges should be propagated}. |
|
233 * <p/> |
|
234 * This default implementation sets the {@link #getValue value} of the |
|
235 * secondary object in the property. |
|
236 */ |
|
237 protected void syncObjectChanges() { |
|
238 T value = getValue(); |
|
239 property.setValue(value); |
|
240 } |
|
241 |
|
242 /** |
|
243 * Does the actual work of propagating changes in the {@link #getProperty |
|
244 * property} to the {@code #getObject secondary object}. Called by {@link |
|
245 * #propertyChanged} after verifing that the two {@link #differ differ} and |
|
246 * that such changes {@link #getSyncPropertyChanges should be propagated}. |
|
247 * <p/> |
|
248 * This default implementation {@link #setValue sets} the value of the |
|
249 * property in the secondary object. |
|
250 */ |
|
251 protected void syncPropertyChanges() { |
|
252 T value = getProperty().getValue(); |
|
253 setValue(value); |
|
254 } |
|
255 } |