| /******************************************************************************* |
| * Copyright (c) 2006 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.jface.internal.databinding.provisional.observable.mapping; |
| |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.jface.internal.databinding.provisional.observable.IObservable; |
| import org.eclipse.jface.internal.databinding.provisional.observable.set.IObservableSet; |
| import org.eclipse.jface.internal.databinding.provisional.observable.set.ISetChangeListener; |
| import org.eclipse.jface.internal.databinding.provisional.observable.set.SetDiff; |
| import org.eclipse.jface.internal.databinding.provisional.observable.set.WritableSet; |
| |
| /** |
| * @since 1.0 |
| * |
| */ |
| public class BidirectionalMapping extends AbstractObservableMapping implements |
| IBidirectionalMapping, IObservableMappingWithDomain { |
| |
| private final IObservableMapping wrappedMapping; |
| |
| private IObservableSet range; |
| |
| private Map valueToElements = new HashMap(); |
| |
| private ISetChangeListener domainListener = new ISetChangeListener() { |
| public void handleSetChange(IObservableSet source, SetDiff diff) { |
| Set rangeAdditions = new HashSet(); |
| for (Iterator it = diff.getAdditions().iterator(); it.hasNext();) { |
| Object added = it.next(); |
| Object mappingValue = wrappedMapping.getMappingValue(added); |
| rangeAdditions.add(mappingValue); |
| addMapping(mappingValue, added); |
| } |
| range.addAll(rangeAdditions); |
| for (Iterator it = diff.getRemovals().iterator(); it.hasNext();) { |
| Object removed = it.next(); |
| removeMapping(wrappedMapping.getMappingValue(removed), removed); |
| } |
| range.retainAll(valueToElements.keySet()); |
| } |
| }; |
| |
| private IMappingChangeListener mappingChangeListener = new IMappingChangeListener() { |
| public void handleMappingValueChange(IObservable source, |
| MappingDiff diff) { |
| Set affectedElements = diff.getElements(); |
| for (Iterator it = affectedElements.iterator(); it.hasNext();) { |
| Object element = it.next(); |
| Object oldFunctionValue = diff.getOldMappingValues(element, |
| new int[0])[0]; |
| Object newFunctionValue = diff.getNewMappingValues(element, |
| new int[0])[0]; |
| removeMapping(oldFunctionValue, element); |
| addMapping(newFunctionValue, element); |
| } |
| Set tempRange = valueToElements.keySet(); |
| range.addAll(tempRange); |
| range.retainAll(tempRange); |
| fireMappingValueChange(diff); |
| } |
| }; |
| |
| private IObservableSet domain; |
| |
| /** |
| * @param functionWithDomain |
| */ |
| public BidirectionalMapping(IObservableMappingWithDomain functionWithDomain) { |
| this(functionWithDomain, functionWithDomain.getDomain()); |
| } |
| |
| /** |
| * @param wrappedMapping |
| * @param domain |
| */ |
| public BidirectionalMapping(IObservableMapping wrappedMapping, |
| IObservableSet domain) { |
| this.wrappedMapping = wrappedMapping; |
| this.domain = domain; |
| Set tempRange = new HashSet(); |
| for (Iterator it = domain.iterator(); it.hasNext();) { |
| Object element = it.next(); |
| Object functionValue = wrappedMapping.getMappingValue(element); |
| addMapping(functionValue, element); |
| tempRange.add(functionValue); |
| } |
| this.range = new WritableSet(tempRange); |
| domain.addSetChangeListener(domainListener); |
| } |
| |
| /** |
| * @param functionValue |
| * @param element |
| * @param b |
| */ |
| private void addMapping(Object functionValue, Object element) { |
| Object elementOrSet = valueToElements.get(functionValue); |
| if (elementOrSet == null) { |
| valueToElements.put(functionValue, element); |
| return; |
| } |
| if (!(elementOrSet instanceof Set)) { |
| elementOrSet = new HashSet(Collections.singleton(elementOrSet)); |
| valueToElements.put(functionValue, elementOrSet); |
| } |
| Set set = (Set) elementOrSet; |
| set.add(element); |
| } |
| |
| /** |
| * @param functionValue |
| * @param element |
| * @param b |
| */ |
| private void removeMapping(Object functionValue, Object element) { |
| Object elementOrSet = valueToElements.get(functionValue); |
| if (elementOrSet instanceof Set) { |
| Set set = (Set) elementOrSet; |
| set.remove(element); |
| if (set.size() == 0) { |
| valueToElements.remove(functionValue); |
| } |
| } else { |
| valueToElements.remove(functionValue); |
| } |
| } |
| |
| protected Object doGetMappingValue(Object element) { |
| return wrappedMapping.getMappingValue(element); |
| } |
| |
| public void setMappingValue(Object element, Object value) { |
| wrappedMapping.setMappingValue(element, value); |
| } |
| |
| public IObservableSet getRange() { |
| return range; |
| } |
| |
| public Set getDomainElementsForValue(Object value) { |
| return null; |
| } |
| |
| public void dispose() { |
| wrappedMapping.removeMappingChangeListener(mappingChangeListener); |
| domain.removeSetChangeListener(domainListener); |
| } |
| |
| public IObservableSet getDomain() { |
| return domain; |
| } |
| |
| public Object getValueType() { |
| return wrappedMapping.getValueType(); |
| } |
| |
| } |