view org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/ValidationStatusMap.d @ 78:0a55d2d5a946

Added file for databinding
author Frank Benoit <benoit@tionex.de>
date Tue, 14 Apr 2009 11:35:29 +0200
parents
children 6be48cf9f95c
line wrap: on
line source

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

module org.eclipse.core.internal.databinding.ValidationStatusMap;

import java.lang.all;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
import org.eclipse.core.databinding.observable.map.MapDiff;
import org.eclipse.core.databinding.observable.map.ObservableMap;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.runtime.IStatus;

/**
 * @since 1.0
 * 
 */
public class ValidationStatusMap : ObservableMap {

    private bool isDirty = true;

    private final WritableList bindings;

    private List dependencies = new ArrayList();

    private IChangeListener markDirtyChangeListener = new class() IChangeListener {
        public void handleChange(ChangeEvent event) {
            markDirty();
        }
    };

    /**
     * @param realm
     * @param bindings
     */
    public this(Realm realm, WritableList bindings) {
        super(realm, new HashMap());
        this.bindings = bindings;
        bindings.addChangeListener(markDirtyChangeListener);
    }

    protected void getterCalled() {
        recompute();
        super.getterCalled();
    }

    private void markDirty() {
        // since we are dirty, we don't need to listen anymore
        removeElementChangeListener();
        final Map oldMap = wrappedMap;
        // lazy computation of diff
        MapDiff mapDiff = new class() MapDiff {
            private MapDiff cachedDiff = null;

            private void ensureCached() {
                if (cachedDiff is null) {
                    recompute();
                    cachedDiff = Diffs.computeMapDiff(oldMap, wrappedMap);
                }
            }

            public Set getAddedKeys() {
                ensureCached();
                return cachedDiff.getAddedKeys();
            }

            public Set getChangedKeys() {
                ensureCached();
                return cachedDiff.getChangedKeys();
            }

            public Object getNewValue(Object key) {
                ensureCached();
                return cachedDiff.getNewValue(key);
            }

            public Object getOldValue(Object key) {
                ensureCached();
                return cachedDiff.getOldValue(key);
            }

            public Set getRemovedKeys() {
                ensureCached();
                return cachedDiff.getRemovedKeys();
            }
        };
        wrappedMap = new HashMap();
        isDirty = true;
        fireMapChange(mapDiff);
    }

    private void recompute() {
        if (isDirty) {
            Map newContents = new HashMap();
            for (Iterator it = bindings.iterator(); it.hasNext();) {
                Binding binding = cast(Binding) it.next();
                IObservableValue validationError = binding
                        .getValidationStatus();
                dependencies.add(validationError);
                validationError.addChangeListener(markDirtyChangeListener);
                IStatus validationStatusValue = cast(IStatus) validationError
                        .getValue();
                newContents.put(binding, validationStatusValue);
            }
            wrappedMap.putAll(newContents);
            isDirty = false;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.core.databinding.observable.list.ObservableList#dispose()
     */
    public void dispose() {
        bindings.removeChangeListener(markDirtyChangeListener);
        removeElementChangeListener();
        super.dispose();
    }

    private void removeElementChangeListener() {
        for (Iterator it = dependencies.iterator(); it.hasNext();) {
            IObservableValue observableValue = cast(IObservableValue) it.next();
            observableValue.removeChangeListener(markDirtyChangeListener);
        }
    }
    
    public synchronized void addChangeListener(IChangeListener listener) {
        // this ensures that the next change will be seen by the new listener.
        recompute();
        super.addChangeListener(listener);
    }
    
    public synchronized void addMapChangeListener(IMapChangeListener listener) {
        // this ensures that the next change will be seen by the new listener.
        recompute();
        super.addMapChangeListener(listener);
    }

}