diff org.eclipse.core.databinding/src/org/eclipse/core/databinding/ValueBinding.d @ 78:0a55d2d5a946

Added file for databinding
author Frank Benoit <benoit@tionex.de>
date Tue, 14 Apr 2009 11:35:29 +0200
parents
children 383ce7bd736b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.core.databinding/src/org/eclipse/core/databinding/ValueBinding.d	Tue Apr 14 11:35:29 2009 +0200
@@ -0,0 +1,248 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 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
+ *     Matthew Hall - bug 220700
+ *******************************************************************************/
+
+module org.eclipse.core.databinding.ValueBinding;
+
+import java.lang.all;
+
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.IValueChangeListener;
+import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.core.databinding.util.Policy;
+import org.eclipse.core.internal.databinding.BindingStatus;
+import org.eclipse.core.internal.databinding.Util;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * @since 1.0
+ * 
+ */
+class ValueBinding : Binding {
+    private final UpdateValueStrategy targetToModel;
+    private final UpdateValueStrategy modelToTarget;
+    private WritableValue validationStatusObservable;
+    private IObservableValue target;
+    private IObservableValue model;
+
+    private bool updatingTarget;
+    private bool updatingModel;
+    private IValueChangeListener targetChangeListener = new class() IValueChangeListener {
+        public void handleValueChange(ValueChangeEvent event) {
+            if (!updatingTarget && !Util.equals(event.diff.getOldValue(), event.diff.getNewValue())) {
+                doUpdate(target, model, targetToModel, false, false);
+            }
+        }
+    };
+    private IValueChangeListener modelChangeListener = new class() IValueChangeListener {
+        public void handleValueChange(ValueChangeEvent event) {
+            if (!updatingModel && !Util.equals(event.diff.getOldValue(), event.diff.getNewValue())) {
+                doUpdate(model, target, modelToTarget, false, false);
+            }
+        }
+    };
+
+    /**
+     * @param targetObservableValue
+     * @param modelObservableValue
+     * @param targetToModel
+     * @param modelToTarget
+     */
+    public this(IObservableValue targetObservableValue,
+            IObservableValue modelObservableValue,
+            UpdateValueStrategy targetToModel, UpdateValueStrategy modelToTarget) {
+        super(targetObservableValue, modelObservableValue);
+        this.target = targetObservableValue;
+        this.model = modelObservableValue;
+        this.targetToModel = targetToModel;
+        this.modelToTarget = modelToTarget;
+        if ((targetToModel.getUpdatePolicy() & (UpdateValueStrategy.POLICY_CONVERT | UpdateValueStrategy.POLICY_UPDATE)) !is 0) {
+            target.addValueChangeListener(targetChangeListener);
+        } else {
+            targetChangeListener = null;
+        }
+        if ((modelToTarget.getUpdatePolicy() & (UpdateValueStrategy.POLICY_CONVERT | UpdateValueStrategy.POLICY_UPDATE)) !is 0) {
+            model.addValueChangeListener(modelChangeListener);
+        } else {
+            modelChangeListener = null;
+        }
+    }
+
+    protected void preInit() {
+        validationStatusObservable = new WritableValue(context
+                .getValidationRealm(), Status.OK_STATUS, IStatus.classinfo);
+    }
+
+    protected void postInit() {
+        if (modelToTarget.getUpdatePolicy() is UpdateValueStrategy.POLICY_UPDATE) {
+            updateModelToTarget();
+        }
+        if (targetToModel.getUpdatePolicy() !is UpdateValueStrategy.POLICY_NEVER) {
+            validateTargetToModel();
+        }
+    }
+
+    public IObservableValue getValidationStatus() {
+        return validationStatusObservable;
+    }
+
+    public void updateTargetToModel() {
+        doUpdate(target, model, targetToModel, true, false);
+    }
+
+    public void updateModelToTarget() {
+        doUpdate(model, target, modelToTarget, true, false);
+    }
+
+    /**
+     * Incorporates the provided <code>newStats</code> into the
+     * <code>multieStatus</code>.
+     * 
+     * @param multiStatus
+     * @param newStatus
+     * @return <code>true</code> if the update should proceed
+     */
+    /* package */bool mergeStatus(MultiStatus multiStatus, IStatus newStatus) {
+        if (!newStatus.isOK()) {
+            multiStatus.add(newStatus);
+            return multiStatus.getSeverity() < IStatus.ERROR;
+        }
+        return true;
+    }
+
+    /*
+     * This method may be moved to UpdateValueStrategy in the future if clients
+     * need more control over how the source value is copied to the destination
+     * observable.
+     */
+    private void doUpdate(IObservableValue source,
+            IObservableValue destination,
+            UpdateValueStrategy updateValueStrategy,
+            bool explicit, bool validateOnly) {
+
+        final int policy = updateValueStrategy.getUpdatePolicy();
+        if (policy is UpdateValueStrategy.POLICY_NEVER)
+            return;
+        if (policy is UpdateValueStrategy.POLICY_ON_REQUEST && !explicit)
+            return;
+
+        source.getRealm().exec(dgRunnable((
+                        IObservableValue source_,
+                        IObservableValue destination_,
+                        UpdateValueStrategy updateValueStrategy_,
+                        bool explicit_, bool validateOnly_) {
+            bool destinationRealmReached = false;
+            final MultiStatus multiStatus = BindingStatus.ok();
+            try {
+                // Get value
+                Object value = source_.getValue();
+
+                // Validate after get
+                IStatus status = updateValueStrategy_
+                        .validateAfterGet(value);
+                if (!mergeStatus(multiStatus, status))
+                    return;
+
+                // Convert value
+                final Object convertedValue = updateValueStrategy_
+                        .convert(value);
+
+                // Validate after convert
+                status = updateValueStrategy_
+                        .validateAfterConvert(convertedValue);
+                if (!mergeStatus(multiStatus, status))
+                    return;
+                if (policy is UpdateValueStrategy.POLICY_CONVERT
+                        && !explicit_)
+                    return;
+
+                // Validate before set
+                status = updateValueStrategy_
+                        .validateBeforeSet(convertedValue);
+                if (!mergeStatus(multiStatus, status))
+                    return;
+                if (validateOnly_)
+                    return;
+
+                // Set value
+                destinationRealmReached = true;
+                destination_.getRealm().exec(dgRunnable((
+                                IObservableValue destination__,
+                                UpdateValueStrategy updateValueStrategy__) {
+                    if (destination__ is target) {
+                        updatingTarget = true;
+                    } else {
+                        updatingModel = true;
+                    }
+                    try {
+                        IStatus setterStatus = updateValueStrategy__
+                                .doSet(destination__, convertedValue);
+
+                        mergeStatus(multiStatus, setterStatus);
+                    } finally {
+                        if (destination__ is target) {
+                            updatingTarget = false;
+                        } else {
+                            updatingModel = false;
+                        }
+                        setValidationStatus(multiStatus);
+                    }
+                }, destination_, updateValueStrategy_ ));
+            } catch (Exception ex) {
+                // This check is necessary as in 3.2.2 Status
+                // doesn't accept a null message (bug 177264).
+                String message = (ex.getMessage() !is null) ? ex
+                        .getMessage() : ""; //$NON-NLS-1$
+
+                mergeStatus(multiStatus, new Status(IStatus.ERROR,
+                        Policy.JFACE_DATABINDING, IStatus.ERROR, message,
+                        ex));
+            } finally {
+                if (!destinationRealmReached) {
+                    setValidationStatus(multiStatus);
+                }
+
+            }
+        }, source, destination, updateValueStrategy, explicit, validateOnly));
+    }
+
+    public void validateModelToTarget() {
+        doUpdate(model, target, modelToTarget, true, true);
+    }
+
+    public void validateTargetToModel() {
+        doUpdate(target, model, targetToModel, true, true);
+    }
+
+    private void setValidationStatus( IStatus status) {
+        validationStatusObservable.getRealm().exec(dgRunnable((IStatus status_) {
+            validationStatusObservable.setValue(status_);
+        }, status));
+    }
+    
+    public void dispose() {
+        if (targetChangeListener !is null) {
+            target.removeValueChangeListener(targetChangeListener);
+            targetChangeListener = null;
+        }
+        if (modelChangeListener !is null) {
+            model.removeValueChangeListener(modelChangeListener);
+            modelChangeListener = null;
+        }
+        target = null;
+        model = null;
+        super.dispose();
+    }
+
+}