blob: 08acd66ab7a180f2d13f65db297131c2b4513f6e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005-2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Brad Reynolds - bug 159539
* Brad Reynolds - bug 140644
* Brad Reynolds - bug 159940
* Brad Reynolds - bug 116920, 159768
* Matthew Hall - bugs 118516, 124684, 218269
* Boris Bokowski - bug 218269
*******************************************************************************/
package org.eclipse.core.databinding;
import java.util.Iterator;
import org.eclipse.core.databinding.observable.Observables;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.internal.databinding.ValidationStatusMap;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IStatus;
/**
* A DataBindingContext is the point of contact for the creation and management
* of {@link Binding bindings}, and aggregates validation statuses of its
* bindings, or more generally, its validation status providers.
* <p>
* A DataBindingContext provides the following abilities:
* <ul>
* <li>Ability to create bindings between
* {@link IObservableValue observable values}.</li>
* <li>Ability to create bindings between
* {@link IObservableList observable lists}.</li>
* <li>Access to the bindings created by the instance.</li>
* <li>Access to the list of validation status providers (this includes all
* bindings).</li>
* </ul>
* </p>
* <p>
* Multiple contexts can be used at any point in time. One strategy for the
* management of contexts is the aggregation of validation statuses. For example
* an <code>IWizardPage</code> could use a single context and the statuses
* could be aggregated to set the page status and fulfillment. Each page in the
* <code>IWizard</code> would have its own context instance.
* </p>
*
* @since 1.0
*/
public class DataBindingContext {
private WritableList bindings;
private WritableList validationStatusProviders;
/**
* Unmodifiable version of {@link #bindings} for public exposure.
*/
private IObservableList unmodifiableBindings;
/**
* Unmodifiable version of {@link #validationStatusProviders} for public
* exposure.
*/
private IObservableList unmodifiableStatusProviders;
private IObservableMap validationStatusMap;
private Realm validationRealm;
/**
* Creates a data binding context, using the current default realm for the
* validation observables.
*
* @see Realm
*/
public DataBindingContext() {
this(Realm.getDefault());
}
/**
* Creates a data binding context using the given realm for the validation
* observables.
*
* @param validationRealm
* the realm to be used for the validation observables
*
* @see Realm
*/
public DataBindingContext(Realm validationRealm) {
Assert.isNotNull(validationRealm, "Validation realm cannot be null"); //$NON-NLS-1$
this.validationRealm = validationRealm;
bindings = new WritableList(validationRealm);
unmodifiableBindings = Observables.unmodifiableObservableList(bindings);
validationStatusProviders = new WritableList(validationRealm);
unmodifiableStatusProviders = Observables
.unmodifiableObservableList(validationStatusProviders);
validationStatusMap = new ValidationStatusMap(validationRealm, bindings);
}
/**
* Creates a {@link Binding} to synchronize the values of two
* {@link IObservableValue observable values}. During synchronization
* validation and conversion can be employed to customize the process. For
* specifics on the customization of the process see
* {@link UpdateValueStrategy}.
*
* @param targetObservableValue
* target value, commonly a UI widget
* @param modelObservableValue
* model value
* @param targetToModel
* strategy to employ when the target is the source of the change
* and the model is the destination
* @param modelToTarget
* strategy to employ when the model is the source of the change
* and the target is the destination
* @return created binding
*
* @see UpdateValueStrategy
*/
public final Binding bindValue(IObservableValue targetObservableValue,
IObservableValue modelObservableValue,
UpdateValueStrategy targetToModel, UpdateValueStrategy modelToTarget) {
UpdateValueStrategy targetToModelStrategy = targetToModel != null ? targetToModel
: createTargetToModelUpdateValueStrategy(targetObservableValue, modelObservableValue);
UpdateValueStrategy modelToTargetStrategy = modelToTarget != null ? modelToTarget
: createModelToTargetUpdateValueStrategy(modelObservableValue, targetObservableValue);
targetToModelStrategy.fillDefaults(targetObservableValue, modelObservableValue);
modelToTargetStrategy.fillDefaults(modelObservableValue, targetObservableValue);
ValueBinding result = new ValueBinding(targetObservableValue,
modelObservableValue, targetToModelStrategy,
modelToTargetStrategy);
result.init(this);
return result;
}
/**
* Returns an update value strategy to be used for copying values from the
* from value to the to value. Clients may override.
*
* @param fromValue
* @param toValue
* @return a update value strategy
*/
protected UpdateValueStrategy createModelToTargetUpdateValueStrategy(
IObservableValue fromValue, IObservableValue toValue) {
return new UpdateValueStrategy();
}
/**
* Returns an update value strategy to be used for copying values from the
* from value to the to value. Clients may override.
*
* @param fromValue
* @param toValue
* @return a update value strategy
*/
protected UpdateValueStrategy createTargetToModelUpdateValueStrategy(
IObservableValue fromValue, IObservableValue toValue) {
return new UpdateValueStrategy();
}
/**
* Creates a {@link Binding} to synchronize the values of two
* {@link IObservableList observable lists}. During synchronization
* validation and conversion can be employed to customize the process. For
* specifics on the customization of the process see
* {@link UpdateListStrategy}.
*
* @param targetObservableList
* target list, commonly a list representing a list in the UI
* @param modelObservableList
* model list
* @param targetToModel
* strategy to employ when the target is the source of the change
* and the model is the destination
* @param modelToTarget
* strategy to employ when the model is the source of the change
* and the target is the destination
* @return created binding
*
* @see UpdateListStrategy
*/
public final Binding bindList(IObservableList targetObservableList,
IObservableList modelObservableList,
UpdateListStrategy targetToModel, UpdateListStrategy modelToTarget) {
UpdateListStrategy targetToModelStrategy = targetToModel != null ? targetToModel
: createTargetToModelUpdateListStrategy(targetObservableList,
modelObservableList);
UpdateListStrategy modelToTargetStrategy = modelToTarget != null ? modelToTarget
: createModelToTargetUpdateListStrategy(modelObservableList,
targetObservableList);
targetToModelStrategy.fillDefaults(targetObservableList,
modelObservableList);
modelToTargetStrategy.fillDefaults(modelObservableList,
targetObservableList);
ListBinding result = new ListBinding(targetObservableList,
modelObservableList, targetToModelStrategy,
modelToTargetStrategy);
result.init(this);
return result;
}
/**
* @param modelObservableList
* @param targetObservableList
* @return an update list strategy
*/
protected UpdateListStrategy createModelToTargetUpdateListStrategy(
IObservableList modelObservableList,
IObservableList targetObservableList) {
return new UpdateListStrategy();
}
/**
* @param targetObservableList
* @param modelObservableList
* @return an update list strategy
*/
protected UpdateListStrategy createTargetToModelUpdateListStrategy(
IObservableList targetObservableList,
IObservableList modelObservableList) {
return new UpdateListStrategy();
}
/**
* Creates a {@link Binding} to synchronize the values of two
* {@link IObservableSet observable sets}. During synchronization
* validation and conversion can be employed to customize the process. For
* specifics on the customization of the process see
* {@link UpdateSetStrategy}.
*
* @param targetObservableSet
* target set, commonly a set representing a set in the UI
* @param modelObservableSet
* model set
* @param targetToModel
* strategy to employ when the target is the source of the change
* and the model is the destination
* @param modelToTarget
* strategy to employ when the model is the source of the change
* and the target is the destination
* @return created binding
* @since 1.1
*/
public final Binding bindSet(IObservableSet targetObservableSet,
IObservableSet modelObservableSet, UpdateSetStrategy targetToModel,
UpdateSetStrategy modelToTarget) {
if (targetToModel == null)
targetToModel = createTargetToModelUpdateSetStrategy(
targetObservableSet, modelObservableSet);
if (modelToTarget == null)
modelToTarget = createModelToTargetUpdateSetStrategy(
modelObservableSet, targetObservableSet);
targetToModel.fillDefaults(targetObservableSet, modelObservableSet);
modelToTarget.fillDefaults(modelObservableSet, targetObservableSet);
SetBinding result = new SetBinding(targetObservableSet,
modelObservableSet, targetToModel, modelToTarget);
result.init(this);
return result;
}
/**
* @param targetObservableSet
* @param modelObservableSet
* @return a default set update strategy
* @since 1.1
*/
protected UpdateSetStrategy createTargetToModelUpdateSetStrategy(
IObservableSet targetObservableSet,
IObservableSet modelObservableSet) {
return new UpdateSetStrategy();
}
/**
* @param modelObservableSet
* @param targetObservableSet
* @return a default set update strategy
* @since 1.1
*/
protected UpdateSetStrategy createModelToTargetUpdateSetStrategy(
IObservableSet modelObservableSet,
IObservableSet targetObservableSet) {
return new UpdateSetStrategy();
}
/**
* Disposes of this data binding context and all bindings and validation
* status providers that were added to this context.
*/
public final void dispose() {
Binding[] bindingArray = (Binding[]) bindings.toArray(new Binding[bindings.size()]);
for (int i = 0; i < bindingArray.length; i++) {
bindingArray[i].dispose();
}
ValidationStatusProvider[] statusProviderArray = (ValidationStatusProvider[]) validationStatusProviders
.toArray(new ValidationStatusProvider[validationStatusProviders
.size()]);
for (int i = 0; i < statusProviderArray.length; i++) {
if (!statusProviderArray[i].isDisposed())
statusProviderArray[i].dispose();
}
}
/**
* Returns an unmodifiable observable list with elements of type
* {@link Binding}, ordered by time of addition.
*
* @return the observable list containing all bindings
*/
public final IObservableList getBindings() {
return unmodifiableBindings;
}
/**
* Returns an unmodifiable observable list with elements of type
* {@link ValidationStatusProvider}, ordered by time of addition.
*
* @return the observable list containing all bindings
* @since 1.1
*/
public final IObservableList getValidationStatusProviders() {
return unmodifiableStatusProviders;
}
/**
* Returns an observable map from bindings (type: {@link Binding}) to
* statuses (type: {@link IStatus}). The keys of the map are the bindings
* returned by {@link #getBindings()}, and the values are the current
* validaion status objects for each binding.
*
* @return the observable map from bindings to status objects.
*
* @deprecated as of 1.1, please use {@link #getValidationStatusProviders()}
*/
public final IObservableMap getValidationStatusMap() {
return validationStatusMap;
}
/**
* Adds the given binding to this data binding context. This will also add
* the given binding to the list of validation status providers.
*
* @param binding
* The binding to add.
* @see #addValidationStatusProvider(ValidationStatusProvider)
* @see #getValidationStatusProviders()
*/
public void addBinding(Binding binding) {
addValidationStatusProvider(binding);
bindings.add(binding);
}
/**
* Adds the given validation status provider to this data binding context.
*
* @param validationStatusProvider
* The validation status provider to add.
* @since 1.1
*/
public void addValidationStatusProvider(
ValidationStatusProvider validationStatusProvider) {
validationStatusProviders.add(validationStatusProvider);
}
/**
* Updates all model observable objects to reflect the current state of the
* target observable objects.
*
*/
public final void updateModels() {
for (Iterator it = bindings.iterator(); it.hasNext();) {
Binding binding = (Binding) it.next();
binding.updateTargetToModel();
}
}
/**
* Updates all target observable objects to reflect the current state of the
* model observable objects.
*
*/
public final void updateTargets() {
for (Iterator it = bindings.iterator(); it.hasNext();) {
Binding binding = (Binding) it.next();
binding.updateModelToTarget();
}
}
/**
* Removes the given binding.
*
* @param binding
* @return <code>true</code> if was associated with the context,
* <code>false</code> if not
*/
public boolean removeBinding(Binding binding) {
return bindings.remove(binding) && removeValidationStatusProvider(binding);
}
/**
* Removes the validation status provider.
*
* @param validationStatusProvider
* @return <code>true</code> if was associated with the context,
* <code>false</code> if not
* @since 1.1
*/
public boolean removeValidationStatusProvider(
ValidationStatusProvider validationStatusProvider) {
return validationStatusProviders.remove(validationStatusProvider);
}
/**
* Returns the validation realm.
*
* @return the realm for the validation observables
* @see Realm
*/
public final Realm getValidationRealm() {
return validationRealm;
}
}