Mercurial > projects > dwt2
comparison org.eclipse.core.databinding.beans/src/org/eclipse/core/databinding/beans/BeansObservables.d @ 95:6208d4f6a277
Added trees for databinding.beans and observable
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Tue, 21 Apr 2009 10:55:51 +0200 |
parents | |
children | b74ac5dfcc06 |
comparison
equal
deleted
inserted
replaced
94:1d37a7813832 | 95:6208d4f6a277 |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2005, 2008 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Brad Reynolds - bug 164268, 171616 | |
11 * Brad Reynolds - bug 147515 | |
12 * Matthew Hall - bug 221704 | |
13 * Thomas Kratz - bug 213787 | |
14 *******************************************************************************/ | |
15 package org.eclipse.core.databinding.beans; | |
16 | |
17 import java.beans.BeanInfo; | |
18 import java.beans.IntrospectionException; | |
19 import java.beans.Introspector; | |
20 import java.beans.PropertyDescriptor; | |
21 | |
22 import org.eclipse.core.databinding.BindingException; | |
23 import org.eclipse.core.databinding.observable.IObservable; | |
24 import org.eclipse.core.databinding.observable.Realm; | |
25 import org.eclipse.core.databinding.observable.list.IObservableList; | |
26 import org.eclipse.core.databinding.observable.map.IObservableMap; | |
27 import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory; | |
28 import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables; | |
29 import org.eclipse.core.databinding.observable.set.IObservableSet; | |
30 import org.eclipse.core.databinding.observable.value.IObservableValue; | |
31 import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator; | |
32 import org.eclipse.core.internal.databinding.beans.BeanObservableMapDecorator; | |
33 import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator; | |
34 import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator; | |
35 import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList; | |
36 import org.eclipse.core.internal.databinding.beans.JavaBeanObservableMap; | |
37 import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet; | |
38 import org.eclipse.core.internal.databinding.beans.JavaBeanObservableValue; | |
39 import org.eclipse.core.internal.databinding.beans.JavaBeanPropertyObservableMap; | |
40 import org.eclipse.core.runtime.Assert; | |
41 | |
42 /** | |
43 * A factory for creating observable objects of Java objects that conform to the | |
44 * <a href="http://java.sun.com/products/javabeans/docs/spec.html">JavaBean | |
45 * specification</a> for bound properties. | |
46 * | |
47 * @since 1.1 | |
48 * | |
49 */ | |
50 final public class BeansObservables { | |
51 | |
52 /** | |
53 * | |
54 */ | |
55 public static final bool DEBUG = true; | |
56 | |
57 /** | |
58 * Returns an observable value in the default realm tracking the current | |
59 * value of the named property of the given bean. | |
60 * | |
61 * @param bean | |
62 * the object | |
63 * @param propertyName | |
64 * the name of the property | |
65 * @return an observable value tracking the current value of the named | |
66 * property of the given bean | |
67 */ | |
68 public static IObservableValue observeValue(Object bean, String propertyName) { | |
69 return observeValue(Realm.getDefault(), bean, propertyName); | |
70 } | |
71 | |
72 /** | |
73 * Returns an observable value in the given realm tracking the current value | |
74 * of the named property of the given bean. | |
75 * | |
76 * @param realm | |
77 * the realm | |
78 * @param bean | |
79 * the object | |
80 * @param propertyName | |
81 * the name of the property | |
82 * @return an observable value tracking the current value of the named | |
83 * property of the given bean | |
84 */ | |
85 public static IObservableValue observeValue(Realm realm, Object bean, | |
86 String propertyName) { | |
87 PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(), | |
88 propertyName); | |
89 return new JavaBeanObservableValue(realm, bean, descriptor); | |
90 } | |
91 | |
92 /** | |
93 * Returns an observable map in the default realm tracking the current | |
94 * values of the named property for the beans in the given set. | |
95 * | |
96 * @param domain | |
97 * the set of bean objects | |
98 * @param beanClass | |
99 * the common base type of bean objects that may be in the set | |
100 * @param propertyName | |
101 * the name of the property | |
102 * @return an observable map tracking the current values of the named | |
103 * property for the beans in the given domain set | |
104 */ | |
105 public static IObservableMap observeMap(IObservableSet domain, | |
106 Class beanClass, String propertyName) { | |
107 PropertyDescriptor descriptor = getPropertyDescriptor(beanClass, | |
108 propertyName); | |
109 return new JavaBeanObservableMap(domain, descriptor); | |
110 } | |
111 | |
112 /** | |
113 * Returns an observable map in the given realm tracking the map-typed named | |
114 * property of the given bean object. | |
115 * | |
116 * @param realm | |
117 * the realm | |
118 * @param bean | |
119 * the bean object | |
120 * @param propertyName | |
121 * the name of the property | |
122 * @return an observable map tracking the map-typed named property of the | |
123 * given bean object | |
124 * @since 1.1 | |
125 */ | |
126 public static IObservableMap observeMap(Realm realm, Object bean, | |
127 String propertyName) { | |
128 PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(), | |
129 propertyName); | |
130 return new JavaBeanPropertyObservableMap(realm, bean, descriptor); | |
131 } | |
132 | |
133 /*package*/ static PropertyDescriptor getPropertyDescriptor(Class beanClass, | |
134 String propertyName) { | |
135 BeanInfo beanInfo; | |
136 try { | |
137 beanInfo = Introspector.getBeanInfo(beanClass); | |
138 } catch (IntrospectionException e) { | |
139 // cannot introspect, give up | |
140 return null; | |
141 } | |
142 PropertyDescriptor[] propertyDescriptors = beanInfo | |
143 .getPropertyDescriptors(); | |
144 for (int i = 0; i < propertyDescriptors.length; i++) { | |
145 PropertyDescriptor descriptor = propertyDescriptors[i]; | |
146 if (descriptor.getName().equals(propertyName)) { | |
147 return descriptor; | |
148 } | |
149 } | |
150 throw new BindingException( | |
151 "Could not find property with name " + propertyName + " in class " + beanClass); //$NON-NLS-1$ //$NON-NLS-2$ | |
152 } | |
153 | |
154 /** | |
155 * Returns an array of observable maps in the default realm tracking the | |
156 * current values of the named propertys for the beans in the given set. | |
157 * | |
158 * @param domain | |
159 * the set of objects | |
160 * @param beanClass | |
161 * the common base type of objects that may be in the set | |
162 * @param propertyNames | |
163 * the array of property names | |
164 * @return an array of observable maps tracking the current values of the | |
165 * named propertys for the beans in the given domain set | |
166 */ | |
167 public static IObservableMap[] observeMaps(IObservableSet domain, | |
168 Class beanClass, String[] propertyNames) { | |
169 IObservableMap[] result = new IObservableMap[propertyNames.length]; | |
170 for (int i = 0; i < propertyNames.length; i++) { | |
171 result[i] = observeMap(domain, beanClass, propertyNames[i]); | |
172 } | |
173 return result; | |
174 } | |
175 | |
176 /** | |
177 * Returns an observable list in the given realm tracking the | |
178 * collection-typed named property of the given bean object. The returned | |
179 * list is mutable. | |
180 * | |
181 * @param realm | |
182 * the realm | |
183 * @param bean | |
184 * the object | |
185 * @param propertyName | |
186 * the name of the collection-typed property | |
187 * @return an observable list tracking the collection-typed named property | |
188 * of the given bean object | |
189 * @see #observeList(Realm, Object, String, Class) | |
190 */ | |
191 public static IObservableList observeList(Realm realm, Object bean, | |
192 String propertyName) { | |
193 return observeList(realm, bean, propertyName, null); | |
194 } | |
195 | |
196 /** | |
197 * Returns an observable list in the given realm tracking the | |
198 * collection-typed named property of the given bean object. The returned | |
199 * list is mutable. When an item is added or removed the setter is invoked | |
200 * for the list on the parent bean to provide notification to other | |
201 * listeners via <code>PropertyChangeEvents</code>. This is done to | |
202 * provide the same behavior as is expected from arrays as specified in the | |
203 * bean spec in section 7.2. | |
204 * | |
205 * @param realm | |
206 * the realm | |
207 * @param bean | |
208 * the bean object | |
209 * @param propertyName | |
210 * the name of the property | |
211 * @param elementType | |
212 * type of the elements in the list. If <code>null</code> and | |
213 * the property is an array the type will be inferred. If | |
214 * <code>null</code> and the property type cannot be inferred | |
215 * element type will be <code>null</code>. | |
216 * @return an observable list tracking the collection-typed named property | |
217 * of the given bean object | |
218 */ | |
219 public static IObservableList observeList(Realm realm, Object bean, | |
220 String propertyName, Class elementType) { | |
221 PropertyDescriptor propertyDescriptor = getPropertyDescriptor(bean | |
222 .getClass(), propertyName); | |
223 elementType = getCollectionElementType(elementType, propertyDescriptor); | |
224 | |
225 return new JavaBeanObservableList(realm, bean, propertyDescriptor, | |
226 elementType); | |
227 } | |
228 | |
229 /** | |
230 * Returns an observable set in the given realm tracking the | |
231 * collection-typed named property of the given bean object | |
232 * | |
233 * @param realm | |
234 * the realm | |
235 * @param bean | |
236 * the bean object | |
237 * @param propertyName | |
238 * the name of the property | |
239 * @return an observable set tracking the collection-typed named property of | |
240 * the given bean object | |
241 */ | |
242 public static IObservableSet observeSet(Realm realm, Object bean, | |
243 String propertyName) { | |
244 return observeSet(realm, bean, propertyName, null); | |
245 } | |
246 | |
247 /** | |
248 * Returns a factory for creating obervable values tracking the given | |
249 * property of a particular bean object | |
250 * | |
251 * @param realm | |
252 * the realm to use | |
253 * @param propertyName | |
254 * the name of the property | |
255 * @return an observable value factory | |
256 */ | |
257 public static IObservableFactory valueFactory(final Realm realm, | |
258 final String propertyName) { | |
259 return new class() IObservableFactory { | |
260 public IObservable createObservable(Object target) { | |
261 return observeValue(realm, target, propertyName); | |
262 } | |
263 }; | |
264 } | |
265 | |
266 /** | |
267 * Returns a factory for creating obervable lists tracking the given | |
268 * property of a particular bean object | |
269 * | |
270 * @param realm | |
271 * the realm to use | |
272 * @param propertyName | |
273 * the name of the property | |
274 * @param elementType | |
275 * @return an observable list factory | |
276 */ | |
277 public static IObservableFactory listFactory(final Realm realm, | |
278 final String propertyName, final Class elementType) { | |
279 return new class() IObservableFactory { | |
280 public IObservable createObservable(Object target) { | |
281 return observeList(realm, target, propertyName, elementType); | |
282 } | |
283 }; | |
284 } | |
285 | |
286 /** | |
287 * Returns a factory for creating obervable sets tracking the given property | |
288 * of a particular bean object | |
289 * | |
290 * @param realm | |
291 * the realm to use | |
292 * @param propertyName | |
293 * the name of the property | |
294 * @return an observable set factory | |
295 */ | |
296 public static IObservableFactory setFactory(final Realm realm, | |
297 final String propertyName) { | |
298 return new class() IObservableFactory { | |
299 public IObservable createObservable(Object target) { | |
300 return observeSet(realm, target, propertyName); | |
301 } | |
302 }; | |
303 } | |
304 | |
305 /** | |
306 * Helper method for | |
307 * <code>MasterDetailObservables.detailValue(master, valueFactory(realm, | |
308 propertyName), propertyType)</code> | |
309 * | |
310 * @param realm | |
311 * @param master | |
312 * @param propertyName | |
313 * @param propertyType | |
314 * can be <code>null</code> | |
315 * @return an observable value that tracks the current value of the named | |
316 * property for the current value of the master observable value | |
317 * | |
318 * @see MasterDetailObservables | |
319 */ | |
320 public static IObservableValue observeDetailValue(Realm realm, | |
321 IObservableValue master, String propertyName, Class propertyType) { | |
322 | |
323 IObservableValue value = MasterDetailObservables.detailValue(master, | |
324 valueFactory(realm, propertyName), propertyType); | |
325 BeanObservableValueDecorator decorator = new BeanObservableValueDecorator( | |
326 value, master, getValueTypePropertyDescriptor(master, | |
327 propertyName)); | |
328 | |
329 return decorator; | |
330 } | |
331 | |
332 /** | |
333 * Helper method for | |
334 * <code>MasterDetailObservables.detailValue(master, valueFactory(realm, | |
335 * propertyName), propertyType)</code>. | |
336 * This method returns an {@link IBeanObservable} with a | |
337 * {@link PropertyDescriptor} based on the given master type and property | |
338 * name. | |
339 * | |
340 * @param realm | |
341 * the realm | |
342 * @param master | |
343 * the master observable value, for example tracking the | |
344 * selection in a list | |
345 * @param masterType | |
346 * the type of the master observable value | |
347 * @param propertyName | |
348 * the property name | |
349 * @param propertyType | |
350 * can be <code>null</code> | |
351 * @return an observable value that tracks the current value of the named | |
352 * property for the current value of the master observable value | |
353 * | |
354 * @see MasterDetailObservables | |
355 * @since 1.1 | |
356 */ | |
357 public static IObservableValue observeDetailValue(Realm realm, | |
358 IObservableValue master, Class masterType, String propertyName, Class propertyType) { | |
359 Assert.isNotNull(masterType, "masterType cannot be null"); //$NON-NLS-1$ | |
360 IObservableValue value = MasterDetailObservables.detailValue(master, | |
361 valueFactory(realm, propertyName), propertyType); | |
362 BeanObservableValueDecorator decorator = new BeanObservableValueDecorator( | |
363 value, master, getPropertyDescriptor(masterType, | |
364 propertyName)); | |
365 | |
366 return decorator; | |
367 } | |
368 | |
369 /** | |
370 * Helper method for | |
371 * <code>MasterDetailObservables.detailList(master, listFactory(realm, | |
372 propertyName, propertyType), propertyType)</code> | |
373 * | |
374 * @param realm | |
375 * @param master | |
376 * @param propertyName | |
377 * @param propertyType | |
378 * can be <code>null</code> | |
379 * @return an observable list that tracks the named property for the current | |
380 * value of the master observable value | |
381 * | |
382 * @see MasterDetailObservables | |
383 */ | |
384 public static IObservableList observeDetailList(Realm realm, | |
385 IObservableValue master, String propertyName, Class propertyType) { | |
386 IObservableList observableList = MasterDetailObservables.detailList( | |
387 master, listFactory(realm, propertyName, propertyType), | |
388 propertyType); | |
389 BeanObservableListDecorator decorator = new BeanObservableListDecorator( | |
390 observableList, master, getValueTypePropertyDescriptor(master, | |
391 propertyName)); | |
392 | |
393 return decorator; | |
394 } | |
395 | |
396 /** | |
397 * Helper method for | |
398 * <code>MasterDetailObservables.detailSet(master, setFactory(realm, | |
399 propertyName), propertyType)</code> | |
400 * | |
401 * @param realm | |
402 * @param master | |
403 * @param propertyName | |
404 * @param propertyType | |
405 * can be <code>null</code> | |
406 * @return an observable set that tracks the named property for the current | |
407 * value of the master observable value | |
408 * | |
409 * @see MasterDetailObservables | |
410 */ | |
411 public static IObservableSet observeDetailSet(Realm realm, | |
412 IObservableValue master, String propertyName, Class propertyType) { | |
413 | |
414 IObservableSet observableSet = MasterDetailObservables.detailSet( | |
415 master, setFactory(realm, propertyName, propertyType), | |
416 propertyType); | |
417 BeanObservableSetDecorator decorator = new BeanObservableSetDecorator( | |
418 observableSet, master, getValueTypePropertyDescriptor(master, | |
419 propertyName)); | |
420 | |
421 return decorator; | |
422 } | |
423 | |
424 /** | |
425 * Helper method for | |
426 * <code>MasterDetailObservables.detailMap(master, mapFactory(realm, propertyName))</code> | |
427 * | |
428 * @param realm | |
429 * the realm | |
430 * @param master | |
431 * @param propertyName | |
432 * @return an observable map that tracks the map-type named property for the | |
433 * current value of the master observable value. | |
434 * @since 1.1 | |
435 */ | |
436 public static IObservableMap observeDetailMap(Realm realm, | |
437 IObservableValue master, String propertyName) { | |
438 IObservableMap observableMap = MasterDetailObservables.detailMap( | |
439 master, mapPropertyFactory(realm, propertyName)); | |
440 BeanObservableMapDecorator decorator = new BeanObservableMapDecorator( | |
441 observableMap, master, getValueTypePropertyDescriptor(master, | |
442 propertyName)); | |
443 return decorator; | |
444 } | |
445 | |
446 /** | |
447 * @param realm | |
448 * @param bean | |
449 * @param propertyName | |
450 * @param elementType | |
451 * can be <code>null</code> | |
452 * @return an observable set that tracks the current value of the named | |
453 * property for given bean object | |
454 */ | |
455 public static IObservableSet observeSet(Realm realm, Object bean, | |
456 String propertyName, Class elementType) { | |
457 PropertyDescriptor propertyDescriptor = getPropertyDescriptor(bean | |
458 .getClass(), propertyName); | |
459 elementType = getCollectionElementType(elementType, propertyDescriptor); | |
460 | |
461 return new JavaBeanObservableSet(realm, bean, propertyDescriptor, | |
462 elementType); | |
463 } | |
464 | |
465 /** | |
466 * @param realm | |
467 * @param propertyName | |
468 * @param elementType | |
469 * can be <code>null</code> | |
470 * @return an observable set factory for creating observable sets | |
471 */ | |
472 public static IObservableFactory setFactory(final Realm realm, | |
473 final String propertyName, final Class elementType) { | |
474 return new class() IObservableFactory { | |
475 public IObservable createObservable(Object target) { | |
476 return observeSet(realm, target, propertyName, elementType); | |
477 } | |
478 }; | |
479 } | |
480 | |
481 /** | |
482 * Returns a factory for creating an observable map. The factory, when | |
483 * provided with an {@link IObservableSet}, will create an | |
484 * {@link IObservableMap} in the same realm as the underlying set that | |
485 * tracks the current values of the named property for the beans in the | |
486 * given set. | |
487 * | |
488 * @param beanClass | |
489 * the common base type of bean objects that may be in the set | |
490 * @param propertyName | |
491 * the name of the property | |
492 * @return a factory for creating {@link IObservableMap} objects | |
493 * | |
494 * @since 1.1 | |
495 */ | |
496 public static IObservableFactory setToMapFactory(final Class beanClass, final String propertyName) { | |
497 return new class() IObservableFactory { | |
498 public IObservable createObservable(Object target) { | |
499 return observeMap(cast(IObservableSet) target, beanClass, propertyName); | |
500 } | |
501 }; | |
502 } | |
503 | |
504 /** | |
505 * Returns a factory for creating an observable map. The factory, when | |
506 * provided with a bean object, will create an {@link IObservableMap} in the | |
507 * given realm that tracks the map-typed named property for the specified | |
508 * bean. | |
509 * | |
510 * @param realm | |
511 * the realm assigned to observables created by the returned | |
512 * factory. | |
513 * @param propertyName | |
514 * the name of the property | |
515 * @return a factory for creating {@link IObservableMap} objects. | |
516 * @since 1.1 | |
517 */ | |
518 public static IObservableFactory mapPropertyFactory(final Realm realm, | |
519 final String propertyName) { | |
520 return new class() IObservableFactory { | |
521 public IObservable createObservable(Object target) { | |
522 return observeMap(realm, target, propertyName); | |
523 } | |
524 }; | |
525 } | |
526 | |
527 /** | |
528 * @param elementType | |
529 * can be <code>null</code> | |
530 * @param propertyDescriptor | |
531 * @return type of the items in a collection/array property | |
532 */ | |
533 /*package*/ static Class getCollectionElementType(Class elementType, | |
534 PropertyDescriptor propertyDescriptor) { | |
535 if (elementType is null) { | |
536 Class propertyType = propertyDescriptor.getPropertyType(); | |
537 elementType = propertyType.isArray() ? propertyType | |
538 .getComponentType() : Object.class; | |
539 } | |
540 | |
541 return elementType; | |
542 } | |
543 | |
544 /** | |
545 * @param observable | |
546 * @param propertyName | |
547 * @return property descriptor or <code>null</code> | |
548 */ | |
549 /* package*/ static PropertyDescriptor getValueTypePropertyDescriptor( | |
550 IObservableValue observable, String propertyName) { | |
551 return (observable.getValueType() !is null) ? getPropertyDescriptor( | |
552 cast(Class) observable.getValueType(), propertyName) : null; | |
553 } | |
554 } |