/******************************************************************************* * Copyright (c) 2007 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 ******************************************************************************/ package org.eclipse.core.databinding; import org.eclipse.core.databinding.conversion.IConverter; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.validation.ValidationStatus; import org.eclipse.core.internal.databinding.BindingMessages; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; /** * Customizes a {@link Binding} between two * {@link IObservableList observable lists}. The following behaviors can be * customized via the strategy: * <ul> * <li>Conversion</li> * <li>Automatic processing</li> * </ul> * <p> * Conversion:<br/> When elements are added they can be * {@link #convert(Object) converted} to the destination element type. * </p> * <p> * Automatic processing:<br/> The processing to perform when the source * observable changes. This behavior is configured via policies provided on * construction of the strategy (e.g. {@link #POLICY_NEVER}, * {@link #POLICY_ON_REQUEST}, {@link #POLICY_UPDATE}). * </p> * * * @see DataBindingContext#bindList(IObservableList, IObservableList, * UpdateListStrategy, UpdateListStrategy) * @see IConverter * @since 1.0 */ public class UpdateListStrategy extends UpdateStrategy { /** * Policy constant denoting that the source observable's state should not be * tracked and that the destination observable's state should never be * updated. */ public static int POLICY_NEVER = notInlined(1); /** * Policy constant denoting that the source observable's state should not be * tracked, but that conversion and updating the destination observable's * state should be performed when explicitly requested. */ public static int POLICY_ON_REQUEST = notInlined(2); /** * Policy constant denoting that the source observable's state should be * tracked, and that conversion and updating the destination observable's * state should be performed automatically on every change of the source * observable state. */ public static int POLICY_UPDATE = notInlined(8); /** * Helper method allowing API evolution of the above constant values. The * compiler will not inline constant values into client code if values are * "computed" using this helper. * * @param i * an integer * @return the same integer */ private static int notInlined(int i) { return i; } protected IConverter converter; private int updatePolicy; protected boolean provideDefaults; /** * Creates a new update list strategy for automatically updating the * destination observable list whenever the source observable list changes. * A default converter will be provided. The defaults can be changed by * calling one of the setter methods. */ public UpdateListStrategy() { this(true, POLICY_UPDATE); } /** * Creates a new update list strategy with a configurable update policy. A * default converter will be provided. The defaults can be changed by * calling one of the setter methods. * * @param updatePolicy * one of {@link #POLICY_NEVER}, {@link #POLICY_ON_REQUEST}, or * {@link #POLICY_UPDATE} */ public UpdateListStrategy(int updatePolicy) { this(true, updatePolicy); } /** * Creates a new update list strategy with a configurable update policy. A * default converter will be provided if <code>provideDefaults</code> is * <code>true</code>. The defaults can be changed by calling one of the * setter methods. * * @param provideDefaults * if <code>true</code>, default validators and a default * converter will be provided based on the observable list's * type. * @param updatePolicy * one of {@link #POLICY_NEVER}, {@link #POLICY_ON_REQUEST}, or * {@link #POLICY_UPDATE} */ public UpdateListStrategy(boolean provideDefaults, int updatePolicy) { this.provideDefaults = provideDefaults; this.updatePolicy = updatePolicy; } /** * When an element is added to the destination converts the element from the * source element type to the destination element type. * <p> * Default implementation will use the * {@link #setConverter(IConverter) converter} if one exists. If no * converter exists no conversion occurs. * </p> * * @param element * @return the converted element */ public Object convert(Object element) { return converter == null ? element : converter.convert(element); } /** * * @param source * @param destination */ protected void fillDefaults(IObservableList source, IObservableList destination) { Object sourceType = source.getElementType(); Object destinationType = destination.getElementType(); if (provideDefaults && sourceType != null && destinationType != null) { if (converter == null) { setConverter(createConverter(sourceType, destinationType)); } } if (converter != null) { if (sourceType != null) { checkAssignable(converter.getFromType(), sourceType, "converter does not convert from type " + sourceType); //$NON-NLS-1$ } if (destinationType != null) { checkAssignable(converter.getToType(), destinationType, "converter does not convert to type " + destinationType); //$NON-NLS-1$ } } } /** * @return the update policy */ public int getUpdatePolicy() { return updatePolicy; } /** * Sets the converter to be invoked when converting added elements from the * source element type to the destination element type. * * @param converter * @return the receiver, to enable method call chaining */ public UpdateListStrategy setConverter(IConverter converter) { this.converter = converter; return this; } /** * Adds the given element at the given index to the given observable list. * Clients may extend but must call the super implementation. * * @param observableList * @param element * @param index * @return a status */ protected IStatus doAdd(IObservableList observableList, Object element, int index) { try { observableList.add(index, element); } catch (Exception ex) { return ValidationStatus.error(BindingMessages .getString("ValueBinding_ErrorWhileSettingValue"), //$NON-NLS-1$ ex); } return Status.OK_STATUS; } /** * Removes the element at the given index from the given observable list. * Clients may extend but must call the super implementation. * * @param observableList * @param index * @return a status */ protected IStatus doRemove(IObservableList observableList, int index) { try { observableList.remove(index); } catch (Exception ex) { return ValidationStatus.error(BindingMessages .getString("ValueBinding_ErrorWhileSettingValue"), //$NON-NLS-1$ ex); } return Status.OK_STATUS; } }