/*******************************************************************************
* Copyright (c) 2013 Pivotal Software, Inc.
* 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:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.dash.livexp;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
import org.springsource.ide.eclipse.commons.livexp.core.ObservableSet;
/**
* Represents a selection of zero or more elements of type T in some UI component.
*
* @author Kris De Volder
*/
public final class MultiSelection<T> {
public static <T> MultiSelection<T> empty(Class<T> type) {
return new MultiSelection<T>(type, LiveSets.emptySet(type));
}
/**
* Converts a 'single' selection to a multi selection.
*/
public static <T> MultiSelection<T> singletonOrEmpty(Class<T> type,
LiveExpression<T> singleSelection) {
return new MultiSelection<T>(type, LiveSets.singletonOrEmpty(singleSelection));
}
public static <T> MultiSelection<T> union(MultiSelection<T> a, MultiSelection<T> b) {
Assert.isLegal(a.getElementType().equals(b.getElementType()));
return from(a.getElementType(), LiveSets.union(a.getElements(), b.getElements()));
}
private final Class<T> elementType;
private final ObservableSet<T> elements;
public MultiSelection(Class<T> elementType, ObservableSet<T> elements) {
this.elementType = elementType;
this.elements = elements;
}
public Class<T> getElementType() {
return elementType;
}
/**
* Filter a selection to retain only elements of a given type.
*/
public <U> MultiSelection<U> filter(Class<U> retainType) {
MultiSelection<U> converted = this.as(retainType);
if (converted!=null) {
//Don't need to filter element-by-element since the selection only
// can contain elements of 'retainType'.
return converted;
} else {
//Selection may contain objects that are not instances of retainType.
return from(retainType, LiveSets.filter(getElements(), retainType));
}
}
/**
* Convert a selection of one type into a selection of a different
* type. The conversion only succeeds if the target-type is assignment
* compatible with the source type.
*
* @return Converted selection or null if the conversion is not legal.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public <U> MultiSelection<U> as(Class<U> toElementType) {
if (toElementType.isAssignableFrom(elementType)) {
return new MultiSelection<U>(toElementType, ((ObservableSet) elements));
} else {
return null;
}
}
/**
* Convert a selection of one type into a selection of a different
* type. The conversion only succeeds if the target-type is assignment
* compatible with the source type.
*
* @return Converted selection
*/
public <U> MultiSelection<U> cast(Class<U> toElementType) throws ClassCastException {
MultiSelection<U> converted = as(toElementType);
if (converted==null) {
throw new ClassCastException(getElementType().getName()+" => "+toElementType.getName());
}
return converted;
}
public ObservableSet<T> getElements() {
return elements;
}
public static <T> MultiSelection<T> from(Class<T> type, ObservableSet<T> elements) {
return new MultiSelection<>(type, elements);
}
public Set<T> getValue() {
return getElements().getValue();
}
/**
* @return The only element in the selection, if exactly one element is selected; or null
* otherwise.
*/
public T getSingle() {
Set<T> es = getValue();
if (es.size()==1) {
for (T t : es) {
return t;
}
}
return null;
}
/**
* Converts a 'multi' selection to a selection of a single element. The single selection
* will be the selected element of the multi-selection if exactly one element is
* currently selected, and 'null' otherwise.
*/
public LiveExpression<T> toSingleSelection() {
LiveExpression<T> singleSelect = new LiveExpression<T>() {
protected T compute() {
return MultiSelection.this.getSingle();
}
};
singleSelect.dependsOn(getElements());
return singleSelect;
}
}