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 }