/***************************************************************************** * Copyright (c) 2010 CEA LIST. * * 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: * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation *****************************************************************************/ package org.eclipse.papyrus.infra.tools.databinding; import java.util.Collection; import java.util.LinkedList; import java.util.List; import org.eclipse.core.databinding.observable.ChangeEvent; import org.eclipse.core.databinding.observable.IChangeListener; import org.eclipse.core.databinding.observable.IObservable; import org.eclipse.core.databinding.observable.value.AbstractObservableValue; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.core.databinding.observable.value.ValueDiff; /** * MultipleObservableValue is used to map a single element * to a collection of model elements. * * It is especially used when displaying a Property View for multiple elements, * when we want to edit the same property for all of them. * * All sub-elements will be edited at the same time, with the same value. */ //TODO : Add listeners on sub-observables, and remove them on dispose public class MultipleObservableValue extends AbstractObservableValue implements AggregatedObservable, IChangeListener { /** * * Constructor. * * @param values * The collection of sub-elements for this MultipleObservableValue * */ public MultipleObservableValue(Collection<IObservableValue> values) { if(values != null) { observableValues.addAll(values); } } /** * * Constructor. * */ public MultipleObservableValue() { } public Object getValueType() { if(observableValues.isEmpty()) { return null; } return observableValues.get(0).getValueType(); } /** * If all objects have the same value, returns this value * Otherwise, returns the defaultGetValue * If the defaultGetValue hasn't been set, returns null */ @Override protected Object doGetValue() { if(hasDifferentValues() || observableValues.isEmpty()) { return null; } return observableValues.get(0).getValue(); } private boolean equals(Object value, Object currentValue) { if(value == currentValue) { return true; } if(value == null) { return false; } return value.equals(currentValue); } @Override protected void doSetValue(Object value) { for(IObservableValue observable : observableValues) { observable.setValue(value); } } public AggregatedObservable aggregate(IObservable observable) { if(observable instanceof IObservableValue) { observableValues.add((IObservableValue)observable); observable.addChangeListener(this); return this; } return null; } /** * @return the list of sub-observable values */ public List<IObservableValue> getObservableValues() { return observableValues; } /** * @return the list of observed values */ public List<Object> getObservedValues() { List<Object> result = new LinkedList<Object>(); for(IObservableValue value : getObservableValues()) { result.add(value.getValue()); } return result; } @Override public synchronized void dispose() { super.dispose(); for(IObservableValue observable : observableValues) { observable.removeChangeListener(this); observable.dispose(); } } /** * The {@link IObservableValue}s aggregated by this Observable */ protected List<IObservableValue> observableValues = new LinkedList<IObservableValue>(); public boolean hasDifferentValues() { if(observableValues.isEmpty()) { return false; } Object currentValue = null; boolean firstValue = true; for(IObservableValue observable : observableValues) { if(firstValue) { firstValue = false; currentValue = observable.getValue(); } else { Object value = observable.getValue(); if(equals(value, currentValue)) { continue; } return true; } } return false; } public void handleChange(ChangeEvent event) { //We're not interested in the old and new values //We just return two different values so that a change event is fired super.fireValueChange(new ValueDiff() { @Override public Object getOldValue() { return true; } @Override public Object getNewValue() { return false; } }); } }