KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > internal > databinding > provisional > DataBindingContext


1 /*******************************************************************************
2  * Copyright (c) 2005, 2006 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  *******************************************************************************/

11 package org.eclipse.jface.internal.databinding.provisional;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.List JavaDoc;
16
17 import org.eclipse.jface.internal.databinding.internal.ValidationErrorList;
18 import org.eclipse.jface.internal.databinding.provisional.conversion.IConverter;
19 import org.eclipse.jface.internal.databinding.provisional.factories.BindSupportFactory;
20 import org.eclipse.jface.internal.databinding.provisional.factories.DefaultBindSupportFactory;
21 import org.eclipse.jface.internal.databinding.provisional.factories.DefaultBindingFactory;
22 import org.eclipse.jface.internal.databinding.provisional.factories.IBindingFactory;
23 import org.eclipse.jface.internal.databinding.provisional.factories.IObservableFactory;
24 import org.eclipse.jface.internal.databinding.provisional.observable.IObservable;
25 import org.eclipse.jface.internal.databinding.provisional.observable.list.IObservableList;
26 import org.eclipse.jface.internal.databinding.provisional.observable.list.ObservableList;
27 import org.eclipse.jface.internal.databinding.provisional.observable.list.WritableList;
28 import org.eclipse.jface.internal.databinding.provisional.observable.value.ComputedValue;
29 import org.eclipse.jface.internal.databinding.provisional.observable.value.IObservableValue;
30 import org.eclipse.jface.internal.databinding.provisional.validation.IDomainValidator;
31 import org.eclipse.jface.internal.databinding.provisional.validation.IValidator;
32 import org.eclipse.jface.internal.databinding.provisional.validation.ValidationError;
33 import org.eclipse.jface.util.Assert;
34
35 /**
36  * A context for binding observable objects with a shared lifecycle. The
37  * factories registered with a data binding context determine how observable
38  * objects are created from description objects, and which converters and
39  * validators are used when no specific converter or validator is given.
40  *
41  * <p>
42  * This interface is not intended to be implemented by clients.
43  * </p>
44  *
45  * <p>
46  * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
47  * part of a work in progress. There is no guarantee that this API will remain
48  * unchanged during the 3.2 release cycle. Please do not use this API without
49  * consulting with the Platform/UI team.
50  * </p>
51  *
52  * @since 1.0
53  *
54  */

