Mercurial > projects > dwt2
diff org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/Diffs.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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/Diffs.d Tue Apr 14 11:35:29 2009 +0200 @@ -0,0 +1,527 @@ +/******************************************************************************* + * Copyright (c) 2006, 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 226216 + *******************************************************************************/ + +module org.eclipse.core.databinding.observable.Diffs; + +import java.lang.all; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import org.eclipse.core.databinding.observable.list.ListDiff; +import org.eclipse.core.databinding.observable.list.ListDiffEntry; +import org.eclipse.core.databinding.observable.map.MapDiff; +import org.eclipse.core.databinding.observable.set.SetDiff; +import org.eclipse.core.databinding.observable.value.ValueDiff; +import org.eclipse.core.internal.databinding.Util; + +/** + * @since 1.0 + * + */ +public class Diffs { + + /** + * @param oldList + * @param newList + * @return the differences between oldList and newList + */ + public static ListDiff computeListDiff(List oldList, List newList) { + List diffEntries = new ArrayList(); + createListDiffs(new ArrayList(oldList), newList, diffEntries); + ListDiff listDiff = createListDiff(cast(ListDiffEntry[]) diffEntries + .toArray(new ListDiffEntry[diffEntries.size()])); + return listDiff; + } + + /** + * adapted from EMF's ListDifferenceAnalyzer + */ + private static void createListDiffs(List oldList, List newList, + List listDiffs) { + int index = 0; + for (Iterator it = newList.iterator(); it.hasNext();) { + Object newValue = it.next(); + if (oldList.size() <= index) { + // append newValue to newList + listDiffs.add(createListDiffEntry(index, true, newValue)); + } else { + bool done; + do { + done = true; + Object oldValue = oldList.get(index); + if (oldValue is null ? newValue !is null : !oldValue.equals(newValue)) { + int oldIndexOfNewValue = listIndexOf(oldList, newValue, index); + if (oldIndexOfNewValue !is -1) { + int newIndexOfOldValue = listIndexOf(newList, oldValue, index); + if (newIndexOfOldValue is -1) { + // removing oldValue from list[index] + listDiffs.add(createListDiffEntry(index, false, oldValue)); + oldList.remove(index); + done = false; + } else if (newIndexOfOldValue > oldIndexOfNewValue) { + // moving oldValue from list[index] to [newIndexOfOldValue] + if (oldList.size() <= newIndexOfOldValue) { + // The element cannot be moved to the correct index + // now, however later iterations will insert elements + // in front of it, eventually moving it into the + // correct spot. + newIndexOfOldValue = oldList.size() - 1; + } + listDiffs.add(createListDiffEntry(index, false, oldValue)); + oldList.remove(index); + listDiffs.add(createListDiffEntry(newIndexOfOldValue, true, oldValue)); + oldList.add(newIndexOfOldValue, oldValue); + done = false; + } else { + // move newValue from list[oldIndexOfNewValue] to [index] + listDiffs.add(createListDiffEntry(oldIndexOfNewValue, false, newValue)); + oldList.remove(oldIndexOfNewValue); + listDiffs.add(createListDiffEntry(index, true, newValue)); + oldList.add(index, newValue); + } + } else { + // add newValue at list[index] + oldList.add(index, newValue); + listDiffs.add(createListDiffEntry(index, true, newValue)); + } + } + } while (!done); + } + ++index; + } + for (int i = oldList.size(); i > index;) { + // remove excess trailing elements not present in newList + listDiffs.add(createListDiffEntry(--i, false, oldList.get(i))); + } + } + + /** + * @param list + * @param object + * @param index + * @return the index, or -1 if not found + */ + private static int listIndexOf(List list, Object object, int index) { + int size = list.size(); + for (int i=index; i<size;i++) { + Object candidate = list.get(i); + if (candidateisnull ? objectisnull : candidate.equals(object)) { + return i; + } + } + return -1; + } + + /** + * Checks whether the two objects are <code>null</code> -- allowing for + * <code>null</code>. + * + * @param left + * The left object to compare; may be <code>null</code>. + * @param right + * The right object to compare; may be <code>null</code>. + * @return <code>true</code> if the two objects are equivalent; + * <code>false</code> otherwise. + */ + public static final bool equals(Object left, Object right) { + return left is null ? right is null : ((right !is null) && left + .equals(right)); + } + + /** + * @param oldSet + * @param newSet + * @return a set diff + */ + public static SetDiff computeSetDiff(Set oldSet, Set newSet) { + Set additions = new HashSet(newSet); + additions.removeAll(oldSet); + Set removals = new HashSet(oldSet); + removals.removeAll(newSet); + return createSetDiff(additions, removals); + } + + /** + * Computes the difference between two maps. + * + * @param oldMap + * @param newMap + * @return a map diff representing the changes needed to turn oldMap into + * newMap + */ + public static MapDiff computeMapDiff(Map oldMap, Map newMap) { + // starts out with all keys from the new map, we will remove keys from + // the old map as we go + final Set addedKeys = new HashSet(newMap.keySet()); + final Set removedKeys = new HashSet(); + final Set changedKeys = new HashSet(); + final Map oldValues = new HashMap(); + final Map newValues = new HashMap(); + for (Iterator it = oldMap.entrySet().iterator(); it.hasNext();) { + Map.Entry oldEntry = cast(Entry) it.next(); + Object oldKey = oldEntry.getKey(); + if (addedKeys.remove(oldKey)) { + // potentially changed key since it is in oldMap and newMap + Object oldValue = oldEntry.getValue(); + Object newValue = newMap.get(oldKey); + if (!Util.equals(oldValue, newValue)) { + changedKeys.add(oldKey); + oldValues.put(oldKey, oldValue); + newValues.put(oldKey, newValue); + } + } else { + removedKeys.add(oldKey); + oldValues.put(oldKey, oldEntry.getValue()); + } + } + for (Iterator it = addedKeys.iterator(); it.hasNext();) { + Object newKey = it.next(); + newValues.put(newKey, newMap.get(newKey)); + } + return new class() MapDiff { + public Set getAddedKeys() { + return addedKeys; + } + + public Set getChangedKeys() { + return changedKeys; + } + + public Set getRemovedKeys() { + return removedKeys; + } + + public Object getNewValue(Object key) { + return newValues.get(key); + } + + public Object getOldValue(Object key) { + return oldValues.get(key); + } + }; + } + + /** + * @param oldValue + * @param newValue + * @return a value diff + */ + public static ValueDiff createValueDiff(Object oldValue, + Object newValue) { + return new class(oldValue, newValue) ValueDiff { + Object oldValue_, newValue_; + this(Object a, Object b){ + oldValue_=a; + newValue_=b; + } + + public Object getOldValue() { + return oldValue_; + } + + public Object getNewValue() { + return newValue_; + } + }; + } + + /** + * @param additions + * @param removals + * @return a set diff + */ + public static SetDiff createSetDiff(Set additions, Set removals) { + return new class() SetDiff { + Set unmodifiableAdditions; + Set unmodifiableRemovals; + this(){ + unmodifiableAdditions = Collections + .unmodifiableSet(additions); + unmodifiableRemovals = Collections.unmodifiableSet(removals); + } + + public Set getAdditions() { + return unmodifiableAdditions; + } + + public Set getRemovals() { + return unmodifiableRemovals; + } + }; + } + + /** + * @param difference + * @return a list diff with one differing entry + */ + public static ListDiff createListDiff(ListDiffEntry difference) { + return createListDiff([ difference ]); + } + + /** + * @param difference1 + * @param difference2 + * @return a list diff with two differing entries + */ + public static ListDiff createListDiff(ListDiffEntry difference1, + ListDiffEntry difference2) { + return createListDiff([ difference1, difference2 ]); + } + + /** + * @param differences + * @return a list diff with the given entries + */ + public static ListDiff createListDiff(ListDiffEntry[] differences) { + return new class() ListDiff { + ListDiffEntry[] differences_; + this(){ + differences_=differences; + } + public ListDiffEntry[] getDifferences() { + return differences_; + } + }; + } + + /** + * @param position + * @param isAddition + * @param element + * @return a list diff entry + */ + public static ListDiffEntry createListDiffEntry(int position, + bool isAddition, Object element) { + return new class() ListDiffEntry { + int position_; + bool isAddition_; + Object element_; + this(){ + position_=position; + isAddition_=isAddition; + element_=element; + } + + public int getPosition() { + return position_; + } + + public bool isAddition() { + return isAddition_; + } + + public Object getElement() { + return element_; + } + }; + } + + /** + * @param addedKey + * @param newValue + * @return a map diff + */ + public static MapDiff createMapDiffSingleAdd(Object addedKey, + Object newValue) { + return new class() MapDiff { + Object addedKey_, newValue_; + this(){ + addedKey_=addedKey; + newValue_=newValue; + } + + public Set getAddedKeys() { + return Collections.singleton(addedKey_); + } + + public Set getChangedKeys() { + return Collections.EMPTY_SET; + } + + public Object getNewValue(Object key) { + return newValue_; + } + + public Object getOldValue(Object key) { + return null; + } + + public Set getRemovedKeys() { + return Collections.EMPTY_SET; + } + }; + } + + /** + * @param existingKey + * @param oldValue + * @param newValue + * @return a map diff + */ + public static MapDiff createMapDiffSingleChange(Object existingKey, + Object oldValue, Object newValue) { + return new class() MapDiff { + Object existingKey_; + Object oldValue_; + Object newValue_; + this(){ + existingKey_=existingKey; + oldValue_=oldValue; + newValue_=newValue; + } + public Set getAddedKeys() { + return Collections.EMPTY_SET; + } + + public Set getChangedKeys() { + return Collections.singleton(existingKey_); + } + + public Object getNewValue(Object key) { + return newValue_; + } + + public Object getOldValue(Object key) { + return oldValue_; + } + + public Set getRemovedKeys() { + return Collections.EMPTY_SET; + } + }; + } + + /** + * @param removedKey + * @param oldValue + * @return a map diff + */ + public static MapDiff createMapDiffSingleRemove(Object removedKey, + Object oldValue) { + return new class() MapDiff { + Object removedKey_; + Object oldValue_; + this(){ + removedKey_=removedKey; + oldValue_=oldValue; + } + + public Set getAddedKeys() { + return Collections.EMPTY_SET; + } + + public Set getChangedKeys() { + return Collections.EMPTY_SET; + } + + public Object getNewValue(Object key) { + return null; + } + + public Object getOldValue(Object key) { + return oldValue_; + } + + public Set getRemovedKeys() { + return Collections.singleton(removedKey_); + } + }; + } + + /** + * @param copyOfOldMap + * @return a map diff + */ + public static MapDiff createMapDiffRemoveAll(Map copyOfOldMap) { + return new class() MapDiff { + Map copyOfOldMap_; + this(){ + copyOfOldMap_=copyOfOldMap; + } + + public Set getAddedKeys() { + return Collections.EMPTY_SET; + } + + public Set getChangedKeys() { + return Collections.EMPTY_SET; + } + + public Object getNewValue(Object key) { + return null; + } + + public Object getOldValue(Object key) { + return copyOfOldMap_.get(key); + } + + public Set getRemovedKeys() { + return copyOfOldMap_.keySet(); + } + }; + } + + /** + * @param addedKeys + * @param removedKeys + * @param changedKeys + * @param oldValues + * @param newValues + * @return a map diff + */ + public static MapDiff createMapDiff(Set addedKeys, + Set removedKeys, Set changedKeys, Map oldValues, + Map newValues) { + return new class() MapDiff { + Set addedKeys_; + Set removedKeys_; + Set changedKeys_; + Map oldValues_; + Map newValues_; + this(){ + addedKeys_=addedKeys; + removedKeys_=removedKeys; + changedKeys_=changedKeys; + oldValues_=oldValues; + newValues_=newValues; + } + + public Set getAddedKeys() { + return addedKeys_; + } + + public Set getChangedKeys() { + return changedKeys_; + } + + public Object getNewValue(Object key) { + return newValues_.get(key); + } + + public Object getOldValue(Object key) { + return oldValues_.get(key); + } + + public Set getRemovedKeys() { + return removedKeys_; + } + }; + } +}