/****************************************************************************** * Copyright (c) 2015, 2016 itemis AG 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: * Alexander Nyßen (itemis AG) - initial API and implementation * *******************************************************************************/ package org.eclipse.gef.common.beans.binding; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.gef.common.beans.value.ObservableMultisetValue; import org.eclipse.gef.common.collections.CollectionUtils; import org.eclipse.gef.common.collections.ObservableMultiset; import com.google.common.collect.Multiset; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; import javafx.beans.binding.ListExpression; import javafx.beans.binding.MapExpression; import javafx.beans.binding.SetExpression; import javafx.beans.binding.StringBinding; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyIntegerProperty; /** * A {@code SetMultimapExpression} is a {@link ObservableMultisetValue} plus * additional convenience methods to generate bindings. * <p> * This class provides identical functionality for {@link Multiset} as * {@link MapExpression} for {@link Map}, {@link SetExpression} for {@link Set}, * or {@link ListExpression} for {@link List}. * * @author anyssen * * @param <E> * The element type of the {@link ObservableMultiset}. */ public abstract class MultisetExpression<E> implements ObservableMultisetValue<E> { private static final class MultisetBindingImpl<E> extends MultisetBinding<E> { private ObservableMultisetValue<E> multisetValue = null; public MultisetBindingImpl(ObservableMultisetValue<E> multisetValue) { this.multisetValue = multisetValue; bind(multisetValue); } @Override protected ObservableMultiset<E> computeValue() { return multisetValue.get(); } } /** * Returns a {@code MultisetExpression} that wraps an * {@link ObservableMultisetValue}. If the {@code ObservableMultisetValue} * is already a {@code MultisetExpression}, it will be returned. Otherwise a * new concrete {@link MultisetBinding} is created that is bound to the * {@code ObservableMultisetValue}. * * @param <E> * The element type of the {@link MultisetExpression}. * * @param multisetValue * The {@code ObservableMultisetValue} for which to return a * {@link MultisetExpression}. * @return The passed in {@link ObservableMultisetValue} if its already a * {@link MultisetExpression}, or a newly created * {@link MultisetBinding} for it. */ public static <E> MultisetExpression<E> multisetExpression( final ObservableMultisetValue<E> multisetValue) { if (multisetValue == null) { throw new IllegalArgumentException( "multisetValue may not be null."); } if (multisetValue instanceof MultisetExpression) { return (MultisetExpression<E>) multisetValue; } return new MultisetBindingImpl<>(multisetValue); } private final ObservableMultiset<E> EMPTY_MULTISET = CollectionUtils .emptyMultiset(); @Override public boolean add(E element) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.add(element) : multiset.add(element); } @Override public int add(E element, int occurrences) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.add(element, occurrences) : multiset.add(element, occurrences); } @Override public boolean addAll(Collection<? extends E> c) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.addAll(c) : multiset.addAll(c); } /** * Creates a {@link StringBinding} that holds the value of the * {@link MultisetExpression} turned into a {@link String}. If the value of * this {@code SetMultimapExpression} changes, the value of the * {@link StringBinding} will be updated automatically. * * @return A new {@code StringBinding}. */ public StringBinding asString() { return (StringBinding) Bindings.convert(this); } @Override public void clear() { final Multiset<E> multiset = get(); if (multiset == null) { EMPTY_MULTISET.clear(); } else { multiset.clear(); } } @Override public boolean contains(Object element) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.contains(element) : multiset.contains(element); } @Override public boolean containsAll(Collection<?> elements) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.containsAll(elements) : multiset.containsAll(elements); } @Override public int count(Object element) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.count(element) : multiset.count(element); } @Override public Set<E> elementSet() { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.elementSet() : multiset.elementSet(); } /** * A boolean property that reflects whether the {@link Multiset} is empty. * * @return A read-only property. * */ public abstract ReadOnlyBooleanProperty emptyProperty(); @Override public Set<com.google.common.collect.Multiset.Entry<E>> entrySet() { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.entrySet() : multiset.entrySet(); } @Override public ObservableMultiset<E> getValue() { return get(); } @Override public boolean isEmpty() { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.isEmpty() : multiset.isEmpty(); } /** * Creates a new {@link BooleanBinding} that indicates whether this * {@link ObservableMultiset} is equal to the passed in * {@link ObservableMultiset}. * * @param other * The {@link ObservableMultiset} to compare this * {@link ObservableMultiset} to. * @return A new {@code BooleanBinding}. */ public BooleanBinding isEqualTo(final ObservableMultiset<?> other) { return Bindings.equal(this, other); } /** * Creates a new {@link BooleanBinding} that indicates whether this * {@link ObservableMultiset} is not equal to the passed in * {@link ObservableMultiset}. * * @param other * The {@link ObservableMultiset} to compare this * {@link ObservableMultiset} to. * @return A new {@code BooleanBinding}. */ public BooleanBinding isNotEqualTo(final ObservableMultiset<?> other) { return Bindings.notEqual(this, other); } /** * Creates a new {@link BooleanBinding} that indicates if the wrapped * {@link ObservableMultiset} is not <code>null</code>. * * @return A new {@code BooleanBinding}. */ public BooleanBinding isNotNull() { return Bindings.isNotNull(this); } /** * Creates a new {@link BooleanBinding} that indicates if the wrapped * {@link ObservableMultiset} is <code>null</code>. * * @return A new {@code BooleanBinding}. */ public BooleanBinding isNull() { return Bindings.isNull(this); } @Override public Iterator<E> iterator() { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.iterator() : multiset.iterator(); } @Override public boolean remove(Object element) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.remove(element) : multiset.remove(element); } @Override public int remove(Object element, int occurrences) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.remove(element, occurrences) : multiset.remove(element, occurrences); } @Override public boolean removeAll(Collection<?> c) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.removeAll(c) : multiset.removeAll(c); } @Override public boolean replaceAll(Multiset<? extends E> multiset) { final ObservableMultiset<E> delegate = get(); return (delegate == null) ? EMPTY_MULTISET.replaceAll(multiset) : delegate.replaceAll(multiset); } @Override public boolean retainAll(Collection<?> c) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.retainAll(c) : multiset.retainAll(c); } @Override public int setCount(E element, int count) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.setCount(element, count) : multiset.setCount(element, count); } @Override public boolean setCount(E element, int oldCount, int newCount) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.setCount(element, oldCount, newCount) : multiset.setCount(element, oldCount, newCount); } @Override public int size() { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.size() : multiset.size(); } /** * An integer property that represents the size of the {@link Multiset}. * * @return A read-only property. */ public abstract ReadOnlyIntegerProperty sizeProperty(); @Override public Object[] toArray() { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.toArray() : multiset.toArray(); } @Override public <T> T[] toArray(T[] a) { final Multiset<E> multiset = get(); return (multiset == null) ? EMPTY_MULTISET.toArray(a) : multiset.toArray(a); } }