55 public final class DataBindingContext {
56
57     /**
58      * Policy constant specifying that update or validation should occur
59      * automatically whenever a bound observable object generates a change
60      * event.
61      */

62     public static final int POLICY_AUTOMATIC = 1;
63
64     /**
65      * Policy constant specifying that update or validation should only occur
66      * when explicitly requested by calling {@link #updateModels() } or
67      * {@link #updateTargets() }.
68      */

69     public static final int POLICY_EXPLICIT = 2;
70
71     /**
72      * Constant specifiying that validation or update events from UI observables
73      * should be triggered early, typically on each keystroke.
74      */

75     public static final int TIME_EARLY = 0;
76
77     /**
78      * Constant specifiying that validation or update events from UI observables
79      * should be triggered late, typically on focus lost.
80      */

81     public static final int TIME_LATE = 1;
82
83     /**
84      * Returns a new data binding context with the given parent.
85      *
86      * @param parent
87      * @return a data binding context
88      */

89     public static DataBindingContext createContext(DataBindingContext parent) {
90         DataBindingContext result = new DataBindingContext(parent);
91         return result;
92     }
93
94     /**
95      * Returns a new data binding context on which the given factories have been
96      * registered using
97      * {@link DataBindingContext#addUpdatableFactory(IUpdatableFactory)}. The
98      * factories will be added in the order given.
99      *
100      * @param observableFactories
101      * @return a data binding context
102      */

103     public static DataBindingContext createContext(
104             IObservableFactory[] observableFactories) {
105         return createContext(observableFactories,
106                 new BindSupportFactory[] { new DefaultBindSupportFactory() },
107                 new IBindingFactory[] { new DefaultBindingFactory() });
108     }
109
110     /**
111      * Returns a new data binding context on which the given factories have been
112      * registered using
113      * {@link DataBindingContext#addUpdatableFactory(IUpdatableFactory)}. The
114      * factories will be added in the order given.
115      *
116      * @param observableFactories
117      * @param bindSupportFactories
118      * @param bindingFactories
119      * @return a data binding context
120      */

121     public static DataBindingContext createContext(
122             IObservableFactory[] observableFactories,
123             BindSupportFactory[] bindSupportFactories,
124             IBindingFactory[] bindingFactories) {
125         DataBindingContext result = new DataBindingContext();
126         if (observableFactories != null)
127             for (int i = 0; i < observableFactories.length; i++) {
128                 result.addObservableFactory(observableFactories[i]);
129             }
130         if (bindSupportFactories != null)
131             for (int i = 0; i < bindSupportFactories.length; i++) {
132                 result.addBindSupportFactory(bindSupportFactories[i]);
133             }
134         if (bindingFactories != null)
135             for (int i = 0; i < bindingFactories.length; i++) {
136                 result.addBindingFactory(bindingFactories[i]);
137             }
138         return result;
139     }
140
141     private List JavaDoc bindingEventListeners = new ArrayList JavaDoc();
142
143     private WritableList bindings = new WritableList();
144
145     private List JavaDoc bindSupportFactories = new ArrayList JavaDoc();
146
147     private List JavaDoc bindingFactories = new ArrayList JavaDoc();
148
149     private List JavaDoc createdObservables = new ArrayList JavaDoc();
150
151     private List JavaDoc factories = new ArrayList JavaDoc();
152
153     private DataBindingContext parent;
154
155     private ComputedValue partialValidationError = new ComputedValue() {
156         protected Object JavaDoc calculate() {
157             int size = partialValidationErrors.size();
158             return size == 0 ? null : partialValidationErrors.get(size - 1);
159         }
160     };
161
162     private ObservableList partialValidationErrors = new ValidationErrorList(
163             bindings, true);
164
165     private ComputedValue validationError = new ComputedValue() {
166         protected Object JavaDoc calculate() {
167             int size = validationErrors.size();
168             return size == 0 ? null : validationErrors.get(size - 1);
169         }
170     };
171
172     private ObservableList validationErrors = new ValidationErrorList(bindings,
173             false);
174
175     /**
176      *
177      */

178     public DataBindingContext() {
179     }
180
181     /**
182      * @param parent
183      *
184      */

185     public DataBindingContext(DataBindingContext parent) {
186         this.parent = parent;
187     }
188
189     /**
190      * Add a listener to the set of listeners that will be notified when an
191      * event occurs in the data flow pipeline that is managed by any binding
192      * created by this data binding context.
193      *
194      * @param listener
195      * The listener to add.
196      */

197     public void addBindingEventListener(IBindingListener listener) {
198         bindingEventListeners.add(listener);
199     }
200
201     /**
202      * Adds a factory that can create converters and validators. The list of
203      * bind support factories is used for creating converters and validators
204      * when binding without specifying a converter or validator.
205      *
206      * @param factory
207      * the factory to add.
208      */

209     public void addBindSupportFactory(BindSupportFactory factory) {
210         bindSupportFactories.add(factory);
211     }
212
213     /**
214      * Adds a factory for creating observable objects from description objects
215      * to this context. The list of observable factories is used for creating
216      * observable objects when binding based on description objects.
217      *
218      * @param observableFactory
219      */

220     public void addObservableFactory(IObservableFactory observableFactory) {
221         // TODO: consider the fact that adding new factories for a given
222
// description
223
// may hide default ones (e.g., a new PropertyDescriptor may overide the
224
// ond for EMF)
225
factories.add(observableFactory);
226     }
227
228     /**
229      * Adds the given factory to the list of binding factories.
230      *
231      * @param factory
232      */

233     public void addBindingFactory(IBindingFactory factory) {
234         bindingFactories.add(factory);
235     }
236
237     /**
238      * Binds targetObservable and modelObservable using converter and validator
239      * as specified in bindSpec. If bindSpec is null, a default converter and
240      * validator is used.
241      *
242      * @param targetObservable
243      * @param modelObservable
244      * @param bindSpec
245      * the bind spec, or null. Any bindSpec object must not be reused
246      * or changed after it is passed to #bind.
247      * @return The Binding that manages this data flow
248      */

249     public Binding bind(IObservable targetObservable,
250             IObservable modelObservable, BindSpec bindSpec) {
251         Binding result = doCreateBinding(targetObservable, modelObservable,
252                 bindSpec, this);
253         if (result != null)
254             return result;
255         throw new BindingException(
256                 "No binding found for target: " + targetObservable.getClass().getName() + ", model: " + modelObservable.getClass().getName()); //$NON-NLS-1$ //$NON-NLS-2$
257
}
258
259     private Binding doCreateBinding(IObservable targetObservable,
260             IObservable modelObservable, BindSpec bindSpec,
261             DataBindingContext originatingContext) {
262         for (int i = bindingFactories.size() - 1; i >= 0; i--) {
263             IBindingFactory factory = (IBindingFactory) bindingFactories.get(i);
264             Binding binding = factory.createBinding(originatingContext, targetObservable,
265                     modelObservable, bindSpec);
266             if (binding != null) {
267                 bindings.add(binding);
268                 return binding;
269             }
270         }
271         if (parent != null) {
272             return parent.doCreateBinding(targetObservable, modelObservable,
273                     bindSpec, originatingContext);
274         }
275         return null;
276     }
277
278     /**
279      * Convenience method to bind targetObservable and
280      * createObservable(modelDescription).
281      *
282      * @param targetObservable
283      * @param modelDescription
284      * @param bindSpec
285      * the bind spec, or null. Any bindSpec object must not be reused
286      * or changed after it is passed to #bind.
287      * @return The Binding that manages this data flow
288      */

289     public Binding bind(IObservable targetObservable, Object JavaDoc modelDescription,
290             BindSpec bindSpec) {
291         return bind(targetObservable, createObservable(modelDescription),
292                 bindSpec);
293     }
294
295     /**
296      * Convenience method to bind createObservable(targetDescription) and
297      * modelObservable.
298      *
299      * @param targetDescription
300      * @param modelObservable
301      * @param bindSpec
302      * the bind spec, or null. Any bindSpec object must not be reused
303      * or changed after it is passed to #bind.
304      * @return The Binding that manages this data flow
305      */

306     public Binding bind(Object JavaDoc targetDescription, IObservable modelObservable,
307             BindSpec bindSpec) {
308         return bind(createObservable(targetDescription), modelObservable,
309                 bindSpec);
310     }
311
312     /**
313      * Convenience method to bind createObservable(targetDescription) and
314      * createObservable(modelDescription).
315      *
316      * @param targetDescription
317      * @param modelDescription
318      * @param bindSpec
319      * the bind spec, or null. Any bindSpec object must not be reused
320      * or changed after it is passed to #bind.
321      * @return The Binding that manages this data flow
322      */

323     public Binding bind(Object JavaDoc targetDescription, Object JavaDoc modelDescription,
324             BindSpec bindSpec) {
325         return bind(createObservable(targetDescription), modelDescription,
326                 bindSpec);
327     }
328
329     /**
330      * Tries to create a converter that can convert from values of type
331      * fromType. Returns <code>null</code> if no converter could be created.
332      * Either toType or modelDescription can be <code>null</code>, but not
333      * both. The implementation of this method will iterate over the registered
334      * bind support factories in reverse order, passing the given arguments to
335      * {@link BindSupportFactory#createConverter(Object, Object)}. The first
336      * non-null converter will be returned.
337      *
338      * @param fromType
339      * @param toType
340      * @return an IConverter, or <code>null</code> if unsuccessful
341      */

342     public IConverter createConverter(Object JavaDoc fromType, Object JavaDoc toType) {
343         for (int i = bindSupportFactories.size() - 1; i >= 0; i--) {
344             BindSupportFactory bindSupportFactory = (BindSupportFactory) bindSupportFactories
345                     .get(i);
346             IConverter converter = bindSupportFactory.createConverter(fromType,
347                     toType);
348             if (converter != null) {
349                 return converter;
350             }
351         }
352         if (parent != null) {
353             return parent.createConverter(fromType, toType);
354         }
355         return null;
356     }
357
358     /**
359      * @param modelType
360      * @return an IValidator, or null if unsuccessful
361      */

362     public IDomainValidator createDomainValidator(Object JavaDoc modelType) {
363         for (int i = bindSupportFactories.size() - 1; i >= 0; i--) {
364             BindSupportFactory bindSupportFactory = (BindSupportFactory) bindSupportFactories
365                     .get(i);
366             IDomainValidator validator = bindSupportFactory
367                     .createDomainValidator(modelType);
368             if (validator != null) {
369                 return validator;
370             }
371         }
372         if (parent != null) {
373             return parent.createDomainValidator(modelType);
374         }
375         return null;
376     }
377
378     /**
379      * Creates an observable object from a description. Description objects are
380      * interpreted by implementors of IObservableFactory, the data binding
381      * framework does not impose any semantics on them.
382      *
383      * @param description
384      * @return IObservable for the given description
385      */

386     public IObservable createObservable(Object JavaDoc description) {
387         IObservable updatable = doCreateObservable(description, this);
388         if (updatable != null) {
389             createdObservables.add(updatable);
390         }
391         return updatable;
392     }
393
394     /**
395      * Tries to create a validator that can validate values of type fromType.
396      * Returns <code>null</code> if no validator could be created. Either
397      * toType or modelDescription can be <code>null</code>, but not both. The
398      * implementation of this method will iterate over the registered bind
399      * support factories in reverse order, passing the given arguments to
400      * {@link BindSupportFactory#createValidator(Class, Class, Object)}. The
401      * first non-null validator will be returned.
402      *
403      * @param fromType
404      * @param toType
405      * @param modelDescription
406      * @return an IValidator, or <code>null</code> if unsuccessful
407      */

408     public IValidator createValidator(Object JavaDoc fromType, Object JavaDoc toType) {
409         for (int i = bindSupportFactories.size() - 1; i >= 0; i--) {
410             BindSupportFactory bindSupportFactory = (BindSupportFactory) bindSupportFactories
411                     .get(i);
412             IValidator validator = bindSupportFactory.createValidator(fromType,
413                     toType);
414             if (validator != null) {
415                 return validator;
416             }
417         }
418         if (parent != null) {
419             return parent.createValidator(fromType, toType);
420         }
421         return null;
422     }
423
424     /**
425      * Disposes of this data binding context and all observable objects created
426      * in this context.
427      */

428     public void dispose() {
429         for (Iterator JavaDoc it = createdObservables.iterator(); it.hasNext();) {
430             IObservable updatable = (IObservable) it.next();
431             updatable.dispose();
432         }
433     }
434
435     private IObservable doCreateObservable(Object JavaDoc description,
436             DataBindingContext thisDatabindingContext) {
437         for (int i = factories.size() - 1; i >= 0; i--) {
438             IObservableFactory factory = (IObservableFactory) factories.get(i);
439             IObservable result = factory.createObservable(description);
440             if (result != null) {
441                 return result;
442             }
443         }
444         if (parent != null) {
445             return parent.doCreateObservable(description,
446                     thisDatabindingContext);
447         }
448         throw new BindingException("could not find updatable for " //$NON-NLS-1$
449
+ description);
450     }
451
452     /**
453      * @param dataBindingContext
454      * @param bindSpec
455      * @param targetType
456      * @param modelType
457      */

458     public void fillBindSpecDefaults(DataBindingContext dataBindingContext,
459             BindSpec bindSpec, Object JavaDoc targetType, Object JavaDoc modelType) {
460         if (bindSpec.getTypeConversionValidator() == null) {
461             bindSpec.setValidator(dataBindingContext.createValidator(
462                     targetType, modelType));
463         }
464         if (bindSpec.getDomainValidator() == null) {
465             bindSpec.setDomainValidator(dataBindingContext
466                     .createDomainValidator(modelType));
467         }
468         if (bindSpec.getModelToTargetConverter() == null) {
469             bindSpec.setModelToTargetConverter(dataBindingContext
470                     .createConverter(modelType, targetType));
471         }
472         if (bindSpec.getTargetToModelConverter() == null) {
473             bindSpec.setTargetToModelConverter(dataBindingContext
474                     .createConverter(targetType, modelType));
475         }
476     }
477
478     /* package */ValidationError fireBindingEvent(BindingEvent event) {
479         ValidationError result = null;
480         for (Iterator JavaDoc bindingEventIter = bindingEventListeners.iterator(); bindingEventIter
481                 .hasNext();) {
482             IBindingListener listener = (IBindingListener) bindingEventIter
483                     .next();
484             result = listener.bindingEvent(event);
485             if (result != null)
486                 break;
487         }
488         return result;
489     }
490
491     /**
492      * Returns an observable list with elements of type Binding, ordered by
493      * creation time
494      *
495      * @return the observable list containing all bindings
496      */

497     public IObservableList getBindings() {
498         return bindings;
499     }
500
501     /**
502      * Returns an observable value of type ValidationError, containing the most
503      * recent partial validation error
504      *
505      * @return the validation error observable
506      */

507     public IObservableValue getPartialValidationError() {
508         return partialValidationError;
509     }
510
511     /**
512      * Returns an observable value of type ValidationError, containing the most
513      * recent full validation error, i.e. the last element of the list returned
514      * by getValidationErrors().
515      *
516      * @return the validation observable
517      */

518     public IObservableValue getValidationError() {
519         return validationError;
520     }
521
522     /**
523      * Returns an observable list with elements of type ValidationError, ordered
524      * by the time of detection
525      *
526      * @return the observable list containing all validation errors
527      */

528     public IObservableList getValidationErrors() {
529         return validationErrors;
530     }
531
532     /**
533      * @param fromType
534      * @param toType
535      * @return whether fromType is assignable to toType
536      */

537     public boolean isAssignableFromTo(Object JavaDoc fromType, Object JavaDoc toType) {
538         for (int i = bindSupportFactories.size() - 1; i >= 0; i--) {
539             BindSupportFactory bindSupportFactory = (BindSupportFactory) bindSupportFactories
540                     .get(i);
541             Boolean JavaDoc result = bindSupportFactory.isAssignableFromTo(fromType,
542                     toType);
543             if (result != null) {
544                 return result.booleanValue();
545             }
546         }
547         if (parent != null) {
548             return parent.isAssignableFromTo(fromType, toType);
549         }
550         // TODO does this default make sense?
551
return true;
552     }
553
554     /**
555      * Registers an IObservable with the data binding context so that it will be
556      * disposed when all other IObservables are disposed. This is only necessary
557      * for observables like SettableValue that are instantiated directly, rather
558      * being created by a data binding context to begin with.
559      *
560      * @param observable
561      * The IObservable to register.
562      */

563     public void registerForDispose(IObservable observable) {
564         createdObservables.add(observable);
565     }
566
567     /**
568      * Removes a listener from the set of listeners that will be notified when
569      * an event occurs in the data flow pipeline that is managed by any binding
570      * created by this data binding context.
571      *
572      * @param listener
573      * The listener to remove.
574      */

575     public void removeBindingEventListener(IBindingListener listener) {
576         bindingEventListeners.remove(listener);
577     }
578
579     /**
580      * Updates all model observable objects to reflect the current state of the
581      * target observable objects.
582      *
583      */

584     public void updateModels() {
585         Assert.isTrue(false, "updateModels is not yet implemented"); //$NON-NLS-1$
586
}
587
588     /**
589      * Updates all target observable objects to reflect the current state of the
590      * model observable objects.
591      *
592      */

593     public void updateTargets() {
594         Assert.isTrue(false, "updateTargets is not yet implemented"); //$NON-NLS-1$
595
}
596
597 }
598
Popular Tags